Update card database to use JSON files #107

Merged
Vylpes merged 6 commits from feature/27-json-setup into develop 2023-12-09 16:48:20 +00:00
19 changed files with 575 additions and 363 deletions

419
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -31,11 +31,11 @@
"discord.js": "^14.3.0", "discord.js": "^14.3.0",
"dotenv": "^16.0.0", "dotenv": "^16.0.0",
"express": "^4.18.2", "express": "^4.18.2",
"glob": "^10.3.10",
"jest": "^29.0.0", "jest": "^29.0.0",
"jest-mock-extended": "^3.0.0", "jest-mock-extended": "^3.0.0",
"minimatch": "9.0.3", "minimatch": "9.0.3",
"mysql": "^2.18.1", "mysql": "^2.18.1",
"sqlite3": "^5.1.6",
"ts-jest": "^29.0.0", "ts-jest": "^29.0.0",
"typeorm": "0.3.17" "typeorm": "0.3.17"
}, },

View file

@ -0,0 +1,41 @@
import { readFileSync } from "fs";
import path from "path";
import Config from "../database/entities/app/Config";
import { glob } from "glob";
import SeriesMetadata from "../contracts/SeriesMetadata";
import { CoreClient } from "../client/client";
export default class CardMetadataFunction {
public static async Execute(overrideSafeMode: boolean = false): Promise<boolean> {
if (!overrideSafeMode && await Config.GetValue('safemode') == "true") return false;
try {
CoreClient.Cards = await this.FindMetadataJSONs();
console.log(`Loaded ${CoreClient.Cards.flatMap(x => x.cards).length} cards to database`);
} catch (e) {
console.error(e);
await Config.SetValue('safemode', 'true');
return false;
}
return true;
}
private static async FindMetadataJSONs(): Promise<SeriesMetadata[]> {
const res: SeriesMetadata[] = [];
const seriesJSONs = await glob(path.join(process.cwd(), 'cards', '/**/*.json'));
for (let jsonPath of seriesJSONs) {
console.log(`Reading file ${jsonPath}`);
const jsonFile = readFileSync(jsonPath);
const parsedJson: SeriesMetadata[] = JSON.parse(jsonFile.toString());
res.push(...parsedJson);
}
return res;
}
}

View file

@ -1,105 +0,0 @@
import { existsSync, readdirSync } from "fs";
import CardDataSource from "../database/dataSources/cardDataSource";
import Card from "../database/entities/card/Card";
import Series from "../database/entities/card/Series";
import path from "path";
import { CardRarity, CardRarityToString } from "../constants/CardRarity";
import Config from "../database/entities/app/Config";
export default class CardSetupFunction {
public static async Execute(): Promise<boolean> {
if (await Config.GetValue('safemode') == "true") return false;
try {
await this.ClearDatabase();
await this.ReadSeries();
await this.ReadCards();
} catch {
await Config.SetValue('safemode', 'true');
return false;
}
return true;
}
private static async ClearDatabase() {
const cardRepository = CardDataSource.getRepository(Card);
await cardRepository.clear();
const seriesRepository = CardDataSource.getRepository(Series);
await seriesRepository.clear();
}
private static async ReadSeries() {
const seriesDir = readdirSync(path.join(process.cwd(), 'cards'));
const seriesRepository = CardDataSource.getRepository(Series);
const seriesToSave: Series[] = [];
for (let dir of seriesDir) {
const dirPart = dir.split(' ');
const seriesId = dirPart.shift();
const seriesName = dirPart.join(' ');
const series = new Series(seriesId!, seriesName, dir);
seriesToSave.push(series);
}
await seriesRepository.save(seriesToSave);
}
private static async ReadCards() {
const loadedSeries = await Series.FetchAll(Series, [ "Cards", "Cards.Series" ]);
const cardRepository = CardDataSource.getRepository(Card);
const cardsToSave: Card[] = [];
for (let series of loadedSeries) {
const cardDirBronze = this.GetCardFiles(CardRarity.Bronze, series);
const cardDirGold = this.GetCardFiles(CardRarity.Gold, series);
const cardDirLegendary = this.GetCardFiles(CardRarity.Legendary, series);
const cardDirSilver = this.GetCardFiles(CardRarity.Silver, series);
const cardDirManga = this.GetCardFiles(CardRarity.Manga, series);
cardsToSave.push(
...this.GenerateCardData(cardDirBronze, CardRarity.Bronze, series),
...this.GenerateCardData(cardDirGold, CardRarity.Gold, series),
...this.GenerateCardData(cardDirLegendary, CardRarity.Legendary, series),
...this.GenerateCardData(cardDirSilver, CardRarity.Silver, series),
...this.GenerateCardData(cardDirManga, CardRarity.Manga, series)
);
}
await cardRepository.save(cardsToSave);
console.log(`Loaded ${cardsToSave.length} cards to database`);
}
private static GenerateCardData(files: string[], rarity: CardRarity, series: Series): Card[] {
const result: Card[] = [];
for (let file of files.filter(x => !x.startsWith('.') && (x.endsWith('.png') || x.endsWith('.jpg') || x.endsWith('.gif')))) {
const filePart = file.split('.');
const cardId = filePart[0];
const cardName = filePart[0];
const card = new Card(cardId, cardName, rarity, path.join(process.cwd(), 'cards', series.Path, CardRarityToString(rarity).toUpperCase(), file), file, series);
result.push(card);
}
return result;
}
private static GetCardFiles(rarity: CardRarity, series: Series): string[] {
const folder = path.join(process.cwd(), 'cards', series.Path, CardRarityToString(rarity).toUpperCase());
const folderExists = existsSync(folder);
return folderExists ? readdirSync(folder) : [];
}
}

View file

@ -1,11 +1,12 @@
import { AttachmentBuilder, ButtonInteraction, DiscordAPIError } 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 { readFileSync } from "fs"; import { readFileSync } from "fs";
import { v4 } from "uuid"; import { v4 } from "uuid";
import { CoreClient } from "../client/client"; import { CoreClient } from "../client/client";
import Inventory from "../database/entities/app/Inventory"; import Inventory from "../database/entities/app/Inventory";
import Config from "../database/entities/app/Config"; import Config from "../database/entities/app/Config";
import CardDropHelperMetadata from "../helpers/CardDropHelperMetadata";
import path from "path";
export default class Reroll extends ButtonEvent { export default class Reroll extends ButtonEvent {
public override async execute(interaction: ButtonInteraction) { public override async execute(interaction: ButtonInteraction) {
@ -14,34 +15,40 @@ export default class Reroll extends ButtonEvent {
return; return;
} }
if (await Config.GetValue('safemode') == "true") if (await Config.GetValue('safemode') == "true") {
{ await interaction.reply('Safe Mode has been activated, please resync to continue.');
await interaction.reply('Safe Mode has been activated, please resync to contunue.');
return; return;
} }
if (!interaction.guild || !interaction.guildId) return; const randomCard = CardDropHelperMetadata.GetRandomCard();
let randomCard = await CardDropHelper.GetRandomCard(); if (!randomCard) {
await interaction.reply('Unable to fetch card, please try again.');
if (process.env.DROP_RARITY && Number(process.env.DROP_RARITY) > 0) { return;
randomCard = await CardDropHelper.GetRandomCardByRarity(Number(process.env.DROP_RARITY));
} }
const image = readFileSync(randomCard.Path); let image: Buffer;
const imageFileName = randomCard.card.path.split("/").pop()!;
try {
image = readFileSync(path.join(process.cwd(), 'cards', randomCard.card.path));
} catch {
await interaction.reply(`Unable to fetch image for card ${randomCard.card.id}`);
return;
}
await interaction.deferReply(); await interaction.deferReply();
const attachment = new AttachmentBuilder(image, { name: randomCard.FileName }); const attachment = new AttachmentBuilder(image, { name: imageFileName });
const inventory = await Inventory.FetchOneByCardNumberAndUserId(interaction.user.id, randomCard.CardNumber); const inventory = await Inventory.FetchOneByCardNumberAndUserId(interaction.user.id, randomCard.card.id);
const quantityClaimed = inventory ? inventory.Quantity : 0; const quantityClaimed = inventory ? inventory.Quantity : 0;
const embed = CardDropHelper.GenerateDropEmbed(randomCard, quantityClaimed || 0); const embed = CardDropHelperMetadata.GenerateDropEmbed(randomCard, quantityClaimed, imageFileName);
const claimId = v4(); const claimId = v4();
const row = CardDropHelper.GenerateDropButtons(randomCard, claimId, interaction.user.id); const row = CardDropHelperMetadata.GenerateDropButtons(randomCard, claimId, interaction.user.id);
try { try {
await interaction.editReply({ await interaction.editReply({

View file

@ -7,13 +7,13 @@ import { Command } from "../type/command";
import { Events } from "./events"; import { Events } from "./events";
import { Util } from "./util"; import { Util } from "./util";
import CardSetupFunction from "../Functions/CardSetupFunction";
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 { Environment } from "../constants/Environment";
import Webhooks from "../webhooks"; import Webhooks from "../webhooks";
import CardMetadataFunction from "../Functions/CardMetadataFunction";
import SeriesMetadata from "../contracts/SeriesMetadata";
export class CoreClient extends Client { export class CoreClient extends Client {
private static _commandItems: ICommandItem[]; private static _commandItems: ICommandItem[];
@ -27,6 +27,7 @@ export class CoreClient extends Client {
public static ClaimId: string; public static ClaimId: string;
public static Environment: Environment; public static Environment: Environment;
public static AllowDrops: boolean; public static AllowDrops: boolean;
public static Cards: SeriesMetadata[];
public static get commandItems(): ICommandItem[] { public static get commandItems(): ICommandItem[] {
return this._commandItems; return this._commandItems;
@ -68,14 +69,10 @@ export class CoreClient extends Client {
.then(() => console.log("App Data Source Initialised")) .then(() => console.log("App Data Source Initialised"))
.catch(err => console.error("Error initialising App Data Source", err)); .catch(err => console.error("Error initialising App Data Source", err));
await CardDataSource.initialize()
.then(() => console.log("Card Data Source Initialised"))
.catch(err => console.error("Error initialising Card Data Source", err));
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 CardSetupFunction.Execute(); await CardMetadataFunction.Execute(true);
this._util.loadEvents(this, CoreClient._eventItems); this._util.loadEvents(this, CoreClient._eventItems);
this._util.loadSlashCommands(this); this._util.loadSlashCommands(this);

View file

@ -1,11 +1,12 @@
import { AttachmentBuilder, CommandInteraction, DiscordAPIError, 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 { 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 Inventory from "../database/entities/app/Inventory"; import Inventory from "../database/entities/app/Inventory";
import Config from "../database/entities/app/Config"; import Config from "../database/entities/app/Config";
import CardDropHelperMetadata from "../helpers/CardDropHelperMetadata";
import path from "path";
export default class Drop extends Command { export default class Drop extends Command {
constructor() { constructor() {
@ -22,28 +23,40 @@ export default class Drop extends Command {
return; return;
} }
if (await Config.GetValue('safemode') == "true") if (await Config.GetValue('safemode') == "true") {
{ await interaction.reply('Safe Mode has been activated, please resync to continue.');
await interaction.reply('Safe Mode has been activated, please resync to contunue.');
return; return;
} }
const randomCard = await CardDropHelper.GetRandomCard(); const randomCard = CardDropHelperMetadata.GetRandomCard();
const image = readFileSync(randomCard.Path); if (!randomCard) {
await interaction.reply('Unable to fetch card, please try again.');
return;
}
let image: Buffer;
const imageFileName = randomCard.card.path.split("/").pop()!;
try {
image = readFileSync(path.join(process.cwd(), 'cards', randomCard.card.path));
} catch {
await interaction.reply(`Unable to fetch image for card ${randomCard.card.id}`);
return;
}
await interaction.deferReply(); await interaction.deferReply();
const attachment = new AttachmentBuilder(image, { name: randomCard.FileName }); const attachment = new AttachmentBuilder(image, { name: imageFileName });
const inventory = await Inventory.FetchOneByCardNumberAndUserId(interaction.user.id, randomCard.CardNumber); const inventory = await Inventory.FetchOneByCardNumberAndUserId(interaction.user.id, randomCard.card.id);
const quantityClaimed = inventory ? inventory.Quantity : 0; const quantityClaimed = inventory ? inventory.Quantity : 0;
const embed = CardDropHelper.GenerateDropEmbed(randomCard, quantityClaimed || 0); const embed = CardDropHelperMetadata.GenerateDropEmbed(randomCard, quantityClaimed, imageFileName);
const claimId = v4(); const claimId = v4();
const row = CardDropHelper.GenerateDropButtons(randomCard, claimId, interaction.user.id); const row = CardDropHelperMetadata.GenerateDropButtons(randomCard, claimId, interaction.user.id);
try { try {
await interaction.editReply({ await interaction.editReply({

View file

@ -1,9 +1,9 @@
import { CacheType, CommandInteraction, PermissionsBitField, SlashCommandBuilder } from "discord.js"; import { CacheType, CommandInteraction, PermissionsBitField, SlashCommandBuilder } from "discord.js";
import { Command } from "../type/command"; import { Command } from "../type/command";
import { ExecException, exec } from "child_process"; import { ExecException, exec } from "child_process";
import CardSetupFunction from "../Functions/CardSetupFunction";
import { CoreClient } from "../client/client"; import { CoreClient } from "../client/client";
import Config from "../database/entities/app/Config"; import Config from "../database/entities/app/Config";
import CardMetadataFunction from "../Functions/CardMetadataFunction";
export default class Gdrivesync extends Command { export default class Gdrivesync extends Command {
constructor() { constructor() {
@ -34,7 +34,8 @@ export default class Gdrivesync extends Command {
await interaction.editReply(`Error while running sync command. Safe Mode has been activated. Code: ${error.code}`); await interaction.editReply(`Error while running sync command. Safe Mode has been activated. Code: ${error.code}`);
await Config.SetValue('safemode', 'true'); await Config.SetValue('safemode', 'true');
} else { } else {
await CardSetupFunction.Execute(); await CardMetadataFunction.Execute();
await interaction.editReply('Synced successfully.'); await interaction.editReply('Synced successfully.');
CoreClient.AllowDrops = true; CoreClient.AllowDrops = true;

View file

@ -1,7 +1,7 @@
import { CacheType, CommandInteraction, PermissionsBitField, SlashCommandBuilder } from "discord.js"; import { CacheType, CommandInteraction, PermissionsBitField, SlashCommandBuilder } from "discord.js";
import { Command } from "../type/command"; import { Command } from "../type/command";
import CardSetupFunction from "../Functions/CardSetupFunction";
import Config from "../database/entities/app/Config"; import Config from "../database/entities/app/Config";
import CardMetadataFunction from "../Functions/CardMetadataFunction";
export default class Resync extends Command { export default class Resync extends Command {
constructor() { constructor() {
@ -23,7 +23,9 @@ export default class Resync extends Command {
return; return;
} }
if (await CardSetupFunction.Execute()) { let result = await CardMetadataFunction.Execute(true);
if (result) {
if (await Config.GetValue('safemode') == "true") { if (await Config.GetValue('safemode') == "true") {
await Config.SetValue('safemode', 'false'); await Config.SetValue('safemode', 'false');
await interaction.reply("Resynced database and disabled safe mode."); await interaction.reply("Resynced database and disabled safe mode.");

View file

@ -1,11 +1,11 @@
import { AttachmentBuilder, CacheType, CommandInteraction, DiscordAPIError, SlashCommandBuilder } from "discord.js"; import { AttachmentBuilder, CacheType, CommandInteraction, DiscordAPIError, SlashCommandBuilder } from "discord.js";
import { Command } from "../../type/command"; import { Command } from "../../type/command";
import Card from "../../database/entities/card/Card";
import { readFileSync } from "fs"; import { readFileSync } from "fs";
import Inventory from "../../database/entities/app/Inventory"; import Inventory from "../../database/entities/app/Inventory";
import CardDropHelper from "../../helpers/CardDropHelper";
import { v4 } from "uuid"; import { v4 } from "uuid";
import { CoreClient } from "../../client/client"; import { CoreClient } from "../../client/client";
import path from "path";
import CardDropHelperMetadata from "../../helpers/CardDropHelperMetadata";
export default class Dropnumber extends Command { export default class Dropnumber extends Command {
constructor() { constructor() {
@ -31,29 +31,42 @@ export default class Dropnumber extends Command {
return; return;
} }
const card = await Card.FetchOneByCardNumber(cardNumber.value.toString(), [ const series = CoreClient.Cards.find(x => x.cards.find(y => y.id == cardNumber.toString()));
"Series"
]); if (!series) {
await interaction.reply('Card not found');
return;
}
const card = series.cards.find(x => x.id == cardNumber.toString());
if (!card) { if (!card) {
await interaction.reply('Card not found'); await interaction.reply('Card not found');
return; return;
} }
const image = readFileSync(card.Path); let image: Buffer;
const imageFileName = card.path.split("/").pop()!;
try {
image = readFileSync(path.join(process.cwd(), 'cards', card.path));
} catch {
await interaction.reply(`Unable to fetch image for card ${card.id}`);
return;
}
await interaction.deferReply(); await interaction.deferReply();
const attachment = new AttachmentBuilder(image, { name: card.FileName }); const attachment = new AttachmentBuilder(image, { name: imageFileName });
const inventory = await Inventory.FetchOneByCardNumberAndUserId(interaction.user.id, card.CardNumber); const inventory = await Inventory.FetchOneByCardNumberAndUserId(interaction.user.id, card.id);
const quantityClaimed = inventory ? inventory.Quantity : 0; const quantityClaimed = inventory ? inventory.Quantity : 0;
const embed = CardDropHelper.GenerateDropEmbed(card, quantityClaimed || 0); const embed = CardDropHelperMetadata.GenerateDropEmbed({ card, series }, quantityClaimed, imageFileName);
const claimId = v4(); const claimId = v4();
const row = CardDropHelper.GenerateDropButtons(card, claimId, interaction.user.id); const row = CardDropHelperMetadata.GenerateDropButtons({ card, series }, claimId, interaction.user.id);
try { try {
await interaction.editReply({ await interaction.editReply({

View file

@ -1,11 +1,12 @@
import { AttachmentBuilder, CacheType, CommandInteraction, DiscordAPIError, SlashCommandBuilder } from "discord.js"; import { AttachmentBuilder, CacheType, CommandInteraction, DiscordAPIError, SlashCommandBuilder } from "discord.js";
import { Command } from "../../type/command"; import { Command } from "../../type/command";
import { CardRarity, CardRarityParse } from "../../constants/CardRarity"; import { CardRarity, CardRarityParse } from "../../constants/CardRarity";
import CardDropHelper from "../../helpers/CardDropHelper";
import { readFileSync } from "fs"; import { readFileSync } from "fs";
import Inventory from "../../database/entities/app/Inventory"; import Inventory from "../../database/entities/app/Inventory";
import { v4 } from "uuid"; import { v4 } from "uuid";
import { CoreClient } from "../../client/client"; import { CoreClient } from "../../client/client";
import CardDropHelperMetadata from "../../helpers/CardDropHelperMetadata";
import path from "path";
export default class Droprarity extends Command { export default class Droprarity extends Command {
constructor() { constructor() {
@ -38,27 +39,35 @@ export default class Droprarity extends Command {
return; return;
} }
const card = await CardDropHelper.GetRandomCardByRarity(rarityType); const card = await CardDropHelperMetadata.GetRandomCardByRarity(rarityType);
if (!card) { if (!card) {
await interaction.reply('Card not found'); await interaction.reply('Card not found');
return; return;
} }
const image = readFileSync(card.Path); let image: Buffer;
const imageFileName = card.card.path.split("/").pop()!;
try {
image = readFileSync(path.join(process.cwd(), 'cards', card.card.path));
} catch {
await interaction.reply(`Unable to fetch image for card ${card.card.id}`);
return;
}
await interaction.deferReply(); await interaction.deferReply();
const attachment = new AttachmentBuilder(image, { name: card.FileName }); const attachment = new AttachmentBuilder(image, { name: imageFileName });
const inventory = await Inventory.FetchOneByCardNumberAndUserId(interaction.user.id, card.CardNumber); const inventory = await Inventory.FetchOneByCardNumberAndUserId(interaction.user.id, card.card.id);
const quantityClaimed = inventory ? inventory.Quantity : 0; const quantityClaimed = inventory ? inventory.Quantity : 0;
const embed = CardDropHelper.GenerateDropEmbed(card, quantityClaimed || 0); const embed = CardDropHelperMetadata.GenerateDropEmbed(card, quantityClaimed, imageFileName);
const claimId = v4(); const claimId = v4();
const row = CardDropHelper.GenerateDropButtons(card, claimId, interaction.user.id); const row = CardDropHelperMetadata.GenerateDropButtons(card, claimId, interaction.user.id);
try { try {
await interaction.editReply({ await interaction.editReply({

View file

@ -1,60 +0,0 @@
import { Column, DeepPartial, EntityTarget, PrimaryColumn, ObjectLiteral, FindOptionsWhere } from "typeorm";
import { v4 } from "uuid";
import AppDataSource from "../database/dataSources/appDataSource";
import CardDataSource from "../database/dataSources/cardDataSource";
export default class CardBaseEntity {
constructor() {
this.Id = v4();
this.WhenCreated = new Date();
this.WhenUpdated = new Date();
}
@PrimaryColumn()
Id: string;
@Column()
WhenCreated: Date;
@Column()
WhenUpdated: Date;
public async Save<T extends CardBaseEntity>(target: EntityTarget<T>, entity: DeepPartial<T>): Promise<void> {
this.WhenUpdated = new Date();
const repository = CardDataSource.getRepository<T>(target);
await repository.save(entity);
}
public static async Remove<T extends CardBaseEntity>(target: EntityTarget<T>, entity: T): Promise<void> {
const repository = CardDataSource.getRepository<T>(target);
await repository.remove(entity);
}
public static async FetchAll<T extends CardBaseEntity>(target: EntityTarget<T>, relations?: string[]): Promise<T[]> {
const repository = CardDataSource.getRepository<T>(target);
const all = await repository.find({ relations: relations || [] });
return all;
}
public static async FetchOneById<T extends CardBaseEntity>(target: EntityTarget<T>, id: string, relations?: string[]): Promise<T | null> {
const repository = CardDataSource.getRepository<T>(target);
const single = await repository.findOne({ where: ({ Id: id } as FindOptionsWhere<T>), relations: relations || {} });
return single;
}
public static async Any<T extends ObjectLiteral>(target: EntityTarget<T>): Promise<boolean> {
const repository = CardDataSource.getRepository<T>(target);
const any = await repository.find();
return any.length > 0;
}
}

View file

@ -0,0 +1,19 @@
import { CardRarity } from "../constants/CardRarity";
export default interface SeriesMetadata {
id: number,
name: string,
cards: CardMetadata[],
}
export interface CardMetadata {
id: string,
name: string,
type: CardRarity,
path: string,
}
export interface DropResult {
series: SeriesMetadata,
card: CardMetadata,
}

View file

@ -1,22 +0,0 @@
import { DataSource } from "typeorm";
import * as dotenv from "dotenv";
dotenv.config();
const CardDataSource = new DataSource({
type: "sqlite",
database: process.env.DB_CARD_FILE!,
synchronize: true,
logging: process.env.DB_LOGGING == "true",
entities: [
"dist/database/entities/card/**/*.js",
],
migrations: [
"dist/database/migrations/card/**/*.js",
],
subscribers: [
"dist/database/subscribers/card/**/*.js",
],
});
export default CardDataSource;

View file

@ -1,53 +0,0 @@
import { Column, Entity, ManyToOne } from "typeorm";
import CardBaseEntity from "../../../contracts/CardBaseEntity";
import { CardRarity } from "../../../constants/CardRarity";
import Series from "./Series";
import CardDataSource from "../../dataSources/cardDataSource";
@Entity()
export default class Card extends CardBaseEntity {
constructor(cardNumber: string, name: string, rarity: CardRarity, path: string, fileName: string, series: Series) {
super();
this.CardNumber = cardNumber;
this.Name = name;
this.Rarity = rarity;
this.Path = path;
this.FileName = fileName;
this.Series = series;
}
@Column()
CardNumber: string;
@Column()
Name: string;
@Column()
Rarity: CardRarity;
@Column()
Path: string;
@Column()
FileName: string;
@ManyToOne(() => Series, x => x.Cards)
Series: Series;
public static async FetchOneByCardNumber(cardNumber: string, relations?: string[]): Promise<Card | null> {
const repository = CardDataSource.getRepository(Card);
const single = await repository.findOne({ where: { CardNumber: cardNumber }, relations: relations || [] });
return single;
}
public static async FetchAllByRarity(rarity: CardRarity, relations?: string[]): Promise<Card[]> {
const repository = CardDataSource.getRepository(Card);
const all = await repository.find({ where: { Rarity: rarity }, relations: relations || [] });
return all;
}
}

View file

@ -1,23 +0,0 @@
import { Column, Entity, OneToMany } from "typeorm";
import CardBaseEntity from "../../../contracts/CardBaseEntity";
import Card from "./Card";
@Entity()
export default class Series extends CardBaseEntity {
constructor(id: string, name: string, path: string) {
super();
this.Id = id;
this.Name = name;
this.Path = path;
}
@Column()
Name: string;
@Column()
Path: string;
@OneToMany(() => Card, x => x.Series)
Cards: Card[];
}

View file

@ -1,10 +1,11 @@
import { ActionRowBuilder, ButtonBuilder, ButtonStyle, EmbedBuilder } from "discord.js"; import { ActionRowBuilder, ButtonBuilder, ButtonStyle, EmbedBuilder } from "discord.js";
import { CardRarity, CardRarityToColour, CardRarityToString } from "../constants/CardRarity"; 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 { DropResult } from "../contracts/SeriesMetadata";
import { CoreClient } from "../client/client";
export default class CardDropHelper { export default class CardDropHelperMetadata {
public static async GetRandomCard(): Promise<Card> { public static GetRandomCard(): DropResult | undefined {
const randomRarity = Math.random() * 100; const randomRarity = Math.random() * 100;
let cardRarity: CardRarity; let cardRarity: CardRarity;
@ -20,39 +21,50 @@ 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 randomCard = await this.GetRandomCardByRarity(cardRarity); const randomCard = this.GetRandomCardByRarity(cardRarity);
return randomCard; return randomCard;
} }
public static async GetRandomCardByRarity(rarity: CardRarity): Promise<Card> { public static GetRandomCardByRarity(rarity: CardRarity): DropResult | undefined {
const allCards = await Card.FetchAllByRarity(rarity, [ "Series" ]); const allCards = CoreClient.Cards
.flatMap(x => x.cards)
.filter(x => x.type == rarity);
const randomCardIndex = Math.floor(Math.random() * allCards.length); const randomCardIndex = Math.floor(Math.random() * allCards.length);
const card = allCards[randomCardIndex]; const card = allCards[randomCardIndex];
const series = CoreClient.Cards
.find(x => x.cards.includes(card));
return card; if (!series) {
return undefined;
} }
public static GenerateDropEmbed(card: Card, quantityClaimed: Number): EmbedBuilder { return {
series: series,
card: card,
};
}
public static GenerateDropEmbed(drop: DropResult, quantityClaimed: Number, imageFileName: string): EmbedBuilder {
let description = ""; let description = "";
description += `Series: ${card.Series.Name}\n`; description += `Series: ${drop.series.name}\n`;
description += `Claimed: ${quantityClaimed}\n`; description += `Claimed: ${quantityClaimed}\n`;
return new EmbedBuilder() return new EmbedBuilder()
.setTitle(card.Name) .setTitle(drop.card.name)
.setDescription(description) .setDescription(description)
.setFooter({ text: CardRarityToString(card.Rarity) }) .setFooter({ text: CardRarityToString(drop.card.type) })
.setColor(CardRarityToColour(card.Rarity)) .setColor(CardRarityToColour(drop.card.type))
.setImage(`attachment://${card.FileName}`); .setImage(`attachment://${imageFileName}`);
} }
public static GenerateDropButtons(card: Card, claimId: string, userId: string): ActionRowBuilder<ButtonBuilder> { public static GenerateDropButtons(drop: DropResult, claimId: string, userId: string): ActionRowBuilder<ButtonBuilder> {
return new ActionRowBuilder<ButtonBuilder>() return new ActionRowBuilder<ButtonBuilder>()
.addComponents( .addComponents(
new ButtonBuilder() new ButtonBuilder()
.setCustomId(`claim ${card.CardNumber} ${claimId} ${userId}`) .setCustomId(`claim ${drop.card.id} ${claimId} ${userId}`)
.setLabel("Claim") .setLabel("Claim")
.setStyle(ButtonStyle.Primary), .setStyle(ButtonStyle.Primary),
new ButtonBuilder() new ButtonBuilder()

View file

@ -1,10 +1,10 @@
import { Request, Response } from "express"; import { Request, Response } from "express";
import CardSetupFunction from "../Functions/CardSetupFunction"; import CardMetadataFunction from "../Functions/CardMetadataFunction";
export default async function ReloadDB(req: Request, res: Response) { export default async function ReloadDB(req: Request, res: Response) {
console.log('Reloading Card DB...'); console.log('Reloading Card DB...');
await CardSetupFunction.Execute(); await CardMetadataFunction.Execute();
res.sendStatus(200); res.sendStatus(200);
} }