From 366c0866c69f7653eeda563804d6e1bf3319735d Mon Sep 17 00:00:00 2001 From: TRACTION <19631364+iamtraction@users.noreply.github.com> Date: Sun, 13 Aug 2023 13:45:03 +0530 Subject: [PATCH 01/12] deps: update Signed-off-by: TRACTION <19631364+iamtraction@users.noreply.github.com> --- package.json | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/package.json b/package.json index 892ed2505..355793be5 100644 --- a/package.json +++ b/package.json @@ -18,32 +18,32 @@ "test": "eslint src --ext .ts" }, "devDependencies": { - "@types/discord-rpc": "^4.0.4", + "@types/discord-rpc": "^4.0.5", "@types/express": "^4.17.17", "@types/http-errors": "^2.0.1", "@types/jsdom": "^21.1.1", - "@types/node": "^20.1.2", - "@typescript-eslint/eslint-plugin": "^5.57.0", - "@typescript-eslint/parser": "^5.57.0", - "eslint": "^8.37.0", - "typescript": "^5.0.3" + "@types/node": "^20.4.10", + "@typescript-eslint/eslint-plugin": "^6.3.0", + "@typescript-eslint/parser": "^6.3.0", + "eslint": "^8.47.0", + "typescript": "^5.1.6" }, "dependencies": { - "@bastion/tesseract": "^5.0.1", + "@bastion/tesseract": "^5.0.3", "@discordjs/opus": "^0.9.0", "@iamtraction/google-translate": "^2.0.1", "@types/gamedig": "^4.0.1", "discord-rpc": "^4.0.1", - "dotenv": "^16.0.3", + "dotenv": "^16.3.1", "emoji-regex": "^10.2.1", "gamedig": "^4.0.6", - "jsdom": "^22.0.0", + "jsdom": "^22.1.0", "libsodium-wrappers": "^0.7.11", - "mathjs": "^11.7.0", + "mathjs": "^11.9.1", "play-dl": "^1.9.6", "r6api.js": "^4.4.1", - "undici": "^5.21.0", - "ytdl-core": "^4.11.3", + "undici": "^5.23.0", + "ytdl-core": "^4.11.5", "ytpl": "^2.3.0" }, "optionalDependencies": { From f8330e99ddab35102daa2209f180bbec1ef13e31 Mon Sep 17 00:00:00 2001 From: TRACTION <19631364+iamtraction@users.noreply.github.com> Date: Sun, 13 Aug 2023 13:45:25 +0530 Subject: [PATCH 02/12] version: 10.11.3 Signed-off-by: TRACTION <19631364+iamtraction@users.noreply.github.com> --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 355793be5..11129b373 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "bastion", - "version": "10.11.2", + "version": "10.11.3", "description": "Get an enhanced Discord experience!", "type": "module", "homepage": "https://bastion.traction.one", From 68cbb6e2591c67a384a72cf6db06c9bc8f1e8635 Mon Sep 17 00:00:00 2001 From: TRACTION <19631364+iamtraction@users.noreply.github.com> Date: Sun, 13 Aug 2023 13:49:25 +0530 Subject: [PATCH 03/12] github(SECURITY.md): update username Ref #1040 Signed-off-by: TRACTION <19631364+iamtraction@users.noreply.github.com> --- .github/SECURITY.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/SECURITY.md b/.github/SECURITY.md index f9f7538cd..8944fa086 100644 --- a/.github/SECURITY.md +++ b/.github/SECURITY.md @@ -11,7 +11,7 @@ ## Reporting a Vulnerability If you find a vulnerability in Bastion, join [Bastion HQ] and send a direct -message to **iamtraction#8383** with the details about the vulnerability and +message to **@iamtraction** with the details about the vulnerability and we will fix it as soon as practical. Once fixed, you will be credited with finding the vulnerability in the release From 13728ecca4a1e17c83297d9ebfa5dae56e0e4bfa Mon Sep 17 00:00:00 2001 From: TRACTION <19631364+iamtraction@users.noreply.github.com> Date: Tue, 15 Aug 2023 03:02:33 +0530 Subject: [PATCH 04/12] chore: linting Signed-off-by: TRACTION <19631364+iamtraction@users.noreply.github.com> --- src/commands/comic/xkcd.ts | 14 +++++------ src/commands/gamestats/aimlab.ts | 29 +++++++++++++++++++--- src/commands/gamestats/apex.ts | 28 +++++++++++++++++++-- src/commands/gamestats/csgo.ts | 26 ++++++++++++++++++-- src/commands/gamestats/fortnite.ts | 13 ++++++++-- src/commands/gamestats/overwatch.ts | 17 ++++++++++++- src/commands/gamestats/valorant.ts | 34 ++++++++++++++++++++++++-- src/commands/search/anime.ts | 2 +- src/commands/search/apod.ts | 14 +++++------ src/commands/search/cryptocurrency.ts | 4 +-- src/commands/search/definitions.ts | 2 +- src/commands/search/game.ts | 30 +++++++++++------------ src/commands/search/manga.ts | 2 +- src/commands/search/movie.ts | 8 +++--- src/commands/search/pokemon.ts | 26 ++++++++++---------- src/commands/search/tv.ts | 8 +++--- src/commands/search/urbanDictionary.ts | 2 +- src/commands/search/weather.ts | 26 ++++++++++---------- src/commands/search/wikipedia.ts | 2 +- src/schedulers/liveStreams.ts | 2 +- src/types.ts | 8 +++--- 21 files changed, 209 insertions(+), 88 deletions(-) diff --git a/src/commands/comic/xkcd.ts b/src/commands/comic/xkcd.ts index 1e8ce6f83..645babb72 100644 --- a/src/commands/comic/xkcd.ts +++ b/src/commands/comic/xkcd.ts @@ -8,14 +8,14 @@ import { Command } from "@bastion/tesseract"; import * as requests from "../../utils/requests.js"; interface XKCD { - title: string; + title?: string; safe_title?: string; - alt: string; - num: string; - day: number; - month: number; - year: number; - img: string; + alt?: string; + num?: string; + day?: number; + month?: number; + year?: number; + img?: string; } class XKCDCommand extends Command { diff --git a/src/commands/gamestats/aimlab.ts b/src/commands/gamestats/aimlab.ts index 1f4ff695e..cf0adf317 100644 --- a/src/commands/gamestats/aimlab.ts +++ b/src/commands/gamestats/aimlab.ts @@ -8,6 +8,27 @@ import { Command } from "@bastion/tesseract"; import * as requests from "../../utils/requests.js"; import { COLORS } from "../../utils/constants.js"; +interface AimLabResponse { + data?: { + aimlabProfile: { + username: string; + ranking: { + rank: { + displayName: string; + level: number; + minSkill: number; + maxSkill: number; + }; + skill: number; + }; + skillScores: { + name: string; + score: number; + }[]; + }; + }; +} + class AimLabCommand extends Command { constructor() { super({ @@ -54,15 +75,15 @@ class AimLabCommand extends Command { }, }); - const body = await response.body.json(); + const body: AimLabResponse = await response.body.json(); if (!body?.data?.aimlabProfile) { return await interaction.editReply(`The profile for **${ username }** was not found.`); } - const skillScores = body.data.aimlabProfile?.skillScores?.length ? body.data.aimlabProfile.skillScores.map((skill: { name: string; score: string }) => ({ + const skillScores = body.data.aimlabProfile?.skillScores?.length ? body.data.aimlabProfile.skillScores.map(skill => ({ name: skill.name[0].toUpperCase() + skill.name.slice(1), - value: (skill.score as unknown as number).toFixed(), + value: skill.score.toFixed(), inline: true, })) : []; @@ -83,7 +104,7 @@ class AimLabCommand extends Command { }, { name: "Skill Rating", - value: (body.data.aimlabProfile?.ranking?.skill as unknown as number)?.toFixed(), + value: body.data.aimlabProfile?.ranking?.skill?.toFixed(), inline: true, }, { diff --git a/src/commands/gamestats/apex.ts b/src/commands/gamestats/apex.ts index e3b347ede..4dea69e10 100644 --- a/src/commands/gamestats/apex.ts +++ b/src/commands/gamestats/apex.ts @@ -9,6 +9,30 @@ import * as requests from "../../utils/requests.js"; import { COLORS } from "../../utils/constants.js"; import Settings from "../../utils/settings.js"; +interface ApexProfileResponse { + data?: { + platformInfo: { + platformUserHandle: string; + avatarUrl: string; + }; + segments: { + type: string; + stats: { + rankScore: { + displayValue: string; + metadata: { + rankName: string; + iconUrl: string; + }; + }; + }; + }[]; + metadata: { + activeLegendName: string; + }; + }; +} + class ApexLegendsCommand extends Command { constructor() { super({ @@ -46,8 +70,8 @@ class ApexLegendsCommand extends Command { "TRN-Api-Key": ((interaction.client as Client).settings as Settings).get("trackerNetworkApiKey"), }); - const body = await response.body.json(); - const overview = body?.data?.segments?.find((s: { type: string }) => s.type === "overview"); + const body: ApexProfileResponse = await response.body.json(); + const overview = body?.data?.segments?.find(s => s.type === "overview"); if (!Object.keys(overview?.stats || {})?.length) return await interaction.editReply(`The profile for **${ username }** was not found in the specified platform.`); diff --git a/src/commands/gamestats/csgo.ts b/src/commands/gamestats/csgo.ts index d87f88949..dd27d0993 100644 --- a/src/commands/gamestats/csgo.ts +++ b/src/commands/gamestats/csgo.ts @@ -9,6 +9,28 @@ import * as requests from "../../utils/requests.js"; import { COLORS } from "../../utils/constants.js"; import Settings from "../../utils/settings.js"; +interface CSGOProfileResponse { + data?: { + platformInfo: { + platformUserHandle: string; + avatarUrl: string; + }; + segments: { + type: string; + stats: { + timePlayed: { + value: number; + }; + rankScore: { + metadata: { + iconUrl: string; + }; + }; + }; + }[]; + }; +} + class CSGOCommand extends Command { constructor() { super({ @@ -34,8 +56,8 @@ class CSGOCommand extends Command { "TRN-Api-Key": ((interaction.client as Client).settings as Settings).get("trackerNetworkApiKey"), }); - const body = await response.body.json(); - const overview = body?.data?.segments?.find((s: { type: string }) => s.type === "overview"); + const body: CSGOProfileResponse = await response.body.json(); + const overview = body?.data?.segments?.find(s => s.type === "overview"); if (!Object.keys(overview?.stats || {})?.length) return await interaction.editReply(`The profile for **${ username }** was not found.`); diff --git a/src/commands/gamestats/fortnite.ts b/src/commands/gamestats/fortnite.ts index 648eaea86..68422eaea 100644 --- a/src/commands/gamestats/fortnite.ts +++ b/src/commands/gamestats/fortnite.ts @@ -9,6 +9,15 @@ import * as requests from "../../utils/requests.js"; import { COLORS } from "../../utils/constants.js"; import Settings from "../../utils/settings.js"; +interface FortniteResponse { + lifeTimeStats?: { + key: string; + value: string; + }[]; + epicUserHandle?: string; + platformNameLong?: string; +} + class FortniteCommand extends Command { constructor() { super({ @@ -46,7 +55,7 @@ class FortniteCommand extends Command { "TRN-Api-Key": ((interaction.client as Client).settings as Settings).get("trackerNetworkApiKey"), }); - const body = await response.body.json(); + const body: FortniteResponse = await response.body.json(); if (!body?.lifeTimeStats?.length) return await interaction.editReply(`The profile for **${ username }** was not found in the specified platform.`); @@ -58,7 +67,7 @@ class FortniteCommand extends Command { name: "Fortnite — Player Stats", }, title: body.epicUserHandle, - fields: body.lifeTimeStats.map((stat: { key: string; value: string }) => ({ + fields: body.lifeTimeStats.map(stat => ({ name: stat.key, value: stat.value, inline: true, diff --git a/src/commands/gamestats/overwatch.ts b/src/commands/gamestats/overwatch.ts index 3cfaa1f06..8cf3dcf0c 100644 --- a/src/commands/gamestats/overwatch.ts +++ b/src/commands/gamestats/overwatch.ts @@ -8,6 +8,21 @@ import { Command } from "@bastion/tesseract"; import * as requests from "../../utils/requests.js"; import { COLORS } from "../../utils/constants.js"; +interface OverwatchResponse { + private?: boolean; + gamesPlayed?: string; + gamesWon?: string; + gamesLost?: string; + ratings?: { + role: string; + group: string; + tier: string; + }[]; + icon?: string; + endorsementIcon?: string; + endorsement?: number; +} + class OverwatchCommand extends Command { constructor() { super({ @@ -53,7 +68,7 @@ class OverwatchCommand extends Command { // get stats const { body } = await requests.get("https://ow-api.com/v1/stats/" + platform + "/" + region + "/" + (username.replace("#", "-")) + "/profile"); - const response = await body.json(); + const response: OverwatchResponse = await body.json(); await interaction.editReply({ embeds: [ diff --git a/src/commands/gamestats/valorant.ts b/src/commands/gamestats/valorant.ts index 44e1d757c..5277d8f01 100644 --- a/src/commands/gamestats/valorant.ts +++ b/src/commands/gamestats/valorant.ts @@ -8,6 +8,36 @@ import { Command } from "@bastion/tesseract"; import * as requests from "../../utils/requests.js"; import { COLORS } from "../../utils/constants.js"; +interface AccountResponse { + data?: { + name: string; + tag: string; + region: string; + account_level: string; + card: { + wide: string; + }; + last_update_raw: number; + }; +} + +interface MMRResponse { + data?: { + current_data: { + elo: string; + currenttierpatched: string; + ranking_in_tier: string; + games_needed_for_rating: string; + images: { + large: string; + }; + }; + by_season: { + number_of_games: string; + }[]; + }; +} + class ValorantCommand extends Command { constructor() { super({ @@ -45,7 +75,7 @@ class ValorantCommand extends Command { // get account data const accountResponse = await requests.get(`https://api.henrikdev.xyz/valorant/v1/account/${ encodeURIComponent(player[0]) }/${ encodeURIComponent(player[1]) }`); - const account = await accountResponse.body.json(); + const account: AccountResponse = await accountResponse.body.json(); if (accountResponse.statusCode !== 200) { await interaction.editReply(`The profile for **${ username }** was not found in the specified region.`); @@ -53,7 +83,7 @@ class ValorantCommand extends Command { // get mmr data const mmrResponse = await requests.get(`https://api.henrikdev.xyz/valorant/v2/mmr/${ region }/${ encodeURIComponent(player[0]) }/${ encodeURIComponent(player[1]) }`); - const mmr = await mmrResponse.body.json(); + const mmr: MMRResponse = await mmrResponse.body.json(); await interaction.editReply({ embeds: [ diff --git a/src/commands/search/anime.ts b/src/commands/search/anime.ts index 58ebd4b20..162eeb9bf 100644 --- a/src/commands/search/anime.ts +++ b/src/commands/search/anime.ts @@ -23,7 +23,7 @@ interface Anime { } interface AnimeResponse { - data: { + data?: { attributes: Anime; }[]; } diff --git a/src/commands/search/apod.ts b/src/commands/search/apod.ts index c77d6864a..4cfe290b2 100644 --- a/src/commands/search/apod.ts +++ b/src/commands/search/apod.ts @@ -9,14 +9,14 @@ import * as requests from "../../utils/requests.js"; import Settings from "../../utils/settings.js"; interface APOD { - copyright: string; - date: string; - explanation: string; + copyright?: string; + date?: string; + explanation?: string; hdurl?: string; - media_type: string; - service_version: string; - title: string; - url: string; + media_type?: string; + service_version?: string; + title?: string; + url?: string; } class APODCommand extends Command { diff --git a/src/commands/search/cryptocurrency.ts b/src/commands/search/cryptocurrency.ts index fc340bbfa..8ab751f1f 100644 --- a/src/commands/search/cryptocurrency.ts +++ b/src/commands/search/cryptocurrency.ts @@ -18,11 +18,11 @@ interface Currency { } interface CurrencyResponse { - status: { + status?: { error_code: number; error_message: string; }; - data: { + data?: { [key: string]: Currency; }; } diff --git a/src/commands/search/definitions.ts b/src/commands/search/definitions.ts index 7ca09742c..88de13a80 100644 --- a/src/commands/search/definitions.ts +++ b/src/commands/search/definitions.ts @@ -49,7 +49,7 @@ class DefinitionsCommand extends Command { // fetch definitions const { body } = await requests.get(`https://api.wordnik.com/v4/word.json/${ encodeURIComponent(word.toLowerCase()) }/definitions?limit=10&sourceDictionaries=all&useCanonical=false&includeTags=false&api_key=${ ((interaction.client as Client).settings as Settings)?.get("wordnikApiKey") }`); - const definitions: Definition[] = await body.json(); + const definitions: Definition[] = await body.json() as unknown[]; if (definitions?.length) { return await interaction.editReply( diff --git a/src/commands/search/game.ts b/src/commands/search/game.ts index 8983645c2..95357b131 100644 --- a/src/commands/search/game.ts +++ b/src/commands/search/game.ts @@ -10,22 +10,22 @@ import { COLORS } from "../../utils/constants.js"; import Settings from "../../utils/settings.js"; interface Game { - alternative_names: string[]; - artworks: string[]; - cover: { + alternative_names?: string[]; + artworks?: string[]; + cover?: { url: string; }; - first_release_date: number; - game_modes: number[]; - genres: string[]; - name: string; - platforms: string[]; - screenshots: []; - summary: string; - total_rating: number; - url: string; - version_title: string; - websites: { + first_release_date?: number; + game_modes?: number[]; + genres?: string[]; + name?: string; + platforms?: string[]; + screenshots?: []; + summary?: string; + total_rating?: number; + url?: string; + version_title?: string; + websites?: { url: string; }[]; } @@ -59,7 +59,7 @@ class GameCommand extends Command { "authorization": "Bearer " + ((interaction.client as Client).settings as Settings)?.get("twitch")?.accessToken, "client-id": ((interaction.client as Client).settings as Settings)?.get("twitch")?.clientId, }); - const games: Game[] = await body.json(); + const games: Game[] = await body.json() as unknown[]; if (games?.length) { return await interaction.editReply({ diff --git a/src/commands/search/manga.ts b/src/commands/search/manga.ts index 29450df2b..c2cc8db79 100644 --- a/src/commands/search/manga.ts +++ b/src/commands/search/manga.ts @@ -20,7 +20,7 @@ interface Manga { } interface MangaResponse { - data: { + data?: { attributes: Manga; }[]; } diff --git a/src/commands/search/movie.ts b/src/commands/search/movie.ts index a4249d29d..5211f0466 100644 --- a/src/commands/search/movie.ts +++ b/src/commands/search/movie.ts @@ -27,10 +27,10 @@ interface Movie { } interface MovieResponse { - page: number; - total_results: number; - total_pages: number; - results: Movie[]; + page?: number; + total_results?: number; + total_pages?: number; + results?: Movie[]; } class MovieCommand extends Command { diff --git a/src/commands/search/pokemon.ts b/src/commands/search/pokemon.ts index aa84189e6..4072cc2e9 100644 --- a/src/commands/search/pokemon.ts +++ b/src/commands/search/pokemon.ts @@ -9,27 +9,27 @@ import * as requests from "../../utils/requests.js"; import { COLORS } from "../../utils/constants.js"; interface Pokemon { - number: string; - name: string; + number?: string; + name?: string; description?: string; - gen: number; + gen?: number; starter?: boolean; mega?: boolean; ultraBeast?: boolean; legendary?: boolean; mythical?: boolean; - species: string; - types: string[]; - abilities: { + species?: string; + types?: string[]; + abilities?: { normal: string[]; hidden: string[]; }; - eggGroups: string[]; - gender: [ number, number ] | []; - height: string; - weight: string; - sprite: string; - family: { + eggGroups?: string[]; + gender?: [ number, number ] | []; + height?: string; + weight?: string; + sprite?: string; + family?: { evolutionLine: string[]; }; } @@ -56,7 +56,7 @@ class PokemonCommand extends Command { // fetch pokemon const { body } = await requests.get(`https://pokeapi.glitch.me/v1/pokemon/${ encodeURIComponent(name) }`); - const pokemon: Pokemon[] = await body.json(); + const pokemon: Pokemon[] = await body.json() as unknown[]; if (pokemon?.length) { return await interaction.editReply({ diff --git a/src/commands/search/tv.ts b/src/commands/search/tv.ts index 75807550b..7c29cd982 100644 --- a/src/commands/search/tv.ts +++ b/src/commands/search/tv.ts @@ -26,10 +26,10 @@ interface TVShow { } interface TVShowResponse { - page: number; - total_results: number; - total_pages: number; - results: TVShow[]; + page?: number; + total_results?: number; + total_pages?: number; + results?: TVShow[]; } class TVCommand extends Command { diff --git a/src/commands/search/urbanDictionary.ts b/src/commands/search/urbanDictionary.ts index c8f230948..5b7b31aac 100644 --- a/src/commands/search/urbanDictionary.ts +++ b/src/commands/search/urbanDictionary.ts @@ -18,7 +18,7 @@ interface Definition { } interface UrbanDictionaryResponse { - list: Definition[]; + list?: Definition[]; } class UrbanDictionaryCommand extends Command { diff --git a/src/commands/search/weather.ts b/src/commands/search/weather.ts index fb2711045..8969cf639 100644 --- a/src/commands/search/weather.ts +++ b/src/commands/search/weather.ts @@ -10,15 +10,15 @@ import { COLORS } from "../../utils/constants.js"; import Settings from "../../utils/settings.js"; interface Weather { - coord: { + coord?: { lat: number; lon: number; }; - weather: { + weather?: { main: string; icon: string; }[]; - main: { + main?: { temp: number; feels_like: number; temp_min: number; @@ -28,31 +28,31 @@ interface Weather { sea_level: number; grnd_level: number; }; - wind: { + wind?: { speed: number; deg: number; }; - clouds: { + clouds?: { all: number; }; - rain: { + rain?: { "1h": number; "3h": number; }; - snow: { + snow?: { "1h": number; "3h": number; }; - visibility: number; - dt: number; - sys: { + visibility?: number; + dt?: number; + sys?: { country: string; sunrise: number; sunset: number; }; - timezone: number; - name: string; - cod: number; + timezone?: number; + name?: string; + cod?: number; message?: string; } diff --git a/src/commands/search/wikipedia.ts b/src/commands/search/wikipedia.ts index 6f5b8f7a9..d999068ac 100644 --- a/src/commands/search/wikipedia.ts +++ b/src/commands/search/wikipedia.ts @@ -17,7 +17,7 @@ interface Wiki { } interface WikipediaResponse { - query: { + query?: { pages: Wiki[]; }; } diff --git a/src/schedulers/liveStreams.ts b/src/schedulers/liveStreams.ts index 357f1590d..defa57177 100644 --- a/src/schedulers/liveStreams.ts +++ b/src/schedulers/liveStreams.ts @@ -47,7 +47,7 @@ class LiveStreamNotificationScheduler extends Scheduler { "client-id": (this.client.settings as Settings).get("twitch").clientId, }); - const streams: TwitchStream[] = (await body.json())?.data || []; + const streams: TwitchStream[] = (await body.json())?.["data"] || []; // streams that were already notified if (!twitchStreams.has(guild.id)) twitchStreams.set(guild.id, []); diff --git a/src/types.ts b/src/types.ts index 186bde06b..6c15aff6e 100644 --- a/src/types.ts +++ b/src/types.ts @@ -79,13 +79,13 @@ export namespace patreon { } export interface PatreonResponse { - readonly data: PatreonEntity[]; - readonly included: PatreonEntity[]; - readonly links: { + readonly data?: PatreonEntity[]; + readonly included?: PatreonEntity[]; + readonly links?: { readonly prev: string; readonly next: string; }; - readonly meta: { + readonly meta?: { readonly pagination: { readonly total: number; }; From 9004e4560b9a4b4eed97026316b6db81f1ed4083 Mon Sep 17 00:00:00 2001 From: TRACTION <19631364+iamtraction@users.noreply.github.com> Date: Tue, 15 Aug 2023 22:43:42 +0530 Subject: [PATCH 05/12] models(Guild): add emailFilterRule field Signed-off-by: TRACTION <19631364+iamtraction@users.noreply.github.com> --- src/models/Guild.ts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/models/Guild.ts b/src/models/Guild.ts index 2bce75541..370581284 100644 --- a/src/models/Guild.ts +++ b/src/models/Guild.ts @@ -33,6 +33,7 @@ export interface Guild { infractionsKickThreshold?: number; infractionsBanThreshold?: number; // automod rules + emailFilterRule?: string; inviteFilterRule?: string; linkFilterRule?: string; // starboard @@ -135,6 +136,11 @@ export default mongoose.model("Guild", new mongoose.S infractionsBanThreshold: { type: Number, }, + emailFilterRule: { + type: String, + unique: true, + sparse: true, + }, inviteFilterRule: { type: String, unique: true, From 9ad5a1028b24af69dd243c4f18e334d56edc9e18 Mon Sep 17 00:00:00 2001 From: TRACTION <19631364+iamtraction@users.noreply.github.com> Date: Tue, 15 Aug 2023 22:44:34 +0530 Subject: [PATCH 06/12] commands(config): add filter emails commands Signed-off-by: TRACTION <19631364+iamtraction@users.noreply.github.com> --- src/commands/config/filter/emails.ts | 87 ++++++++++++++++++++++++++++ 1 file changed, 87 insertions(+) create mode 100644 src/commands/config/filter/emails.ts diff --git a/src/commands/config/filter/emails.ts b/src/commands/config/filter/emails.ts new file mode 100644 index 000000000..32bb9b038 --- /dev/null +++ b/src/commands/config/filter/emails.ts @@ -0,0 +1,87 @@ +/*! + * @author TRACTION (iamtraction) + * @copyright 2023 + */ +import { AutoModerationActionOptions, AutoModerationActionType, AutoModerationRuleEventType, AutoModerationRuleTriggerType, ChatInputCommandInteraction, PermissionFlagsBits } from "discord.js"; +import { Command, Logger } from "@bastion/tesseract"; + +import GuildModel from "../../../models/Guild.js"; + +class FilterEmailsCommand extends Command { + constructor() { + super({ + name: "emails", + description: "Configure Email Filter AutoMod rule in the server.", + userPermissions: [ PermissionFlagsBits.ManageGuild ], + clientPermissions: [ PermissionFlagsBits.ManageGuild ], + }); + } + + public async exec(interaction: ChatInputCommandInteraction<"cached">): Promise { + await interaction.deferReply(); + + // get guild document + const guildDocument = await GuildModel.findById(interaction.guildId); + + // get the email filter rule if it exists + const emailFilterRule = guildDocument.emailFilterRule && await interaction.guild.autoModerationRules.fetch({ + autoModerationRule: guildDocument.emailFilterRule, + cache: false, + }).catch(Logger.ignore); + + // toggle email filter rule if it exists + if (emailFilterRule) { + const newEmailFilterRule = await emailFilterRule.setEnabled(!emailFilterRule.enabled, `${ emailFilterRule.enabled ? "Disable" : "Enable" } Email Filter`); + return await interaction.editReply(`I've ${ newEmailFilterRule.enabled ? "enabled" : "disabled" } the **${ newEmailFilterRule.name }** AutoMod rule.`); + } + + const actions: AutoModerationActionOptions[] = [ + { + type: AutoModerationActionType.BlockMessage, + metadata: { + customMessage: "You are not allowed to send emails in this channel.", + }, + }, + { + type: AutoModerationActionType.Timeout, + metadata: { + durationSeconds: 60, + }, + }, + ]; + + if (interaction.guild.channels.cache.has(guildDocument.moderationLogChannel)) { + actions.push({ + type: AutoModerationActionType.SendAlertMessage, + metadata: { + channel: guildDocument.moderationLogChannel, + }, + }); + } + + // create email filter rule + const newEmailFilterRule = await interaction.guild.autoModerationRules.create({ + enabled: true, + name: "Block Emails", + eventType: AutoModerationRuleEventType.MessageSend, + triggerType: AutoModerationRuleTriggerType.Keyword, + triggerMetadata: { + regexPatterns: [ + "[A-Za-z0-9.+~_-]+\\@[A-Za-z0-9.-]+\\.[A-Za-z0-9.-]+", + ], + }, + actions, + reason: "Configure Email Filter", + }); + + // update email filter rule id + guildDocument.emailFilterRule = newEmailFilterRule.id; + + // save document + await guildDocument.save(); + + return await interaction.editReply("I've configured the email filter AutoMod rule."); + } +} + +export { FilterEmailsCommand as Command }; From e10b8f6335ea9f041609903904c2b0a1d717c48c Mon Sep 17 00:00:00 2001 From: TRACTION <19631364+iamtraction@users.noreply.github.com> Date: Tue, 15 Aug 2023 22:50:16 +0530 Subject: [PATCH 07/12] chore: generate commands data Signed-off-by: TRACTION <19631364+iamtraction@users.noreply.github.com> --- commands.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/commands.json b/commands.json index efd90bcc9..000809eab 100644 --- a/commands.json +++ b/commands.json @@ -1 +1 @@ -[{"type":1,"name":"about","description":"Displays some basic information to help you get started with Bastion.","options":[]},{"type":1,"name":"calculate","description":"Evaluates the specified mathematical expression.","options":[{"type":3,"name":"expression","description":"The expression you want to evaluate.","required":true}]},{"type":1,"name":"changes","description":"See the changes introduced in the current version of Bastion.","options":[]},{"type":1,"name":"channel","description":"Command Group - channel","options":[{"type":1,"name":"create","description":"Create a new channel in the server.","options":[{"type":3,"name":"name","description":"The name of the new channel.","required":true},{"type":4,"name":"type","description":"The type of the new channel.","choices":[{"name":"Text","value":0},{"name":"Voice","value":2},{"name":"Announcement","value":5},{"name":"Stage","value":13},{"name":"Category","value":4}],"required":true},{"type":3,"name":"topic","description":"The topic for the new channel."},{"type":4,"name":"limit","description":"Limit the number of users for the new (voice) channel.","min_value":1,"max_value":99},{"type":4,"name":"slowmode","description":"Enable slowmode with the specified interval (in seconds).","min_value":0,"max_value":21600},{"type":5,"name":"nsfw","description":"Should the channel be NSFW."},{"type":3,"name":"reason","description":"The reason for creating the channel."}]},{"type":1,"name":"delete","description":"Delete the current (or the specified) channel.","options":[{"type":7,"name":"channel","description":"The channel you want to delete."},{"type":3,"name":"reason","description":"The reason for deleting the channel."}]},{"type":1,"name":"info","description":"Displays information on the current (or specified) channel.","options":[{"type":7,"name":"channel","description":"The channel whose information you want to display."}]},{"type":1,"name":"update","description":"Update the specified channel in the server.","options":[{"type":7,"name":"channel","description":"The channel you want to update."},{"type":3,"name":"name","description":"The new name for the channel."},{"type":3,"name":"topic","description":"The new topic for the channel."},{"type":4,"name":"limit","description":"The new limit of users for the (voice) channel.","min_value":1,"max_value":99},{"type":4,"name":"slowmode","description":"The new slowmode interval (in seconds).","min_value":0,"max_value":21600},{"type":5,"name":"nsfw","description":"Should the channel be NSFW."},{"type":3,"name":"reason","description":"The reason for updating the channel."}]}]},{"type":1,"name":"claim","description":"Claim any rewards available to you.","options":[]},{"type":1,"name":"comic","description":"Command Group - comic","options":[{"type":1,"name":"garfield","description":"Check the latest Garfield comic.","options":[]},{"type":1,"name":"phd","description":"Check the latest PHD comic, or the specified issue.","options":[{"type":4,"name":"issue","description":"Issue number to see the comic.","min_value":1}]},{"type":1,"name":"xkcd","description":"Check the latest xkcd comic, or the specified issue.","options":[{"type":4,"name":"issue","description":"Issue number to see the comic.","min_value":1}]}]},{"type":1,"name":"config","description":"Command Group - config","options":[{"type":1,"name":"auto-roles","description":"Configure roles that will be auto assigned to members when they join the server.","options":[{"type":8,"name":"role","description":"The role you want to add or remove as an auto role."},{"type":5,"name":"bots","description":"Whether this role should be auto assigned to bots."}]},{"type":1,"name":"auto-threads","description":"Configure auto threads in the server.","options":[]},{"type":1,"name":"farewell","description":"Configure farewell messages in the server.","options":[{"type":7,"name":"channel","description":"The channel where the farewell messages will be sent.","channel_types":[0]},{"type":3,"name":"message","description":"The custom farewell message."},{"type":4,"name":"timeout","description":"The interval after which the farewell message will be deleted.","min_value":1,"max_value":30}]},{"type":2,"name":"filter","description":"Subcommand Group - filter","options":[{"type":1,"name":"invites","description":"Configure Invite Filter AutoMod rule in the server.","options":[]},{"type":1,"name":"links","description":"Configure Link Filter AutoMod rule in the server.","options":[]}]},{"type":1,"name":"gambling","description":"Configure gambling in the server.","options":[{"type":10,"name":"multiplier","description":"The reward multiplier."}]},{"type":1,"name":"gamification","description":"Configure gamification in the server.","options":[{"type":5,"name":"messages","description":"Should it show the level up messages."},{"type":7,"name":"channel","description":"The channel where the level up messages will be sent.","channel_types":[0]},{"type":10,"name":"multiplier","description":"The reward multiplier."}]},{"type":1,"name":"greeting","description":"Configure greeting messages in the server.","options":[{"type":7,"name":"channel","description":"The channel where the greeting messages will be sent.","channel_types":[0]},{"type":3,"name":"message","description":"The custom greeting message."},{"type":4,"name":"timeout","description":"The interval after which the greeting message will be deleted.","min_value":1,"max_value":30}]},{"type":1,"name":"live-streams","description":"Follow streamers and get notified in the specified channel when they go live.","options":[{"type":3,"name":"twitch","description":"The twitch channel you want to follow."},{"type":7,"name":"channel","description":"The channel where the notifications will be sent.","channel_types":[0]},{"type":3,"name":"message","description":"The custom message for notification."}]},{"type":2,"name":"logs","description":"Subcommand Group - logs","options":[{"type":1,"name":"content","description":"Configure whether deleted and edited message content should be shown in server logs.","options":[]},{"type":1,"name":"mod","description":"Configure channel for logging moderation events.","options":[{"type":7,"name":"channel","description":"The channel where moderation events will be logged.","channel_types":[0]}]},{"type":1,"name":"server","description":"Configure channel for logging server events.","options":[{"type":7,"name":"channel","description":"The channel where server events will be logged.","channel_types":[0]}]}]},{"type":1,"name":"music","description":"Configure music in the server.","options":[]},{"type":1,"name":"reports","description":"Configure user reports in the server.","options":[{"type":7,"name":"channel","description":"The channel where user reports will be sent.","channel_types":[0]}]},{"type":2,"name":"select-roles","description":"Subcommand Group - select-roles","options":[{"type":1,"name":"add","description":"Create a new Select Role Group.","options":[{"type":3,"name":"message","description":"The content of the Select Role Message for users.","required":true},{"type":7,"name":"channel","description":"The channel where you want to send the Select Role Message.","channel_types":[5,0,2]},{"type":4,"name":"type","description":"The behavior of the Select Role Group.","choices":[{"name":"Add Only","value":1},{"name":"Remove Only","value":2}]},{"type":4,"name":"ui","description":"The variant of Select Role UI.","choices":[{"name":"Buttons","value":0},{"name":"Select Menu","value":1}]},{"type":4,"name":"min","description":"The minimum number of roles users are allowed to select.","min_value":0,"max_value":25},{"type":4,"name":"max","description":"The maximum number of roles users are allowed to select.","min_value":1,"max_value":25}]},{"type":1,"name":"list","description":"List all the Select Role Groups.","options":[{"type":7,"name":"channel","description":"List Select Role Groups only from this channel.","channel_types":[5,0,2]}]},{"type":1,"name":"remove","description":"Remove the specified Select Role Group.","options":[{"type":3,"name":"id","description":"The Select Role Group ID.","required":true}]}]},{"type":1,"name":"self-roles","description":"Configure roles that users can assign to themselves.","options":[{"type":8,"name":"role","description":"The role you want to add or remove as a self role."}]},{"type":1,"name":"starboard","description":"Configure starboard in the server.","options":[{"type":7,"name":"channel","description":"The channel where starred messages will be logged.","channel_types":[0]},{"type":4,"name":"threshold","description":"The minimum number of stars a message needs.","min_value":2}]},{"type":1,"name":"streamer-role","description":"Set the role someone is assigned in the server when they start streaming.","options":[{"type":8,"name":"role","description":"The role that should be assigned to users."}]},{"type":1,"name":"suggestions","description":"Configure suggestions in the server.","options":[{"type":7,"name":"channel","description":"The channel where suggestions will be sent.","channel_types":[0]}]},{"type":1,"name":"triggers","description":"Configure triggers and responses in the server.","options":[{"type":3,"name":"add","description":"The pattern that will trigger the response."},{"type":3,"name":"remove","description":"The trigger that you want to remove."},{"type":3,"name":"message","description":"The message response for the trigger."},{"type":3,"name":"emoji","description":"The reaction emoji response for the trigger."}]},{"type":1,"name":"verification","description":"Configure verification in the server.","options":[{"type":8,"name":"role","description":"The role users are assigned when are verified."},{"type":3,"name":"text","description":"Type a text message that will be shown to the users trying to verify."}]},{"type":1,"name":"voice-sessions","description":"Configure voice sessions in the server.","options":[{"type":3,"name":"create","description":"Name of the new voice session category."}]},{"type":1,"name":"voting-channels","description":"Configure voting channels in the server.","options":[{"type":7,"name":"add","description":"The channel you want to add as a voting channel.","channel_types":[0]},{"type":7,"name":"remove","description":"The channel you want to remove as a voting channel.","channel_types":[0]}]}]},{"type":1,"name":"donate","description":"See the ways you can contribute to support the Bastion bot project.","options":[]},{"type":1,"name":"emoji","description":"Command Group - emoji","options":[{"type":1,"name":"info","description":"Displays information on the specified custom emoji.","options":[{"type":3,"name":"emoji","description":"The emoji you want to display.","required":true}]}]},{"type":1,"name":"games","description":"Command Group - games","options":[{"type":1,"name":"8ball","description":"Ask any question to the magic 8 ball and get answers.","options":[{"type":3,"name":"question","description":"The question you want to ask the magic 8 ball.","required":true}]},{"type":1,"name":"flip","description":"Flip coins and see the result.","options":[{"type":4,"name":"coins","description":"The number of coins to flip.","min_value":1,"max_value":128}]},{"type":1,"name":"roll","description":"Roll dice and see the result. Supports dice notation.","options":[{"type":3,"name":"notation","description":"The dice notation."}]},{"type":1,"name":"rps","description":"Play rock paper scissor with Bastion.","options":[{"type":3,"name":"choice","description":"Your choice.","choices":[{"name":"Rock","value":"ROCK"},{"name":"Paper","value":"PAPER"},{"name":"Scissor","value":"SCISSOR"}],"required":true}]},{"type":1,"name":"russian-roulette","description":"Play a game of Russian roulette.","options":[{"type":4,"name":"rounds","description":"The number rounds you want to play.","min_value":1,"max_value":6}]}]},{"type":1,"name":"game-server","description":"Fetch information from nearly any game server that makes its status publicly available.","options":[{"type":3,"name":"game","description":"The game ID for the game server.","required":true},{"type":3,"name":"hostname","description":"The IP address or domain name of the game server.","required":true},{"type":4,"name":"port","description":"The connection port number of the game server. Use the query port if connection port doesn't work.","min_value":1,"max_value":65535}]},{"type":1,"name":"gamestats","description":"Command Group - gamestats","options":[{"type":1,"name":"aimlab","description":"Check stats of any Aim Lab player.","options":[{"type":3,"name":"username","description":"The username of the player.","required":true}]},{"type":1,"name":"apex","description":"Check stats of any Apex Legends player.","options":[{"type":3,"name":"username","description":"The username of the player.","required":true},{"type":3,"name":"platform","description":"The platform of the player.","choices":[{"name":"PC","value":"origin"},{"name":"PlayStation","value":"psn"},{"name":"Xbox","value":"xbl"}],"required":true}]},{"type":1,"name":"csgo","description":"Check stats of any Counter-Strike: Global Offensive player.","options":[{"type":3,"name":"username","description":"The username of the player.","required":true}]},{"type":1,"name":"fortnite","description":"Check stats of any Fortnite player.","options":[{"type":3,"name":"username","description":"The username of the player.","required":true},{"type":3,"name":"platform","description":"The platform of the player.","choices":[{"name":"PC","value":"kbm"},{"name":"Console","value":"gamepad"},{"name":"Mobile","value":"touch"}],"required":true}]},{"type":1,"name":"overwatch","description":"Check stats of any Overwatch 2 player.","options":[{"type":3,"name":"username","description":"The BattleTag or username of the player.","required":true},{"type":3,"name":"platform","description":"The platform of the player.","choices":[{"name":"PC","value":"pc"},{"name":"PlayStation","value":"psn"},{"name":"Xbox","value":"xbl"},{"name":"Nintendo Switch","value":"nintendo-switch"}]},{"type":3,"name":"region","description":"The region of the player.","choices":[{"name":"Americas","value":"us"},{"name":"Europe","value":"eu"},{"name":"Asia","value":"asia"}]}]},{"type":1,"name":"rainbow6","description":"Check stats of any Rainbow 6 player.","options":[{"type":3,"name":"username","description":"The username of the player.","required":true},{"type":3,"name":"platform","description":"The platform of the player.","choices":[{"name":"PC","value":"uplay"},{"name":"PlayStation","value":"psn"},{"name":"Xbox","value":"xbl"}],"required":true}]},{"type":1,"name":"valorant","description":"Check stats of any Valorant player.","options":[{"type":3,"name":"username","description":"The name tag of the player.","required":true},{"type":3,"name":"region","description":"The region of the account.","choices":[{"name":"Americas","value":"na"},{"name":"Europe","value":"eu"},{"name":"Asia-Pacific","value":"ap"},{"name":"Korea","value":"kr"}],"required":true}]}]},{"type":1,"name":"give","description":"Give Bastion Coins and Experience Points to server members or take it from them.","options":[{"type":6,"name":"user","description":"The user whose coins and XP will be updated.","required":true},{"type":4,"name":"coins","description":"The amount of coins you want to give or take.","required":true},{"type":4,"name":"xp","description":"The amount of XP you want to give or take.","required":true}]},{"type":1,"name":"giveaway","description":"Run giveaways in the server.","options":[{"type":3,"name":"title","description":"The title for the giveaway.","required":true},{"type":3,"name":"description","description":"The description for the giveaway."},{"type":4,"name":"winners","description":"The number of winners for the giveaway.","min_value":1,"max_value":9007199254740991},{"type":4,"name":"timer","description":"Number of hours the giveaway should run.","min_value":1,"max_value":720}]},{"type":1,"name":"iam","description":"Assign a self assignable role to yourself.","options":[{"type":8,"name":"role","description":"The role you want to assign yourself."}]},{"type":1,"name":"invite","description":"Generates an instant invite for the server.","options":[{"type":5,"name":"temporary","description":"Kick the members if they aren't assigned a role within 24 hours."}]},{"type":1,"name":"leaderboard","description":"Displays the server's leaderboard. You're ranked based on their level, XP, karma, and Bastion Coins.","options":[]},{"type":1,"name":"lmgtfy","description":"Send a LMGTFY link for the search query that teaches people how to do an internet search.","options":[{"type":3,"name":"query","description":"The search query.","required":true},{"type":3,"name":"site","description":"The search engine to use.","choices":[{"name":"DuckDuckGo","value":"d"},{"name":"Google","value":"g"},{"name":"Bing","value":"b"}]}]},{"type":1,"name":"message","description":"Command Group - message","options":[{"type":1,"name":"clear","description":"Clear recent messages (newer than two weeks) in the channel.","options":[{"type":4,"name":"limit","description":"Limit the numbers of messages that should be deleted.","min_value":1},{"type":5,"name":"bots","description":"Should it delete messages from bots."},{"type":5,"name":"pinned","description":"Should it delete messages that are pinned."},{"type":5,"name":"system","description":"Should it delete system messages."},{"type":6,"name":"user","description":"Only delete messages from this user."}]}]},{"type":1,"name":"music","description":"Command Group - music","options":[{"type":1,"name":"join","description":"Moves you to the voice channel where Bastion is currently connected.","options":[]},{"type":1,"name":"now","description":"Shows the song playing right now.","options":[]},{"type":1,"name":"pause","description":"Pause the music playback in the voice channel.","options":[]},{"type":1,"name":"play","description":"Play a specified song in the server.","options":[{"type":3,"name":"song","description":"The song name or link you want to play.","required":true}]},{"type":1,"name":"queue","description":"Displays the current music queue in the server.","options":[{"type":3,"name":"remove","description":"Remove songs matching the specified text from the music queue."},{"type":5,"name":"clear","description":"Remove all songs from the music queue."}]},{"type":1,"name":"resume","description":"Resume the music playback in the voice channel.","options":[]},{"type":1,"name":"shuffle","description":"Shuffle the current music queue.","options":[]},{"type":1,"name":"skip","description":"Skip the current music track that's being played in the voice channel.","options":[]},{"type":1,"name":"stop","description":"Stop the music playback and disconnect from the voice channel.","options":[]}]},{"type":1,"name":"poll","description":"Run polls in the server.","options":[{"type":3,"name":"question","description":"The question for the poll.","required":true},{"type":3,"name":"option1","description":"The first option for the poll's answer.","required":true},{"type":3,"name":"option2","description":"The first option for the poll's answer.","required":true},{"type":3,"name":"option3","description":"The first option for the poll's answer."},{"type":3,"name":"option4","description":"The first option for the poll's answer."},{"type":4,"name":"timer","description":"Number of hours the poll should run.","min_value":1,"max_value":720}]},{"type":1,"name":"profile","description":"Displays the Bastion profile of the specified user.","options":[{"type":6,"name":"user","description":"The user whose profile you want to display."}]},{"type":1,"name":"report","description":"Report a server member to the moderators of the server.","options":[{"type":6,"name":"user","description":"The user you want to report.","required":true},{"type":3,"name":"reason","description":"The reason you want to report the user.","required":true}]},{"type":1,"name":"role","description":"Command Group - role","options":[{"type":1,"name":"config","description":"Set the description & emoji of the specified role.","options":[{"type":8,"name":"role","description":"The role which you want to configure.","required":true},{"type":3,"name":"emoji","description":"The emoji you want to set as the role emoji."},{"type":3,"name":"description","description":"A description for the role (max 100 characters)."}]},{"type":1,"name":"create","description":"Create a new role in the server.","options":[{"type":3,"name":"name","description":"The name of the new role.","required":true},{"type":3,"name":"color","description":"The color for the new role (in HEX code)."},{"type":5,"name":"icon","description":"The icon for the new role (Image URL or Emoji)."},{"type":5,"name":"hoist","description":"Should the members be displayed separately from others."},{"type":5,"name":"mentionable","description":"Should the role be mentionable."},{"type":3,"name":"reason","description":"The reason for creating the role."}]},{"type":1,"name":"delete","description":"Delete the specified role.","options":[{"type":8,"name":"role","description":"The role you want to delete.","required":true},{"type":3,"name":"reason","description":"The reason for deleting the role."}]},{"type":1,"name":"info","description":"Displays information on the specified role.","options":[{"type":8,"name":"role","description":"The role whose information you want to display.","required":true}]},{"type":1,"name":"levels","description":"Configure level roles. When members reach a level, they get assigned to roles in the level.","options":[{"type":8,"name":"role","description":"The role that should be assigned to users."},{"type":4,"name":"level","description":"The level at which the role should be assigned.","min_value":0},{"type":4,"name":"remove","description":"The level which you want to remove.","min_value":0}]},{"type":1,"name":"update","description":"Update the specified role in the server.","options":[{"type":8,"name":"role","description":"The role you want to update.","required":true},{"type":3,"name":"name","description":"The new name for the role."},{"type":3,"name":"color","description":"The new color for the role (in HEX code)."},{"type":5,"name":"icon","description":"The new icon for the role (Image URL or Emoji)."},{"type":5,"name":"hoist","description":"Should the members be displayed separately from others."},{"type":5,"name":"mentionable","description":"Should the role be mentionable."},{"type":3,"name":"reason","description":"The reason for updating the role."}]}]},{"type":1,"name":"say","description":"Replies with the message you ask it to say.","options":[{"type":3,"name":"message","description":"The message you want Bastion to say.","required":true}]},{"type":1,"name":"search","description":"Command Group - search","options":[{"type":1,"name":"anime","description":"Searches for information on the specified anime.","options":[{"type":3,"name":"name","description":"The name of the anime.","required":true}]},{"type":1,"name":"apod","description":"Displays the astronomy picture of the day from NASA.","options":[]},{"type":1,"name":"cryptocurrency","description":"Searches for information on the specified crypto currency.","options":[{"type":3,"name":"symbol","description":"The symbol of the crypto currency.","required":true}]},{"type":1,"name":"definitions","description":"Displays the definitions for the specified word.","options":[{"type":3,"name":"word","description":"The word you want to lookup.","required":true}]},{"type":1,"name":"game","description":"Searches for information on the specified game.","options":[{"type":3,"name":"name","description":"The name of the game.","required":true}]},{"type":1,"name":"manga","description":"Searches for information on the specified manga.","options":[{"type":3,"name":"name","description":"The name of the manga.","required":true}]},{"type":1,"name":"movie","description":"Searches for information on the specified movie.","options":[{"type":3,"name":"name","description":"The name of the movie.","required":true}]},{"type":1,"name":"pokemon","description":"Searches for information on the specified pokémon.","options":[{"type":3,"name":"name","description":"The name (or number) of the Pokémon.","required":true}]},{"type":1,"name":"redirects","description":"Follows all the redirects in the specified URL and displays the final URL.","options":[{"type":3,"name":"url","description":"The URL you want to follow.","required":true}]},{"type":1,"name":"tv","description":"Searches for information on the specified TV show.","options":[{"type":3,"name":"name","description":"The name of the TV show.","required":true}]},{"type":1,"name":"urban-dictionary","description":"Searches Urban Dictionary for the specified word.","options":[{"type":3,"name":"word","description":"The word you want to lookup.","required":true}]},{"type":1,"name":"weather","description":"Displays the weather forcast of the specified location.","options":[{"type":3,"name":"location","description":"The location for the weather forcast.","required":true}]},{"type":1,"name":"wikipedia","description":"Searches Wikipedia for the specified query.","options":[{"type":3,"name":"query","description":"The search query.","required":true}]}]},{"type":1,"name":"server","description":"Command Group - server","options":[{"type":1,"name":"info","description":"Displays information on the server.","options":[]},{"type":1,"name":"prune","description":"Kicks the inactive members (without any roles) from the server.","options":[{"type":4,"name":"days","description":"The number of days of inactivity required for kicking.","min_value":1},{"type":8,"name":"role","description":"Inactive members check includes this role."},{"type":3,"name":"reason","description":"The reason for pruning the inactive members."}]}]},{"type":1,"name":"status","description":"Displays Bastion's status. You can also see Discord's status.","options":[{"type":5,"name":"shard","description":"Displays the status of the current shard."}]},{"type":1,"name":"su","description":"Command Group - su","options":[{"type":1,"name":"eval","description":"Evaluate JavaScript code in Bastion's context.","options":[{"type":3,"name":"code","description":"The code you want to execute.","required":true},{"type":5,"name":"public","description":"Display the output to everyone."}]},{"type":1,"name":"exec","description":"Execute terminal commands on the system where Bastion is running.","options":[{"type":3,"name":"command","description":"The command you want to execute.","required":true},{"type":5,"name":"public","description":"Display the output to everyone."}]},{"type":1,"name":"reload","description":"Reload Bastion's settings.","options":[]},{"type":1,"name":"shutdown","description":"Shutdown Bastion directly from Discord.","options":[]}]},{"type":1,"name":"suggest","description":"Send a suggestion to the server staff.","options":[{"type":3,"name":"suggestion","description":"What do you want to suggest?","required":true}]},{"type":1,"name":"thread","description":"Command Group - thread","options":[{"type":1,"name":"close","description":"Close and lock the thread.","options":[]},{"type":1,"name":"name","description":"Change the name of the thread.","options":[{"type":3,"name":"name","description":"The new name for the thread.","required":true}]}]},{"type":1,"name":"translate","description":"Translates the specified text from one language to another.","options":[{"type":3,"name":"text","description":"The text you want to translate.","required":true},{"type":3,"name":"to","description":"The language you want to translate to."},{"type":3,"name":"from","description":"The language you want to translate from."}]},{"type":1,"name":"user","description":"Command Group - user","options":[{"type":1,"name":"avatar","description":"Displays the avatar of the specified user.","options":[{"type":6,"name":"user","description":"The user whose avatar you want to display."}]},{"type":1,"name":"info","description":"Displays information on the specified user.","options":[{"type":6,"name":"user","description":"The user whose information you want to display."}]},{"type":1,"name":"infractions","description":"Configure infraction actions and displays infractions of the specified user.","options":[{"type":4,"name":"timeout","description":"Number of violations after which a user is timed out.","min_value":1},{"type":4,"name":"kick","description":"Number of violations after which a user is kicked.","min_value":1},{"type":4,"name":"ban","description":"Number of violations after which a user is banned.","min_value":1},{"type":6,"name":"user","description":"The user whose infractions you want to display."},{"type":4,"name":"remove","description":"The infraction you want to remove from the user.","min_value":1}]}]},{"type":1,"name":"warn","description":"Warn server members and add infractions to their server profile.","options":[{"type":6,"name":"user","description":"The user you want to warn.","required":true},{"type":3,"name":"reason","description":"The reason for the warning.","required":true}]}] \ No newline at end of file +[{"type":2,"name":"Blacklist","description":""},{"type":1,"name":"about","description":"Displays some basic information to help you get started with Bastion.","options":[]},{"type":1,"name":"calculate","description":"Evaluates the specified mathematical expression.","options":[{"type":3,"name":"expression","description":"The expression you want to evaluate.","required":true}]},{"type":1,"name":"changes","description":"See the changes introduced in the current version of Bastion.","options":[]},{"type":1,"name":"channel","description":"Command Group - channel","options":[{"type":1,"name":"create","description":"Create a new channel in the server.","options":[{"type":3,"name":"name","description":"The name of the new channel.","required":true},{"type":4,"name":"type","description":"The type of the new channel.","choices":[{"name":"Text","value":0},{"name":"Voice","value":2},{"name":"Announcement","value":5},{"name":"Stage","value":13},{"name":"Category","value":4}],"required":true},{"type":3,"name":"topic","description":"The topic for the new channel."},{"type":4,"name":"limit","description":"Limit the number of users for the new (voice) channel.","min_value":1,"max_value":99},{"type":4,"name":"slowmode","description":"Enable slowmode with the specified interval (in seconds).","min_value":0,"max_value":21600},{"type":5,"name":"nsfw","description":"Should the channel be NSFW."},{"type":3,"name":"reason","description":"The reason for creating the channel."}]},{"type":1,"name":"delete","description":"Delete the current (or the specified) channel.","options":[{"type":7,"name":"channel","description":"The channel you want to delete."},{"type":3,"name":"reason","description":"The reason for deleting the channel."}]},{"type":1,"name":"info","description":"Displays information on the current (or specified) channel.","options":[{"type":7,"name":"channel","description":"The channel whose information you want to display."}]},{"type":1,"name":"update","description":"Update the specified channel in the server.","options":[{"type":7,"name":"channel","description":"The channel you want to update."},{"type":3,"name":"name","description":"The new name for the channel."},{"type":3,"name":"topic","description":"The new topic for the channel."},{"type":4,"name":"limit","description":"The new limit of users for the (voice) channel.","min_value":1,"max_value":99},{"type":4,"name":"slowmode","description":"The new slowmode interval (in seconds).","min_value":0,"max_value":21600},{"type":5,"name":"nsfw","description":"Should the channel be NSFW."},{"type":3,"name":"reason","description":"The reason for updating the channel."}]}]},{"type":1,"name":"claim","description":"Claim any rewards available to you.","options":[]},{"type":1,"name":"comic","description":"Command Group - comic","options":[{"type":1,"name":"garfield","description":"Check the latest Garfield comic.","options":[]},{"type":1,"name":"phd","description":"Check the latest PHD comic, or the specified issue.","options":[{"type":4,"name":"issue","description":"Issue number to see the comic.","min_value":1}]},{"type":1,"name":"xkcd","description":"Check the latest xkcd comic, or the specified issue.","options":[{"type":4,"name":"issue","description":"Issue number to see the comic.","min_value":1}]}]},{"type":1,"name":"config","description":"Command Group - config","options":[{"type":1,"name":"auto-roles","description":"Configure roles that will be auto assigned to members when they join the server.","options":[{"type":8,"name":"role","description":"The role you want to add or remove as an auto role."},{"type":5,"name":"bots","description":"Whether this role should be auto assigned to bots."}]},{"type":1,"name":"auto-threads","description":"Configure auto threads in the server.","options":[]},{"type":1,"name":"farewell","description":"Configure farewell messages in the server.","options":[{"type":7,"name":"channel","description":"The channel where the farewell messages will be sent.","channel_types":[0]},{"type":3,"name":"message","description":"The custom farewell message."},{"type":4,"name":"timeout","description":"The interval after which the farewell message will be deleted.","min_value":1,"max_value":30}]},{"type":2,"name":"filter","description":"Subcommand Group - filter","options":[{"type":1,"name":"emails","description":"Configure Email Filter AutoMod rule in the server.","options":[]},{"type":1,"name":"invites","description":"Configure Invite Filter AutoMod rule in the server.","options":[]},{"type":1,"name":"links","description":"Configure Link Filter AutoMod rule in the server.","options":[]}]},{"type":1,"name":"gambling","description":"Configure gambling in the server.","options":[{"type":10,"name":"multiplier","description":"The reward multiplier."}]},{"type":1,"name":"gamification","description":"Configure gamification in the server.","options":[{"type":5,"name":"messages","description":"Should it show the level up messages."},{"type":7,"name":"channel","description":"The channel where the level up messages will be sent.","channel_types":[0]},{"type":10,"name":"multiplier","description":"The reward multiplier."}]},{"type":1,"name":"greeting","description":"Configure greeting messages in the server.","options":[{"type":7,"name":"channel","description":"The channel where the greeting messages will be sent.","channel_types":[0]},{"type":3,"name":"message","description":"The custom greeting message."},{"type":4,"name":"timeout","description":"The interval after which the greeting message will be deleted.","min_value":1,"max_value":30}]},{"type":1,"name":"live-streams","description":"Follow streamers and get notified in the specified channel when they go live.","options":[{"type":3,"name":"twitch","description":"The twitch channel you want to follow."},{"type":7,"name":"channel","description":"The channel where the notifications will be sent.","channel_types":[0]},{"type":3,"name":"message","description":"The custom message for notification."}]},{"type":2,"name":"logs","description":"Subcommand Group - logs","options":[{"type":1,"name":"content","description":"Configure whether deleted and edited message content should be shown in server logs.","options":[]},{"type":1,"name":"mod","description":"Configure channel for logging moderation events.","options":[{"type":7,"name":"channel","description":"The channel where moderation events will be logged.","channel_types":[0]}]},{"type":1,"name":"server","description":"Configure channel for logging server events.","options":[{"type":7,"name":"channel","description":"The channel where server events will be logged.","channel_types":[0]}]}]},{"type":1,"name":"music","description":"Configure music in the server.","options":[]},{"type":1,"name":"reports","description":"Configure user reports in the server.","options":[{"type":7,"name":"channel","description":"The channel where user reports will be sent.","channel_types":[0]}]},{"type":2,"name":"select-roles","description":"Subcommand Group - select-roles","options":[{"type":1,"name":"add","description":"Create a new Select Role Group.","options":[{"type":3,"name":"message","description":"The content of the Select Role Message for users.","required":true},{"type":7,"name":"channel","description":"The channel where you want to send the Select Role Message.","channel_types":[5,0,2]},{"type":4,"name":"type","description":"The behavior of the Select Role Group.","choices":[{"name":"Add Only","value":1},{"name":"Remove Only","value":2}]},{"type":4,"name":"ui","description":"The variant of Select Role UI.","choices":[{"name":"Buttons","value":0},{"name":"Select Menu","value":1}]},{"type":4,"name":"min","description":"The minimum number of roles users are allowed to select.","min_value":0,"max_value":25},{"type":4,"name":"max","description":"The maximum number of roles users are allowed to select.","min_value":1,"max_value":25}]},{"type":1,"name":"list","description":"List all the Select Role Groups.","options":[{"type":7,"name":"channel","description":"List Select Role Groups only from this channel.","channel_types":[5,0,2]}]},{"type":1,"name":"remove","description":"Remove the specified Select Role Group.","options":[{"type":3,"name":"id","description":"The Select Role Group ID.","required":true}]},{"type":1,"name":"sync","description":"Sync the specified Select Role Group.","options":[{"type":3,"name":"id","description":"The Select Role Group ID.","required":true}]}]},{"type":1,"name":"self-roles","description":"Configure roles that users can assign to themselves.","options":[{"type":8,"name":"role","description":"The role you want to add or remove as a self role."}]},{"type":1,"name":"starboard","description":"Configure starboard in the server.","options":[{"type":7,"name":"channel","description":"The channel where starred messages will be logged.","channel_types":[0]},{"type":4,"name":"threshold","description":"The minimum number of stars a message needs.","min_value":2}]},{"type":1,"name":"streamer-role","description":"Set the role someone is assigned in the server when they start streaming.","options":[{"type":8,"name":"role","description":"The role that should be assigned to users."}]},{"type":1,"name":"suggestions","description":"Configure suggestions in the server.","options":[{"type":7,"name":"channel","description":"The channel where suggestions will be sent.","channel_types":[0]}]},{"type":1,"name":"triggers","description":"Configure triggers and responses in the server.","options":[{"type":3,"name":"add","description":"The pattern that will trigger the response."},{"type":3,"name":"remove","description":"The trigger that you want to remove."},{"type":3,"name":"message","description":"The message response for the trigger."},{"type":3,"name":"emoji","description":"The reaction emoji response for the trigger."}]},{"type":1,"name":"verification","description":"Configure verification in the server.","options":[{"type":8,"name":"role","description":"The role users are assigned when are verified."},{"type":3,"name":"text","description":"Type a text message that will be shown to the users trying to verify."}]},{"type":1,"name":"voice-sessions","description":"Configure voice sessions in the server.","options":[{"type":3,"name":"create","description":"Name of the new voice session category."}]},{"type":1,"name":"voting-channels","description":"Configure voting channels in the server.","options":[{"type":7,"name":"add","description":"The channel you want to add as a voting channel.","channel_types":[0]},{"type":7,"name":"remove","description":"The channel you want to remove as a voting channel.","channel_types":[0]}]}]},{"type":1,"name":"donate","description":"See the ways you can contribute to support the Bastion bot project.","options":[]},{"type":1,"name":"emoji","description":"Command Group - emoji","options":[{"type":1,"name":"info","description":"Displays information on the specified custom emoji.","options":[{"type":3,"name":"emoji","description":"The emoji you want to display.","required":true}]}]},{"type":1,"name":"games","description":"Command Group - games","options":[{"type":1,"name":"8ball","description":"Ask any question to the magic 8 ball and get answers.","options":[{"type":3,"name":"question","description":"The question you want to ask the magic 8 ball.","required":true}]},{"type":1,"name":"flip","description":"Flip coins and see the result.","options":[{"type":4,"name":"coins","description":"The number of coins to flip.","min_value":1,"max_value":128}]},{"type":1,"name":"roll","description":"Roll dice and see the result. Supports dice notation.","options":[{"type":3,"name":"notation","description":"The dice notation."}]},{"type":1,"name":"rps","description":"Play rock paper scissor with Bastion.","options":[{"type":3,"name":"choice","description":"Your choice.","choices":[{"name":"Rock","value":"ROCK"},{"name":"Paper","value":"PAPER"},{"name":"Scissor","value":"SCISSOR"}],"required":true}]},{"type":1,"name":"russian-roulette","description":"Play a game of Russian roulette.","options":[{"type":4,"name":"rounds","description":"The number rounds you want to play.","min_value":1,"max_value":6}]}]},{"type":1,"name":"game-server","description":"Fetch information from nearly any game server that makes its status publicly available.","options":[{"type":3,"name":"game","description":"The game ID for the game server.","required":true},{"type":3,"name":"hostname","description":"The IP address or domain name of the game server.","required":true},{"type":4,"name":"port","description":"The connection port number of the game server. Use the query port if connection port doesn't work.","min_value":1,"max_value":65535}]},{"type":1,"name":"gamestats","description":"Command Group - gamestats","options":[{"type":1,"name":"aimlab","description":"Check stats of any Aim Lab player.","options":[{"type":3,"name":"username","description":"The username of the player.","required":true}]},{"type":1,"name":"apex","description":"Check stats of any Apex Legends player.","options":[{"type":3,"name":"username","description":"The username of the player.","required":true},{"type":3,"name":"platform","description":"The platform of the player.","choices":[{"name":"PC","value":"origin"},{"name":"PlayStation","value":"psn"},{"name":"Xbox","value":"xbl"}],"required":true}]},{"type":1,"name":"csgo","description":"Check stats of any Counter-Strike: Global Offensive player.","options":[{"type":3,"name":"username","description":"The username of the player.","required":true}]},{"type":1,"name":"fortnite","description":"Check stats of any Fortnite player.","options":[{"type":3,"name":"username","description":"The username of the player.","required":true},{"type":3,"name":"platform","description":"The platform of the player.","choices":[{"name":"PC","value":"kbm"},{"name":"Console","value":"gamepad"},{"name":"Mobile","value":"touch"}],"required":true}]},{"type":1,"name":"overwatch","description":"Check stats of any Overwatch 2 player.","options":[{"type":3,"name":"username","description":"The BattleTag or username of the player.","required":true},{"type":3,"name":"platform","description":"The platform of the player.","choices":[{"name":"PC","value":"pc"},{"name":"PlayStation","value":"psn"},{"name":"Xbox","value":"xbl"},{"name":"Nintendo Switch","value":"nintendo-switch"}]},{"type":3,"name":"region","description":"The region of the player.","choices":[{"name":"Americas","value":"us"},{"name":"Europe","value":"eu"},{"name":"Asia","value":"asia"}]}]},{"type":1,"name":"rainbow6","description":"Check stats of any Rainbow 6 player.","options":[{"type":3,"name":"username","description":"The username of the player.","required":true},{"type":3,"name":"platform","description":"The platform of the player.","choices":[{"name":"PC","value":"uplay"},{"name":"PlayStation","value":"psn"},{"name":"Xbox","value":"xbl"}],"required":true}]},{"type":1,"name":"valorant","description":"Check stats of any Valorant player.","options":[{"type":3,"name":"username","description":"The name tag of the player.","required":true},{"type":3,"name":"region","description":"The region of the account.","choices":[{"name":"Americas","value":"na"},{"name":"Europe","value":"eu"},{"name":"Asia-Pacific","value":"ap"},{"name":"Korea","value":"kr"}],"required":true}]}]},{"type":1,"name":"give","description":"Give Bastion Coins and Experience Points to server members or take it from them.","options":[{"type":6,"name":"user","description":"The user whose coins and XP will be updated.","required":true},{"type":4,"name":"coins","description":"The amount of coins you want to give or take.","required":true},{"type":4,"name":"xp","description":"The amount of XP you want to give or take.","required":true}]},{"type":1,"name":"giveaway","description":"Run giveaways in the server.","options":[{"type":3,"name":"title","description":"The title for the giveaway.","required":true},{"type":3,"name":"description","description":"The description for the giveaway."},{"type":4,"name":"winners","description":"The number of winners for the giveaway.","min_value":1,"max_value":9007199254740991},{"type":4,"name":"timer","description":"Number of hours the giveaway should run.","min_value":1,"max_value":720}]},{"type":1,"name":"iam","description":"Assign a self assignable role to yourself.","options":[{"type":8,"name":"role","description":"The role you want to assign yourself."}]},{"type":1,"name":"invite","description":"Generates an instant invite for the server.","options":[{"type":5,"name":"temporary","description":"Kick the members if they aren't assigned a role within 24 hours."}]},{"type":1,"name":"leaderboard","description":"Displays the server's leaderboard. You're ranked based on their level, XP, karma, and Bastion Coins.","options":[]},{"type":1,"name":"lmgtfy","description":"Send a LMGTFY link for the search query that teaches people how to do an internet search.","options":[{"type":3,"name":"query","description":"The search query.","required":true},{"type":3,"name":"site","description":"The search engine to use.","choices":[{"name":"DuckDuckGo","value":"d"},{"name":"Google","value":"g"},{"name":"Bing","value":"b"}]}]},{"type":1,"name":"message","description":"Command Group - message","options":[{"type":1,"name":"clear","description":"Clear recent messages (newer than two weeks) in the channel.","options":[{"type":4,"name":"limit","description":"Limit the numbers of messages that should be deleted.","min_value":1},{"type":5,"name":"bots","description":"Should it delete messages from bots."},{"type":5,"name":"pinned","description":"Should it delete messages that are pinned."},{"type":5,"name":"system","description":"Should it delete system messages."},{"type":6,"name":"user","description":"Only delete messages from this user."}]}]},{"type":1,"name":"music","description":"Command Group - music","options":[{"type":1,"name":"join","description":"Moves you to the voice channel where Bastion is currently connected.","options":[]},{"type":1,"name":"now","description":"Shows the song playing right now.","options":[]},{"type":1,"name":"pause","description":"Pause the music playback in the voice channel.","options":[]},{"type":1,"name":"play","description":"Play a specified song in the server.","options":[{"type":3,"name":"song","description":"The song name or link you want to play.","required":true}]},{"type":1,"name":"queue","description":"Displays the current music queue in the server.","options":[{"type":3,"name":"remove","description":"Remove songs matching the specified text from the music queue."},{"type":5,"name":"clear","description":"Remove all songs from the music queue."}]},{"type":1,"name":"resume","description":"Resume the music playback in the voice channel.","options":[]},{"type":1,"name":"shuffle","description":"Shuffle the current music queue.","options":[]},{"type":1,"name":"skip","description":"Skip the current music track that's being played in the voice channel.","options":[]},{"type":1,"name":"stop","description":"Stop the music playback and disconnect from the voice channel.","options":[]}]},{"type":1,"name":"poll","description":"Run polls in the server.","options":[{"type":3,"name":"question","description":"The question for the poll.","required":true},{"type":3,"name":"option1","description":"The first option for the poll's answer.","required":true},{"type":3,"name":"option2","description":"The first option for the poll's answer.","required":true},{"type":3,"name":"option3","description":"The first option for the poll's answer."},{"type":3,"name":"option4","description":"The first option for the poll's answer."},{"type":4,"name":"timer","description":"Number of hours the poll should run.","min_value":1,"max_value":720}]},{"type":1,"name":"profile","description":"Displays the Bastion profile of the specified user.","options":[{"type":6,"name":"user","description":"The user whose profile you want to display."}]},{"type":1,"name":"report","description":"Report a server member to the moderators of the server.","options":[{"type":6,"name":"user","description":"The user you want to report.","required":true},{"type":3,"name":"reason","description":"The reason you want to report the user.","required":true}]},{"type":1,"name":"role","description":"Command Group - role","options":[{"type":1,"name":"config","description":"Set the description & emoji of the specified role.","options":[{"type":8,"name":"role","description":"The role which you want to configure.","required":true},{"type":3,"name":"emoji","description":"The emoji you want to set as the role emoji."},{"type":3,"name":"description","description":"A description for the role (max 100 characters)."}]},{"type":1,"name":"create","description":"Create a new role in the server.","options":[{"type":3,"name":"name","description":"The name of the new role.","required":true},{"type":3,"name":"color","description":"The color for the new role (in HEX code)."},{"type":5,"name":"icon","description":"The icon for the new role (Image URL or Emoji)."},{"type":5,"name":"hoist","description":"Should the members be displayed separately from others."},{"type":5,"name":"mentionable","description":"Should the role be mentionable."},{"type":3,"name":"reason","description":"The reason for creating the role."}]},{"type":1,"name":"delete","description":"Delete the specified role.","options":[{"type":8,"name":"role","description":"The role you want to delete.","required":true},{"type":3,"name":"reason","description":"The reason for deleting the role."}]},{"type":1,"name":"info","description":"Displays information on the specified role.","options":[{"type":8,"name":"role","description":"The role whose information you want to display.","required":true}]},{"type":1,"name":"levels","description":"Configure level roles. When members reach a level, they get assigned to roles in the level.","options":[{"type":8,"name":"role","description":"The role that should be assigned to users."},{"type":4,"name":"level","description":"The level at which the role should be assigned.","min_value":0},{"type":4,"name":"remove","description":"The level which you want to remove.","min_value":0}]},{"type":1,"name":"update","description":"Update the specified role in the server.","options":[{"type":8,"name":"role","description":"The role you want to update.","required":true},{"type":3,"name":"name","description":"The new name for the role."},{"type":3,"name":"color","description":"The new color for the role (in HEX code)."},{"type":5,"name":"icon","description":"The new icon for the role (Image URL or Emoji)."},{"type":5,"name":"hoist","description":"Should the members be displayed separately from others."},{"type":5,"name":"mentionable","description":"Should the role be mentionable."},{"type":3,"name":"reason","description":"The reason for updating the role."}]}]},{"type":1,"name":"say","description":"Replies with the message you ask it to say.","options":[{"type":3,"name":"message","description":"The message you want Bastion to say.","required":true}]},{"type":1,"name":"search","description":"Command Group - search","options":[{"type":1,"name":"anime","description":"Searches for information on the specified anime.","options":[{"type":3,"name":"name","description":"The name of the anime.","required":true}]},{"type":1,"name":"apod","description":"Displays the astronomy picture of the day from NASA.","options":[]},{"type":1,"name":"cryptocurrency","description":"Searches for information on the specified crypto currency.","options":[{"type":3,"name":"symbol","description":"The symbol of the crypto currency.","required":true}]},{"type":1,"name":"definitions","description":"Displays the definitions for the specified word.","options":[{"type":3,"name":"word","description":"The word you want to lookup.","required":true}]},{"type":1,"name":"game","description":"Searches for information on the specified game.","options":[{"type":3,"name":"name","description":"The name of the game.","required":true}]},{"type":1,"name":"manga","description":"Searches for information on the specified manga.","options":[{"type":3,"name":"name","description":"The name of the manga.","required":true}]},{"type":1,"name":"movie","description":"Searches for information on the specified movie.","options":[{"type":3,"name":"name","description":"The name of the movie.","required":true}]},{"type":1,"name":"pokemon","description":"Searches for information on the specified pokémon.","options":[{"type":3,"name":"name","description":"The name (or number) of the Pokémon.","required":true}]},{"type":1,"name":"redirects","description":"Follows all the redirects in the specified URL and displays the final URL.","options":[{"type":3,"name":"url","description":"The URL you want to follow.","required":true}]},{"type":1,"name":"tv","description":"Searches for information on the specified TV show.","options":[{"type":3,"name":"name","description":"The name of the TV show.","required":true}]},{"type":1,"name":"urban-dictionary","description":"Searches Urban Dictionary for the specified word.","options":[{"type":3,"name":"word","description":"The word you want to lookup.","required":true}]},{"type":1,"name":"weather","description":"Displays the weather forcast of the specified location.","options":[{"type":3,"name":"location","description":"The location for the weather forcast.","required":true}]},{"type":1,"name":"wikipedia","description":"Searches Wikipedia for the specified query.","options":[{"type":3,"name":"query","description":"The search query.","required":true}]}]},{"type":1,"name":"server","description":"Command Group - server","options":[{"type":1,"name":"info","description":"Displays information on the server.","options":[]},{"type":1,"name":"prune","description":"Kicks the inactive members (without any roles) from the server.","options":[{"type":4,"name":"days","description":"The number of days of inactivity required for kicking.","min_value":1},{"type":8,"name":"role","description":"Inactive members check includes this role."},{"type":3,"name":"reason","description":"The reason for pruning the inactive members."}]}]},{"type":1,"name":"status","description":"Displays Bastion's status. You can also see Discord's status.","options":[{"type":5,"name":"shard","description":"Displays the status of the current shard."}]},{"type":1,"name":"su","description":"Command Group - su","options":[{"type":1,"name":"eval","description":"Evaluate JavaScript code in Bastion's context.","options":[{"type":3,"name":"code","description":"The code you want to execute.","required":true},{"type":5,"name":"public","description":"Display the output to everyone."}]},{"type":1,"name":"exec","description":"Execute terminal commands on the system where Bastion is running.","options":[{"type":3,"name":"command","description":"The command you want to execute.","required":true},{"type":5,"name":"public","description":"Display the output to everyone."}]},{"type":1,"name":"reload","description":"Reload Bastion's settings.","options":[]},{"type":1,"name":"shutdown","description":"Shutdown Bastion directly from Discord.","options":[]}]},{"type":1,"name":"suggest","description":"Send a suggestion to the server staff.","options":[{"type":3,"name":"suggestion","description":"What do you want to suggest?","required":true}]},{"type":1,"name":"thread","description":"Command Group - thread","options":[{"type":1,"name":"close","description":"Close and lock the thread.","options":[]},{"type":1,"name":"name","description":"Change the name of the thread.","options":[{"type":3,"name":"name","description":"The new name for the thread.","required":true}]}]},{"type":1,"name":"translate","description":"Translates the specified text from one language to another.","options":[{"type":3,"name":"text","description":"The text you want to translate.","required":true},{"type":3,"name":"to","description":"The language you want to translate to."},{"type":3,"name":"from","description":"The language you want to translate from."}]},{"type":1,"name":"user","description":"Command Group - user","options":[{"type":1,"name":"avatar","description":"Displays the avatar of the specified user.","options":[{"type":6,"name":"user","description":"The user whose avatar you want to display."}]},{"type":1,"name":"info","description":"Displays information on the specified user.","options":[{"type":6,"name":"user","description":"The user whose information you want to display."}]},{"type":1,"name":"infractions","description":"Configure infraction actions and displays infractions of the specified user.","options":[{"type":4,"name":"timeout","description":"Number of violations after which a user is timed out.","min_value":1},{"type":4,"name":"kick","description":"Number of violations after which a user is kicked.","min_value":1},{"type":4,"name":"ban","description":"Number of violations after which a user is banned.","min_value":1},{"type":6,"name":"user","description":"The user whose infractions you want to display."},{"type":4,"name":"remove","description":"The infraction you want to remove from the user.","min_value":1}]}]},{"type":1,"name":"warn","description":"Warn server members and add infractions to their server profile.","options":[{"type":6,"name":"user","description":"The user you want to warn.","required":true},{"type":3,"name":"reason","description":"The reason for the warning.","required":true}]}] \ No newline at end of file From 42b7c61ea4542ee1b4a278617b3903fa0b0662d3 Mon Sep 17 00:00:00 2001 From: TRACTION <19631364+iamtraction@users.noreply.github.com> Date: Tue, 15 Aug 2023 22:54:44 +0530 Subject: [PATCH 08/12] version: 10.12.0 Signed-off-by: TRACTION <19631364+iamtraction@users.noreply.github.com> --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 11129b373..f7b45e4d6 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "bastion", - "version": "10.11.3", + "version": "10.12.0", "description": "Get an enhanced Discord experience!", "type": "module", "homepage": "https://bastion.traction.one", From ae13f0c122e3c28bdbba5d99fd132d934b9d2d88 Mon Sep 17 00:00:00 2001 From: TRACTION <19631364+iamtraction@users.noreply.github.com> Date: Sat, 19 Aug 2023 16:41:01 +0530 Subject: [PATCH 09/12] deps: update Signed-off-by: TRACTION <19631364+iamtraction@users.noreply.github.com> --- package.json | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index f7b45e4d6..56905fac0 100644 --- a/package.json +++ b/package.json @@ -22,21 +22,21 @@ "@types/express": "^4.17.17", "@types/http-errors": "^2.0.1", "@types/jsdom": "^21.1.1", - "@types/node": "^20.4.10", - "@typescript-eslint/eslint-plugin": "^6.3.0", - "@typescript-eslint/parser": "^6.3.0", + "@types/node": "^20.5.1", + "@typescript-eslint/eslint-plugin": "^6.4.0", + "@typescript-eslint/parser": "^6.4.0", "eslint": "^8.47.0", "typescript": "^5.1.6" }, "dependencies": { - "@bastion/tesseract": "^5.0.3", + "@bastion/tesseract": "^5.0.4", "@discordjs/opus": "^0.9.0", "@iamtraction/google-translate": "^2.0.1", "@types/gamedig": "^4.0.1", "discord-rpc": "^4.0.1", "dotenv": "^16.3.1", "emoji-regex": "^10.2.1", - "gamedig": "^4.0.6", + "gamedig": "^4.0.7", "jsdom": "^22.1.0", "libsodium-wrappers": "^0.7.11", "mathjs": "^11.9.1", From be0e36eb633b6df9055ad0fba4e3588820355986 Mon Sep 17 00:00:00 2001 From: TRACTION <19631364+iamtraction@users.noreply.github.com> Date: Sat, 19 Aug 2023 16:42:06 +0530 Subject: [PATCH 10/12] settings: add example for custom status Signed-off-by: TRACTION <19631364+iamtraction@users.noreply.github.com> --- settings.example.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/settings.example.yaml b/settings.example.yaml index ea5b7dcdf..d17f4476d 100644 --- a/settings.example.yaml +++ b/settings.example.yaml @@ -27,7 +27,7 @@ mongoURI: "mongodb://127.0.0.1:27017/bastion" # Presences # Bastion will cycle through these activities randomly. # status — online / idle / dnd / invisible -# activity — 0 (Playing) / 1 (Streaming) / 2 (Listening) / 3 (Watching) / 5 (Competing) +# activity — 0 (Playing) / 1 (Streaming) / 2 (Listening) / 3 (Watching) / 4 (Custom) / 5 (Competing) # name — string # url — Twitch URL when `activity` is set to presences: From 7c172400fa801e48e1f313fe870c0dd49ea54b84 Mon Sep 17 00:00:00 2001 From: TRACTION <19631364+iamtraction@users.noreply.github.com> Date: Sat, 19 Aug 2023 16:43:45 +0530 Subject: [PATCH 11/12] settings: fix example string Signed-off-by: TRACTION <19631364+iamtraction@users.noreply.github.com> --- settings.example.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/settings.example.yaml b/settings.example.yaml index d17f4476d..41c0a537e 100644 --- a/settings.example.yaml +++ b/settings.example.yaml @@ -29,7 +29,7 @@ mongoURI: "mongodb://127.0.0.1:27017/bastion" # status — online / idle / dnd / invisible # activity — 0 (Playing) / 1 (Streaming) / 2 (Listening) / 3 (Watching) / 4 (Custom) / 5 (Competing) # name — string -# url — Twitch URL when `activity` is set to +# url — Twitch URL when `activity` is set to `1` (Streaming) presences: - status: "online" activity: 3 From 879eeaced45751dd48bc68128da3f4a49d2f1360 Mon Sep 17 00:00:00 2001 From: TRACTION <19631364+iamtraction@users.noreply.github.com> Date: Sun, 27 Aug 2023 20:18:14 +0530 Subject: [PATCH 12/12] commands(pokemon): use pokedex API v2 Ref https://github.com/PokeDevs/pokedex-api/issues/17 Signed-off-by: TRACTION <19631364+iamtraction@users.noreply.github.com> --- src/commands/search/pokemon.ts | 73 +++++++++++++++++++--------------- 1 file changed, 40 insertions(+), 33 deletions(-) diff --git a/src/commands/search/pokemon.ts b/src/commands/search/pokemon.ts index 4072cc2e9..06a0f8189 100644 --- a/src/commands/search/pokemon.ts +++ b/src/commands/search/pokemon.ts @@ -9,29 +9,44 @@ import * as requests from "../../utils/requests.js"; import { COLORS } from "../../utils/constants.js"; interface Pokemon { - number?: string; + number?: number; name?: string; - description?: string; + codename?: string; gen?: number; - starter?: boolean; - mega?: boolean; - ultraBeast?: boolean; - legendary?: boolean; - mythical?: boolean; species?: string; - types?: string[]; + types?: string[], abilities?: { - normal: string[]; - hidden: string[]; - }; - eggGroups?: string[]; - gender?: [ number, number ] | []; + name: string; + description: string; + hidden: boolean; + }[]; height?: string; weight?: string; - sprite?: string; - family?: { - evolutionLine: string[]; + mega?: boolean | { + stone: string; + sprite: string; + }; + baseStats?: { + hp: number; + attack: number; + defense: number; + spAtk: number; + spDef: number; + speed: number; + }; + training?: { + evYield: string; + catchRate: string; + baseFriendship: string; + baseExp: string; + growthRate: string; + }; + breeding?: { + gender: string; + eggGroups: string[]; + eggCycles: string; }; + sprite?: string; } class PokemonCommand extends Command { @@ -55,7 +70,7 @@ class PokemonCommand extends Command { const name = interaction.options.getString("name"); // fetch pokemon - const { body } = await requests.get(`https://pokeapi.glitch.me/v1/pokemon/${ encodeURIComponent(name) }`); + const { body } = await requests.get(`https://ex.traction.one/pokedex/pokemon/${ encodeURIComponent(name) }`); const pokemon: Pokemon[] = await body.json() as unknown[]; if (pokemon?.length) { @@ -64,19 +79,19 @@ class PokemonCommand extends Command { { color: COLORS.PRIMARY, author: { - name: (pokemon[0].mythical ? "Mythical " : "") + (pokemon[0].legendary ? "Legendary " : "") + (pokemon[0].mega ? "Mega" : "") + (pokemon[0].ultraBeast ? "Ultra Beast" : "") + (pokemon[0].starter ? "Starter " : "") + "Pokémon", + name: (pokemon[0].codename ? "Ultra Beast" : "") + "Pokémon", }, title: pokemon[0].name, - description: "Discovered in generation " + pokemon[0].gen, + description: pokemon[0].species, fields: [ { name: "Number", - value: pokemon[0].number, + value: "#" + pokemon[0].number?.toString(), inline: true, }, { - name: "Species", - value: pokemon[0].species, + name: "Generation", + value: pokemon[0].gen?.toString(), inline: true, }, { @@ -86,17 +101,17 @@ class PokemonCommand extends Command { }, { name: "Abilities", - value: `Normal: ${pokemon[0].abilities.normal.join(", ") || "-"}\nHidden: ${pokemon[0].abilities.hidden.join(", ") || "-"}`, + value: pokemon[0].abilities.map(a => a.name).join("\n") || "Undiscovered", inline: true, }, { name: "Egg Groups", - value: pokemon[0].eggGroups.join("\n"), + value: pokemon[0].breeding?.eggGroups.join("\n"), inline: true, }, { name: "Gender Ratio", - value: pokemon[0].gender.length ? `${pokemon[0].gender[0]}:${pokemon[0].gender[1]}` : "Genderless", + value: pokemon[0].breeding?.gender || "Undiscovered", inline: true, }, { @@ -109,14 +124,6 @@ class PokemonCommand extends Command { value: pokemon[0].weight, inline: true, }, - { - name: "Evolution Line", - value: pokemon[0].family.evolutionLine.join(" -> "), - }, - { - name: "Description", - value: pokemon[0].description, - }, ], thumbnail: { url: pokemon[0].sprite,