Compare commits

..

No commits in common. "9ea3bbe29d752199789ebff01baf323616c47a10" and "53656ba0da53a8b4e694be85ea2d0768ed700e9c" have entirely different histories.

21 changed files with 152 additions and 1339 deletions

View file

@ -7,17 +7,13 @@
# any secret values.
BOT_TOKEN=
BOT_VER=0.7.0
BOT_VER=0.6.4
BOT_AUTHOR=Vylpes
BOT_OWNERID=147392775707426816
BOT_CLIENTID=682942374040961060
BOT_ENV=4
BOT_ADMINS=147392775707426816,887272961504071690
BOT_LOGLEVEL=info
BOT_LOG_DISCORD_ENABLE=false
BOT_LOG_DISCORD_LEVEL=warn
BOT_LOG_DISCORD_WEBHOOK=
BOT_LOG_DISCORD_SERVICE=
ABOUT_FUNDING=
ABOUT_REPO=
@ -37,4 +33,4 @@ DB_CARD_FILE=:memory:
EXPRESS_PORT=3302
GDRIVESYNC_AUTO=true
GDRIVESYNC_AUTO=true

View file

@ -55,16 +55,12 @@ jobs:
GDRIVESYNC_AUTO: ${{ vars.PROD_GDRIVESYNC_AUTO }}
EXPRESS_PORT: ${{ secrets.PROD_EXPRESS_PORT }}
BOT_LOGLEVEL: ${{ vars.PROD_BOT_LOGLEVEL }}
BOT_LOG_DISCORD_ENABLE: ${{ vars.PROD_BOT_LOG_DISCORD_ENABLE }}
BOT_LOG_DISCORD_LEVEL: ${{ vars.PROD_BOT_LOG_DISCORD_LEVEL }}
BOT_LOG_DISCORD_WEBHOOK: ${{ secrets.PROD_BOT_LOG_DISCORD_WEBHOOK }}
BOT_LOG_DISCORD_SERVICE: ${{ vars.PROD_BOT_LOG_DISCORD_SERVICE }}
with:
host: ${{ secrets.PROD_SSH_HOST }}
username: ${{ secrets.PROD_SSH_USER }}
key: ${{ secrets.PROD_SSH_KEY }}
port: ${{ secrets.PROD_SSH_PORT }}
envs: DB_NAME,DB_AUTH_USER,DB_AUTH_PASS,DB_HOST,DB_PORT,DB_ROOT_HOST,DB_SYNC,DB_LOGGING,DB_DATA_LOCATION,BOT_TOKEN,BOT_VER,BOT_AUTHOR,BOT_OWNERID,BOT_CLIENTID,ABOUT_FUNDING,ABOUT_REPO,BOT_ENV,BOT_ADMINS,DATA_DIR,GDRIVESYNC_AUTO,SERVER_PATH,EXPRESS_PORT,BOT_LOGLEVEL,BOT_LOG_DISCORD_ENABLE,BOT_LOG_DISCORD_LEVEL,BOT_LOG_DISCORD_WEBHOOK,BOT_LOG_DISCORD_SERVICE
envs: DB_NAME,DB_AUTH_USER,DB_AUTH_PASS,DB_HOST,DB_PORT,DB_ROOT_HOST,DB_SYNC,DB_LOGGING,DB_DATA_LOCATION,BOT_TOKEN,BOT_VER,BOT_AUTHOR,BOT_OWNERID,BOT_CLIENTID,ABOUT_FUNDING,ABOUT_REPO,BOT_ENV,BOT_ADMINS,DATA_DIR,GDRIVESYNC_AUTO,SERVER_PATH,EXPRESS_PORT,BOT_LOGLEVEL
script: |
source .sshrc \
&& cd /home/vylpes/apps/card-drop/card-drop_prod \

View file

@ -55,16 +55,12 @@ jobs:
GDRIVESYNC_AUTO: ${{ vars.STAGE_GDRIVESYNC_AUTO }}
EXPRESS_PORT: ${{ secrets.STAGE_EXPRESS_PORT }}
BOT_LOGLEVEL: ${{ vars.STAGE_BOT_LOGLEVEL }}
BOT_LOG_DISCORD_ENABLE: ${{ vars.STAGE_BOT_LOG_DISCORD_ENABLE }}
BOT_LOG_DISCORD_LEVEL: ${{ vars.STAGE_BOT_LOG_DISCORD_LEVEL }}
BOT_LOG_DISCORD_WEBHOOK: ${{ secrets.STAGE_BOT_LOG_DISCORD_WEBHOOK }}
BOT_LOG_DISCORD_SERVICE: ${{ vars.STAGE_BOT_LOG_DISCORD_SERVICE }}
with:
host: ${{ secrets.STAGE_SSH_HOST }}
username: ${{ secrets.STAGE_SSH_USER }}
key: ${{ secrets.STAGE_SSH_KEY }}
port: ${{ secrets.STAGE_SSH_PORT }}
envs: DB_NAME,DB_AUTH_USER,DB_AUTH_PASS,DB_HOST,DB_PORT,DB_ROOT_HOST,DB_SYNC,DB_LOGGING,DB_DATA_LOCATION,BOT_TOKEN,BOT_VER,BOT_AUTHOR,BOT_OWNERID,BOT_CLIENTID,ABOUT_FUNDING,ABOUT_REPO,BOT_ENV,BOT_ADMINS,DATA_DIR,GDRIVESYNC_AUTO,SERVER_PATH,EXPRESS_PORT,BOT_LOGLEVEL,BOT_LOG_DISCORD_ENABLE,BOT_LOG_DISCORD_LEVEL,BOT_LOG_DISCORD_WEBHOOK,BOT_LOG_DISCORD_SERVICE
envs: DB_NAME,DB_AUTH_USER,DB_AUTH_PASS,DB_HOST,DB_PORT,DB_ROOT_HOST,DB_SYNC,DB_LOGGING,DB_DATA_LOCATION,BOT_TOKEN,BOT_VER,BOT_AUTHOR,BOT_OWNERID,BOT_CLIENTID,ABOUT_FUNDING,ABOUT_REPO,BOT_ENV,BOT_ADMINS,DATA_DIR,GDRIVESYNC_AUTO,SERVER_PATH,EXPRESS_PORT,BOT_LOGLEVEL
script: |
source .sshrc \
&& cd /home/vylpes/apps/card-drop/card-drop_stage \

View file

@ -1,6 +1,6 @@
{
"name": "card-drop",
"version": "0.7.0",
"version": "0.6.4",
"main": "./dist/bot.js",
"typings": "./dist",
"scripts": {
@ -31,30 +31,26 @@
"@types/jest": "^29.0.0",
"@types/uuid": "^9.0.0",
"body-parser": "^1.20.2",
"canvas": "^2.11.2",
"clone-deep": "^4.0.1",
"cron": "^3.1.7",
"discord.js": "^14.15.3",
"discord.js": "^14.3.0",
"dotenv": "^16.0.0",
"express": "^4.18.2",
"glob": "^10.3.10",
"jest": "^29.0.0",
"jest-mock-extended": "^3.0.0",
"jimp": "^0.22.12",
"minimatch": "9.0.5",
"minimatch": "9.0.4",
"mysql": "^2.18.1",
"ts-jest": "^29.0.0",
"typeorm": "0.3.20",
"winston": "^3.11.0",
"winston-daily-rotate-file": "^5.0.0",
"winston-discord-transport": "^1.3.0"
"winston": "^3.11.0"
},
"overrides": {
"undici": "^5.28.3"
},
"devDependencies": {
"@types/node": "^20.0.0",
"@typescript-eslint/eslint-plugin": "^7.0.0",
"@typescript-eslint/eslint-plugin": "^6.16.0",
"@typescript-eslint/parser": "^6.16.0",
"eslint": "^8.56.0",
"np": "^9.0.0",

View file

@ -20,14 +20,6 @@ export default class Claim extends ButtonEvent {
const droppedBy = interaction.customId.split(" ")[3];
const userId = interaction.user.id;
const whenDropped = interaction.message.createdAt;
const lastClaimableDate = new Date(Date.now() - (1000 * 60 * 5)); // 5 minutes ago
if (whenDropped < lastClaimableDate) {
await interaction.channel.send(`${interaction.user}, Cards can only be claimed within 5 minutes of it being dropped!`);
return;
}
AppLogger.LogSilly("Button/Claim", `Parameters: cardNumber=${cardNumber}, claimId=${claimId}, droppedBy=${droppedBy}, userId=${userId}`);
const user = await User.FetchOneById(User, userId) || new User(userId, CardConstants.StartingCurrency);
@ -76,7 +68,7 @@ export default class Claim extends ButtonEvent {
const imageFileName = card.card.path.split("/").pop()!;
const embed = CardDropHelperMetadata.GenerateDropEmbed(card, inventory.Quantity, imageFileName, interaction.user.username, user.Currency);
const embed = CardDropHelperMetadata.GenerateDropEmbed(card, inventory.Quantity, imageFileName, interaction.user.username);
const row = CardDropHelperMetadata.GenerateDropButtons(card, claimId, interaction.user.id, true);
await interaction.editReply({
@ -84,4 +76,4 @@ export default class Claim extends ButtonEvent {
components: [ row ],
});
}
}
}

View file

@ -11,8 +11,6 @@ export default class Inventory extends ButtonEvent {
const page = interaction.customId.split(" ")[2];
AppLogger.LogSilly("Button/Inventory", `Parameters: userid=${userid}, page=${page}`);
await interaction.deferUpdate();
const member = interaction.guild.members.cache.find(x => x.id == userid) || await interaction.guild.members.fetch(userid);
@ -26,20 +24,14 @@ export default class Inventory extends ButtonEvent {
const embed = await InventoryHelper.GenerateInventoryPage(member.user.username, member.user.id, Number(page));
if (!embed) {
await interaction.followUp("No page for user found.");
return;
}
await interaction.editReply({
files: [ embed.image ],
await interaction.update({
embeds: [ embed.embed ],
components: [ embed.row ],
});
} catch (e) {
AppLogger.LogError("Button/Inventory", `Error generating inventory page for ${member.user.username} with id ${member.user.id}: ${e}`);
await interaction.followUp("An error has occurred running this command.");
await interaction.reply("No page for user found.");
}
}
}
}

View file

@ -59,7 +59,7 @@ export default class Reroll extends ButtonEvent {
const inventory = await Inventory.FetchOneByCardNumberAndUserId(interaction.user.id, randomCard.card.id);
const quantityClaimed = inventory ? inventory.Quantity : 0;
const embed = CardDropHelperMetadata.GenerateDropEmbed(randomCard, quantityClaimed, imageFileName, undefined, user.Currency);
const embed = CardDropHelperMetadata.GenerateDropEmbed(randomCard, quantityClaimed, imageFileName);
const claimId = v4();
@ -78,4 +78,4 @@ export default class Reroll extends ButtonEvent {
await interaction.editReply(`Unable to send next drop. Please try again, and report this if it keeps happening. (${randomCard.card.id})`);
}
}
}
}

View file

@ -24,14 +24,11 @@ export default class Series extends ButtonEvent {
const seriesid = interaction.customId.split(" ")[2];
const page = interaction.customId.split(" ")[3];
await interaction.deferUpdate();
const embed = SeriesHelper.GenerateSeriesViewPage(Number(seriesid), Number(page));
const embed = await SeriesHelper.GenerateSeriesViewPage(Number(seriesid), Number(page), interaction.user.id);
await interaction.editReply({
await interaction.update({
embeds: [ embed!.embed ],
components: [ embed!.row ],
files: [ embed!.image ],
});
}
@ -45,4 +42,4 @@ export default class Series extends ButtonEvent {
components: [ embed!.row ],
});
}
}
}

View file

@ -1,7 +1,4 @@
import path from "path";
import { Logger, createLogger, format, transports } from "winston";
import DailyRotateFile from "winston-daily-rotate-file";
import DiscordTransport from "winston-discord-transport";
export default class AppLogger {
public static Logger: Logger;
@ -22,21 +19,12 @@ export default class AppLogger {
customFormat,
),
defaultMeta: { service: "bot" },
transports: [],
transports: [
new transports.File({ filename: "error.log", level: "error" }),
new transports.File({ filename: "combined.log" }),
],
});
if (process.env.DATA_DIR) {
const logDir = path.join(process.env.DATA_DIR, "logs");
logger.add(new DailyRotateFile({
filename: "bot-%DATE%.log",
dirname: logDir,
datePattern: "YYYY-MM-DD-HH",
maxSize: "20m",
maxFiles: "14d",
}));
}
if (outputToConsole) {
logger.add(new transports.Console({
format: format.combine(
@ -46,18 +34,6 @@ export default class AppLogger {
)}));
}
if (process.env.BOT_LOG_DISCORD_ENABLE == "true") {
if (process.env.BOT_LOG_DISCORD_WEBHOOK) {
logger.add(new DiscordTransport({
webhook: process.env.BOT_LOG_DISCORD_WEBHOOK.toString(),
defaultMeta: { service: process.env.BOT_LOG_DISCORD_SERVICE },
level: process.env.BOT_LOG_DISCORD_LEVEL,
}));
} else {
throw "BOT_LOG_DISCORD_WEBHOOK is required to enable discord logger support.";
}
}
AppLogger.Logger = logger;
AppLogger.LogInfo("AppLogger", `Log Level: ${logLevel}`);
@ -86,4 +62,4 @@ export default class AppLogger {
public static LogSilly(label: string, message: string) {
AppLogger.Logger.silly({ label, message });
}
}
}

View file

@ -16,7 +16,6 @@ import { SeriesMetadata } from "../contracts/SeriesMetadata";
import AppLogger from "./appLogger";
import TimerHelper from "../helpers/TimerHelper";
import GiveCurrency from "../timers/GiveCurrency";
import PurgeClaims from "../timers/PurgeClaims";
export class CoreClient extends Client {
private static _commandItems: ICommandItem[];
@ -80,10 +79,8 @@ export class CoreClient extends Client {
.then(() => {
AppLogger.LogInfo("Client", "App Data Source Initialised");
this._timerHelper.AddTimer("*/20 * * * *", "Europe/London", GiveCurrency, false);
this._timerHelper.AddTimer("0 0 * * *", "Europe/London", PurgeClaims, false);
this._timerHelper.StartAllTimers();
const timerId = this._timerHelper.AddTimer("*/20 * * * *", "Europe/London", GiveCurrency, false);
this._timerHelper.StartTimer(timerId);
})
.catch(err => {
AppLogger.LogError("Client", "App Data Source Initialisation Failed");

View file

@ -67,7 +67,7 @@ export default class Drop extends Command {
const inventory = await Inventory.FetchOneByCardNumberAndUserId(interaction.user.id, randomCard.card.id);
const quantityClaimed = inventory ? inventory.Quantity : 0;
const embed = CardDropHelperMetadata.GenerateDropEmbed(randomCard, quantityClaimed, imageFileName, undefined, user.Currency);
const embed = CardDropHelperMetadata.GenerateDropEmbed(randomCard, quantityClaimed, imageFileName);
const claimId = v4();
@ -88,4 +88,4 @@ export default class Drop extends Command {
}
}
}
}

View file

@ -26,8 +26,6 @@ export default class Inventory extends Command {
const user = userOption ? userOption.user! : interaction.user;
await interaction.deferReply();
AppLogger.LogSilly("Commands/Inventory", `Parameters: page=${page?.value}, user=${user.id}`);
try {
@ -39,20 +37,14 @@ export default class Inventory extends Command {
const embed = await InventoryHelper.GenerateInventoryPage(user.username, user.id, pageNumber);
if (!embed) {
await interaction.followUp("No page for user found.");
return;
}
await interaction.followUp({
files: [ embed.image ],
await interaction.reply({
embeds: [ embed.embed ],
components: [ embed.row ],
});
} catch (e) {
AppLogger.LogError("Commands/Inventory", e as string);
await interaction.followUp("An error has occurred running this command.");
await interaction.reply("No page for user found.");
}
}
}
}

View file

@ -47,8 +47,6 @@ export default class Series extends Command {
AppLogger.LogSilly("Commands/Series/View", `Parameters: id=${id?.value}`);
await interaction.deferReply();
if (!id) return;
const series = CoreClient.Cards.find(x => x.id == id.value);
@ -56,17 +54,13 @@ export default class Series extends Command {
if (!series) {
AppLogger.LogVerbose("Commands/Series/View", "Series not found.");
await interaction.followUp("Series not found.");
await interaction.reply("Series not found.");
return;
}
const embed = await SeriesHelper.GenerateSeriesViewPage(series.id, 0, interaction.user.id);
const embed = SeriesHelper.GenerateSeriesViewPage(series.id, 0);
await interaction.followUp({
embeds: [ embed!.embed ],
components: [ embed!.row ],
files: [ embed!.image ],
});
await interaction.reply({ embeds: [ embed!.embed ], components: [ embed!.row ]});
}
private async ListSeries(interaction: CommandInteraction) {
@ -74,4 +68,4 @@ export default class Series extends Command {
await interaction.reply({ embeds: [ embed!.embed ], components: [ embed!.row ]});
}
}
}

View file

@ -39,12 +39,6 @@ export default class AppBaseEntity {
await repository.remove(entity);
}
public static async RemoveMany<T extends AppBaseEntity>(target: EntityTarget<T>, entity: T[]): Promise<void> {
const repository = AppDataSource.getRepository<T>(target);
await repository.remove(entity);
}
public static async FetchAll<T extends AppBaseEntity>(target: EntityTarget<T>, relations?: string[]): Promise<T[]> {
const repository = AppDataSource.getRepository<T>(target);

View file

@ -54,4 +54,4 @@ export default class Inventory extends AppBaseEntity {
return all;
}
}
}

View file

@ -4,7 +4,6 @@ import CardRarityChances from "../constants/CardRarityChances";
import { DropResult } from "../contracts/SeriesMetadata";
import { CoreClient } from "../client/client";
import AppLogger from "../client/appLogger";
import CardConstants from "../constants/CardConstants";
export default class CardDropHelperMetadata {
public static GetRandomCard(): DropResult | undefined {
@ -78,46 +77,25 @@ export default class CardDropHelperMetadata {
return { card, series };
}
public static GenerateDropEmbed(drop: DropResult, quantityClaimed: number, imageFileName: string, claimedBy?: string, currency?: number): EmbedBuilder {
public static GenerateDropEmbed(drop: DropResult, quantityClaimed: number, imageFileName: string, claimedBy?: string): EmbedBuilder {
AppLogger.LogSilly("CardDropHelperMetadata/GenerateDropEmbed", `Parameters: drop=${drop.card.id}, quantityClaimed=${quantityClaimed}, imageFileName=${imageFileName}`);
const description = drop.series.name;
let description = "";
description += `Series: ${drop.series.name}\n`;
description += `Claimed: ${quantityClaimed}\n`;
const embed = new EmbedBuilder()
if (claimedBy != null) {
description += `Claimed by: ${claimedBy}\n`;
} else {
description += "Claimed by: (UNCLAIMED)\n";
}
return new EmbedBuilder()
.setTitle(drop.card.name)
.setDescription(description)
.setFooter({ text: `${CardRarityToString(drop.card.type)} · ${drop.card.id}` })
.setColor(CardRarityToColour(drop.card.type))
.setImage(`attachment://${imageFileName}`)
.addFields([
{
name: "Claimed",
value: `${quantityClaimed}`,
inline: true,
}
]);
if (claimedBy != null) {
embed.addFields([
{
name: "Claimed by",
value: claimedBy,
inline: true,
}
]);
}
if (currency != null) {
embed.addFields([
{
name: "Currency",
value: `${currency}`,
inline: true,
}
]);
}
return embed;
.setImage(`attachment://${imageFileName}`);
}
public static GenerateDropButtons(drop: DropResult, claimId: string, userId: string, disabled: boolean = false): ActionRowBuilder<ButtonBuilder> {
@ -127,7 +105,7 @@ export default class CardDropHelperMetadata {
.addComponents(
new ButtonBuilder()
.setCustomId(`claim ${drop.card.id} ${claimId} ${userId}`)
.setLabel(`Claim (${CardConstants.ClaimCost} 🪙)`)
.setLabel("Claim")
.setStyle(ButtonStyle.Primary)
.setDisabled(disabled),
new ButtonBuilder()
@ -135,4 +113,4 @@ export default class CardDropHelperMetadata {
.setLabel("Reroll")
.setStyle(ButtonStyle.Secondary));
}
}
}

View file

@ -1,62 +0,0 @@
import {createCanvas, loadImage} from "canvas";
import path from "path";
import AppLogger from "../client/appLogger";
import {existsSync} from "fs";
import Inventory from "../database/entities/app/Inventory";
import Jimp from "jimp";
interface CardInput {
id: string;
path: string;
}
export default class ImageHelper {
public static async GenerateCardImageGrid(cards: CardInput[], userId?: string): Promise<Buffer> {
const gridWidth = 3;
const gridHeight = Math.ceil(cards.length / gridWidth);
const imageWidth = 526;
const imageHeight = 712;
const canvasWidth = imageWidth * gridWidth;
const canvasHeight = imageHeight * gridHeight;
const canvas = createCanvas(canvasWidth, canvasHeight);
const ctx = canvas.getContext("2d");
for (let i = 0; i < cards.length; i++) {
const card = cards[i];
const filePath = path.join(process.env.DATA_DIR!, "cards", card.path);
const exists = existsSync(filePath);
if (!exists) {
AppLogger.LogError("ImageHelper/GenerateCardImageGrid", `Failed to load image from path ${card.path}`);
continue;
}
const imageData = await Jimp.read(filePath);
if (userId != null) {
const claimed = await Inventory.FetchOneByCardNumberAndUserId(userId, card.id);
if (!claimed || claimed.Quantity == 0) {
imageData.greyscale();
}
}
const image = await loadImage(await imageData.getBufferAsync("image/png"));
const x = i % gridWidth;
const y = Math.floor(i / gridWidth);
const imageX = imageWidth * x;
const imageY = imageHeight * y;
ctx.drawImage(image, imageX, imageY);
}
return canvas.toBuffer();
}
}

View file

@ -1,11 +1,10 @@
import { ActionRowBuilder, AttachmentBuilder, ButtonBuilder, ButtonStyle, EmbedBuilder } from "discord.js";
import { ActionRowBuilder, ButtonBuilder, ButtonStyle, EmbedBuilder } from "discord.js";
import Inventory from "../database/entities/app/Inventory";
import { CoreClient } from "../client/client";
import EmbedColours from "../constants/EmbedColours";
import { CardRarity, CardRarityToString } from "../constants/CardRarity";
import cloneDeep from "clone-deep";
import AppLogger from "../client/appLogger";
import ImageHelper from "./ImageHelper";
interface InventoryPage {
id: number,
@ -19,26 +18,16 @@ interface InventoryPageCards {
name: string,
type: CardRarity,
quantity: number,
path: string,
}
interface ReturnedInventoryPage {
embed: EmbedBuilder,
row: ActionRowBuilder<ButtonBuilder>,
image: AttachmentBuilder,
}
export default class InventoryHelper {
public static async GenerateInventoryPage(username: string, userid: string, page: number): Promise<ReturnedInventoryPage | undefined> {
public static async GenerateInventoryPage(username: string, userid: string, page: number): Promise<{ embed: EmbedBuilder, row: ActionRowBuilder<ButtonBuilder> }> {
AppLogger.LogSilly("Helpers/InventoryHelper", `Parameters: username=${username}, userid=${userid}, page=${page}`);
const cardsPerPage = 9;
const cardsPerPage = 15;
const inventory = await Inventory.FetchAllByUserId(userid);
if (!inventory || inventory.length == 0) return undefined;
const clientCards = cloneDeep(CoreClient.Cards);
const allSeriesClaimed = clientCards
@ -73,7 +62,6 @@ export default class InventoryHelper {
name: card.name,
type: card.type,
quantity: item.Quantity,
path: card.path,
});
}
@ -89,15 +77,15 @@ export default class InventoryHelper {
const currentPage = pages[page];
if (!currentPage) {
return undefined;
AppLogger.LogError("Helpers/InventoryHelper", "Unable to find page");
return Promise.reject("Unable to find page");
}
const embed = new EmbedBuilder()
.setTitle(username)
.setDescription(`**${currentPage.name} (${currentPage.seriesSubpage + 1})**\n${currentPage.cards.map(x => `[${x.id}] ${x.name} (${CardRarityToString(x.type)}) x${x.quantity}`).join("\n")}`)
.setFooter({ text: `Page ${page + 1} of ${pages.length}` })
.setColor(EmbedColours.Ok)
.setImage("attachment://page.png");
.setColor(EmbedColours.Ok);
const row = new ActionRowBuilder<ButtonBuilder>()
.addComponents(
@ -112,9 +100,6 @@ export default class InventoryHelper {
.setStyle(ButtonStyle.Primary)
.setDisabled(page + 1 == pages.length));
const buffer = await ImageHelper.GenerateCardImageGrid(currentPage.cards.map(x => ({ id: x.id, path: x.path })));
const image = new AttachmentBuilder(buffer, { name: "page.png" });
return { embed, row, image };
return { embed, row };
}
}
}

View file

@ -1,16 +1,15 @@
import { ActionRowBuilder, AttachmentBuilder, ButtonBuilder, ButtonStyle, EmbedBuilder } from "discord.js";
import { ActionRowBuilder, ButtonBuilder, ButtonStyle, EmbedBuilder } from "discord.js";
import AppLogger from "../client/appLogger";
import cloneDeep from "clone-deep";
import { CoreClient } from "../client/client";
import EmbedColours from "../constants/EmbedColours";
import { CardRarityToString } from "../constants/CardRarity";
import ImageHelper from "./ImageHelper";
export default class SeriesHelper {
public static async GenerateSeriesViewPage(seriesId: number, page: number, userId: string): Promise<{ embed: EmbedBuilder, row: ActionRowBuilder<ButtonBuilder>, image: AttachmentBuilder } | null> {
public static GenerateSeriesViewPage(seriesId: number, page: number): { embed: EmbedBuilder, row: ActionRowBuilder<ButtonBuilder> } | null {
AppLogger.LogSilly("Helpers/SeriesHelper", `Parameters: seriesId=${seriesId}, page=${page}`);
const itemsPerPage = 9;
const itemsPerPage = 15;
const series = cloneDeep(CoreClient.Cards)
.find(x => x.id == seriesId);
@ -21,7 +20,6 @@ export default class SeriesHelper {
}
const totalPages = Math.ceil(series.cards.length / itemsPerPage);
const totalCards = series.cards.length;
if (page > totalPages) {
AppLogger.LogVerbose("Helpers/SeriesHelper", `Trying to find page greater than what exists for this series. Page: ${page} but there are only ${totalPages} pages`);
@ -38,8 +36,7 @@ export default class SeriesHelper {
.setTitle(series.name)
.setColor(EmbedColours.Ok)
.setDescription(description)
.setFooter({ text: `${series.id} · ${totalCards} cards · Page ${page + 1} of ${totalPages}` })
.setImage("attachment://page.png");
.setFooter({ text: `${series.id} · ${series.cards.length} cards · Page ${page + 1} of ${totalPages}` });
const row = new ActionRowBuilder<ButtonBuilder>()
.addComponents(
@ -52,12 +49,9 @@ export default class SeriesHelper {
.setCustomId(`series view ${seriesId} ${page + 1}`)
.setLabel("Next")
.setStyle(ButtonStyle.Primary)
.setDisabled(page + 1 == totalPages));
.setDisabled(page + 1 > totalPages));
const buffer = await ImageHelper.GenerateCardImageGrid(cardsOnPage.map(x => ({id: x.id, path: x.path})), userId);
const image = new AttachmentBuilder(buffer, { name: "page.png" });
return { embed, row, image };
return { embed, row };
}
public static GenerateSeriesListPage(page: number): { embed: EmbedBuilder, row: ActionRowBuilder<ButtonBuilder> } | null {
@ -78,7 +72,7 @@ export default class SeriesHelper {
const seriesOnPage = series.splice(page * itemsPerPage, itemsPerPage);
const description = seriesOnPage
.map(x => `[${x.id}] ${x.name} (${x.cards.length} cards)`)
.map(x => `[${x.id}] ${x.name}`)
.join("\n");
const embed = new EmbedBuilder()
@ -98,8 +92,8 @@ export default class SeriesHelper {
.setCustomId(`series list ${page + 1}`)
.setLabel("Next")
.setStyle(ButtonStyle.Primary)
.setDisabled(page + 1 == totalPages));
.setDisabled(page + 1 > totalPages));
return { embed, row };
}
}
}

View file

@ -1,14 +0,0 @@
import AppLogger from "../client/appLogger";
import Claim from "../database/entities/app/Claim";
export default async function PurgeClaims() {
const claims = await Claim.FetchAll(Claim);
const whenLastClaimable = new Date(Date.now() - (1000 * 60 * 5)); // 5 minutes ago
const expiredClaims = claims.filter(x => x.WhenCreated < whenLastClaimable);
await Claim.RemoveMany(Claim, expiredClaims);
AppLogger.LogInfo("Timers/PurgeClaims", `Purged ${expiredClaims.length} claims from the database`);
}

1156
yarn.lock

File diff suppressed because it is too large Load diff