updated profile and centralized functions

This commit is contained in:
DeSqBlocki
2026-08-22 23:33:20 +02:00
parent 08d1a8c5cd
commit 030b4b8883
18 changed files with 3747 additions and 1202 deletions
+415
View File
@@ -0,0 +1,415 @@
const {
SlashCommandBuilder,
MessageFlags
} = require(
"discord.js"
);
const {
requireAdminAccess
} = require(
"../../utils/permissions"
);
const {
reconcileProfileAchievements,
auditProfileSystem
} = require(
"../../utils/profileSystem"
);
/*
* ============================================================
* COMMAND
* ============================================================
*/
module.exports = {
data:
new SlashCommandBuilder()
.setName(
"profileadmin"
)
.setDescription(
"Profile and achievement administration."
)
/*
* =================================================
* RECONCILE
* =================================================
*/
.addSubcommand(
subcommand =>
subcommand
.setName(
"reconcile"
)
.setDescription(
"Re-evaluate stored statistics for achievements."
)
.addUserOption(
option =>
option
.setName(
"user"
)
.setDescription(
"Only reconcile this user's profile."
)
.setRequired(
false
)
)
.addBooleanOption(
option =>
option
.setName(
"dry-run"
)
.setDescription(
"Show what would change without unlocking anything."
)
.setRequired(
false
)
)
)
/*
* =================================================
* AUDIT
* =================================================
*/
.addSubcommand(
subcommand =>
subcommand
.setName(
"audit"
)
.setDescription(
"Audit the profile and achievement system."
)
),
/*
* ========================================================
* EXECUTE
* ========================================================
*/
async execute(
interaction
) {
/*
* Runtime authorization.
*
* This intentionally replaces:
*
* .setDefaultMemberPermissions(
* PermissionFlagsBits.Administrator
* )
*
* so BOT_AUTHOR_ID can also invoke the command.
*/
if (
!await requireAdminAccess(
interaction
)
) {
return;
}
const subcommand =
interaction.options
.getSubcommand();
switch (
subcommand
) {
case "reconcile":
return runReconcile(
interaction
);
case "audit":
return runAudit(
interaction
);
default:
return interaction.reply({
content:
"Unknown profile administration action.",
flags:
MessageFlags.Ephemeral
});
}
}
};
/*
* ============================================================
* RECONCILE
* ============================================================
*/
async function runReconcile(
interaction
) {
const target =
interaction.options.getUser(
"user"
);
const dryRun =
interaction.options.getBoolean(
"dry-run"
)
??
false;
/*
* This can touch multiple Mongo documents,
* so acknowledge the interaction first.
*/
await interaction.deferReply({
flags:
MessageFlags.Ephemeral
});
try {
const result =
await reconcileProfileAchievements(
interaction.guildId,
{
userId:
target?.id
??
null,
dryRun
}
);
const lines = [
dryRun
? "### 🔎 Profile Reconciliation — Dry Run"
: "### ✅ Profile Reconciliation Complete",
"",
target
? `Target: ${target}`
: "Target: **Entire Guild**",
"",
`Profiles checked: **${result.profilesChecked ?? 0}**`,
`Achievement unlocks found: **${result.unlocksFound ?? 0}**`
];
if (
!dryRun
) {
lines.push(
`Achievements unlocked: **${result.unlocksApplied ?? 0}**`
);
}
if (
result.skippedEventOnly !==
undefined
) {
lines.push(
`Event-only checks skipped: **${result.skippedEventOnly}**`
);
}
if (
Array.isArray(
result.details
)
&&
result.details.length >
0
) {
const preview =
result.details
.slice(
0,
15
)
.map(
entry => {
if (
typeof entry ===
"string"
) {
return `• ${entry}`;
}
return (
`• <@${entry.userId}> — ` +
`${entry.achievementName ?? entry.achievementId}`
);
}
);
lines.push(
"",
"### Changes",
...preview
);
if (
result.details.length >
preview.length
) {
lines.push(
"",
`*...and ${result.details.length - preview.length} more.*`
);
}
}
return interaction.editReply({
content:
lines.join(
"\n"
)
});
} catch (error) {
console.error(
"[ProfileAdmin] Reconciliation failed:",
error
);
return interaction.editReply({
content:
"Profile reconciliation failed. Check the bot logs for details."
});
}
}
/*
* ============================================================
* AUDIT
* ============================================================
*/
async function runAudit(
interaction
) {
await interaction.deferReply({
flags:
MessageFlags.Ephemeral
});
try {
const result =
await auditProfileSystem(
interaction.guildId
);
const lines = [
"### 🧾 Profile System Audit",
"",
`Profile documents: **${result.profileDocuments ?? 0}**`,
`Achievement documents: **${result.achievementDocuments ?? 0}**`,
`Active achievement definitions: **${result.activeAchievements ?? 0}**`,
`Legacy achievement definitions: **${result.legacyAchievements ?? 0}**`,
`Guild badges: **${result.badges ?? 0}**`,
`Claimed badges: **${result.claimedBadges ?? 0}**`,
`Available badges: **${result.availableBadges ?? 0}**`
];
if (
Array.isArray(
result.warnings
)
&&
result.warnings.length >
0
) {
lines.push(
"",
"### ⚠️ Warnings",
...result.warnings.map(
warning =>
`• ${warning}`
)
);
}
else {
lines.push(
"",
"✅ No obvious profile-system issues were found."
);
}
return interaction.editReply({
content:
lines.join(
"\n"
)
});
} catch (error) {
console.error(
"[ProfileAdmin] Audit failed:",
error
);
return interaction.editReply({
content:
"Profile audit failed. Check the bot logs for details."
});
}
}
+61
View File
@@ -0,0 +1,61 @@
const {
SlashCommandBuilder
} = require("discord.js");
const {
buildRecordsEmbed,
getRecordChoices
} = require(
"../../utils/profileRecords"
);
module.exports = {
data:
new SlashCommandBuilder()
.setName(
"records"
)
.setDescription(
"View Shai Cookie and Crumb Saucer records"
)
.addStringOption(
option =>
option
.setName(
"category"
)
.setDescription(
"Record category"
)
.setRequired(
true
)
.addChoices(
...getRecordChoices()
)
),
async execute(
interaction
) {
const category =
interaction.options.getString(
"category",
true
);
const embed =
await buildRecordsEmbed({
guildId:
interaction.guildId,
category,
botUserId:
interaction.client.user.id,
limit: 10
});
return interaction.reply({
embeds: [embed]
});
}
};