Kord/src/services/InviteService.ts

89 lines
3.0 KiB
TypeScript

import { Client, Guild, Invite, GuildMember } from 'discord.js';
import { redis } from '../cache';
import { prisma } from '../database';
import { logger } from '../utils/logger';
export class InviteService {
public static async cacheAllInvites(client: Client) {
for (const [, guild] of client.guilds.cache) {
await this.cacheGuildInvites(guild);
}
logger.info('InviteMaster: Finished caching all invites.');
}
public static async cacheGuildInvites(guild: Guild) {
try {
const invites = await guild.invites.fetch();
const inviteData = invites.map(inv => ({
code: inv.code,
uses: inv.uses || 0
}));
await redis.set(`invites:${guild.id}`, JSON.stringify(inviteData));
} catch (error) {
logger.error(`InviteMaster: Failed to cache invites for guild ${guild.id}:`, error);
}
}
public static async handleInviteCreate(invite: Invite) {
if (!invite.guild) return;
logger.debug(`InviteMaster: New invite created: ${invite.code}`);
await this.cacheGuildInvites(invite.guild as Guild);
}
public static async handleInviteDelete(invite: Invite) {
if (!invite.guild) return;
logger.debug(`InviteMaster: Invite deleted: ${invite.code}`);
await this.cacheGuildInvites(invite.guild as Guild);
}
public static async handleMemberAdd(member: GuildMember) {
const guild = member.guild;
try {
// Fetch current active invites
const newInvites = await guild.invites.fetch();
const cachedData = await redis.get(`invites:${guild.id}`);
let usedInvite: Invite | undefined;
if (cachedData) {
const cachedInvites: { code: string, uses: number }[] = JSON.parse(cachedData);
// Find the invite where 'uses' has increased
usedInvite = newInvites.find(inv => {
const cached = cachedInvites.find(c => c.code === inv.code);
return cached ? (inv.uses || 0) > cached.uses : false;
});
}
// Update the cache immediately to account for this new join
await this.cacheGuildInvites(guild);
if (usedInvite) {
logger.info(`InviteMaster: ${member.user.tag} joined using invite ${usedInvite.code}`);
// Check DB for mapped role
const inviteRole = await prisma.inviteRole.findFirst({
where: {
guildId: guild.id,
inviteCode: usedInvite.code
}
});
if (inviteRole) {
const role = guild.roles.cache.get(inviteRole.roleId);
if (role) {
await member.roles.add(role);
logger.info(`InviteMaster: Assigned role ${role.name} to ${member.user.tag}`);
} else {
logger.warn(`InviteMaster: Role ${inviteRole.roleId} mapped to invite ${usedInvite.code} not found.`);
}
}
} else {
logger.info(`InviteMaster: ${member.user.tag} joined but invite could not be determined (ex: Vanity URL).`);
}
} catch (error) {
logger.error(`InviteMaster: Failed to handle member add tracking:`, error);
}
}
}