feat(discord-bot): improve 'track', 'tejtrack' commands and tracking service

This commit is contained in:
Pihkaal
2025-12-05 19:42:02 +01:00
parent 66474dc813
commit 8c78725e65
5 changed files with 126 additions and 161 deletions

View File

@@ -1,65 +1,56 @@
import type { Command } from "~/commands";
import { untrackWovPlayer } from "~/services/tracking";
import { isWovPlayerTracked, untrackWovPlayer } from "~/services/tracking";
import { searchPlayer } from "~/services/wov";
import { createErrorEmbed, createInfoEmbed } from "~/utils/discord";
import { replyError, createInfoEmbed, replySuccess } from "~/utils/discord";
import { env } from "~/env";
const STAFF_ROLE_ID = "1147963065640439900";
export const tejtrackCommand: Command = async (message, args) => {
const client = message.client;
if (!message.member) return;
if (!message.member.roles.cache.has(STAFF_ROLE_ID)) {
await message.reply(
createErrorEmbed("Tu t'es cru chez mémé ou quoi faut être staff"),
);
// check staff permission
if (!message.member?.roles.cache.has(env.DISCORD_STAFF_ROLE_ID)) {
await replyError(message, "Tu t'es cru chez mémé ou quoi faut être staff");
return;
}
let playerName = args[0];
const playerName = args[0];
if (!playerName) {
await message.reply(
createErrorEmbed(
await replyError(
message,
"Usage:`@LBF untrack NOM_JOUEUR`, exemple: `@LBF untrack Yuno`.\n**Attention les majuscules sont importantes**",
),
);
return;
}
const player = await searchPlayer(playerName);
if (!player) {
await message.reply(
createErrorEmbed(
await replyError(
message,
"Cette personne n'existe pas.\n**Attention les majuscules sont importantes**",
),
);
return;
}
const res = await untrackWovPlayer(player.id);
switch (res.event) {
case "notTracked": {
await message.reply(
createInfoEmbed(
if (!(await isWovPlayerTracked(player.id))) {
await replyError(
message,
`Pas de tracker pour \`${playerName}\` [\`${player.id}\`]`,
),
);
break;
return;
}
case "trackerRemoved": {
await message.reply(
createInfoEmbed(
await untrackWovPlayer(player.id);
await replySuccess(
message,
`Tracker enlevé pour \`${playerName}\` [\`${player.id}\`]`,
),
);
const chan = client.channels.cache.get(env.DISCORD_TRACKING_CHANNEL);
const chan = message.client.channels.cache.get(env.DISCORD_TRACKING_CHANNEL);
if (!chan?.isSendable()) throw "Invalid tracking channel";
await chan.send(
createInfoEmbed(`### [REMOVED] \`${playerName}\` [\`${player.id}\`]`),
createInfoEmbed(
`### [REMOVED] \`${playerName}\` [\`${player.id}\`]`,
0xea0000,
),
);
break;
}
}
};

View File

@@ -1,78 +1,54 @@
import type { Command } from "~/commands";
import { trackWovPlayer } from "~/services/tracking";
import { trackWovPlayer, isWovPlayerTracked } from "~/services/tracking";
import { searchPlayer } from "~/services/wov";
import { createErrorEmbed, createInfoEmbed } from "~/utils/discord";
import { replyError, createInfoEmbed, replySuccess } from "~/utils/discord";
import { env } from "~/env";
const STAFF_ROLE_ID = "1147963065640439900";
export const trackCommand: Command = async (message, args) => {
const client = message.client;
if (!message.member) return;
if (!message.member.roles.cache.has(STAFF_ROLE_ID)) {
await message.reply(
createErrorEmbed("Tu t'es cru chez mémé ou quoi faut être staff"),
);
// check staff permission
if (!message.member?.roles.cache.has(env.DISCORD_STAFF_ROLE_ID)) {
await replyError(message, "Tu t'es cru chez mémé ou quoi faut être staff");
return;
}
let playerName = args[0];
const playerName = args[0];
if (!playerName) {
await message.reply(
createErrorEmbed(
await replyError(
message,
"Usage:`@LBF track NOM_JOUEUR`, exemple: `@LBF track Yuno`.\n**Attention les majuscules sont importantes**",
),
);
return;
}
const player = await searchPlayer(playerName);
if (!player) {
await message.reply(
createErrorEmbed(
await replyError(
message,
"Cette personne n'existe pas.\n**Attention les majuscules sont importantes**",
),
);
return;
}
const res = await trackWovPlayer(player.id);
switch (res.event) {
case "notFound": {
await message.reply(
createErrorEmbed(
"Cette personne n'existe pas.\n**Attention les majuscules sont importantes**",
),
const alreadyTracked = await isWovPlayerTracked(player.id);
if (alreadyTracked) {
await replyError(
message,
`Tracker déjà enregistré pour \`${playerName}\` [\`${player.id}\`]`,
);
return;
}
case "registered": {
await message.reply(
createInfoEmbed(
await trackWovPlayer(player.id);
await replySuccess(
message,
`Tracker enregistré pour \`${playerName}\` [\`${player.id}\`]`,
),
);
const chan = client.channels.cache.get(env.DISCORD_TRACKING_CHANNEL);
const chan = message.client.channels.cache.get(env.DISCORD_TRACKING_CHANNEL);
if (!chan?.isSendable()) throw "Invalid tracking channel";
await chan.send(
createInfoEmbed(`### [NEW] \`${playerName}\` [\`${player.id}\`]`),
);
return;
}
case "none": {
await message.reply(
createInfoEmbed(
`Tracker déjà enregistré pour \`${playerName}\` [\`${player.id}\`]`,
),
);
return;
}
case "changed": {
// ignored
break;
}
}
};

View File

@@ -1,7 +1,11 @@
import type { Client } from "discord.js";
import { env } from "~/env";
import { listTrackedPlayers, trackWovPlayer } from "~/services/tracking";
import { checkForNewQuest } from "~/services/wov";
import {
listTrackedPlayers,
getTrackedPlayerUsernames,
addUsernameToHistory,
} from "~/services/tracking";
import { checkForNewQuest, getPlayer } from "~/services/wov";
import { createInfoEmbed } from "~/utils/discord";
import { askForGrinders } from "~/utils/quest";
import { commands } from "~/commands";
@@ -16,17 +20,23 @@ const questCheckCron = async (client: Client) => {
const trackingCron = async (client: Client) => {
const trackedPlayers = await listTrackedPlayers();
for (const playerId of trackedPlayers) {
const res = await trackWovPlayer(playerId);
if (res.event !== "changed") return;
const player = await getPlayer(playerId);
if (!player) continue;
const usernames = await getTrackedPlayerUsernames(playerId);
if (usernames.includes(player.username)) continue;
await addUsernameToHistory(playerId, player.username);
const chan = client.channels.cache.get(env.DISCORD_TRACKING_CHANNEL);
if (!chan?.isSendable()) throw "Invalid tracking channel";
const lastUsername = res.oldUsernames[res.oldUsernames.length - 1];
const lastUsername = usernames[usernames.length - 1];
await chan.send(
createInfoEmbed(
`### [UPDATE] \`${lastUsername}\` -> \`${res.newUsername}\` [\`${playerId}\`]\n\n**Nouveau pseudo:** \`${res.newUsername}\`\n**Anciens pseudos:**\n${res.oldUsernames.map((x) => `- \`${x}\``).join("\n")}`,
`### [UPDATE] \`${lastUsername}\` -> \`${player.username}\` [\`${playerId}\`]\n\n**Nouveau pseudo:** \`${player.username}\`\n**Anciens pseudos:**\n${usernames.map((x) => `- \`${x}\``).join("\n")}`,
0x00ea00,
),
);
}

View File

@@ -11,33 +11,40 @@ export async function listTrackedPlayers(): Promise<string[]> {
return players.map((p) => p.playerId);
}
export async function untrackWovPlayer(
playerId: string,
): Promise<{ event: "notTracked" } | { event: "trackerRemoved" }> {
export async function isWovPlayerTracked(playerId: string): Promise<boolean> {
const player = await db.query.trackedPlayers.findFirst({
where: eq(tables.trackedPlayers.playerId, playerId),
});
if (!player) return { event: "notTracked" };
return player !== undefined;
}
export async function untrackWovPlayer(playerId: string): Promise<void> {
await db
.delete(tables.trackedPlayers)
.where(eq(tables.trackedPlayers.playerId, playerId));
return { event: "trackerRemoved" };
}
export async function trackWovPlayer(playerId: string): Promise<
| { event: "notFound" }
| {
event: "registered";
}
| { event: "changed"; oldUsernames: string[]; newUsername: string }
| { event: "none" }
> {
export async function trackWovPlayer(playerId: string): Promise<void> {
const alreadyTracked = await isWovPlayerTracked(playerId);
if (alreadyTracked) return;
const player = await getPlayer(playerId);
if (!player) return { event: "notFound" };
if (!player) return;
await db.insert(tables.trackedPlayers).values({
playerId,
});
await db.insert(tables.usernameHistory).values({
playerId,
username: player.username,
});
}
export async function getTrackedPlayerUsernames(
playerId: string,
): Promise<string[]> {
const tracked = await db.query.trackedPlayers.findFirst({
where: eq(tables.trackedPlayers.playerId, playerId),
with: {
@@ -47,40 +54,21 @@ export async function trackWovPlayer(playerId: string): Promise<
},
});
if (tracked) {
const currentUsernames = tracked.usernameHistory.map((h) => h.username);
if (!tracked) return [];
return tracked.usernameHistory.map((h) => h.username);
}
if (!currentUsernames.includes(player.username)) {
export async function addUsernameToHistory(
playerId: string,
username: string,
): Promise<void> {
await db.insert(tables.usernameHistory).values({
playerId,
username: player.username,
username,
});
await db
.update(tables.trackedPlayers)
.set({ updatedAt: new Date() })
.where(eq(tables.trackedPlayers.playerId, playerId));
return {
event: "changed",
oldUsernames: currentUsernames,
newUsername: player.username,
};
} else {
return {
event: "none",
};
}
} else {
await db.insert(tables.trackedPlayers).values({
playerId,
});
await db.insert(tables.usernameHistory).values({
playerId,
username: player.username,
});
return { event: "registered" };
}
}

View File

@@ -72,7 +72,7 @@ export const makeResultEmbed = async (
export const createErrorEmbed = (
message: string,
color = 15335424,
color = 0xea0000,
): MessageCreateOptions => ({
embeds: [
{
@@ -84,7 +84,7 @@ export const createErrorEmbed = (
export const createSuccessEmbed = (
message: string,
color = 65280,
color = 0x00ea00,
): MessageCreateOptions => ({
embeds: [
{