added bankruptcy
This commit is contained in:
@@ -0,0 +1,188 @@
|
||||
const { getCollections, getCookieBalance, getUnixTime } = require("./cookieEconomy");
|
||||
const { trackProfileEvent } = require("./profileSystem");
|
||||
|
||||
const BANKRUPTCY_COLLECTION = "items_bankruptcy";
|
||||
const BANKRUPTCY_GRANT = 1000;
|
||||
const BANKRUPTCY_COOLDOWN = 1 * 60 * 60;
|
||||
|
||||
function getBankruptcyCollection() {
|
||||
return getCollections().db.collection(BANKRUPTCY_COLLECTION);
|
||||
}
|
||||
|
||||
async function ensureBankruptcyIndexes() {
|
||||
const bankruptcy = getBankruptcyCollection();
|
||||
|
||||
await bankruptcy.createIndex(
|
||||
{ userId: 1, guildId: 1 },
|
||||
{ unique: true }
|
||||
);
|
||||
}
|
||||
|
||||
async function getBankruptcyStatus(userId, guildId) {
|
||||
const balance = await getCookieBalance(userId);
|
||||
const document = await getBankruptcyCollection().findOne({
|
||||
userId,
|
||||
guildId
|
||||
});
|
||||
|
||||
const now = getUnixTime();
|
||||
const nextAvailableAt = Number(document?.nextAvailableAt ?? 0);
|
||||
|
||||
return {
|
||||
balance,
|
||||
eligible: balance === 0 && nextAvailableAt <= now,
|
||||
nextAvailableAt,
|
||||
claims: Number(document?.claims ?? 0)
|
||||
};
|
||||
}
|
||||
|
||||
async function declareBankruptcy(interaction, userId = interaction.user.id) {
|
||||
const guildId = interaction.guildId;
|
||||
|
||||
if (!guildId) {
|
||||
return {
|
||||
ok: false,
|
||||
reason: "GUILD_ONLY"
|
||||
};
|
||||
}
|
||||
|
||||
const { cookies } = getCollections();
|
||||
const bankruptcy = getBankruptcyCollection();
|
||||
const now = getUnixTime();
|
||||
|
||||
const previous = await bankruptcy.findOne({
|
||||
userId,
|
||||
guildId
|
||||
});
|
||||
|
||||
const nextAvailableAt = Number(previous?.nextAvailableAt ?? 0);
|
||||
|
||||
if (nextAvailableAt > now) {
|
||||
return {
|
||||
ok: false,
|
||||
reason: "COOLDOWN",
|
||||
nextAvailableAt
|
||||
};
|
||||
}
|
||||
|
||||
let claimLock;
|
||||
|
||||
try {
|
||||
claimLock = await bankruptcy.findOneAndUpdate(
|
||||
{
|
||||
userId,
|
||||
guildId,
|
||||
$or: [
|
||||
{ nextAvailableAt: { $exists: false } },
|
||||
{ nextAvailableAt: { $lte: now } }
|
||||
]
|
||||
},
|
||||
{
|
||||
$set: {
|
||||
nextAvailableAt: now + BANKRUPTCY_COOLDOWN,
|
||||
lastClaimedAt: now
|
||||
},
|
||||
$inc: {
|
||||
claims: 1
|
||||
},
|
||||
$setOnInsert: {
|
||||
userId,
|
||||
guildId
|
||||
}
|
||||
},
|
||||
{
|
||||
upsert: true,
|
||||
returnDocument: "after"
|
||||
}
|
||||
);
|
||||
} catch (error) {
|
||||
if (error?.code !== 11000) {
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
if (!claimLock) {
|
||||
const status = await getBankruptcyStatus(userId, guildId);
|
||||
|
||||
return {
|
||||
ok: false,
|
||||
reason: "COOLDOWN",
|
||||
nextAvailableAt: status.nextAvailableAt
|
||||
};
|
||||
}
|
||||
|
||||
let credit;
|
||||
|
||||
try {
|
||||
credit = await cookies.updateOne(
|
||||
{
|
||||
userId,
|
||||
$or: [
|
||||
{ cookies: 0 },
|
||||
{ cookies: { $exists: false } }
|
||||
]
|
||||
},
|
||||
{
|
||||
$inc: {
|
||||
cookies: BANKRUPTCY_GRANT
|
||||
},
|
||||
$setOnInsert: {
|
||||
userId
|
||||
}
|
||||
},
|
||||
{
|
||||
upsert: true
|
||||
}
|
||||
);
|
||||
} catch (error) {
|
||||
if (error?.code !== 11000) {
|
||||
throw error;
|
||||
}
|
||||
|
||||
credit = { modifiedCount: 0, upsertedCount: 0 };
|
||||
}
|
||||
|
||||
if (credit.modifiedCount !== 1 && credit.upsertedCount !== 1) {
|
||||
await bankruptcy.updateOne(
|
||||
{ userId, guildId },
|
||||
{
|
||||
$set: {
|
||||
nextAvailableAt,
|
||||
lastClaimedAt: previous?.lastClaimedAt ?? null,
|
||||
claims: Number(previous?.claims ?? 0)
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
return {
|
||||
ok: false,
|
||||
reason: "BALANCE_NOT_ZERO",
|
||||
balance: await getCookieBalance(userId)
|
||||
};
|
||||
}
|
||||
|
||||
await trackProfileEvent(
|
||||
interaction,
|
||||
userId,
|
||||
{
|
||||
type: "cookie_gain",
|
||||
amount: BANKRUPTCY_GRANT
|
||||
}
|
||||
);
|
||||
|
||||
return {
|
||||
ok: true,
|
||||
amount: BANKRUPTCY_GRANT,
|
||||
balance: BANKRUPTCY_GRANT,
|
||||
nextAvailableAt: now + BANKRUPTCY_COOLDOWN,
|
||||
claims: Number(claimLock.claims ?? 1)
|
||||
};
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
BANKRUPTCY_GRANT,
|
||||
BANKRUPTCY_COOLDOWN,
|
||||
ensureBankruptcyIndexes,
|
||||
getBankruptcyStatus,
|
||||
declareBankruptcy
|
||||
};
|
||||
@@ -27,30 +27,30 @@ const HEIST_METHODS = {
|
||||
baseChance: 0.65,
|
||||
minStealPercent: 0.01,
|
||||
maxStealPercent: 0.03,
|
||||
maxStealAmount: 1500,
|
||||
maxStealAmount: 5000,
|
||||
minPenaltyPercent: 0.01,
|
||||
maxPenaltyPercent: 0.04,
|
||||
maxPenaltyAmount: 750
|
||||
maxPenaltyAmount: 1500
|
||||
},
|
||||
|
||||
Hack: {
|
||||
baseChance: 0.45,
|
||||
minStealPercent: 0.03,
|
||||
maxStealPercent: 0.06,
|
||||
maxStealAmount: 3500,
|
||||
maxStealAmount: 12500,
|
||||
minPenaltyPercent: 0.03,
|
||||
maxPenaltyPercent: 0.07,
|
||||
maxPenaltyAmount: 2000
|
||||
maxPenaltyAmount: 4000
|
||||
},
|
||||
|
||||
Smash: {
|
||||
baseChance: 0.25,
|
||||
minStealPercent: 0.06,
|
||||
maxStealPercent: 0.12,
|
||||
maxStealAmount: 7500,
|
||||
maxStealAmount: 25000,
|
||||
minPenaltyPercent: 0.06,
|
||||
maxPenaltyPercent: 0.12,
|
||||
maxPenaltyAmount: 5000
|
||||
maxPenaltyAmount: 10000
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -26,6 +26,7 @@ const {
|
||||
const COLLECT_COOLDOWN =
|
||||
60 * 60;
|
||||
|
||||
const COLLECT_MAX = 1000;
|
||||
|
||||
/*
|
||||
* IMPORTANT:
|
||||
@@ -223,7 +224,7 @@ async function collectCookiesFromSaucer(
|
||||
const amount =
|
||||
Math.floor(
|
||||
Math.random() *
|
||||
1000
|
||||
COLLECT_MAX
|
||||
)
|
||||
+
|
||||
1;
|
||||
|
||||
+78
-219
@@ -6,101 +6,56 @@ const {
|
||||
} = require("discord.js");
|
||||
|
||||
const {
|
||||
getCookieBalance,
|
||||
temporaryEphemeralReply
|
||||
getCookieBalance
|
||||
} = require("./cookieEconomy");
|
||||
|
||||
const {
|
||||
createInteractionSession,
|
||||
requireInteractionSession
|
||||
} = require("./interactionSession");
|
||||
|
||||
/*
|
||||
* ============================================================
|
||||
* MAIN MENU
|
||||
* ============================================================
|
||||
*/
|
||||
async function showCrumbSaucer(interaction) {
|
||||
if (interaction.isButton()) {
|
||||
const session = await requireInteractionSession(interaction);
|
||||
|
||||
async function showCrumbSaucer(
|
||||
interaction
|
||||
) {
|
||||
/*
|
||||
* Button navigation must preserve ownership.
|
||||
*/
|
||||
|
||||
if (
|
||||
interaction.isButton()
|
||||
) {
|
||||
const ownerId =
|
||||
getCrumbSaucerSessionOwner(
|
||||
interaction
|
||||
);
|
||||
|
||||
|
||||
if (
|
||||
ownerId !==
|
||||
interaction.user.id
|
||||
) {
|
||||
return temporaryEphemeralReply(
|
||||
interaction,
|
||||
{
|
||||
content:
|
||||
"This isn't your Crumb Saucer session."
|
||||
}
|
||||
);
|
||||
if (!session) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
const balance = await getCookieBalance(interaction.user.id);
|
||||
const embed = buildMainMenuEmbed(interaction.user, balance);
|
||||
|
||||
const balance =
|
||||
await getCookieBalance(
|
||||
interaction.user.id
|
||||
);
|
||||
|
||||
|
||||
const embed =
|
||||
buildMainMenuEmbed(
|
||||
interaction.user,
|
||||
balance
|
||||
);
|
||||
|
||||
|
||||
if (
|
||||
interaction.isButton()
|
||||
) {
|
||||
return interaction.update({
|
||||
embeds: [
|
||||
embed
|
||||
],
|
||||
|
||||
components:
|
||||
buildMainMenuButtons()
|
||||
embeds: [embed],
|
||||
components: buildMainMenuButtons()
|
||||
});
|
||||
}
|
||||
|
||||
const balance = await getCookieBalance(interaction.user.id);
|
||||
const embed = buildMainMenuEmbed(interaction.user, balance);
|
||||
|
||||
return interaction.reply({
|
||||
embeds: [
|
||||
embed
|
||||
],
|
||||
|
||||
components:
|
||||
buildMainMenuButtons()
|
||||
await interaction.reply({
|
||||
embeds: [embed],
|
||||
components: buildMainMenuButtons()
|
||||
});
|
||||
|
||||
const message = await interaction.fetchReply();
|
||||
|
||||
await createInteractionSession(
|
||||
interaction,
|
||||
{
|
||||
messageId: message.id,
|
||||
ownerId: interaction.user.id,
|
||||
kind: "crumbSaucer"
|
||||
}
|
||||
);
|
||||
|
||||
return message;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* ============================================================
|
||||
* MAIN MENU EMBED
|
||||
* ============================================================
|
||||
*/
|
||||
|
||||
function buildMainMenuEmbed(
|
||||
user,
|
||||
balance
|
||||
) {
|
||||
function buildMainMenuEmbed(user, balance) {
|
||||
return new EmbedBuilder()
|
||||
.setTitle(
|
||||
"🎰 The Crumb Saucer"
|
||||
)
|
||||
|
||||
.setTitle("🎰 The Crumb Saucer")
|
||||
.setDescription(
|
||||
[
|
||||
`Welcome, ${user}!`,
|
||||
@@ -121,158 +76,78 @@ function buildMainMenuEmbed(
|
||||
"Bet on Red, Black, Odd, Even, or Zero.",
|
||||
"",
|
||||
"### 🏦 Vault Heist",
|
||||
"Attempt to breach ShaiBot's Cookie Vault."
|
||||
"Attempt to breach ShaiBot's Cookie Vault.",
|
||||
"",
|
||||
"### 🛟 Bankruptcy",
|
||||
"At exactly 0 Cookies, claim a 1,000 Cookie starter kit."
|
||||
].join("\n")
|
||||
)
|
||||
|
||||
.addFields({
|
||||
name:
|
||||
"Your Vault",
|
||||
|
||||
value:
|
||||
`**${balance.toLocaleString()} 🍪**`
|
||||
name: "Your Vault",
|
||||
value: `**${balance.toLocaleString()} 🍪**`
|
||||
})
|
||||
|
||||
.setFooter({
|
||||
text:
|
||||
`crumbSaucer:${user.id}`
|
||||
text: `crumbSaucer:${user.id}`
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* ============================================================
|
||||
* MAIN MENU BUTTONS
|
||||
* ============================================================
|
||||
*/
|
||||
|
||||
function buildMainMenuButtons() {
|
||||
return [
|
||||
new ActionRowBuilder()
|
||||
.addComponents(
|
||||
new ButtonBuilder()
|
||||
.setCustomId(
|
||||
"crumbSaucerSlots"
|
||||
)
|
||||
.setLabel(
|
||||
"Slots"
|
||||
)
|
||||
.setEmoji(
|
||||
"🎰"
|
||||
)
|
||||
.setStyle(
|
||||
ButtonStyle.Primary
|
||||
),
|
||||
.setCustomId("crumbSaucerSlots")
|
||||
.setLabel("Slots")
|
||||
.setEmoji("🎰")
|
||||
.setStyle(ButtonStyle.Primary),
|
||||
|
||||
new ButtonBuilder()
|
||||
.setCustomId(
|
||||
"crumbSaucerBlackjack"
|
||||
)
|
||||
.setLabel(
|
||||
"Blackjack"
|
||||
)
|
||||
.setEmoji(
|
||||
"🃏"
|
||||
)
|
||||
.setStyle(
|
||||
ButtonStyle.Success
|
||||
),
|
||||
.setCustomId("crumbSaucerBlackjack")
|
||||
.setLabel("Blackjack")
|
||||
.setEmoji("🃏")
|
||||
.setStyle(ButtonStyle.Success),
|
||||
|
||||
new ButtonBuilder()
|
||||
.setCustomId(
|
||||
"crumbSaucerRoulette"
|
||||
)
|
||||
.setLabel(
|
||||
"Roulette"
|
||||
)
|
||||
.setEmoji(
|
||||
"🎡"
|
||||
)
|
||||
.setStyle(
|
||||
ButtonStyle.Primary
|
||||
),
|
||||
.setCustomId("crumbSaucerRoulette")
|
||||
.setLabel("Roulette")
|
||||
.setEmoji("🎡")
|
||||
.setStyle(ButtonStyle.Primary),
|
||||
|
||||
new ButtonBuilder()
|
||||
.setCustomId(
|
||||
"crumbSaucerHeist"
|
||||
)
|
||||
.setLabel(
|
||||
"Vault Heist"
|
||||
)
|
||||
.setEmoji(
|
||||
"🏦"
|
||||
)
|
||||
.setStyle(
|
||||
ButtonStyle.Danger
|
||||
)
|
||||
.setCustomId("crumbSaucerHeist")
|
||||
.setLabel("Vault Heist")
|
||||
.setEmoji("🏦")
|
||||
.setStyle(ButtonStyle.Danger)
|
||||
),
|
||||
|
||||
new ActionRowBuilder()
|
||||
.addComponents(
|
||||
new ButtonBuilder()
|
||||
.setCustomId(
|
||||
"crumbSaucerCollectMenu"
|
||||
)
|
||||
.setLabel(
|
||||
"Cookie Bakery"
|
||||
)
|
||||
.setEmoji(
|
||||
"🍪"
|
||||
)
|
||||
.setStyle(
|
||||
ButtonStyle.Success
|
||||
),
|
||||
|
||||
/*
|
||||
* Do NOT use global "abort" here.
|
||||
*
|
||||
* The dedicated handler validates
|
||||
* Crumb Saucer ownership first.
|
||||
*/
|
||||
.setCustomId("crumbSaucerCollectMenu")
|
||||
.setLabel("Cookie Bakery")
|
||||
.setEmoji("🍪")
|
||||
.setStyle(ButtonStyle.Success),
|
||||
|
||||
new ButtonBuilder()
|
||||
.setCustomId(
|
||||
"crumbSaucerClose"
|
||||
)
|
||||
.setLabel(
|
||||
"Close"
|
||||
)
|
||||
.setEmoji(
|
||||
"✖️"
|
||||
)
|
||||
.setStyle(
|
||||
ButtonStyle.Secondary
|
||||
)
|
||||
.setCustomId("crumbSaucerBankruptcy")
|
||||
.setLabel("Bankruptcy")
|
||||
.setEmoji("🛟")
|
||||
.setStyle(ButtonStyle.Secondary),
|
||||
|
||||
new ButtonBuilder()
|
||||
.setCustomId("sessionClose")
|
||||
.setLabel("Close")
|
||||
.setEmoji("✖️")
|
||||
.setStyle(ButtonStyle.Secondary)
|
||||
)
|
||||
];
|
||||
}
|
||||
|
||||
function getCrumbSaucerSessionOwner(interaction) {
|
||||
const footer = interaction.message?.embeds?.[0]?.footer?.text;
|
||||
const parts = footer?.split(":") ?? [];
|
||||
|
||||
/*
|
||||
* ============================================================
|
||||
* SESSION OWNER
|
||||
* ============================================================
|
||||
*/
|
||||
|
||||
function getCrumbSaucerSessionOwner(
|
||||
interaction
|
||||
) {
|
||||
const footer =
|
||||
interaction.message
|
||||
?.embeds?.[0]
|
||||
?.footer
|
||||
?.text;
|
||||
|
||||
|
||||
const parts =
|
||||
footer?.split(":")
|
||||
??
|
||||
[];
|
||||
|
||||
|
||||
switch (
|
||||
parts[0]
|
||||
) {
|
||||
switch (parts[0]) {
|
||||
case "crumbSaucer":
|
||||
case "crumbSaucerCollect":
|
||||
case "crumbSaucerSlots":
|
||||
@@ -283,35 +158,19 @@ function getCrumbSaucerSessionOwner(
|
||||
case "crumbRouletteBet":
|
||||
case "crumbRouletteResult":
|
||||
case "cookieHeist":
|
||||
|
||||
return parts[1];
|
||||
|
||||
|
||||
/*
|
||||
* Active Blackjack:
|
||||
*
|
||||
* crumbBlackjack:<gameId>:<userId>
|
||||
*/
|
||||
|
||||
case "crumbBlackjack":
|
||||
|
||||
return parts[2];
|
||||
|
||||
|
||||
default:
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* ============================================================
|
||||
* EXPORTS
|
||||
* ============================================================
|
||||
*/
|
||||
|
||||
module.exports = {
|
||||
showCrumbSaucer,
|
||||
buildMainMenuEmbed,
|
||||
buildMainMenuButtons,
|
||||
getCrumbSaucerSessionOwner
|
||||
};
|
||||
};
|
||||
|
||||
@@ -0,0 +1,284 @@
|
||||
const { EmbedBuilder, MessageFlags } = require("discord.js");
|
||||
const { mClient } = require("../index");
|
||||
|
||||
const DATABASE_NAME = process.env.M_DB;
|
||||
const SESSION_COLLECTION = "items_sessions";
|
||||
const DEFAULT_SESSION_LIFETIME_MS = 24 * 60 * 60 * 1000;
|
||||
|
||||
function getSessionCollection() {
|
||||
if (!DATABASE_NAME) {
|
||||
throw new Error("M_DB is not configured in .env");
|
||||
}
|
||||
|
||||
return mClient.db(DATABASE_NAME).collection(SESSION_COLLECTION);
|
||||
}
|
||||
|
||||
async function ensureInteractionSessionIndexes() {
|
||||
const sessions = getSessionCollection();
|
||||
|
||||
await sessions.createIndex(
|
||||
{ messageId: 1 },
|
||||
{ unique: true }
|
||||
);
|
||||
|
||||
await sessions.createIndex(
|
||||
{ expiresAt: 1 },
|
||||
{ expireAfterSeconds: 0 }
|
||||
);
|
||||
}
|
||||
|
||||
async function createInteractionSession(
|
||||
interaction,
|
||||
{
|
||||
messageId = null,
|
||||
ownerId = interaction.user.id,
|
||||
kind = "menu",
|
||||
targetId = null,
|
||||
metadata = {},
|
||||
lifetimeMs = DEFAULT_SESSION_LIFETIME_MS
|
||||
} = {}
|
||||
) {
|
||||
const resolvedMessageId =
|
||||
messageId ?? interaction.message?.id;
|
||||
|
||||
if (!resolvedMessageId) {
|
||||
throw new Error("SESSION_MESSAGE_ID_REQUIRED");
|
||||
}
|
||||
|
||||
const sessions = getSessionCollection();
|
||||
const now = new Date();
|
||||
const expiresAt = new Date(now.getTime() + lifetimeMs);
|
||||
|
||||
await sessions.updateOne(
|
||||
{ messageId: resolvedMessageId },
|
||||
{
|
||||
$set: {
|
||||
messageId: resolvedMessageId,
|
||||
ownerId,
|
||||
guildId: interaction.guildId ?? null,
|
||||
channelId: interaction.channelId ?? null,
|
||||
kind,
|
||||
targetId,
|
||||
metadata,
|
||||
active: true,
|
||||
updatedAt: now,
|
||||
expiresAt
|
||||
},
|
||||
$setOnInsert: {
|
||||
createdAt: now
|
||||
}
|
||||
},
|
||||
{ upsert: true }
|
||||
);
|
||||
|
||||
return sessions.findOne({ messageId: resolvedMessageId });
|
||||
}
|
||||
|
||||
async function registerReplySession(interaction, options = {}) {
|
||||
const message = await interaction.fetchReply();
|
||||
|
||||
return createInteractionSession(
|
||||
interaction,
|
||||
{
|
||||
...options,
|
||||
messageId: message.id
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
async function getInteractionSession(interaction) {
|
||||
const messageId = interaction.message?.id;
|
||||
|
||||
if (!messageId) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return getSessionCollection().findOne({
|
||||
messageId,
|
||||
active: true,
|
||||
expiresAt: { $gt: new Date() }
|
||||
});
|
||||
}
|
||||
|
||||
function inferLegacyOwnerId(interaction) {
|
||||
const footer = interaction.message?.embeds?.[0]?.footer?.text;
|
||||
const parts = footer?.split(":") ?? [];
|
||||
|
||||
if (!parts.length) {
|
||||
return null;
|
||||
}
|
||||
|
||||
switch (parts[0]) {
|
||||
case "profile":
|
||||
case "crumbSaucer":
|
||||
case "crumbSaucerCollect":
|
||||
case "crumbSaucerSlots":
|
||||
case "crumbSaucerSlotsResult":
|
||||
case "crumbSaucerBlackjack":
|
||||
case "crumbBlackjackResult":
|
||||
case "crumbRouletteMenu":
|
||||
case "crumbRouletteBet":
|
||||
case "crumbRouletteResult":
|
||||
case "cookieHeist":
|
||||
return parts[1] ?? null;
|
||||
|
||||
case "crumbBlackjack":
|
||||
return parts[2] ?? null;
|
||||
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
async function replySessionError(
|
||||
interaction,
|
||||
content = "This isn't your session."
|
||||
) {
|
||||
const payload = {
|
||||
content,
|
||||
flags: MessageFlags.Ephemeral
|
||||
};
|
||||
|
||||
if (interaction.replied || interaction.deferred) {
|
||||
return interaction.followUp(payload);
|
||||
}
|
||||
|
||||
return interaction.reply(payload);
|
||||
}
|
||||
|
||||
async function requireInteractionSession(
|
||||
interaction,
|
||||
{
|
||||
kinds = null,
|
||||
allowLegacy = true
|
||||
} = {}
|
||||
) {
|
||||
const session = await getInteractionSession(interaction);
|
||||
|
||||
if (session) {
|
||||
if (session.ownerId !== interaction.user.id) {
|
||||
await replySessionError(interaction);
|
||||
return null;
|
||||
}
|
||||
|
||||
if (
|
||||
Array.isArray(kinds) &&
|
||||
kinds.length > 0 &&
|
||||
!kinds.includes(session.kind)
|
||||
) {
|
||||
await replySessionError(
|
||||
interaction,
|
||||
"This control belongs to a different session."
|
||||
);
|
||||
return null;
|
||||
}
|
||||
|
||||
return session;
|
||||
}
|
||||
|
||||
if (allowLegacy) {
|
||||
const ownerId = inferLegacyOwnerId(interaction);
|
||||
|
||||
if (ownerId) {
|
||||
if (ownerId !== interaction.user.id) {
|
||||
await replySessionError(interaction);
|
||||
return null;
|
||||
}
|
||||
|
||||
return {
|
||||
messageId: interaction.message?.id ?? null,
|
||||
ownerId,
|
||||
guildId: interaction.guildId ?? null,
|
||||
channelId: interaction.channelId ?? null,
|
||||
kind: "legacy",
|
||||
targetId: null,
|
||||
metadata: {},
|
||||
active: true,
|
||||
legacy: true
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
messageId: interaction.message?.id ?? null,
|
||||
ownerId: interaction.user.id,
|
||||
kind: "unmanaged",
|
||||
metadata: {},
|
||||
active: true,
|
||||
unmanaged: true
|
||||
};
|
||||
}
|
||||
|
||||
async function guardSessionInteraction(interaction) {
|
||||
if (!interaction.isButton()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const session = await getInteractionSession(interaction);
|
||||
|
||||
if (session) {
|
||||
if (session.ownerId === interaction.user.id) {
|
||||
return true;
|
||||
}
|
||||
|
||||
await replySessionError(interaction);
|
||||
return false;
|
||||
}
|
||||
|
||||
const ownerId = inferLegacyOwnerId(interaction);
|
||||
|
||||
if (!ownerId || ownerId === interaction.user.id) {
|
||||
return true;
|
||||
}
|
||||
|
||||
await replySessionError(interaction);
|
||||
return false;
|
||||
}
|
||||
|
||||
async function closeInteractionSession(interaction) {
|
||||
const session = await requireInteractionSession(interaction);
|
||||
|
||||
if (!session) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (session.messageId && !session.unmanaged) {
|
||||
await getSessionCollection().updateOne(
|
||||
{ messageId: session.messageId },
|
||||
{
|
||||
$set: {
|
||||
active: false,
|
||||
closedAt: new Date(),
|
||||
updatedAt: new Date()
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
const embed = new EmbedBuilder()
|
||||
.setTitle("Session Closed")
|
||||
.setDescription("Closing menu. . .");
|
||||
|
||||
await interaction.update({
|
||||
embeds: [embed],
|
||||
components: []
|
||||
});
|
||||
|
||||
setTimeout(() => {
|
||||
interaction.deleteReply().catch(() => {});
|
||||
}, 1200);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
ensureInteractionSessionIndexes,
|
||||
createInteractionSession,
|
||||
registerReplySession,
|
||||
getInteractionSession,
|
||||
requireInteractionSession,
|
||||
guardSessionInteraction,
|
||||
closeInteractionSession,
|
||||
replySessionError,
|
||||
inferLegacyOwnerId
|
||||
};
|
||||
@@ -1610,9 +1610,7 @@ function buildProfileButtons() {
|
||||
),
|
||||
|
||||
new ButtonBuilder()
|
||||
.setCustomId(
|
||||
"profileClose"
|
||||
)
|
||||
.setCustomId("sessionClose")
|
||||
.setLabel(
|
||||
"Close"
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user