[WIP] Trading and TradingStore implementation 1
This commit is contained in:
@@ -2,6 +2,7 @@ const { SlashCommandBuilder, ComponentType, ActionRowBuilder, ButtonBuilder, But
|
|||||||
const { customAlphabet } = require("nanoid");
|
const { customAlphabet } = require("nanoid");
|
||||||
const { Card, User } = require("../models");
|
const { Card, User } = require("../models");
|
||||||
const { UserUtils, CardUtils, GeneralUtils } = require("../util");
|
const { UserUtils, CardUtils, GeneralUtils } = require("../util");
|
||||||
|
const stores = require("../stores");
|
||||||
require('dotenv').config();
|
require('dotenv').config();
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
@@ -24,6 +25,7 @@ module.exports = {
|
|||||||
{ name: 'add_primary', value: 'add_primary' },
|
{ name: 'add_primary', value: 'add_primary' },
|
||||||
{ name: 'add_secondary', value: 'add_secondary' },
|
{ name: 'add_secondary', value: 'add_secondary' },
|
||||||
{ name: 'toggle_maintenance', value: 'toggle_maintenance' },
|
{ name: 'toggle_maintenance', value: 'toggle_maintenance' },
|
||||||
|
{ name: 'store', value: 'store' },
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
.addStringOption((option) =>
|
.addStringOption((option) =>
|
||||||
@@ -144,6 +146,12 @@ module.exports = {
|
|||||||
ephemeral: false
|
ephemeral: false
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
|
case "store":
|
||||||
|
interaction.editReply({
|
||||||
|
content: `${JSON.stringify(stores)}`,
|
||||||
|
ephemeral: false
|
||||||
|
});
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
interaction.editReply({
|
interaction.editReply({
|
||||||
content: `Your permission level is ${await UserUtils.getPermissionLevel(interaction.member)}`,
|
content: `Your permission level is ${await UserUtils.getPermissionLevel(interaction.member)}`,
|
||||||
|
|||||||
193
commands/trade.js
Normal file
193
commands/trade.js
Normal file
@@ -0,0 +1,193 @@
|
|||||||
|
const { SlashCommandBuilder, EmbedBuilder, ActionRowBuilder, ButtonBuilder, ButtonStyle } = require("discord.js");
|
||||||
|
const { Card, User } = require("../models");
|
||||||
|
const { UserUtils, CardUtils } = require("../util");
|
||||||
|
const { TradeStore } = require("../stores");
|
||||||
|
|
||||||
|
const tradeTimeout = 90000;
|
||||||
|
module.exports = {
|
||||||
|
data: new SlashCommandBuilder()
|
||||||
|
.setName("trade")
|
||||||
|
.setDescription("Start trading with a User")
|
||||||
|
.addSubcommand((subcommand) =>
|
||||||
|
subcommand
|
||||||
|
.setName("start")
|
||||||
|
.setDescription("Start a trade with a User")
|
||||||
|
.addUserOption((option) =>
|
||||||
|
option
|
||||||
|
.setName("user")
|
||||||
|
.setDescription("User to trade with")
|
||||||
|
.setRequired(true)
|
||||||
|
))
|
||||||
|
.addSubcommand((subcommand) =>
|
||||||
|
subcommand
|
||||||
|
.setName("view")
|
||||||
|
.setDescription("View active trade")
|
||||||
|
)
|
||||||
|
.addSubcommand((subcommand) =>
|
||||||
|
subcommand
|
||||||
|
.setName("add")
|
||||||
|
.setDescription("Add a card to the trade")
|
||||||
|
.addStringOption((option) =>
|
||||||
|
option
|
||||||
|
.setName("card")
|
||||||
|
.setDescription("Card to add")
|
||||||
|
.setRequired(true)
|
||||||
|
.setAutocomplete(true)
|
||||||
|
)
|
||||||
|
),
|
||||||
|
permissionLevel: 0,
|
||||||
|
async execute(interaction) {
|
||||||
|
let user1 = await UserUtils.getUserByDiscordId(interaction.member.id);
|
||||||
|
let trade = await TradeStore.getTradeByUser(user1.id);
|
||||||
|
|
||||||
|
switch (interaction.options.getSubcommand()) {
|
||||||
|
case "start":
|
||||||
|
await interaction.deferReply();
|
||||||
|
let user2 = await UserUtils.getUserByDiscordId(interaction.options.getUser("user").id);
|
||||||
|
//Attach usernames for convenience
|
||||||
|
user2.name = interaction.options.getUser("user").username;
|
||||||
|
user1.name = interaction.member.user.username;
|
||||||
|
this.startTrade(interaction, user1, user2);
|
||||||
|
break;
|
||||||
|
case "view":
|
||||||
|
await interaction.deferReply();
|
||||||
|
this.viewTrade(interaction, trade);
|
||||||
|
break;
|
||||||
|
case "add":
|
||||||
|
if (!trade) {
|
||||||
|
await interaction.reply({ content: "You don't have an active trade", ephemeral: true });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
await interaction.deferReply();
|
||||||
|
let card = await Card.findOne({
|
||||||
|
where:
|
||||||
|
{ identifier: interaction.options.getString("card") , userId: user1.id }
|
||||||
|
},
|
||||||
|
include: [
|
||||||
|
{ model: Character, include: [{ model: Band }] },
|
||||||
|
{ model: User}
|
||||||
|
]);
|
||||||
|
this.addCardToTrade(interaction, trade, card);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
async startTrade(interaction, user1, user2) {
|
||||||
|
if (!user2) {
|
||||||
|
await interaction.editReply({ content: "This User is not registered yet!" });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (user2.discordId === interaction.member.id) {
|
||||||
|
await interaction.editReply({ content: "You can't trade with yourself!" });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (await TradeStore.getTradeByUser(user1.id)) {
|
||||||
|
await interaction.editReply({ content: "You are already in a Trade!" });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (await TradeStore.getTradeByUser(user2.id)) {
|
||||||
|
await interaction.editReply({ content: "This User is already in a Trade!" });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let trade = new TradeStore.Trade(CardUtils.generateIdentifier(), user1, user2);
|
||||||
|
await TradeStore.addTrade(trade);
|
||||||
|
this.viewTrade(interaction, trade);
|
||||||
|
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
async addCardToTrade(interaction, trade, card) {
|
||||||
|
//find card by identifier if owned by user
|
||||||
|
|
||||||
|
if (!card) {
|
||||||
|
await interaction.reply({ content: "You don't own this card", ephemeral: true });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (card.userId !== trade.user1.id) {
|
||||||
|
await interaction.editReply({ content: "You don't own this Card!" });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (trade.user1.id === interaction.member.id) {
|
||||||
|
trade.user1Cards.push(card);
|
||||||
|
} else {
|
||||||
|
trade.user2Cards.push(card);
|
||||||
|
}
|
||||||
|
this.viewTrade(interaction, trade);
|
||||||
|
},
|
||||||
|
|
||||||
|
async viewTrade(interaction, trade) {
|
||||||
|
if (!trade) {
|
||||||
|
await interaction.editReply({ content: "This Trade does not exist!" });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
//delete existing trade message
|
||||||
|
if (trade.embed) {
|
||||||
|
await trade.embed.delete();
|
||||||
|
}
|
||||||
|
|
||||||
|
let user1Cards = "No cards"
|
||||||
|
let user2Cards = "No cards"
|
||||||
|
// for each of user1's cards in the trade
|
||||||
|
for (card of trade.user1Cards) {
|
||||||
|
//get the card object
|
||||||
|
let card = await Card.findOne({
|
||||||
|
where: {
|
||||||
|
identifier: cardIdentifier
|
||||||
|
},
|
||||||
|
include: [
|
||||||
|
{ model: Character, include: [{ model: Band }] },
|
||||||
|
{ model: User}
|
||||||
|
]
|
||||||
|
});
|
||||||
|
//add it to the list
|
||||||
|
user1Cards += `${card.identifier}\n`;
|
||||||
|
}
|
||||||
|
// for each of user2's cards in the trade
|
||||||
|
for (card of trade.user2Cards) {
|
||||||
|
//get the card object
|
||||||
|
let card = await Card.findOne({
|
||||||
|
const embed = new EmbedBuilder()
|
||||||
|
.setTitle(`Trade [${trade.id}] ${trade.user1.name} with ${trade.user2.name}`)
|
||||||
|
.setDescription("DUMMY DESCRIPTION")
|
||||||
|
.addFields(
|
||||||
|
{ name: `${trade.user1.name}'s cards`, value: user1Cards },
|
||||||
|
{ name: `${trade.user2.name}'s cards`, value: `DATA2` }
|
||||||
|
)
|
||||||
|
.setColor(0x00ff00)
|
||||||
|
.setFooter({ text: `TRADE`, iconURL: 'https://cdn.discordapp.com/attachments/856904078754971658/1017431187234508820/fp.png' });
|
||||||
|
|
||||||
|
const row = new ActionRowBuilder();
|
||||||
|
row.addComponents(
|
||||||
|
new ButtonBuilder()
|
||||||
|
.setCustomId(`cancel-trade-${trade.id}`)
|
||||||
|
.setLabel('Cancel')
|
||||||
|
.setStyle(ButtonStyle.Danger)
|
||||||
|
);
|
||||||
|
let reply = await interaction.editReply({ embeds: [embed], components: [row] });
|
||||||
|
trade.embed = reply;
|
||||||
|
|
||||||
|
//button collector
|
||||||
|
const filter = (button) => button.user.id === trade.user1.discordId || button.user.id === trade.user2.discordId;
|
||||||
|
const collector = reply.createMessageComponentCollector({ filter, time: tradeTimeout });
|
||||||
|
|
||||||
|
collector.on('collect', async (button) => {
|
||||||
|
if (button.customId === `cancel-trade-${trade.id}`) {
|
||||||
|
await TradeStore.removeTrade(trade);
|
||||||
|
collector.stop("cancel");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
collector.on('end', async (collected, reason) => {
|
||||||
|
console.log(`Collected ${collected.size} items, reason: ${reason}`);
|
||||||
|
if (reason === "time") {
|
||||||
|
await TradeStore.removeTrade(trade);
|
||||||
|
await trade.embed.edit({ content: `Trade ${trade.id} expired`, embeds: [], components: [] });
|
||||||
|
}
|
||||||
|
if (reason === "cancel") {
|
||||||
|
await trade.embed.edit({ content: `Trade ${trade.id} cancelled`, embeds: [], components: [] });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -3,7 +3,7 @@ const { UserUtils } = require('../util');
|
|||||||
const { Card, Character, User } = require('../models');
|
const { Card, Character, User } = require('../models');
|
||||||
const Sequelize = require('sequelize');
|
const Sequelize = require('sequelize');
|
||||||
const { QUALITY_NAMES } = require('../config/constants');
|
const { QUALITY_NAMES } = require('../config/constants');
|
||||||
|
const { TestStore } = require('../stores');
|
||||||
module.exports = {
|
module.exports = {
|
||||||
name: "interactionCreate",
|
name: "interactionCreate",
|
||||||
async execute (interaction) {
|
async execute (interaction) {
|
||||||
@@ -20,6 +20,12 @@ module.exports = {
|
|||||||
choices = await this.fetchCards(focusedOption, { user: user, ownedOnly: true });
|
choices = await this.fetchCards(focusedOption, { user: user, ownedOnly: true });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (interaction.commandName === "trade") {
|
||||||
|
if (focusedOption.name === "card") {
|
||||||
|
choices = await this.fetchCards(focusedOption, { user: user, ownedOnly: true });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (interaction.commandName === 'view') {
|
if (interaction.commandName === 'view') {
|
||||||
const viewType = interaction.options.getString('type');
|
const viewType = interaction.options.getString('type');
|
||||||
|
|
||||||
|
|||||||
25
stores/index.js
Normal file
25
stores/index.js
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
const fs = require('fs');
|
||||||
|
const path = require('path');
|
||||||
|
const basename = path.basename(__filename);
|
||||||
|
const utils = {};
|
||||||
|
|
||||||
|
fs
|
||||||
|
.readdirSync(__dirname)
|
||||||
|
.filter(file => {
|
||||||
|
return (file.indexOf('.') !== 0) && (file !== basename) && (file.slice(-3) === '.js');
|
||||||
|
})
|
||||||
|
.forEach(file => {
|
||||||
|
const util = require(path.join(__dirname, file));
|
||||||
|
utils[util.name] = util;
|
||||||
|
console.log(`Registered Store: ${util.name}`);
|
||||||
|
});
|
||||||
|
|
||||||
|
Object.keys(utils).forEach(modelName => {
|
||||||
|
if (utils[modelName].associate) {
|
||||||
|
utils[modelName].associate(utils);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
module.exports = utils;
|
||||||
33
stores/tradeStore.js
Normal file
33
stores/tradeStore.js
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
module.exports = {
|
||||||
|
name: "TradeStore",
|
||||||
|
activeTrades: [],
|
||||||
|
|
||||||
|
async addTrade(trade) {
|
||||||
|
this.activeTrades.push(trade);
|
||||||
|
},
|
||||||
|
|
||||||
|
async removeTrade(trade) {
|
||||||
|
this.activeTrades.splice(this.activeTrades.indexOf(trade), 1);
|
||||||
|
},
|
||||||
|
|
||||||
|
async getTradeById(tradeId) {
|
||||||
|
return this.activeTrades.find(trade => trade.id === tradeId);
|
||||||
|
},
|
||||||
|
|
||||||
|
async getTradeByUser(userId) {
|
||||||
|
return this.activeTrades.find(trade => trade.user1.id === userId || trade.user2.id === userId);
|
||||||
|
},
|
||||||
|
|
||||||
|
Trade: class Trade {
|
||||||
|
constructor(id, user1, user2) {
|
||||||
|
this.id = id;
|
||||||
|
this.user1 = user1;
|
||||||
|
this.user2 = user2;
|
||||||
|
this.embed = null;
|
||||||
|
this.user1Cards = [];
|
||||||
|
this.user2Cards = [];
|
||||||
|
this.user1Accept = false;
|
||||||
|
this.user2Accept = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user