Compare commits
28 commits
0dc430b7d5
...
091b8e5205
Author | SHA1 | Date | |
---|---|---|---|
091b8e5205 | |||
4a5f624da3 | |||
2462ca105a | |||
21bef358b3 | |||
87bef546d3 | |||
647e811c64 | |||
204fd1689f | |||
0026ab659b | |||
9f6e4f4883 | |||
08f01c0210 | |||
3be95bf1ac | |||
ec2b523702 | |||
28d745bf5c | |||
ffc3fcaf89 | |||
6d1e41d697 | |||
f38d1ef23a | |||
b1aab93fad | |||
ce75d8fab6 | |||
6c78c0f74d | |||
c24cfc3463 | |||
53a51fdf96 | |||
c5fc2760c4 | |||
ef19adcdfb | |||
65583f6da2 | |||
e030cb3757 | |||
94c358cfec | |||
39710843a6 | |||
4260b120e7 |
30 changed files with 1164 additions and 720 deletions
11
.dev.env
11
.dev.env
|
@ -7,17 +7,15 @@
|
||||||
# any secret values.
|
# any secret values.
|
||||||
|
|
||||||
BOT_TOKEN=
|
BOT_TOKEN=
|
||||||
BOT_VER=0.1.8 DEV
|
BOT_VER=0.2 DEV
|
||||||
BOT_AUTHOR=Vylpes
|
BOT_AUTHOR=Vylpes
|
||||||
BOT_OWNERID=147392775707426816
|
BOT_OWNERID=147392775707426816
|
||||||
BOT_CLIENTID=682942374040961060
|
BOT_CLIENTID=682942374040961060
|
||||||
|
BOT_ENV=4
|
||||||
|
|
||||||
ABOUT_FUNDING=
|
ABOUT_FUNDING=
|
||||||
ABOUT_REPO=
|
ABOUT_REPO=
|
||||||
|
|
||||||
DROP_RARITY=-1
|
|
||||||
DROP_CARD=-1
|
|
||||||
|
|
||||||
DB_HOST=127.0.0.1
|
DB_HOST=127.0.0.1
|
||||||
DB_PORT=3301
|
DB_PORT=3301
|
||||||
DB_NAME=carddrop
|
DB_NAME=carddrop
|
||||||
|
@ -27,3 +25,8 @@ DB_SYNC=true
|
||||||
DB_LOGGING=true
|
DB_LOGGING=true
|
||||||
|
|
||||||
DB_CARD_FILE=:memory:
|
DB_CARD_FILE=:memory:
|
||||||
|
|
||||||
|
EXPRESS_PORT=3303
|
||||||
|
|
||||||
|
GDRIVESYNC_WHITELIST=147392775707426816,887272961504071690
|
||||||
|
GDRIVESYNC_AUTO=true
|
||||||
|
|
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -108,3 +108,4 @@ config.json
|
||||||
ormconfig.json
|
ormconfig.json
|
||||||
gdrive-credentials.json
|
gdrive-credentials.json
|
||||||
cards/
|
cards/
|
||||||
|
*.db
|
11
.prod.env
11
.prod.env
|
@ -7,17 +7,15 @@
|
||||||
# any secret values.
|
# any secret values.
|
||||||
|
|
||||||
BOT_TOKEN=
|
BOT_TOKEN=
|
||||||
BOT_VER=0.1.8
|
BOT_VER=0.2
|
||||||
BOT_AUTHOR=Vylpes
|
BOT_AUTHOR=Vylpes
|
||||||
BOT_OWNERID=147392775707426816
|
BOT_OWNERID=147392775707426816
|
||||||
BOT_CLIENTID=1093810443589529631
|
BOT_CLIENTID=1093810443589529631
|
||||||
|
BOT_ENV=1
|
||||||
|
|
||||||
ABOUT_FUNDING=
|
ABOUT_FUNDING=
|
||||||
ABOUT_REPO=
|
ABOUT_REPO=
|
||||||
|
|
||||||
DROP_RARITY=-1
|
|
||||||
DROP_CARD=-1
|
|
||||||
|
|
||||||
DB_HOST=127.0.0.1
|
DB_HOST=127.0.0.1
|
||||||
DB_PORT=3321
|
DB_PORT=3321
|
||||||
DB_NAME=carddrop
|
DB_NAME=carddrop
|
||||||
|
@ -27,3 +25,8 @@ DB_SYNC=false
|
||||||
DB_LOGGING=false
|
DB_LOGGING=false
|
||||||
|
|
||||||
DB_CARD_FILE=:memory:
|
DB_CARD_FILE=:memory:
|
||||||
|
|
||||||
|
EXPRESS_PORT=3323
|
||||||
|
|
||||||
|
GDRIVESYNC_WHITELIST=147392775707426816,887272961504071690
|
||||||
|
GDRIVESYNC_AUTO=false
|
||||||
|
|
11
.stage.env
11
.stage.env
|
@ -7,17 +7,15 @@
|
||||||
# any secret values.
|
# any secret values.
|
||||||
|
|
||||||
BOT_TOKEN=
|
BOT_TOKEN=
|
||||||
BOT_VER=0.1.8 BETA
|
BOT_VER=0.2 BETA
|
||||||
BOT_AUTHOR=Vylpes
|
BOT_AUTHOR=Vylpes
|
||||||
BOT_OWNERID=147392775707426816
|
BOT_OWNERID=147392775707426816
|
||||||
BOT_CLIENTID=1147976642942214235
|
BOT_CLIENTID=1147976642942214235
|
||||||
|
BOT_ENV=2
|
||||||
|
|
||||||
ABOUT_FUNDING=
|
ABOUT_FUNDING=
|
||||||
ABOUT_REPO=
|
ABOUT_REPO=
|
||||||
|
|
||||||
DROP_RARITY=-1
|
|
||||||
DROP_CARD=-1
|
|
||||||
|
|
||||||
DB_HOST=127.0.0.1
|
DB_HOST=127.0.0.1
|
||||||
DB_PORT=3311
|
DB_PORT=3311
|
||||||
DB_NAME=carddrop
|
DB_NAME=carddrop
|
||||||
|
@ -27,3 +25,8 @@ DB_SYNC=false
|
||||||
DB_LOGGING=false
|
DB_LOGGING=false
|
||||||
|
|
||||||
DB_CARD_FILE=:memory:
|
DB_CARD_FILE=:memory:
|
||||||
|
|
||||||
|
EXPRESS_PORT=3313
|
||||||
|
|
||||||
|
GDRIVESYNC_WHITELIST=147392775707426816,887272961504071690
|
||||||
|
GDRIVESYNC_AUTO=false
|
||||||
|
|
|
@ -0,0 +1,8 @@
|
||||||
|
CREATE TABLE `config` (
|
||||||
|
`Id` VARCHAR(255) NOT NULL,
|
||||||
|
`WhenCreated` DATETIME NOT NULL,
|
||||||
|
`WhenUpdated` DATETIME NOT NULL,
|
||||||
|
`Key` VARCHAR(255) NOT NULL,
|
||||||
|
`Value` VARCHAR(255) NOT NULL,
|
||||||
|
PRIMARY KEY (`Id`)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
|
15
package.json
15
package.json
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "card-drop",
|
"name": "card-drop",
|
||||||
"version": "0.1.8",
|
"version": "0.2.0",
|
||||||
"main": "./dist/bot.js",
|
"main": "./dist/bot.js",
|
||||||
"typings": "./dist",
|
"typings": "./dist",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
@ -23,22 +23,23 @@
|
||||||
"homepage": "https://gitea.vylpes.xyz/External/card-drop",
|
"homepage": "https://gitea.vylpes.xyz/External/card-drop",
|
||||||
"funding": "https://ko-fi.com/vylpes",
|
"funding": "https://ko-fi.com/vylpes",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@discordjs/rest": "^1.1.0",
|
"@discordjs/rest": "^2.0.0",
|
||||||
"@types/jest": "^29.5.7",
|
"@types/express": "^4.17.20",
|
||||||
|
"@types/jest": "^29.0.0",
|
||||||
"@types/uuid": "^9.0.0",
|
"@types/uuid": "^9.0.0",
|
||||||
|
"body-parser": "^1.20.2",
|
||||||
"discord.js": "^14.3.0",
|
"discord.js": "^14.3.0",
|
||||||
"dotenv": "^16.0.0",
|
"dotenv": "^16.0.0",
|
||||||
"googleapis": "^126.0.0",
|
"express": "^4.18.2",
|
||||||
"jest": "^29.7.0",
|
"jest": "^29.0.0",
|
||||||
"jest-mock-extended": "^3.0.0",
|
"jest-mock-extended": "^3.0.0",
|
||||||
"minimatch": "9.0.2",
|
"minimatch": "9.0.3",
|
||||||
"mysql": "^2.18.1",
|
"mysql": "^2.18.1",
|
||||||
"sqlite3": "^5.1.6",
|
"sqlite3": "^5.1.6",
|
||||||
"ts-jest": "^29.0.0",
|
"ts-jest": "^29.0.0",
|
||||||
"typeorm": "0.3.17"
|
"typeorm": "0.3.17"
|
||||||
},
|
},
|
||||||
"resolutions": {
|
"resolutions": {
|
||||||
"**/@babel/traverse": "^7.23.2",
|
|
||||||
"**/undici": "^5.26.2"
|
"**/undici": "^5.26.2"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
|
5
scripts/gdrive_sync_stage.sh
Normal file
5
scripts/gdrive_sync_stage.sh
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
cd ~/apps/card-drop/card-drop_stage \
|
||||||
|
&& rclone sync card-drop-gdrive: ./cards \
|
||||||
|
&& curl -X POST http://localhost:3313/api/reload-db
|
|
@ -4,15 +4,22 @@ import Card from "../database/entities/card/Card";
|
||||||
import Series from "../database/entities/card/Series";
|
import Series from "../database/entities/card/Series";
|
||||||
import path from "path";
|
import path from "path";
|
||||||
import { CardRarity, CardRarityToString } from "../constants/CardRarity";
|
import { CardRarity, CardRarityToString } from "../constants/CardRarity";
|
||||||
|
import Config from "../database/entities/app/Config";
|
||||||
|
|
||||||
export default class CardSetupFunction {
|
export default class CardSetupFunction {
|
||||||
public async Execute() {
|
public static async Execute() {
|
||||||
|
if (await Config.GetValue('safemode') == "true") return;
|
||||||
|
|
||||||
|
try {
|
||||||
await this.ClearDatabase();
|
await this.ClearDatabase();
|
||||||
await this.ReadSeries();
|
await this.ReadSeries();
|
||||||
await this.ReadCards();
|
await this.ReadCards();
|
||||||
|
} catch {
|
||||||
|
await Config.SetValue('safemode', 'true');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async ClearDatabase() {
|
private static async ClearDatabase() {
|
||||||
const cardRepository = CardDataSource.getRepository(Card);
|
const cardRepository = CardDataSource.getRepository(Card);
|
||||||
await cardRepository.clear();
|
await cardRepository.clear();
|
||||||
|
|
||||||
|
@ -20,7 +27,7 @@ export default class CardSetupFunction {
|
||||||
await seriesRepository.clear();
|
await seriesRepository.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
private async ReadSeries() {
|
private static async ReadSeries() {
|
||||||
const seriesDir = readdirSync(path.join(process.cwd(), 'cards'));
|
const seriesDir = readdirSync(path.join(process.cwd(), 'cards'));
|
||||||
|
|
||||||
const seriesRepository = CardDataSource.getRepository(Series);
|
const seriesRepository = CardDataSource.getRepository(Series);
|
||||||
|
@ -41,7 +48,7 @@ export default class CardSetupFunction {
|
||||||
await seriesRepository.save(seriesToSave);
|
await seriesRepository.save(seriesToSave);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async ReadCards() {
|
private static async ReadCards() {
|
||||||
const loadedSeries = await Series.FetchAll(Series, [ "Cards", "Cards.Series" ]);
|
const loadedSeries = await Series.FetchAll(Series, [ "Cards", "Cards.Series" ]);
|
||||||
|
|
||||||
const cardRepository = CardDataSource.getRepository(Card);
|
const cardRepository = CardDataSource.getRepository(Card);
|
||||||
|
@ -69,7 +76,7 @@ export default class CardSetupFunction {
|
||||||
console.log(`Loaded ${cardsToSave.length} cards to database`);
|
console.log(`Loaded ${cardsToSave.length} cards to database`);
|
||||||
}
|
}
|
||||||
|
|
||||||
private GenerateCardData(files: string[], rarity: CardRarity, series: Series): Card[] {
|
private static GenerateCardData(files: string[], rarity: CardRarity, series: Series): Card[] {
|
||||||
const result: Card[] = [];
|
const result: Card[] = [];
|
||||||
|
|
||||||
for (let file of files.filter(x => !x.startsWith('.') && (x.endsWith('.png') || x.endsWith('.jpg') || x.endsWith('.gif')))) {
|
for (let file of files.filter(x => !x.startsWith('.') && (x.endsWith('.png') || x.endsWith('.jpg') || x.endsWith('.gif')))) {
|
||||||
|
@ -86,7 +93,7 @@ export default class CardSetupFunction {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private GetCardFiles(rarity: CardRarity, series: Series): string[] {
|
private static GetCardFiles(rarity: CardRarity, series: Series): string[] {
|
||||||
const folder = path.join(process.cwd(), 'cards', series.Path, CardRarityToString(rarity).toUpperCase());
|
const folder = path.join(process.cwd(), 'cards', series.Path, CardRarityToString(rarity).toUpperCase());
|
||||||
const folderExists = existsSync(folder);
|
const folderExists = existsSync(folder);
|
||||||
|
|
||||||
|
|
21
src/bot.ts
21
src/bot.ts
|
@ -2,6 +2,8 @@ import * as dotenv from "dotenv";
|
||||||
import { CoreClient } from "./client/client";
|
import { CoreClient } from "./client/client";
|
||||||
import { IntentsBitField } from "discord.js";
|
import { IntentsBitField } from "discord.js";
|
||||||
import Registry from "./registry";
|
import Registry from "./registry";
|
||||||
|
import { existsSync } from "fs";
|
||||||
|
import { ExecException, exec } from "child_process";
|
||||||
|
|
||||||
dotenv.config();
|
dotenv.config();
|
||||||
|
|
||||||
|
@ -11,12 +13,15 @@ const requiredConfigs: string[] = [
|
||||||
"BOT_AUTHOR",
|
"BOT_AUTHOR",
|
||||||
"BOT_OWNERID",
|
"BOT_OWNERID",
|
||||||
"BOT_CLIENTID",
|
"BOT_CLIENTID",
|
||||||
|
"BOT_ENV",
|
||||||
"DB_HOST",
|
"DB_HOST",
|
||||||
"DB_PORT",
|
"DB_PORT",
|
||||||
"DB_AUTH_USER",
|
"DB_AUTH_USER",
|
||||||
"DB_AUTH_PASS",
|
"DB_AUTH_PASS",
|
||||||
"DB_SYNC",
|
"DB_SYNC",
|
||||||
"DB_LOGGING",
|
"DB_LOGGING",
|
||||||
|
"EXPRESS_PORT",
|
||||||
|
"GDRIVESYNC_WHITELIST",
|
||||||
]
|
]
|
||||||
|
|
||||||
requiredConfigs.forEach(config => {
|
requiredConfigs.forEach(config => {
|
||||||
|
@ -34,4 +39,20 @@ Registry.RegisterCommands();
|
||||||
Registry.RegisterEvents();
|
Registry.RegisterEvents();
|
||||||
Registry.RegisterButtonEvents();
|
Registry.RegisterButtonEvents();
|
||||||
|
|
||||||
|
if (!existsSync(`${process.cwd()}/cards`) && process.env.GDRIVESYNC_AUTO && process.env.GDRIVESYNC_AUTO == 'true') {
|
||||||
|
console.log("Card directory not found, syncing...");
|
||||||
|
|
||||||
|
CoreClient.AllowDrops = false;
|
||||||
|
|
||||||
|
exec(`rclone sync card-drop-gdrive: ${process.cwd()}/cards`, async (error: ExecException | null) => {
|
||||||
|
if (error) {
|
||||||
|
console.error(error.code);
|
||||||
|
throw `Error while running sync command. Code: ${error.code}`;
|
||||||
|
} else {
|
||||||
|
console.log('Synced successfully.');
|
||||||
|
CoreClient.AllowDrops = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
client.start();
|
client.start();
|
|
@ -40,6 +40,6 @@ export default class Claim extends ButtonEvent {
|
||||||
|
|
||||||
await claim.Save(eClaim, claim);
|
await claim.Save(eClaim, claim);
|
||||||
|
|
||||||
await interaction.reply('Card claimed');
|
await interaction.reply(`Card claimed by ${interaction.user}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,29 +1,31 @@
|
||||||
import { ActionRowBuilder, AttachmentBuilder, ButtonBuilder, ButtonInteraction, ButtonStyle, CacheType, DiscordAPIError, EmbedBuilder } from "discord.js";
|
import { AttachmentBuilder, ButtonInteraction, DiscordAPIError } from "discord.js";
|
||||||
import { ButtonEvent } from "../type/buttonEvent";
|
import { ButtonEvent } from "../type/buttonEvent";
|
||||||
import CardDropHelper from "../helpers/CardDropHelper";
|
import CardDropHelper from "../helpers/CardDropHelper";
|
||||||
import { readFileSync } from "fs";
|
import { readFileSync } from "fs";
|
||||||
import { CardRarityToColour, CardRarityToString } from "../constants/CardRarity";
|
|
||||||
import { v4 } from "uuid";
|
import { v4 } from "uuid";
|
||||||
import { CoreClient } from "../client/client";
|
import { CoreClient } from "../client/client";
|
||||||
import Card from "../database/entities/card/Card";
|
import Inventory from "../database/entities/app/Inventory";
|
||||||
|
import Config from "../database/entities/app/Config";
|
||||||
|
|
||||||
export default class Reroll extends ButtonEvent {
|
export default class Reroll extends ButtonEvent {
|
||||||
public override async execute(interaction: ButtonInteraction) {
|
public override async execute(interaction: ButtonInteraction) {
|
||||||
|
if (!CoreClient.AllowDrops) {
|
||||||
|
await interaction.reply('Bot is currently syncing, please wait until its done.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (await Config.GetValue('safemode') == "true")
|
||||||
|
{
|
||||||
|
await interaction.reply('Safe Mode has been activated, please resync to contunue.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (!interaction.guild || !interaction.guildId) return;
|
if (!interaction.guild || !interaction.guildId) return;
|
||||||
|
|
||||||
let randomCard = await CardDropHelper.GetRandomCard();
|
let randomCard = await CardDropHelper.GetRandomCard();
|
||||||
|
|
||||||
if (process.env.DROP_RARITY && Number(process.env.DROP_RARITY) > 0) {
|
if (process.env.DROP_RARITY && Number(process.env.DROP_RARITY) > 0) {
|
||||||
randomCard = await CardDropHelper.GetRandomCardByRarity(Number(process.env.DROP_RARITY));
|
randomCard = await CardDropHelper.GetRandomCardByRarity(Number(process.env.DROP_RARITY));
|
||||||
} else if (process.env.DROP_CARD && process.env.DROP_CARD != '-1') {
|
|
||||||
let card = await Card.FetchOneByCardNumber(process.env.DROP_CARD, [ "Series" ]);
|
|
||||||
|
|
||||||
if (!card) {
|
|
||||||
await interaction.reply("Card not found");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
randomCard = card;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const image = readFileSync(randomCard.Path);
|
const image = readFileSync(randomCard.Path);
|
||||||
|
@ -32,26 +34,14 @@ export default class Reroll extends ButtonEvent {
|
||||||
|
|
||||||
const attachment = new AttachmentBuilder(image, { name: randomCard.FileName });
|
const attachment = new AttachmentBuilder(image, { name: randomCard.FileName });
|
||||||
|
|
||||||
const embed = new EmbedBuilder()
|
const inventory = await Inventory.FetchOneByCardNumberAndUserId(interaction.user.id, randomCard.CardNumber);
|
||||||
.setTitle(randomCard.Name)
|
const quantityClaimed = inventory ? inventory.Quantity : 0;
|
||||||
.setDescription(randomCard.Series.Name)
|
|
||||||
.setFooter({ text: CardRarityToString(randomCard.Rarity) })
|
|
||||||
.setColor(CardRarityToColour(randomCard.Rarity))
|
|
||||||
.setImage(`attachment://${randomCard.FileName}`);
|
|
||||||
|
|
||||||
const row = new ActionRowBuilder<ButtonBuilder>();
|
const embed = CardDropHelper.GenerateDropEmbed(randomCard, quantityClaimed || 0);
|
||||||
|
|
||||||
const claimId = v4();
|
const claimId = v4();
|
||||||
|
|
||||||
row.addComponents(
|
const row = CardDropHelper.GenerateDropButtons(randomCard, claimId, interaction.user.id);
|
||||||
new ButtonBuilder()
|
|
||||||
.setCustomId(`claim ${randomCard.CardNumber} ${claimId} ${interaction.user.id}`)
|
|
||||||
.setLabel("Claim")
|
|
||||||
.setStyle(ButtonStyle.Primary),
|
|
||||||
new ButtonBuilder()
|
|
||||||
.setCustomId(`reroll`)
|
|
||||||
.setLabel("Reroll")
|
|
||||||
.setStyle(ButtonStyle.Secondary));
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await interaction.editReply({
|
await interaction.editReply({
|
||||||
|
@ -62,7 +52,6 @@ export default class Reroll extends ButtonEvent {
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error(e);
|
console.error(e);
|
||||||
|
|
||||||
|
|
||||||
if (e instanceof DiscordAPIError) {
|
if (e instanceof DiscordAPIError) {
|
||||||
await interaction.editReply(`Unable to send next drop. Please try again, and report this if it keeps happening. Code: ${e.code}`);
|
await interaction.editReply(`Unable to send next drop. Please try again, and report this if it keeps happening. Code: ${e.code}`);
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -12,6 +12,8 @@ import CardDataSource from "../database/dataSources/cardDataSource";
|
||||||
import IButtonEventItem from "../contracts/IButtonEventItem";
|
import IButtonEventItem from "../contracts/IButtonEventItem";
|
||||||
import { ButtonEvent } from "../type/buttonEvent";
|
import { ButtonEvent } from "../type/buttonEvent";
|
||||||
import AppDataSource from "../database/dataSources/appDataSource";
|
import AppDataSource from "../database/dataSources/appDataSource";
|
||||||
|
import { Environment } from "../constants/Environment";
|
||||||
|
import Webhooks from "../webhooks";
|
||||||
|
|
||||||
export class CoreClient extends Client {
|
export class CoreClient extends Client {
|
||||||
private static _commandItems: ICommandItem[];
|
private static _commandItems: ICommandItem[];
|
||||||
|
@ -20,9 +22,11 @@ export class CoreClient extends Client {
|
||||||
|
|
||||||
private _events: Events;
|
private _events: Events;
|
||||||
private _util: Util;
|
private _util: Util;
|
||||||
private _cardSetupFunc: CardSetupFunction;
|
private _webhooks: Webhooks;
|
||||||
|
|
||||||
public static ClaimId: string;
|
public static ClaimId: string;
|
||||||
|
public static Environment: Environment;
|
||||||
|
public static AllowDrops: boolean;
|
||||||
|
|
||||||
public static get commandItems(): ICommandItem[] {
|
public static get commandItems(): ICommandItem[] {
|
||||||
return this._commandItems;
|
return this._commandItems;
|
||||||
|
@ -46,7 +50,12 @@ export class CoreClient extends Client {
|
||||||
|
|
||||||
this._events = new Events();
|
this._events = new Events();
|
||||||
this._util = new Util();
|
this._util = new Util();
|
||||||
this._cardSetupFunc = new CardSetupFunction();
|
this._webhooks = new Webhooks();
|
||||||
|
|
||||||
|
CoreClient.Environment = Number(process.env.BOT_ENV);
|
||||||
|
console.log(`Bot Environment: ${CoreClient.Environment}`);
|
||||||
|
|
||||||
|
CoreClient.AllowDrops = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async start() {
|
public async start() {
|
||||||
|
@ -66,39 +75,54 @@ export class CoreClient extends Client {
|
||||||
super.on("interactionCreate", this._events.onInteractionCreate);
|
super.on("interactionCreate", this._events.onInteractionCreate);
|
||||||
super.on("ready", this._events.onReady);
|
super.on("ready", this._events.onReady);
|
||||||
|
|
||||||
await this._cardSetupFunc.Execute();
|
await CardSetupFunction.Execute();
|
||||||
|
|
||||||
await super.login(process.env.BOT_TOKEN);
|
|
||||||
|
|
||||||
this._util.loadEvents(this, CoreClient._eventItems);
|
this._util.loadEvents(this, CoreClient._eventItems);
|
||||||
this._util.loadSlashCommands(this);
|
this._util.loadSlashCommands(this);
|
||||||
|
|
||||||
|
this._webhooks.start();
|
||||||
|
|
||||||
|
console.log(`Registered Commands: ${CoreClient._commandItems.flatMap(x => x.Name).join(", ")}`);
|
||||||
|
console.log(`Registered Events: ${CoreClient._eventItems.flatMap(x => x.EventType).join(", ")}`);
|
||||||
|
console.log(`Registered Buttons: ${CoreClient._buttonEvents.flatMap(x => x.ButtonId).join(", ")}`);
|
||||||
|
|
||||||
|
await super.login(process.env.BOT_TOKEN);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static RegisterCommand(name: string, command: Command, serverId?: string) {
|
public static RegisterCommand(name: string, command: Command, environment: Environment = Environment.All, serverId?: string) {
|
||||||
const item: ICommandItem = {
|
const item: ICommandItem = {
|
||||||
Name: name,
|
Name: name,
|
||||||
|
Environment: environment,
|
||||||
Command: command,
|
Command: command,
|
||||||
ServerId: serverId,
|
ServerId: serverId,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (environment &= CoreClient.Environment) {
|
||||||
CoreClient._commandItems.push(item);
|
CoreClient._commandItems.push(item);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static RegisterEvent(eventType: EventType, func: Function) {
|
public static RegisterEvent(eventType: EventType, func: Function, environment: Environment = Environment.All) {
|
||||||
const item: IEventItem = {
|
const item: IEventItem = {
|
||||||
EventType: eventType,
|
EventType: eventType,
|
||||||
ExecutionFunction: func,
|
ExecutionFunction: func,
|
||||||
|
Environment: environment,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (environment &= CoreClient.Environment) {
|
||||||
CoreClient._eventItems.push(item);
|
CoreClient._eventItems.push(item);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static RegisterButtonEvent(buttonId: string, event: ButtonEvent) {
|
public static RegisterButtonEvent(buttonId: string, event: ButtonEvent, environment: Environment = Environment.All) {
|
||||||
const item: IButtonEventItem = {
|
const item: IButtonEventItem = {
|
||||||
ButtonId: buttonId,
|
ButtonId: buttonId,
|
||||||
Event: event,
|
Event: event,
|
||||||
|
Environment: environment,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (environment &= CoreClient.Environment) {
|
||||||
CoreClient._buttonEvents.push(item);
|
CoreClient._buttonEvents.push(item);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -10,9 +10,15 @@ export class Util {
|
||||||
const globalCommands = registeredCommands.filter(x => !x.ServerId);
|
const globalCommands = registeredCommands.filter(x => !x.ServerId);
|
||||||
const guildCommands = registeredCommands.filter(x => x.ServerId);
|
const guildCommands = registeredCommands.filter(x => x.ServerId);
|
||||||
|
|
||||||
const globalCommandData: SlashCommandBuilder[] = globalCommands
|
const globalCommandData: SlashCommandBuilder[] = [];
|
||||||
.filter(x => x.Command.CommandBuilder)
|
|
||||||
.flatMap(x => x.Command.CommandBuilder);
|
for (let command of globalCommands) {
|
||||||
|
if (!command.Command.CommandBuilder) continue;
|
||||||
|
|
||||||
|
if (command.Environment &= CoreClient.Environment) {
|
||||||
|
globalCommandData.push(command.Command.CommandBuilder);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const guildIds: string[] = [];
|
const guildIds: string[] = [];
|
||||||
|
|
||||||
|
@ -32,9 +38,15 @@ export class Util {
|
||||||
);
|
);
|
||||||
|
|
||||||
for (let guild of guildIds) {
|
for (let guild of guildIds) {
|
||||||
const guildCommandData = guildCommands.filter(x => x.ServerId == guild)
|
const guildCommandData: SlashCommandBuilder[] = [];
|
||||||
.filter(x => x.Command.CommandBuilder)
|
|
||||||
.flatMap(x => x.Command.CommandBuilder);
|
for (let command of guildCommands.filter(x => x.ServerId == guild)) {
|
||||||
|
if (!command.Command.CommandBuilder) continue;
|
||||||
|
|
||||||
|
if (command.Environment &= CoreClient.Environment) {
|
||||||
|
guildCommandData.push(command.Command.CommandBuilder);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!client.guilds.cache.has(guild)) continue;
|
if (!client.guilds.cache.has(guild)) continue;
|
||||||
|
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
import { ActionRowBuilder, AttachmentBuilder, ButtonBuilder, ButtonStyle, CommandInteraction, DiscordAPIError, EmbedBuilder, SlashCommandBuilder } from "discord.js";
|
import { AttachmentBuilder, CommandInteraction, DiscordAPIError, SlashCommandBuilder } from "discord.js";
|
||||||
import { Command } from "../type/command";
|
import { Command } from "../type/command";
|
||||||
import CardDropHelper from "../helpers/CardDropHelper";
|
import CardDropHelper from "../helpers/CardDropHelper";
|
||||||
import { CardRarityToColour, CardRarityToString } from "../constants/CardRarity";
|
|
||||||
import { readFileSync } from "fs";
|
import { readFileSync } from "fs";
|
||||||
import { CoreClient } from "../client/client";
|
import { CoreClient } from "../client/client";
|
||||||
import { v4 } from "uuid";
|
import { v4 } from "uuid";
|
||||||
import Card from "../database/entities/card/Card";
|
import Inventory from "../database/entities/app/Inventory";
|
||||||
|
import Config from "../database/entities/app/Config";
|
||||||
|
|
||||||
export default class Drop extends Command {
|
export default class Drop extends Command {
|
||||||
constructor() {
|
constructor() {
|
||||||
|
@ -17,47 +17,33 @@ export default class Drop extends Command {
|
||||||
}
|
}
|
||||||
|
|
||||||
public override async execute(interaction: CommandInteraction) {
|
public override async execute(interaction: CommandInteraction) {
|
||||||
let randomCard = await CardDropHelper.GetRandomCard();
|
if (!CoreClient.AllowDrops) {
|
||||||
|
await interaction.reply('Bot is currently syncing, please wait until its done.');
|
||||||
if (process.env.DROP_RARITY && Number(process.env.DROP_RARITY) > 0) {
|
|
||||||
randomCard = await CardDropHelper.GetRandomCardByRarity(Number(process.env.DROP_RARITY));
|
|
||||||
} else if (process.env.DROP_CARD && process.env.DROP_CARD != '-1') {
|
|
||||||
let card = await Card.FetchOneByCardNumber(process.env.DROP_CARD, [ "Series" ]);
|
|
||||||
|
|
||||||
if (!card) {
|
|
||||||
await interaction.reply("Card not found");
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
randomCard = card;
|
if (await Config.GetValue('safemode') == "true")
|
||||||
|
{
|
||||||
|
await interaction.reply('Safe Mode has been activated, please resync to contunue.');
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const randomCard = await CardDropHelper.GetRandomCard();
|
||||||
|
|
||||||
const image = readFileSync(randomCard.Path);
|
const image = readFileSync(randomCard.Path);
|
||||||
|
|
||||||
await interaction.deferReply();
|
await interaction.deferReply();
|
||||||
|
|
||||||
const attachment = new AttachmentBuilder(image, { name: randomCard.FileName });
|
const attachment = new AttachmentBuilder(image, { name: randomCard.FileName });
|
||||||
|
|
||||||
const embed = new EmbedBuilder()
|
const inventory = await Inventory.FetchOneByCardNumberAndUserId(interaction.user.id, randomCard.CardNumber);
|
||||||
.setTitle(randomCard.Name)
|
const quantityClaimed = inventory ? inventory.Quantity : 0;
|
||||||
.setDescription(randomCard.Series.Name)
|
|
||||||
.setFooter({ text: CardRarityToString(randomCard.Rarity) })
|
|
||||||
.setColor(CardRarityToColour(randomCard.Rarity))
|
|
||||||
.setImage(`attachment://${randomCard.FileName}`);
|
|
||||||
|
|
||||||
const row = new ActionRowBuilder<ButtonBuilder>();
|
const embed = CardDropHelper.GenerateDropEmbed(randomCard, quantityClaimed || 0);
|
||||||
|
|
||||||
const claimId = v4();
|
const claimId = v4();
|
||||||
|
|
||||||
row.addComponents(
|
const row = CardDropHelper.GenerateDropButtons(randomCard, claimId, interaction.user.id);
|
||||||
new ButtonBuilder()
|
|
||||||
.setCustomId(`claim ${randomCard.CardNumber} ${claimId} ${interaction.user.id}`)
|
|
||||||
.setLabel("Claim")
|
|
||||||
.setStyle(ButtonStyle.Primary),
|
|
||||||
new ButtonBuilder()
|
|
||||||
.setCustomId(`reroll`)
|
|
||||||
.setLabel("Reroll")
|
|
||||||
.setStyle(ButtonStyle.Secondary));
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await interaction.editReply({
|
await interaction.editReply({
|
||||||
|
@ -68,7 +54,6 @@ export default class Drop extends Command {
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error(e);
|
console.error(e);
|
||||||
|
|
||||||
|
|
||||||
if (e instanceof DiscordAPIError) {
|
if (e instanceof DiscordAPIError) {
|
||||||
await interaction.editReply(`Unable to send next drop. Please try again, and report this if it keeps happening. Code: ${e.code}`);
|
await interaction.editReply(`Unable to send next drop. Please try again, and report this if it keeps happening. Code: ${e.code}`);
|
||||||
} else {
|
} else {
|
||||||
|
|
45
src/commands/gdrivesync.ts
Normal file
45
src/commands/gdrivesync.ts
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
import { CacheType, CommandInteraction, PermissionsBitField, SlashCommandBuilder } from "discord.js";
|
||||||
|
import { Command } from "../type/command";
|
||||||
|
import { ExecException, exec } from "child_process";
|
||||||
|
import CardSetupFunction from "../Functions/CardSetupFunction";
|
||||||
|
import { CoreClient } from "../client/client";
|
||||||
|
import Config from "../database/entities/app/Config";
|
||||||
|
|
||||||
|
export default class Gdrivesync extends Command {
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
|
||||||
|
super.CommandBuilder = new SlashCommandBuilder()
|
||||||
|
.setName('gdrivesync')
|
||||||
|
.setDescription('Sync google drive to the bot')
|
||||||
|
.setDefaultMemberPermissions(PermissionsBitField.Flags.Administrator);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override async execute(interaction: CommandInteraction<CacheType>) {
|
||||||
|
if (!interaction.isChatInputCommand()) return;
|
||||||
|
|
||||||
|
const whitelistedUsers = process.env.GDRIVESYNC_WHITELIST!.split(',');
|
||||||
|
|
||||||
|
if (!whitelistedUsers.find(x => x == interaction.user.id)) {
|
||||||
|
await interaction.reply("Only whitelisted users can use this command.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
await interaction.reply('Syncing, this might take a while...');
|
||||||
|
|
||||||
|
CoreClient.AllowDrops = false;
|
||||||
|
|
||||||
|
exec(`rclone sync card-drop-gdrive: ${process.cwd()}/cards`, async (error: ExecException | null) => {
|
||||||
|
if (error) {
|
||||||
|
await interaction.editReply(`Error while running sync command. Safe Mode has been activated. Code: ${error.code}`);
|
||||||
|
await Config.SetValue('safemode', 'true');
|
||||||
|
} else {
|
||||||
|
await CardSetupFunction.Execute();
|
||||||
|
await interaction.editReply('Synced successfully.');
|
||||||
|
|
||||||
|
CoreClient.AllowDrops = true;
|
||||||
|
await Config.SetValue('safemode', 'false');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
76
src/commands/stage/dropnumber.ts
Normal file
76
src/commands/stage/dropnumber.ts
Normal file
|
@ -0,0 +1,76 @@
|
||||||
|
import { AttachmentBuilder, CacheType, CommandInteraction, DiscordAPIError, SlashCommandBuilder } from "discord.js";
|
||||||
|
import { Command } from "../../type/command";
|
||||||
|
import Card from "../../database/entities/card/Card";
|
||||||
|
import { readFileSync } from "fs";
|
||||||
|
import Inventory from "../../database/entities/app/Inventory";
|
||||||
|
import CardDropHelper from "../../helpers/CardDropHelper";
|
||||||
|
import { v4 } from "uuid";
|
||||||
|
import { CoreClient } from "../../client/client";
|
||||||
|
|
||||||
|
export default class Dropnumber extends Command {
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
|
||||||
|
super.CommandBuilder = new SlashCommandBuilder()
|
||||||
|
.setName('dropnumber')
|
||||||
|
.setDescription('(TEST) Summon a specific card')
|
||||||
|
.addStringOption(x =>
|
||||||
|
x
|
||||||
|
.setName('cardnumber')
|
||||||
|
.setDescription('The card number to summon')
|
||||||
|
.setRequired(true));
|
||||||
|
}
|
||||||
|
|
||||||
|
public override async execute(interaction: CommandInteraction<CacheType>) {
|
||||||
|
if (!interaction.isChatInputCommand()) return;
|
||||||
|
|
||||||
|
const cardNumber = interaction.options.get('cardnumber');
|
||||||
|
|
||||||
|
if (!cardNumber || !cardNumber.value) {
|
||||||
|
await interaction.reply('Card Number is required');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const card = await Card.FetchOneByCardNumber(cardNumber.value.toString(), [
|
||||||
|
"Series"
|
||||||
|
]);
|
||||||
|
|
||||||
|
if (!card) {
|
||||||
|
await interaction.reply('Card not found');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const image = readFileSync(card.Path);
|
||||||
|
|
||||||
|
await interaction.deferReply();
|
||||||
|
|
||||||
|
const attachment = new AttachmentBuilder(image, { name: card.FileName });
|
||||||
|
|
||||||
|
const inventory = await Inventory.FetchOneByCardNumberAndUserId(interaction.user.id, card.CardNumber);
|
||||||
|
const quantityClaimed = inventory ? inventory.Quantity : 0;
|
||||||
|
|
||||||
|
const embed = CardDropHelper.GenerateDropEmbed(card, quantityClaimed || 0);
|
||||||
|
|
||||||
|
const claimId = v4();
|
||||||
|
|
||||||
|
const row = CardDropHelper.GenerateDropButtons(card, claimId, interaction.user.id);
|
||||||
|
|
||||||
|
try {
|
||||||
|
await interaction.editReply({
|
||||||
|
embeds: [ embed ],
|
||||||
|
files: [ attachment ],
|
||||||
|
components: [ row ],
|
||||||
|
});
|
||||||
|
} catch (e) {
|
||||||
|
console.error(e);
|
||||||
|
|
||||||
|
if (e instanceof DiscordAPIError) {
|
||||||
|
await interaction.editReply(`Unable to send next drop. Please try again, and report this if it keeps happening. Code: ${e.code}`);
|
||||||
|
} else {
|
||||||
|
await interaction.editReply(`Unable to send next drop. Please try again, and report this if it keeps happening.Code: UNKNOWN`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CoreClient.ClaimId = claimId;
|
||||||
|
}
|
||||||
|
}
|
81
src/commands/stage/droprarity.ts
Normal file
81
src/commands/stage/droprarity.ts
Normal file
|
@ -0,0 +1,81 @@
|
||||||
|
import { AttachmentBuilder, CacheType, CommandInteraction, DiscordAPIError, SlashCommandBuilder } from "discord.js";
|
||||||
|
import { Command } from "../../type/command";
|
||||||
|
import { CardRarity, CardRarityParse } from "../../constants/CardRarity";
|
||||||
|
import CardDropHelper from "../../helpers/CardDropHelper";
|
||||||
|
import { readFileSync } from "fs";
|
||||||
|
import Inventory from "../../database/entities/app/Inventory";
|
||||||
|
import { v4 } from "uuid";
|
||||||
|
import { CoreClient } from "../../client/client";
|
||||||
|
|
||||||
|
export default class Droprarity extends Command {
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
|
||||||
|
super.CommandBuilder = new SlashCommandBuilder()
|
||||||
|
.setName('droprarity')
|
||||||
|
.setDescription('(TEST) Summon a random card of a specific rarity')
|
||||||
|
.addStringOption(x =>
|
||||||
|
x
|
||||||
|
.setName('rarity')
|
||||||
|
.setDescription('The rarity you want to summon')
|
||||||
|
.setRequired(true));
|
||||||
|
}
|
||||||
|
|
||||||
|
public override async execute(interaction: CommandInteraction<CacheType>) {
|
||||||
|
if (!interaction.isChatInputCommand()) return;
|
||||||
|
|
||||||
|
const rarity = interaction.options.get('rarity');
|
||||||
|
|
||||||
|
if (!rarity || !rarity.value) {
|
||||||
|
await interaction.reply('Rarity is required');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const rarityType = CardRarityParse(rarity.value.toString());
|
||||||
|
|
||||||
|
if (rarityType == CardRarity.Unknown) {
|
||||||
|
await interaction.reply('Invalid rarity');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const card = await CardDropHelper.GetRandomCardByRarity(rarityType);
|
||||||
|
|
||||||
|
if (!card) {
|
||||||
|
await interaction.reply('Card not found');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const image = readFileSync(card.Path);
|
||||||
|
|
||||||
|
await interaction.deferReply();
|
||||||
|
|
||||||
|
const attachment = new AttachmentBuilder(image, { name: card.FileName });
|
||||||
|
|
||||||
|
const inventory = await Inventory.FetchOneByCardNumberAndUserId(interaction.user.id, card.CardNumber);
|
||||||
|
const quantityClaimed = inventory ? inventory.Quantity : 0;
|
||||||
|
|
||||||
|
const embed = CardDropHelper.GenerateDropEmbed(card, quantityClaimed || 0);
|
||||||
|
|
||||||
|
const claimId = v4();
|
||||||
|
|
||||||
|
const row = CardDropHelper.GenerateDropButtons(card, claimId, interaction.user.id);
|
||||||
|
|
||||||
|
try {
|
||||||
|
await interaction.editReply({
|
||||||
|
embeds: [ embed ],
|
||||||
|
files: [ attachment ],
|
||||||
|
components: [ row ],
|
||||||
|
});
|
||||||
|
} catch (e) {
|
||||||
|
console.error(e);
|
||||||
|
|
||||||
|
if (e instanceof DiscordAPIError) {
|
||||||
|
await interaction.editReply(`Unable to send next drop. Please try again, and report this if it keeps happening. Code: ${e.code}`);
|
||||||
|
} else {
|
||||||
|
await interaction.editReply(`Unable to send next drop. Please try again, and report this if it keeps happening. Code: UNKNOWN`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CoreClient.ClaimId = claimId;
|
||||||
|
}
|
||||||
|
}
|
|
@ -42,3 +42,20 @@ export function CardRarityToColour(rarity: CardRarity): number {
|
||||||
return EmbedColours.MangaCard;
|
return EmbedColours.MangaCard;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function CardRarityParse(rarity: string): CardRarity {
|
||||||
|
switch (rarity.toLowerCase()) {
|
||||||
|
case "bronze":
|
||||||
|
return CardRarity.Bronze;
|
||||||
|
case "silver":
|
||||||
|
return CardRarity.Silver;
|
||||||
|
case "gold":
|
||||||
|
return CardRarity.Gold;
|
||||||
|
case "legendary":
|
||||||
|
return CardRarity.Legendary;
|
||||||
|
case "manga":
|
||||||
|
return CardRarity.Manga;
|
||||||
|
default:
|
||||||
|
return CardRarity.Unknown;
|
||||||
|
}
|
||||||
|
}
|
9
src/constants/Environment.ts
Normal file
9
src/constants/Environment.ts
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
export enum Environment {
|
||||||
|
None = 0,
|
||||||
|
Production = 1 << 0,
|
||||||
|
Stage = 1 << 1,
|
||||||
|
Local = 1 << 2,
|
||||||
|
|
||||||
|
All = Production | Stage | Local,
|
||||||
|
Test = Stage | Local,
|
||||||
|
}
|
|
@ -1,6 +1,8 @@
|
||||||
|
import { Environment } from "../constants/Environment";
|
||||||
import { ButtonEvent } from "../type/buttonEvent";
|
import { ButtonEvent } from "../type/buttonEvent";
|
||||||
|
|
||||||
export default interface IButtonEventItem {
|
export default interface IButtonEventItem {
|
||||||
ButtonId: string,
|
ButtonId: string,
|
||||||
Event: ButtonEvent,
|
Event: ButtonEvent,
|
||||||
|
Environment: Environment,
|
||||||
}
|
}
|
|
@ -1,7 +1,9 @@
|
||||||
|
import { Environment } from "../constants/Environment";
|
||||||
import { Command } from "../type/command";
|
import { Command } from "../type/command";
|
||||||
|
|
||||||
export default interface ICommandItem {
|
export default interface ICommandItem {
|
||||||
Name: string,
|
Name: string,
|
||||||
Command: Command,
|
Command: Command,
|
||||||
|
Environment: Environment,
|
||||||
ServerId?: string,
|
ServerId?: string,
|
||||||
}
|
}
|
|
@ -1,7 +1,9 @@
|
||||||
|
|
||||||
|
import { Environment } from "../constants/Environment";
|
||||||
import { EventType } from "../constants/EventType";
|
import { EventType } from "../constants/EventType";
|
||||||
|
|
||||||
export default interface IEventItem {
|
export default interface IEventItem {
|
||||||
EventType: EventType,
|
EventType: EventType,
|
||||||
ExecutionFunction: Function,
|
ExecutionFunction: Function,
|
||||||
|
Environment: Environment,
|
||||||
}
|
}
|
53
src/database/entities/app/Config.ts
Normal file
53
src/database/entities/app/Config.ts
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
import { Column, Entity } from "typeorm";
|
||||||
|
import AppBaseEntity from "../../../contracts/AppBaseEntity";
|
||||||
|
import AppDataSource from "../../dataSources/appDataSource";
|
||||||
|
|
||||||
|
@Entity()
|
||||||
|
export default class Config extends AppBaseEntity {
|
||||||
|
constructor(key: string, value: string) {
|
||||||
|
super();
|
||||||
|
|
||||||
|
this.Key = key;
|
||||||
|
this.Value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Column()
|
||||||
|
Key: string;
|
||||||
|
|
||||||
|
@Column()
|
||||||
|
Value: string;
|
||||||
|
|
||||||
|
public SetValue(value: string) {
|
||||||
|
this.Value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static async FetchOneByKey(key: string): Promise<Config | null> {
|
||||||
|
const repository = AppDataSource.getRepository(Config);
|
||||||
|
|
||||||
|
const single = await repository.findOne({ where: { Key: key }});
|
||||||
|
|
||||||
|
return single;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static async GetValue(key: string): Promise<string | undefined> {
|
||||||
|
const config = await Config.FetchOneByKey(key);
|
||||||
|
|
||||||
|
if (!config) return undefined;
|
||||||
|
|
||||||
|
return config.Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static async SetValue(key: string, value: string) {
|
||||||
|
const config = await Config.FetchOneByKey(key);
|
||||||
|
|
||||||
|
if (!config) {
|
||||||
|
const newConfig = new Config(key, value);
|
||||||
|
|
||||||
|
await newConfig.Save(Config, newConfig);
|
||||||
|
} else {
|
||||||
|
config.SetValue(value);
|
||||||
|
|
||||||
|
await config.Save(Config, config);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,15 @@
|
||||||
|
import { MigrationInterface, QueryRunner } from "typeorm"
|
||||||
|
import MigrationHelper from "../../../../helpers/MigrationHelper"
|
||||||
|
|
||||||
|
export class CreateConfig1699814500650 implements MigrationInterface {
|
||||||
|
|
||||||
|
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||||
|
MigrationHelper.Up('1699814500650-createConfig', '0.2', [
|
||||||
|
"01-table/Config",
|
||||||
|
], queryRunner);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async down(queryRunner: QueryRunner): Promise<void> {
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -1,7 +1,7 @@
|
||||||
import { CardRarity } from "../constants/CardRarity";
|
import { ActionRowBuilder, ButtonBuilder, ButtonStyle, EmbedBuilder } from "discord.js";
|
||||||
|
import { CardRarity, CardRarityToColour, CardRarityToString } from "../constants/CardRarity";
|
||||||
import CardRarityChances from "../constants/CardRarityChances";
|
import CardRarityChances from "../constants/CardRarityChances";
|
||||||
import Card from "../database/entities/card/Card";
|
import Card from "../database/entities/card/Card";
|
||||||
import Series from "../database/entities/card/Series";
|
|
||||||
|
|
||||||
export default class CardDropHelper {
|
export default class CardDropHelper {
|
||||||
public static async GetRandomCard(): Promise<Card> {
|
public static async GetRandomCard(): Promise<Card> {
|
||||||
|
@ -20,18 +20,7 @@ export default class CardDropHelper {
|
||||||
else if (randomRarity < mangaChance) cardRarity = CardRarity.Manga;
|
else if (randomRarity < mangaChance) cardRarity = CardRarity.Manga;
|
||||||
else cardRarity = CardRarity.Legendary;
|
else cardRarity = CardRarity.Legendary;
|
||||||
|
|
||||||
const allSeries = await Series.FetchAll(Series, [ "Cards", "Cards.Series" ]);
|
const randomCard = await this.GetRandomCardByRarity(cardRarity);
|
||||||
const allSeriesWithCards = allSeries.filter(x => x.Cards.length > 0 && x.Cards.find(x => x.Rarity == cardRarity));
|
|
||||||
|
|
||||||
const randomSeriesIndex = Math.floor(Math.random() * allSeriesWithCards.length);
|
|
||||||
|
|
||||||
const randomSeries = allSeriesWithCards[randomSeriesIndex];
|
|
||||||
|
|
||||||
const allCards = randomSeries.Cards.filter(x => x.Rarity == cardRarity && x.Path && x.FileName);
|
|
||||||
|
|
||||||
const randomCardIndex = Math.floor(Math.random() * allCards.length);
|
|
||||||
|
|
||||||
const randomCard = allCards[randomCardIndex];
|
|
||||||
|
|
||||||
return randomCard;
|
return randomCard;
|
||||||
}
|
}
|
||||||
|
@ -45,4 +34,30 @@ export default class CardDropHelper {
|
||||||
|
|
||||||
return card;
|
return card;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static GenerateDropEmbed(card: Card, quantityClaimed: Number): EmbedBuilder {
|
||||||
|
let description = "";
|
||||||
|
description += `Series: ${card.Series.Name}\n`;
|
||||||
|
description += `Claimed: ${quantityClaimed}\n`;
|
||||||
|
|
||||||
|
return new EmbedBuilder()
|
||||||
|
.setTitle(card.Name)
|
||||||
|
.setDescription(description)
|
||||||
|
.setFooter({ text: CardRarityToString(card.Rarity) })
|
||||||
|
.setColor(CardRarityToColour(card.Rarity))
|
||||||
|
.setImage(`attachment://${card.FileName}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static GenerateDropButtons(card: Card, claimId: string, userId: string): ActionRowBuilder<ButtonBuilder> {
|
||||||
|
return new ActionRowBuilder<ButtonBuilder>()
|
||||||
|
.addComponents(
|
||||||
|
new ButtonBuilder()
|
||||||
|
.setCustomId(`claim ${card.CardNumber} ${claimId} ${userId}`)
|
||||||
|
.setLabel("Claim")
|
||||||
|
.setStyle(ButtonStyle.Primary),
|
||||||
|
new ButtonBuilder()
|
||||||
|
.setCustomId(`reroll`)
|
||||||
|
.setLabel("Reroll")
|
||||||
|
.setStyle(ButtonStyle.Secondary));
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -1,83 +0,0 @@
|
||||||
import { Auth, drive_v3, google } from "googleapis";
|
|
||||||
import IGDriveFolderListing from "../contracts/IGDriveFolderListing";
|
|
||||||
import path, { resolve } from "path";
|
|
||||||
import os from 'os';
|
|
||||||
import uuid, { v4 } from 'uuid';
|
|
||||||
import { createWriteStream } from "fs";
|
|
||||||
|
|
||||||
export default class GoogleDriveHelper {
|
|
||||||
private _auth: Auth.GoogleAuth;
|
|
||||||
private _drive: drive_v3.Drive;
|
|
||||||
|
|
||||||
constructor() {
|
|
||||||
this._auth = new google.auth.GoogleAuth({
|
|
||||||
keyFile: "gdrive-credentials.json",
|
|
||||||
scopes: [
|
|
||||||
"https://www.googleapis.com/auth/drive.readonly",
|
|
||||||
"https://www.googleapis.com/auth/drive.metadata.readonly",
|
|
||||||
],
|
|
||||||
});
|
|
||||||
|
|
||||||
this._drive = google.drive( { version: "v3", auth: this._auth });
|
|
||||||
}
|
|
||||||
|
|
||||||
public async listFolder(folderId: string, pageSize: number): Promise<IGDriveFolderListing[]> {
|
|
||||||
const params = {
|
|
||||||
pageSize: pageSize,
|
|
||||||
fields: "nextPageToken, files(id, name)",
|
|
||||||
q: `'${folderId}' in parents and trashed=false`
|
|
||||||
}
|
|
||||||
|
|
||||||
const res = await this._drive.files.list(params);
|
|
||||||
|
|
||||||
return res.data.files as IGDriveFolderListing[];
|
|
||||||
}
|
|
||||||
|
|
||||||
public downloadFile(fileId: string) {
|
|
||||||
const res = this._drive.files.get({
|
|
||||||
fileId: fileId,
|
|
||||||
alt: 'media',
|
|
||||||
}, {
|
|
||||||
responseType: 'stream',
|
|
||||||
})
|
|
||||||
.then(res => {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
const filePath = path.join(process.cwd(), 'temp', v4());
|
|
||||||
const dest = createWriteStream(filePath);
|
|
||||||
let progress = 0;
|
|
||||||
|
|
||||||
res.data
|
|
||||||
.on('end', () => {
|
|
||||||
resolve(filePath);
|
|
||||||
})
|
|
||||||
.on('error', err => {
|
|
||||||
reject(err);
|
|
||||||
})
|
|
||||||
.on('data', d => {
|
|
||||||
progress += d.length;
|
|
||||||
})
|
|
||||||
.pipe(dest);
|
|
||||||
});
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
public async exportFile(fileId: string, mimeType: string) {
|
|
||||||
const destPath = path.join(process.cwd(), 'temp', v4());
|
|
||||||
const dest = createWriteStream(destPath);
|
|
||||||
|
|
||||||
const res = await this._drive.files.export({
|
|
||||||
fileId: fileId,
|
|
||||||
mimeType: mimeType
|
|
||||||
}, {
|
|
||||||
responseType: 'stream',
|
|
||||||
});
|
|
||||||
|
|
||||||
await new Promise((resolve, reject) => {
|
|
||||||
res.data
|
|
||||||
.on('error', reject)
|
|
||||||
.pipe(dest)
|
|
||||||
.on('error', reject)
|
|
||||||
.on('finish', resolve);
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
10
src/hooks/ReloadDB.ts
Normal file
10
src/hooks/ReloadDB.ts
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
import { Request, Response } from "express";
|
||||||
|
import CardSetupFunction from "../Functions/CardSetupFunction";
|
||||||
|
|
||||||
|
export default async function ReloadDB(req: Request, res: Response) {
|
||||||
|
console.log('Reloading Card DB...');
|
||||||
|
|
||||||
|
await CardSetupFunction.Execute();
|
||||||
|
|
||||||
|
res.sendStatus(200);
|
||||||
|
}
|
|
@ -1,15 +1,29 @@
|
||||||
import { CoreClient } from "./client/client";
|
import { CoreClient } from "./client/client";
|
||||||
|
|
||||||
|
// Global Command Imports
|
||||||
import About from "./commands/about";
|
import About from "./commands/about";
|
||||||
import Drop from "./commands/drop";
|
import Drop from "./commands/drop";
|
||||||
|
import Gdrivesync from "./commands/gdrivesync";
|
||||||
|
|
||||||
|
// Test Command Imports
|
||||||
|
import Dropnumber from "./commands/stage/dropnumber";
|
||||||
|
import Droprarity from "./commands/stage/droprarity";
|
||||||
|
|
||||||
|
// Button Event Imports
|
||||||
import Claim from "./buttonEvents/Claim";
|
import Claim from "./buttonEvents/Claim";
|
||||||
import Reroll from "./buttonEvents/Reroll";
|
import Reroll from "./buttonEvents/Reroll";
|
||||||
|
import { Environment } from "./constants/Environment";
|
||||||
|
|
||||||
export default class Registry {
|
export default class Registry {
|
||||||
public static RegisterCommands() {
|
public static RegisterCommands() {
|
||||||
|
// Global Commands
|
||||||
CoreClient.RegisterCommand('about', new About());
|
CoreClient.RegisterCommand('about', new About());
|
||||||
CoreClient.RegisterCommand('drop', new Drop());
|
CoreClient.RegisterCommand('drop', new Drop());
|
||||||
|
CoreClient.RegisterCommand('gdrivesync', new Gdrivesync());
|
||||||
|
|
||||||
|
// Test Commands
|
||||||
|
CoreClient.RegisterCommand('dropnumber', new Dropnumber(), Environment.Test);
|
||||||
|
CoreClient.RegisterCommand('droprarity', new Droprarity(), Environment.Test);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static RegisterEvents() {
|
public static RegisterEvents() {
|
||||||
|
|
30
src/webhooks.ts
Normal file
30
src/webhooks.ts
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
import bodyParser from "body-parser";
|
||||||
|
import express, { Application } from "express";
|
||||||
|
import ReloadDB from "./hooks/ReloadDB";
|
||||||
|
|
||||||
|
export default class Webhooks {
|
||||||
|
private app: Application;
|
||||||
|
|
||||||
|
private port = process.env.EXPRESS_PORT!;
|
||||||
|
|
||||||
|
public start() {
|
||||||
|
this.setupApp();
|
||||||
|
this.setupRoutes();
|
||||||
|
this.setupListen();
|
||||||
|
}
|
||||||
|
|
||||||
|
private setupApp() {
|
||||||
|
this.app = express();
|
||||||
|
this.app.use(bodyParser.json());
|
||||||
|
}
|
||||||
|
|
||||||
|
private setupRoutes() {
|
||||||
|
this.app.post('/api/reload-db', ReloadDB);
|
||||||
|
}
|
||||||
|
|
||||||
|
private setupListen() {
|
||||||
|
this.app.listen(this.port, () => {
|
||||||
|
console.log(`API listening on port ${this.port}`);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue