pkgs/bot/src/server/discord.ts (view raw)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 |
import config from "@/config";
import type { Ticket } from "@/database/schema";
import client from "@/discord";
import { marshallIntoApiUser } from "./api";
import _logger from "@/utils/logging";
import type { User as UserProfile, Ticket as ApiTicket } from "@stealth-developers/api";
const logger = _logger.child({ name: "server" });
export const cache = new Map<string, UserProfile | null>();
export async function getUsers(ids: (string | null | undefined)[]): Promise<void> {
const uniqueIds = [...new Set(ids.filter(Boolean) as string[])];
const missingIds = uniqueIds.filter((id) => id !== "system" && !cache.has(id));
if (missingIds.length === 0) return;
logger.debug(missingIds, `fetching ${missingIds.length} users`);
const guild = client.guilds.cache.get(config.discord.guild);
if (guild) {
try {
const members = await guild.members.fetch({ user: missingIds });
members.forEach((member) => cache.set(member.id, marshallIntoApiUser(member)));
} catch (err) {
logger.error({ err }, "failed to fetch guild members chunk");
}
}
const stillMissing = missingIds.filter((id) => !cache.has(id));
if (stillMissing.length > 0) {
await Promise.all(
stillMissing.map(async (id) => {
try {
const user = await client.users.fetch(id);
cache.set(id, marshallIntoApiUser(user));
} catch {
cache.set(id, null);
}
}),
);
}
}
export async function getUser(id: string): Promise<UserProfile | null> {
await getUsers([id]);
return cache.get(id) || null;
}
export async function hydrateTickets(allTickets: Ticket[]): Promise<ApiTicket[]> {
const allIds = new Set<string>();
for (const ticket of allTickets) {
if (ticket.authorId) allIds.add(ticket.authorId);
if (ticket.openedBy) allIds.add(ticket.openedBy);
if (ticket.closedBy && ticket.closedBy !== "reporter") allIds.add(ticket.closedBy);
}
await getUsers([...allIds]);
return allTickets.map((ticket) => {
const fallbackSubject: UserProfile = {
id: ticket.authorId,
name: "Subject",
avatarUrl: "",
isModerator: false,
};
return {
number: String(ticket.id),
status: ticket.status as "open" | "closed" | "archived",
closedBy: ticket.closedBy ? (cache.get(ticket.closedBy) ?? null) : null,
closedAt: ticket.closedAt?.toUTCString() || null,
topic: ticket.topic,
closeReason: ticket.closeReason,
privateReason: ticket.privateReason,
openedAt: ticket.createdAt?.toUTCString(),
openedBy: ticket.openedBy ? (cache.get(ticket.openedBy) ?? null) : null,
subject: cache.get(ticket.authorId) ?? fallbackSubject,
};
});
}
|