264 lines
8.9 KiB
JavaScript
264 lines
8.9 KiB
JavaScript
const {
|
|
SlashCommandBuilder,
|
|
PermissionFlagsBits,
|
|
MessageFlags,
|
|
EmbedBuilder
|
|
} = require("discord.js");
|
|
|
|
const {
|
|
reconcileUserAchievements,
|
|
reconcileAllAchievements,
|
|
auditProfileData
|
|
} = require(
|
|
"../../utils/profileMaintenance"
|
|
);
|
|
|
|
module.exports = {
|
|
data:
|
|
new SlashCommandBuilder()
|
|
.setName(
|
|
"profileadmin"
|
|
)
|
|
.setDescription(
|
|
"Administrative profile maintenance tools"
|
|
)
|
|
.setDefaultMemberPermissions(
|
|
PermissionFlagsBits.Administrator
|
|
)
|
|
.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"
|
|
)
|
|
),
|
|
|
|
async execute(
|
|
interaction
|
|
) {
|
|
const subcommand =
|
|
interaction.options.getSubcommand();
|
|
|
|
await interaction.deferReply({
|
|
flags:
|
|
MessageFlags.Ephemeral
|
|
});
|
|
|
|
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
|
|
}
|
|
)
|
|
]
|
|
});
|
|
}
|
|
|
|
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."
|
|
)
|
|
]
|
|
});
|
|
}
|
|
};
|