Files
ShaiBot/commands/applications/profileAdmin.js
T
2026-08-27 21:35:06 +02:00

630 lines
20 KiB
JavaScript

const {
SlashCommandBuilder,
MessageFlags,
EmbedBuilder
} = require("discord.js");
const {
reconcileUserAchievements,
reconcileAllAchievements,
grantMaintenanceReward,
getMaintenanceRewardStatus,
auditProfileData,
DEFAULT_MAINTENANCE_REWARD_ID,
DEFAULT_MAINTENANCE_REWARD_AMOUNT
} = require(
"../../utils/profileMaintenance"
);
const {
requireAdminAccess
} = require(
"../../utils/permissions"
);
module.exports = {
data:
new SlashCommandBuilder()
.setName(
"profileadmin"
)
.setDescription(
"Administrative profile maintenance tools"
)
.addSubcommand(
subcommand =>
subcommand
.setName(
"reconcile"
)
.setDescription(
"Backfill database-trackable achievements"
)
.addUserOption(
option =>
option
.setName(
"user"
)
.setDescription(
"Only reconcile this user; omit for everyone"
)
)
.addBooleanOption(
option =>
option
.setName(
"dry-run"
)
.setDescription(
"Show what would change without writing it"
)
)
)
.addSubcommand(
subcommand =>
subcommand
.setName(
"audit"
)
.setDescription(
"Audit stored profile statistics for inconsistencies"
)
)
.addSubcommand(
subcommand =>
subcommand
.setName(
"maintenance-reward"
)
.setDescription(
"Grant an idempotent maintenance reward to stored profile users"
)
.addStringOption(
option =>
option
.setName(
"reward-id"
)
.setDescription(
`Unique reward ID; defaults to ${DEFAULT_MAINTENANCE_REWARD_ID}`
)
)
.addIntegerOption(
option =>
option
.setName(
"amount"
)
.setDescription(
`Cookies per player; defaults to ${DEFAULT_MAINTENANCE_REWARD_AMOUNT}`
)
.setMinValue(
1
)
)
.addBooleanOption(
option =>
option
.setName(
"dry-run"
)
.setDescription(
"Preview recipients without granting Cookies"
)
)
)
.addSubcommand(
subcommand =>
subcommand
.setName(
"maintenance-status"
)
.setDescription(
"Show maintenance reward claim status"
)
.addStringOption(
option =>
option
.setName(
"reward-id"
)
.setDescription(
`Reward ID; defaults to ${DEFAULT_MAINTENANCE_REWARD_ID}`
)
)
),
async execute(
interaction
) {
/*
* Allows:
*
* - Discord Administrators
* - BOT_AUTHOR_ID from .env
*/
if (
!await requireAdminAccess(
interaction
)
) {
return;
}
const subcommand =
interaction.options.getSubcommand();
await interaction.deferReply({
flags:
MessageFlags.Ephemeral
});
try {
if (
subcommand ===
"reconcile"
) {
const user =
interaction.options.getUser(
"user"
);
const dryRun =
interaction.options.getBoolean(
"dry-run"
) ?? false;
if (user) {
const result =
await reconcileUserAchievements({
guildId:
interaction.guildId,
userId:
user.id,
dryRun
});
return interaction.editReply({
embeds: [
new EmbedBuilder()
.setTitle(
"🛠️ Profile Reconciliation"
)
.setDescription(
`${dryRun ? "Dry run for" : "Reconciled"} ${user}.`
)
.addFields(
{
name:
"New unlocks",
value:
`**${result.unlocked}**`,
inline:
true
},
{
name:
"Definitions checked",
value:
`**${result.checked}**`,
inline:
true
},
{
name:
"Event-only skipped",
value:
`**${result.skippedEventOnly}**`,
inline:
true
}
)
]
});
}
const summary =
await reconcileAllAchievements({
guildId:
interaction.guildId,
dryRun
});
return interaction.editReply({
embeds: [
new EmbedBuilder()
.setTitle(
"🛠️ Profile Reconciliation"
)
.setDescription(
`${dryRun ? "Dry run completed" : "Reconciliation completed"} for stored profile users.`
)
.addFields(
{
name:
"Users",
value:
`**${summary.users}**`,
inline:
true
},
{
name:
"New unlocks",
value:
`**${summary.unlocked}**`,
inline:
true
},
{
name:
"Event-only checks skipped",
value:
`**${summary.skippedEventOnly}**`,
inline:
true
}
)
]
});
}
if (
subcommand ===
"maintenance-reward"
) {
const rewardId =
interaction.options.getString(
"reward-id"
)
??
DEFAULT_MAINTENANCE_REWARD_ID;
const amount =
interaction.options.getInteger(
"amount"
)
??
DEFAULT_MAINTENANCE_REWARD_AMOUNT;
/*
* Safer admin default:
*
* If omitted, maintenance-reward previews
* instead of paying immediately.
*
* Pass dry-run:false explicitly to execute.
*/
const dryRun =
interaction.options.getBoolean(
"dry-run"
)
??
true;
const summary =
await grantMaintenanceReward({
guildId:
interaction.guildId,
rewardId,
amount,
dryRun
});
return interaction.editReply({
embeds: [
new EmbedBuilder()
.setTitle(
dryRun
? "🧪 Maintenance Reward Dry Run"
: "🎁 Maintenance Reward"
)
.setDescription(
dryRun
? "No Cookies were granted. Run again with `dry-run:false` to execute this reward."
: `Maintenance compensation **${rewardId}** has been processed.`
)
.addFields(
{
name:
"Reward ID",
value:
`\`${summary.rewardId}\``,
inline:
false
},
{
name:
"Per player",
value:
`**${summary.amount.toLocaleString()} 🍪**`,
inline:
true
},
{
name:
"Stored profiles",
value:
`**${summary.users}**`,
inline:
true
},
{
name:
dryRun
? "Would receive"
: "Granted",
value:
`**${dryRun ? summary.eligible : summary.granted}**`,
inline:
true
},
{
name:
"Already claimed",
value:
`**${summary.alreadyClaimed}**`,
inline:
true
},
{
name:
"Failed",
value:
`**${summary.failed}**`,
inline:
true
}
)
]
});
}
if (
subcommand ===
"maintenance-status"
) {
const rewardId =
interaction.options.getString(
"reward-id"
)
??
DEFAULT_MAINTENANCE_REWARD_ID;
const status =
await getMaintenanceRewardStatus({
guildId:
interaction.guildId,
rewardId
});
return interaction.editReply({
embeds: [
new EmbedBuilder()
.setTitle(
"🎁 Maintenance Reward Status"
)
.addFields(
{
name:
"Reward ID",
value:
`\`${status.rewardId}\``,
inline:
false
},
{
name:
"Default amount",
value:
`**${status.amount.toLocaleString()} 🍪**`,
inline:
true
},
{
name:
"Stored profiles",
value:
`**${status.users}**`,
inline:
true
},
{
name:
"Claimed",
value:
`**${status.claimed}**`,
inline:
true
},
{
name:
"Remaining",
value:
`**${status.remaining}**`,
inline:
true
}
)
]
});
}
const audit =
await auditProfileData(
interaction.guildId
);
const issuePreview =
audit.issues
.slice(
0,
10
)
.join(
"\n"
);
return interaction.editReply({
embeds: [
new EmbedBuilder()
.setTitle(
"🔎 Profile Data Audit"
)
.addFields(
{
name:
"Stats documents",
value:
`**${audit.statDocuments}**`,
inline:
true
},
{
name:
"Achievement documents",
value:
`**${audit.achievementDocuments}**`,
inline:
true
},
{
name:
"Active achievements",
value:
`**${audit.activeAchievements}**`,
inline:
true
},
{
name:
"Global badges",
value:
`**${audit.badgeDocuments}** (${audit.claimedBadges} claimed)`,
inline:
true
},
{
name:
"Orphan achievement docs",
value:
`**${audit.orphanAchievementDocs}**`,
inline:
true
},
{
name:
"Issues",
value:
`**${audit.issueCount}**`,
inline:
true
}
)
.setDescription(
issuePreview
? `First issues:\n${issuePreview}`
: "No structural inconsistencies found."
)
]
});
}
catch (error) {
console.error(
`[ProfileAdmin] ${subcommand} failed:`,
error
);
return interaction.editReply({
embeds: [
new EmbedBuilder()
.setTitle(
"❌ Profile Admin Error"
)
.setDescription(
"The maintenance action failed. Check the bot logs for details."
)
]
});
}
}
};