discord-starboard-plus
Version:
Discord Starboard Plus: A clean, maintainable starboard system for Discord.js bots. Features per-guild configuration, TypeScript support. Highlight your community's favorite messages with customizable starboards.
142 lines • 4.99 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.ValidationService = void 0;
const discord_js_1 = require("discord.js");
/**
* Service for validating reactions, messages, and permissions.
* Centralizes all validation logic following SRP.
*/
class ValidationService {
logger;
constructor(logger) {
this.logger = logger;
}
/**
* Check if a reaction should be processed for starboard.
*
* FIX: Corrected the logic bug from the original code.
* Original buggy code: `!user.bot || !this.options.ignoreBots` always returned true
* Fixed: Properly checks if bots should be ignored
*/
shouldProcessReaction(reaction, user, options) {
// Null checks
if (!reaction || !user) {
return false;
}
// Check if reaction matches configured emoji
const emojiMatch = reaction.emoji.name === options.starEmoji ||
reaction.emoji.toString() === options.starEmoji;
if (!emojiMatch) {
return false;
}
// FIX: Correct logic for ignoring bot reactions
// If ignoreBots is true AND user is a bot, reject the reaction
if (options.ignoreBots && user.bot) {
this.logger.info('Ignoring bot reaction', { userId: user.id });
return false;
}
// Check for self-reaction (author starring their own message)
if (options.ignoreSelf) {
const messageAuthorId = reaction.message.author?.id;
if (messageAuthorId === user.id) {
this.logger.info('Ignoring self-reaction', { userId: user.id });
return false;
}
}
return true;
}
/**
* Check if a message is valid for starboard processing.
*/
isMessageValid(message, options) {
// Must be in a guild
if (!message.guild) {
return false;
}
// Check ignored guilds
if (options.ignoreGuilds.includes(message.guild.id)) {
this.logger.info('Ignoring message from configured guild', {
guildId: message.guild.id
});
return false;
}
// Check ignored channels
if (options.ignoredChannels.includes(message.channel.id)) {
this.logger.info('Ignoring message from configured channel', {
channelId: message.channel.id
});
return false;
}
// Check NSFW setting using modern discord.js pattern
if (!options.allowNSFW && this.isNSFWChannel(message)) {
this.logger.info('Ignoring NSFW channel message', {
channelId: message.channel.id
});
return false;
}
return true;
}
/**
* Get the count of valid reactions (excluding bots if configured).
*
* FIX: Corrected the filter logic from the original code.
* This always returned true because of incorrect boolean logic.
*/
async getValidReactionCount(reaction, options) {
const users = await reaction.users.fetch();
const validUsers = users.filter(user => {
if (options.ignoreBots) {
return !user.bot;
}
return true;
});
return validUsers.size;
}
/**
* Get the starboard channel for a guild.
* Validates that the channel exists and is a text-based channel.
*/
getStarboardChannel(guildId, options, client) {
const guild = client.guilds.cache.get(guildId);
if (!guild) {
this.logger.error('Guild not found', null, { guildId });
return null;
}
const channel = guild.channels.cache.get(options.starboardChannelID);
if (!channel) {
this.logger.error('Starboard channel not found', null, {
channelId: options.starboardChannelID,
guildId
});
return null;
}
if (!this.isTextChannel(channel)) {
this.logger.error('Starboard channel is not a text channel', null, {
channelId: options.starboardChannelID,
channelType: channel.type
});
return null;
}
return channel;
}
/**
* Check if a channel is a text-based channel that can receive messages.
*/
isTextChannel(channel) {
return channel.type === discord_js_1.ChannelType.GuildText ||
channel.type === discord_js_1.ChannelType.GuildAnnouncement;
}
/**
* Check if a message is in an NSFW channel.
*/
isNSFWChannel(message) {
const channel = message.channel;
// Check if channel has nsfw property (text-based channels)
if ('nsfw' in channel) {
return channel.nsfw === true;
}
return false;
}
}
exports.ValidationService = ValidationService;
//# sourceMappingURL=ValidationService.js.map