feat: automod

#8886 djs
This commit is contained in:
March 7th
2022-12-20 22:46:50 +07:00
parent ef2deb64f7
commit 294005bac7
22 changed files with 1191 additions and 4 deletions

View File

@@ -4,6 +4,10 @@ class ActionsManager {
constructor(client) {
this.client = client;
this.register(require('./AutoModerationActionExecution'));
this.register(require('./AutoModerationRuleCreate'));
this.register(require('./AutoModerationRuleDelete'));
this.register(require('./AutoModerationRuleUpdate'));
this.register(require('./ChannelCreate'));
this.register(require('./ChannelDelete'));
this.register(require('./ChannelUpdate'));

View File

@@ -0,0 +1,26 @@
'use strict';
const Action = require('./Action');
const AutoModerationActionExecution = require('../../structures/AutoModerationActionExecution');
const { Events } = require('../../util/Constants');
class AutoModerationActionExecutionAction extends Action {
handle(data) {
const { client } = this;
const guild = client.guilds.cache.get(data.guild_id);
if (guild) {
/**
* Emitted whenever an auto moderation rule is triggered.
* <info>This event requires the {@link Permissions.FLAGS.MANAGE_GUILD} permission.</info>
* @event Client#autoModerationActionExecution
* @param {AutoModerationActionExecution} autoModerationActionExecution The data of the execution
*/
client.emit(Events.AUTO_MODERATION_ACTION_EXECUTION, new AutoModerationActionExecution(data, guild));
}
return {};
}
}
module.exports = AutoModerationActionExecutionAction;

View File

@@ -0,0 +1,27 @@
'use strict';
const Action = require('./Action');
const { Events } = require('../../util/Constants');
class AutoModerationRuleCreateAction extends Action {
handle(data) {
const { client } = this;
const guild = client.guilds.cache.get(data.guild_id);
if (guild) {
const autoModerationRule = guild.autoModerationRules._add(data);
/**
* Emitted whenever an auto moderation rule is created.
* <info>This event requires the {@link Permissions.FLAGS.MANAGE_GUILD} permission.</info>
* @event Client#autoModerationRuleCreate
* @param {AutoModerationRule} autoModerationRule The created auto moderation rule
*/
client.emit(Events.AUTO_MODERATION_RULE_CREATE, autoModerationRule);
}
return {};
}
}
module.exports = AutoModerationRuleCreateAction;

View File

@@ -0,0 +1,31 @@
'use strict';
const Action = require('./Action');
const { Events } = require('../../util/Constants');
class AutoModerationRuleDeleteAction extends Action {
handle(data) {
const { client } = this;
const guild = client.guilds.cache.get(data.guild_id);
if (guild) {
const autoModerationRule = guild.autoModerationRules.cache.get(data.id);
if (autoModerationRule) {
guild.autoModerationRules.cache.delete(autoModerationRule.id);
/**
* Emitted whenever an auto moderation rule is deleted.
* <info>This event requires the {@link Permissions.FLAGS.MANAGE_GUILD} permission.</info>
* @event Client#autoModerationRuleDelete
* @param {AutoModerationRule} autoModerationRule The deleted auto moderation rule
*/
client.emit(Events.AUTO_MODERATION_RULE_DELETE, autoModerationRule);
}
}
return {};
}
}
module.exports = AutoModerationRuleDeleteAction;

View File

@@ -0,0 +1,29 @@
'use strict';
const Action = require('./Action');
const { Events } = require('../../util/Constants');
class AutoModerationRuleUpdateAction extends Action {
handle(data) {
const { client } = this;
const guild = client.guilds.cache.get(data.guild_id);
if (guild) {
const oldAutoModerationRule = guild.autoModerationRules.cache.get(data.id)?._clone() ?? null;
const newAutoModerationRule = guild.autoModerationRules._add(data);
/**
* Emitted whenever an auto moderation rule gets updated.
* <info>This event requires the {@link Permissions.FLAGS.MANAGE_GUILD} permission.</info>
* @event Client#autoModerationRuleUpdate
* @param {?AutoModerationRule} oldAutoModerationRule The auto moderation rule before the update
* @param {AutoModerationRule} newAutoModerationRule The auto moderation rule after the update
*/
client.emit(Events.AUTO_MODERATION_RULE_UPDATE, oldAutoModerationRule, newAutoModerationRule);
}
return {};
}
}
module.exports = AutoModerationRuleUpdateAction;

View File

@@ -0,0 +1,5 @@
'use strict';
module.exports = (client, packet) => {
client.actions.AutoModerationActionExecution.handle(packet.d);
};

View File

@@ -0,0 +1,5 @@
'use strict';
module.exports = (client, packet) => {
client.actions.AutoModerationRuleCreate.handle(packet.d);
};

View File

@@ -0,0 +1,5 @@
'use strict';
module.exports = (client, packet) => {
client.actions.AutoModerationRuleDelete.handle(packet.d);
};

View File

@@ -0,0 +1,5 @@
'use strict';
module.exports = (client, packet) => {
client.actions.AutoModerationRuleUpdate.handle(packet.d);
};

View File

@@ -10,6 +10,10 @@ const handlers = Object.fromEntries([
['APPLICATION_COMMAND_CREATE', require('./APPLICATION_COMMAND_CREATE')],
['APPLICATION_COMMAND_DELETE', require('./APPLICATION_COMMAND_DELETE')],
['APPLICATION_COMMAND_UPDATE', require('./APPLICATION_COMMAND_UPDATE')],
['AUTO_MODERATION_ACTION_EXECUTION', require('./AUTO_MODERATION_ACTION_EXECUTION')],
['AUTO_MODERATION_RULE_CREATE', require('./AUTO_MODERATION_RULE_CREATE')],
['AUTO_MODERATION_RULE_DELETE', require('./AUTO_MODERATION_RULE_DELETE')],
['AUTO_MODERATION_RULE_UPDATE', require('./AUTO_MODERATION_RULE_UPDATE')],
['CALL_CREATE', require('./CALL_CREATE')],
['CALL_UPDATE', require('./CALL_UPDATE')],
['CALL_DELETE', require('./CALL_DELETE')],

View File

@@ -38,6 +38,7 @@ exports.PurchasedFlags = require('./util/PurchasedFlags');
// Managers
exports.ApplicationCommandManager = require('./managers/ApplicationCommandManager');
exports.ApplicationCommandPermissionsManager = require('./managers/ApplicationCommandPermissionsManager');
exports.AutoModerationRuleManager = require('./managers/AutoModerationRuleManager');
exports.BaseGuildEmojiManager = require('./managers/BaseGuildEmojiManager');
exports.CachedManager = require('./managers/CachedManager');
exports.ChannelManager = require('./managers/ChannelManager');
@@ -76,6 +77,8 @@ exports.AnonymousGuild = require('./structures/AnonymousGuild');
exports.Application = require('./structures/interfaces/Application');
exports.ApplicationCommand = require('./structures/ApplicationCommand');
exports.AutocompleteInteraction = require('./structures/AutocompleteInteraction');
exports.AutoModerationActionExecution = require('./structures/AutoModerationActionExecution');
exports.AutoModerationRule = require('./structures/AutoModerationRule');
exports.Base = require('./structures/Base');
exports.BaseCommandInteraction = require('./structures/BaseCommandInteraction');
exports.BaseGuild = require('./structures/BaseGuild');

View File

@@ -0,0 +1,289 @@
'use strict';
const { Collection } = require('@discordjs/collection');
const CachedManager = require('./CachedManager');
const AutoModerationRule = require('../structures/AutoModerationRule');
const {
AutoModerationRuleEventTypes,
AutoModerationRuleTriggerTypes,
AutoModerationActionTypes,
AutoModerationRuleKeywordPresetTypes,
} = require('../util/Constants');
/**
* Manages API methods for auto moderation rules and stores their cache.
* @extends {CachedManager}
*/
class AutoModerationRuleManager extends CachedManager {
constructor(guild, iterable) {
super(guild.client, AutoModerationRule, iterable);
/**
* The guild this manager belongs to.
* @type {Guild}
*/
this.guild = guild;
}
_add(data, cache) {
return super._add(data, cache, { extras: [this.guild] });
}
/**
* Options used to set the trigger metadata of an auto moderation rule.
* @typedef {Object} AutoModerationTriggerMetadataOptions
* @property {string[]} [keywordFilter] The substrings that will be searched for in the content
* @property {string[]} [regexPatterns] The regular expression patterns
* which will be matched against the content
* <info>Only Rust-flavored regular expressions are supported.</info>
* @property {AutoModerationRuleKeywordPresetType[]} [presets]
* The internally pre-defined wordsets which will be searched for in the content
* @property {string[]} [allowList] The substrings that will be exempt from triggering
* {@link AutoModerationRuleTriggerType.KEYWORD} and {@link AutoModerationRuleTriggerType.KEYWORD_PRESET}
* @property {?number} [mentionTotalLimit] The total number of role & user mentions allowed per message
*/
/**
* Options used to set the actions of an auto moderation rule.
* @typedef {Object} AutoModerationActionOptions
* @property {AutoModerationActionType} type The type of this auto moderation rule action
* @property {AutoModerationActionMetadataOptions} [metadata] Additional metadata needed during execution
* <info>This property is required if using a `type` of
* {@link AutoModerationActionType.SEND_ALERT_MESSAGE} or {@link AutoModerationActionType.TIMEOUT}.</info>
*/
/**
* Options used to set the metadata of an auto moderation rule action.
* @typedef {Object} AutoModerationActionMetadataOptions
* @property {GuildTextChannelResolvable|ThreadChannel} [channel] The channel to which content will be logged
* @property {number} [durationSeconds] The timeout duration in seconds
*/
/**
* Options used to create an auto moderation rule.
* @typedef {Object} AutoModerationRuleCreateOptions
* @property {string} name The name of the auto moderation rule
* @property {AutoModerationRuleEventType} eventType The event type of the auto moderation rule
* @property {AutoModerationRuleTriggerType} triggerType The trigger type of the auto moderation rule
* @property {AutoModerationTriggerMetadataOptions} [triggerMetadata] The trigger metadata of the auto moderation rule
* <info>This property is required if using a `triggerType` of
* {@link AutoModerationRuleTriggerTypes.KEYWORD}, {@link AutoModerationRuleTriggerTypes.KEYWORD_PRESET},
* or {@link AutoModerationRuleTriggerTypes.MENTION_SPAM}.</info>
* @property {AutoModerationActionOptions[]} actions
* The actions that will execute when the auto moderation rule is triggered
* @property {boolean} [enabled] Whether the auto moderation rule should be enabled
* @property {Collection<Snowflake, Role>|RoleResolvable[]} [exemptRoles]
* The roles that should not be affected by the auto moderation rule
* @property {Collection<Snowflake, GuildChannel|ThreadChannel>|GuildChannelResolvable[]} [exemptChannels]
* The channels that should not be affected by the auto moderation rule
* @property {string} [reason] The reason for creating the auto moderation rule
*/
/**
* Creates a new auto moderation rule.
* @param {AutoModerationRuleCreateOptions} options Options for creating the auto moderation rule
* @returns {Promise<AutoModerationRule>}
*/
async create({
name,
eventType,
triggerType,
triggerMetadata,
actions,
enabled,
exemptRoles,
exemptChannels,
reason,
}) {
const data = await this.client.api.guilds(this.guild.id)['auto-moderation'].rules.post({
data: {
name,
event_type: typeof eventType === 'number' ? eventType : AutoModerationRuleEventTypes[eventType],
trigger_type: typeof triggerType === 'number' ? triggerType : AutoModerationRuleTriggerTypes[triggerType],
trigger_metadata: triggerMetadata && {
keyword_filter: triggerMetadata.keywordFilter,
regex_patterns: triggerMetadata.regexPatterns,
presets: triggerMetadata.presets?.map(preset =>
typeof preset === 'number' ? preset : AutoModerationRuleKeywordPresetTypes[preset],
),
allow_list: triggerMetadata.allowList,
mention_total_limit: triggerMetadata.mentionTotalLimit,
},
actions: actions?.map(action => ({
type: typeof action.type === 'number' ? action.type : AutoModerationActionTypes[action.type],
metadata: {
duration_seconds: action.metadata?.durationSeconds,
channel_id: action.metadata?.channel && this.guild.channels.resolveId(action.metadata.channel),
},
})),
enabled,
exempt_roles: exemptRoles?.map(exemptRole => this.guild.roles.resolveId(exemptRole)),
exempt_channels: exemptChannels?.map(exemptChannel => this.guild.channels.resolveId(exemptChannel)),
},
reason,
});
return this._add(data);
}
/**
* Options used to edit an auto moderation rule.
* @typedef {Object} AutoModerationRuleEditOptions
* @property {string} [name] The name of the auto moderation rule
* @property {AutoModerationRuleEventType} [eventType] The event type of the auto moderation rule
* @property {AutoModerationTriggerMetadataOptions} [triggerMetadata] The trigger metadata of the auto moderation rule
* @property {AutoModerationActionOptions[]} [actions]
* The actions that will execute when the auto moderation rule is triggered
* @property {boolean} [enabled] Whether the auto moderation rule should be enabled
* @property {Collection<Snowflake, Role>|RoleResolvable[]} [exemptRoles]
* The roles that should not be affected by the auto moderation rule
* @property {Collection<Snowflake, GuildChannel|ThreadChannel>|GuildChannelResolvable[]} [exemptChannels]
* The channels that should not be affected by the auto moderation rule
* @property {string} [reason] The reason for creating the auto moderation rule
*/
/**
* Edits an auto moderation rule.
* @param {AutoModerationRuleResolvable} autoModerationRule The auto moderation rule to edit
* @param {AutoModerationRuleEditOptions} options Options for editing the auto moderation rule
* @returns {Promise<AutoModerationRule>}
*/
async edit(
autoModerationRule,
{ name, eventType, triggerMetadata, actions, enabled, exemptRoles, exemptChannels, reason },
) {
const autoModerationRuleId = this.resolveId(autoModerationRule);
const data = await this.client.api
.guilds(this.guild.id)('auto-moderation')
.rules(autoModerationRuleId)
.patch({
data: {
name,
event_type: typeof eventType === 'number' ? eventType : AutoModerationRuleEventTypes[eventType],
trigger_metadata: triggerMetadata && {
keyword_filter: triggerMetadata.keywordFilter,
regex_patterns: triggerMetadata.regexPatterns,
presets: triggerMetadata.presets?.map(preset =>
typeof preset === 'number' ? preset : AutoModerationRuleKeywordPresetTypes[preset],
),
allow_list: triggerMetadata.allowList,
mention_total_limit: triggerMetadata.mentionTotalLimit,
},
actions: actions?.map(action => ({
type: typeof action.type === 'number' ? action.type : AutoModerationActionTypes[action.type],
metadata: {
duration_seconds: action.metadata?.durationSeconds,
channel_id: action.metadata?.channel && this.guild.channels.resolveId(action.metadata.channel),
},
})),
enabled,
exempt_roles: exemptRoles?.map(exemptRole => this.guild.roles.resolveId(exemptRole)),
exempt_channels: exemptChannels?.map(exemptChannel => this.guild.channels.resolveId(exemptChannel)),
},
reason,
});
return this._add(data);
}
/**
* Data that can be resolved to give an AutoModerationRule object. This can be:
* * An AutoModerationRule
* * A Snowflake
* @typedef {AutoModerationRule|Snowflake} AutoModerationRuleResolvable
*/
/**
* Options used to fetch a single auto moderation rule from a guild.
* @typedef {BaseFetchOptions} FetchAutoModerationRuleOptions
* @property {AutoModerationRuleResolvable} autoModerationRule The auto moderation rule to fetch
*/
/**
* Options used to fetch all auto moderation rules from a guild.
* @typedef {Object} FetchAutoModerationRulesOptions
* @property {boolean} [cache] Whether to cache the fetched auto moderation rules
*/
/**
* Fetches auto moderation rules from Discord.
* @param {AutoModerationRuleResolvable|FetchAutoModerationRuleOptions|FetchAutoModerationRulesOptions} [options]
* Options for fetching auto moderation rule(s)
* @returns {Promise<AutoModerationRule|Collection<Snowflake, AutoModerationRule>>}
* @example
* // Fetch all auto moderation rules from a guild without caching
* guild.autoModerationRules.fetch({ cache: false })
* .then(console.log)
* .catch(console.error);
* @example
* // Fetch a single auto moderation rule
* guild.autoModerationRules.fetch('979083472868098119')
* .then(console.log)
* .catch(console.error);
* @example
* // Fetch a single auto moderation rule without checking cache and without caching
* guild.autoModerationRules.fetch({ autoModerationRule: '979083472868098119', cache: false, force: true })
* .then(console.log)
* .catch(console.error)
*/
fetch(options) {
if (!options) return this._fetchMany();
const { autoModerationRule, cache, force } = options;
const resolvedAutoModerationRule = this.resolveId(autoModerationRule ?? options);
if (resolvedAutoModerationRule) {
return this._fetchSingle({ autoModerationRule: resolvedAutoModerationRule, cache, force });
}
return this._fetchMany(options);
}
async _fetchSingle({ autoModerationRule, cache, force = false }) {
if (!force) {
const existing = this.cache.get(autoModerationRule);
if (existing) return existing;
}
const data = await this.client.api.guilds(this.guild.id)('auto-moderation').rules(autoModerationRule).get();
return this._add(data, cache);
}
async _fetchMany(options = {}) {
const data = await this.client.api.guilds(this.guild.id)('auto-moderation').rules.get();
return data.reduce(
(col, autoModerationRule) => col.set(autoModerationRule.id, this._add(autoModerationRule, options.cache)),
new Collection(),
);
}
/**
* Deletes an auto moderation rule.
* @param {AutoModerationRuleResolvable} autoModerationRule The auto moderation rule to delete
* @param {string} [reason] The reason for deleting the auto moderation rule
* @returns {Promise<void>}
*/
async delete(autoModerationRule, reason) {
const autoModerationRuleId = this.resolveId(autoModerationRule);
await this.client.api.guilds(this.guild.id)('auto-moderation').rules(autoModerationRuleId).delete({ reason });
}
/**
* Resolves an {@link AutoModerationRuleResolvable} to an {@link AutoModerationRule} object.
* @method resolve
* @memberof AutoModerationRuleManager
* @instance
* @param {AutoModerationRuleResolvable} autoModerationRule The AutoModerationRule resolvable to resolve
* @returns {?AutoModerationRule}
*/
/**
* Resolves an {@link AutoModerationRuleResolvable} to a {@link AutoModerationRule} id.
* @method resolveId
* @memberof AutoModerationRuleManager
* @instance
* @param {AutoModerationRuleResolvable} autoModerationRule The AutoModerationRule resolvable to resolve
* @returns {?Snowflake}
*/
}
module.exports = AutoModerationRuleManager;

View File

@@ -0,0 +1,89 @@
'use strict';
const { AutoModerationRuleTriggerTypes } = require('../util/Constants');
/**
* Represents the structure of an executed action when an {@link AutoModerationRule} is triggered.
*/
class AutoModerationActionExecution {
constructor(data, guild) {
/**
* The guild where this action was executed from.
* @type {Guild}
*/
this.guild = guild;
/**
* The action that was executed.
* @type {AutoModerationAction}
*/
this.action = data.action;
/**
* The id of the auto moderation rule this action belongs to.
* @type {Snowflake}
*/
this.ruleId = data.rule_id;
/**
* The trigger type of the auto moderation rule which was triggered.
* @type {AutoModerationRuleTriggerType}
*/
this.ruleTriggerType = AutoModerationRuleTriggerTypes[data.rule_trigger_type];
/**
* The id of the user that triggered this action.
* @type {Snowflake}
*/
this.userId = data.user_id;
/**
* The id of the channel where this action was triggered from.
* @type {?Snowflake}
*/
this.channelId = data.channel_id ?? null;
/**
* The id of the message that triggered this action.
* @type {?Snowflake}
* <info>This will not be present if the message was blocked or the content was not part of any message.</info>
*/
this.messageId = data.message_id ?? null;
/**
* The id of any system auto moderation messages posted as a result of this action.
* @type {?Snowflake}
*/
this.alertSystemMessageId = data.alert_system_message_id ?? null;
/**
* The content that triggered this action.
* <info>This property requires the {@link GatewayIntentBits.MessageContent} privileged gateway intent.</info>
* @type {string}
*/
this.content = data.content;
/**
* The word or phrase configured in the rule that triggered this action.
* @type {?string}
*/
this.matchedKeyword = data.matched_keyword ?? null;
/**
* The substring in content that triggered this action.
* @type {?string}
*/
this.matchedContent = data.matched_content ?? null;
}
/**
* The auto moderation rule this action belongs to.
* @type {?AutoModerationRule}
* @readonly
*/
get autoModerationRule() {
return this.guild.autoModerationRules.cache.get(this.ruleId) ?? null;
}
}
module.exports = AutoModerationActionExecution;

View File

@@ -0,0 +1,279 @@
'use strict';
const { Collection } = require('@discordjs/collection');
const Base = require('./Base');
const {
AutoModerationRuleKeywordPresetTypes,
AutoModerationRuleTriggerTypes,
AutoModerationRuleEventTypes,
AutoModerationActionTypes,
} = require('../util/Constants');
/**
* Represents an auto moderation rule.
* @extends {Base}
*/
class AutoModerationRule extends Base {
constructor(client, data, guild) {
super(client);
/**
* The id of this auto moderation rule.
* @type {Snowflake}
*/
this.id = data.id;
/**
* The guild this auto moderation rule is for.
* @type {Guild}
*/
this.guild = guild;
/**
* The user that created this auto moderation rule.
* @type {Snowflake}
*/
this.creatorId = data.creator_id;
/**
* The trigger type of this auto moderation rule.
* @type {AutoModerationRuleTriggerType}
*/
this.triggerType = AutoModerationRuleTriggerTypes[data.trigger_type];
this._patch(data);
}
_patch(data) {
if ('name' in data) {
/**
* The name of this auto moderation rule.
* @type {string}
*/
this.name = data.name;
}
if ('event_type' in data) {
/**
* The event type of this auto moderation rule.
* @type {AutoModerationRuleEventType}
*/
this.eventType = AutoModerationRuleEventTypes[data.event_type];
}
if ('trigger_metadata' in data) {
/**
* Additional data used to determine whether an auto moderation rule should be triggered.
* @typedef {Object} AutoModerationTriggerMetadata
* @property {string[]} keywordFilter The substrings that will be searched for in the content
* @property {string[]} regexPatterns The regular expression patterns which will be matched against the content
* <info>Only Rust-flavored regular expressions are supported.</info>
* @property {AutoModerationRuleKeywordPresetType[]} presets
* The internally pre-defined wordsets which will be searched for in the content
* @property {string[]} allowList The substrings that will be exempt from triggering
* {@link AutoModerationRuleTriggerTypes.Keyword} and {@link AutoModerationRuleTriggerTypes.KeywordPreset}
* @property {?number} mentionTotalLimit The total number of role & user mentions allowed per message
*/
/**
* The trigger metadata of the rule.
* @type {AutoModerationTriggerMetadata}
*/
this.triggerMetadata = {
keywordFilter: data.trigger_metadata.keyword_filter ?? [],
regexPatterns: data.trigger_metadata.regex_patterns ?? [],
presets: data.trigger_metadata.presets?.map(preset => AutoModerationRuleKeywordPresetTypes[preset]) ?? [],
allowList: data.trigger_metadata.allow_list ?? [],
mentionTotalLimit: data.trigger_metadata.mention_total_limit ?? null,
};
}
if ('actions' in data) {
/**
* An object containing information about an auto moderation rule action.
* @typedef {Object} AutoModerationAction
* @property {AutoModerationActionType} type The type of this auto moderation rule action
* @property {AutoModerationActionMetadata} metadata Additional metadata needed during execution
*/
/**
* Additional data used when an auto moderation rule is executed.
* @typedef {Object} AutoModerationActionMetadata
* @property {?Snowflake} channelId The id of the channel to which content will be logged
* @property {?number} durationSeconds The timeout duration in seconds
*/
/**
* The actions of this auto moderation rule.
* @type {AutoModerationAction[]}
*/
this.actions = data.actions.map(action => ({
type: AutoModerationActionTypes[action.type],
metadata: {
durationSeconds: action.metadata.duration_seconds ?? null,
channelId: action.metadata.channel_id ?? null,
},
}));
}
if ('enabled' in data) {
/**
* Whether this auto moderation rule is enabled.
* @type {boolean}
*/
this.enabled = data.enabled;
}
if ('exempt_roles' in data) {
/**
* The roles exempt by this auto moderation rule.
* @type {Collection<Snowflake, Role>}
*/
this.exemptRoles = new Collection(
data.exempt_roles.map(exemptRole => [exemptRole, this.guild.roles.cache.get(exemptRole)]),
);
}
if ('exempt_channels' in data) {
/**
* The channels exempt by this auto moderation rule.
* @type {Collection<Snowflake, GuildChannel|ThreadChannel>}
*/
this.exemptChannels = new Collection(
data.exempt_channels.map(exemptChannel => [exemptChannel, this.guild.channels.cache.get(exemptChannel)]),
);
}
}
/**
* Edits this auto moderation rule.
* @param {AutoModerationRuleEditOptions} options Options for editing this auto moderation rule
* @returns {Promise<AutoModerationRule>}
*/
edit(options) {
return this.guild.autoModerationRules.edit(this.id, options);
}
/**
* Deletes this auto moderation rule.
* @param {string} [reason] The reason for deleting this auto moderation rule
* @returns {Promise<void>}
*/
delete(reason) {
return this.guild.autoModerationRules.delete(this.id, reason);
}
/**
* Sets the name for this auto moderation rule.
* @param {string} name The name of this auto moderation rule
* @param {string} [reason] The reason for changing the name of this auto moderation rule
* @returns {Promise<AutoModerationRule>}
*/
setName(name, reason) {
return this.edit({ name, reason });
}
/**
* Sets the event type for this auto moderation rule.
* @param {AutoModerationRuleEventType} eventType The event type of this auto moderation rule
* @param {string} [reason] The reason for changing the event type of this auto moderation rule
* @returns {Promise<AutoModerationRule>}
*/
setEventType(eventType, reason) {
return this.edit({ eventType, reason });
}
/**
* Sets the keyword filter for this auto moderation rule.
* @param {string[]} keywordFilter The keyword filter of this auto moderation rule
* @param {string} [reason] The reason for changing the keyword filter of this auto moderation rule
* @returns {Promise<AutoModerationRule>}
*/
setKeywordFilter(keywordFilter, reason) {
return this.edit({ triggerMetadata: { ...this.triggerMetadata, keywordFilter }, reason });
}
/**
* Sets the regular expression patterns for this auto moderation rule.
* @param {string[]} regexPatterns The regular expression patterns of this auto moderation rule
* <info>Only Rust-flavored regular expressions are supported.</info>
* @param {string} [reason] The reason for changing the regular expression patterns of this auto moderation rule
* @returns {Promise<AutoModerationRule>}
*/
setRegexPatterns(regexPatterns, reason) {
return this.edit({ triggerMetadata: { ...this.triggerMetadata, regexPatterns }, reason });
}
/**
* Sets the presets for this auto moderation rule.
* @param {AutoModerationRuleKeywordPresetType[]} presets The presets of this auto moderation rule
* @param {string} [reason] The reason for changing the presets of this auto moderation rule
* @returns {Promise<AutoModerationRule>}
*/
setPresets(presets, reason) {
return this.edit({ triggerMetadata: { ...this.triggerMetadata, presets }, reason });
}
/**
* Sets the allow list for this auto moderation rule.
* @param {string[]} allowList The allow list of this auto moderation rule
* @param {string} [reason] The reason for changing the allow list of this auto moderation rule
* @returns {Promise<AutoModerationRule>}
*/
setAllowList(allowList, reason) {
return this.edit({ triggerMetadata: { ...this.triggerMetadata, allowList }, reason });
}
/**
* Sets the mention total limit for this auto moderation rule.
* @param {number} mentionTotalLimit The mention total limit of this auto moderation rule
* @param {string} [reason] The reason for changing the mention total limit of this auto moderation rule
* @returns {Promise<AutoModerationRule>}
*/
setMentionTotalLimit(mentionTotalLimit, reason) {
return this.edit({ triggerMetadata: { ...this.triggerMetadata, mentionTotalLimit }, reason });
}
/**
* Sets the actions for this auto moderation rule.
* @param {AutoModerationActionOptions} actions The actions of this auto moderation rule
* @param {string} [reason] The reason for changing the actions of this auto moderation rule
* @returns {Promise<AutoModerationRule>}
*/
setActions(actions, reason) {
return this.edit({ actions, reason });
}
/**
* Sets whether this auto moderation rule should be enabled.
* @param {boolean} [enabled=true] Whether to enable this auto moderation rule
* @param {string} [reason] The reason for enabling or disabling this auto moderation rule
* @returns {Promise<AutoModerationRule>}
*/
setEnabled(enabled = true, reason) {
return this.edit({ enabled, reason });
}
/**
* Sets the exempt roles for this auto moderation rule.
* @param {Collection<Snowflake, Role>|RoleResolvable[]} [exemptRoles] The exempt roles of this auto moderation rule
* @param {string} [reason] The reason for changing the exempt roles of this auto moderation rule
* @returns {Promise<AutoModerationRule>}
*/
setExemptRoles(exemptRoles, reason) {
return this.edit({ exemptRoles, reason });
}
/**
* Sets the exempt channels for this auto moderation rule.
* @param {Collection<Snowflake, GuildChannel|ThreadChannel>|GuildChannelResolvable[]} [exemptChannels]
* The exempt channels of this auto moderation rule
* @param {string} [reason] The reason for changing the exempt channels of this auto moderation rule
* @returns {Promise<AutoModerationRule>}
*/
setExemptChannels(exemptChannels, reason) {
return this.edit({ exemptChannels, reason });
}
}
module.exports = AutoModerationRule;

View File

@@ -10,6 +10,7 @@ const Integration = require('./Integration');
const Webhook = require('./Webhook');
const WelcomeScreen = require('./WelcomeScreen');
const { Error } = require('../errors');
const AutoModerationRuleManager = require('../managers/AutoModerationRuleManager');
const GuildBanManager = require('../managers/GuildBanManager');
const GuildChannelManager = require('../managers/GuildChannelManager');
const GuildEmojiManager = require('../managers/GuildEmojiManager');
@@ -111,6 +112,12 @@ class Guild extends AnonymousGuild {
*/
this.scheduledEvents = new GuildScheduledEventManager(this);
/**
* A manager of the auto moderation rules of this guild.
* @type {AutoModerationRuleManager}
*/
this.autoModerationRules = new AutoModerationRuleManager(this);
if (!data) return;
if (data.unavailable) {

View File

@@ -1,13 +1,14 @@
'use strict';
const { Collection } = require('@discordjs/collection');
const AutoModerationRule = require('./AutoModerationRule');
const { GuildScheduledEvent } = require('./GuildScheduledEvent');
const Integration = require('./Integration');
const Invite = require('./Invite');
const { StageInstance } = require('./StageInstance');
const { Sticker } = require('./Sticker');
const Webhook = require('./Webhook');
const { OverwriteTypes, PartialTypes } = require('../util/Constants');
const { OverwriteTypes, PartialTypes, AutoModerationRuleTriggerTypes } = require('../util/Constants');
const SnowflakeUtil = require('../util/SnowflakeUtil');
const Util = require('../util/Util');
@@ -26,6 +27,7 @@ const Util = require('../util/Util');
* * STICKER
* * THREAD
* * GUILD_SCHEDULED_EVENT
* * AUTO_MODERATION
* @typedef {string} AuditLogTargetType
*/
@@ -49,6 +51,7 @@ const Targets = {
STAGE_INSTANCE: 'STAGE_INSTANCE',
STICKER: 'STICKER',
THREAD: 'THREAD',
AUTO_MODERATION: 'AUTO_MODERATION',
UNKNOWN: 'UNKNOWN',
};
@@ -102,6 +105,12 @@ const Targets = {
* * THREAD_CREATE: 110
* * THREAD_UPDATE: 111
* * THREAD_DELETE: 112
* * AUTO_MODERATION_RULE_CREATE: 140
* * AUTO_MODERATION_RULE_UPDATE: 141
* * AUTO_MODERATION_RULE_DELETE: 142
* * AUTO_MODERATION_BLOCK_MESSAGE: 143
* * AUTO_MODERATION_FLAG_TO_CHANNEL: 144
* * AUTO_MODERATION_USER_COMMUNICATION_DISABLED: 145
* @typedef {?(number|string)} AuditLogAction
* @see {@link https://discord.com/developers/docs/resources/audit-log#audit-log-entry-object-audit-log-events}
*/
@@ -160,6 +169,12 @@ const Actions = {
THREAD_CREATE: 110,
THREAD_UPDATE: 111,
THREAD_DELETE: 112,
AUTO_MODERATION_RULE_CREATE: 140,
AUTO_MODERATION_RULE_UPDATE: 141,
AUTO_MODERATION_RULE_DELETE: 142,
AUTO_MODERATION_BLOCK_MESSAGE: 143,
AUTO_MODERATION_FLAG_TO_CHANNEL: 144,
AUTO_MODERATION_USER_COMMUNICATION_DISABLED: 145,
};
/**
@@ -193,6 +208,17 @@ class GuildAuditLogs {
}
}
/**
* Cached auto moderation rules.
* @type {Collection<Snowflake, AutoModerationRule>}
* @private
*/
this.autoModerationRules = data.auto_moderation_rules.reduce(
(autoModerationRules, autoModerationRule) =>
autoModerationRules.set(autoModerationRule.id, guild.autoModerationRules._add(autoModerationRule)),
new Collection(),
);
/**
* The entries for this guild's audit logs
* @type {Collection<Snowflake, GuildAuditLogsEntry>}
@@ -229,10 +255,11 @@ class GuildAuditLogs {
* * A sticker
* * A guild scheduled event
* * A thread
* * An auto moderation rule
* * An object with an id key if target was deleted
* * An object where the keys represent either the new value or the old value
* @typedef {?(Object|Guild|Channel|User|Role|Invite|Webhook|GuildEmoji|Message|Integration|StageInstance|Sticker|
* GuildScheduledEvent)} AuditLogEntryTarget
* GuildScheduledEvent|AutoModerationRule)} AuditLogEntryTarget
*/
/**
@@ -254,6 +281,7 @@ class GuildAuditLogs {
if (target < 100) return Targets.STICKER;
if (target < 110) return Targets.GUILD_SCHEDULED_EVENT;
if (target < 120) return Targets.THREAD;
if (target >= 140 && target < 150) return Targets.AUTO_MODERATION;
return Targets.UNKNOWN;
}
@@ -288,6 +316,8 @@ class GuildAuditLogs {
Actions.STICKER_CREATE,
Actions.GUILD_SCHEDULED_EVENT_CREATE,
Actions.THREAD_CREATE,
Actions.AUTO_MODERATION_RULE_CREATE,
Actions.AUTO_MODERATION_BLOCK_MESSAGE,
].includes(action)
) {
return 'CREATE';
@@ -313,6 +343,7 @@ class GuildAuditLogs {
Actions.STICKER_DELETE,
Actions.GUILD_SCHEDULED_EVENT_DELETE,
Actions.THREAD_DELETE,
Actions.AUTO_MODERATION_RULE_DELETE,
].includes(action)
) {
return 'DELETE';
@@ -335,6 +366,7 @@ class GuildAuditLogs {
Actions.STICKER_UPDATE,
Actions.GUILD_SCHEDULED_EVENT_UPDATE,
Actions.THREAD_UPDATE,
Actions.AUTO_MODERATION_RULE_UPDATE,
].includes(action)
) {
return 'UPDATE';
@@ -476,6 +508,15 @@ class GuildAuditLogsEntry {
};
break;
case Actions.AUTO_MODERATION_BLOCK_MESSAGE:
case Actions.AUTO_MODERATION_FLAG_TO_CHANNEL:
case Actions.AUTO_MODERATION_USER_COMMUNICATION_DISABLED:
this.extra = {
autoModerationRuleName: data.options.auto_moderation_rule_name,
autoModerationRuleTriggerType: AutoModerationRuleTriggerTypes[data.options.auto_moderation_rule_trigger_type],
};
break;
default:
break;
}
@@ -603,6 +644,20 @@ class GuildAuditLogsEntry {
{ id: data.target_id, guild_id: guild.id },
),
);
} else if (targetType === Targets.AUTO_MODERATION) {
this.target =
guild.autoModerationRules.cache.get(data.target_id) ??
new AutoModerationRule(
guild.client,
this.changes.reduce(
(o, c) => {
o[c.key] = c.new ?? c.old;
return o;
},
{ id: data.target_id, guild_id: guild.id },
),
guild,
);
} else if (data.target_id) {
this.target = guild[`${targetType.toLowerCase()}s`]?.cache.get(data.target_id) ?? { id: data.target_id };
}

View File

@@ -329,6 +329,10 @@ exports.Opcodes = {
* * APPLICATION_COMMAND_CREATE: applicationCommandCreate (deprecated)
* * APPLICATION_COMMAND_DELETE: applicationCommandDelete (deprecated)
* * APPLICATION_COMMAND_UPDATE: applicationCommandUpdate (deprecated)
* * AUTO_MODERATION_ACTION_EXECUTION: autoModerationActionExecution
* * AUTO_MODERATION_RULE_CREATE: autoModerationRuleCreate
* * AUTO_MODERATION_RULE_DELETE: autoModerationRuleDelete
* * AUTO_MODERATION_RULE_UPDATE: autoModerationRuleUpdate
* * CALL_CREATE: callCreate
* * CALL_DELETE: callDelete
* * CALL_UPDATE: callUpdate
@@ -414,6 +418,10 @@ exports.Events = {
APPLICATION_COMMAND_CREATE: 'applicationCommandCreate',
APPLICATION_COMMAND_DELETE: 'applicationCommandDelete',
APPLICATION_COMMAND_UPDATE: 'applicationCommandUpdate',
AUTO_MODERATION_ACTION_EXECUTION: 'autoModerationActionExecution',
AUTO_MODERATION_RULE_CREATE: 'autoModerationRuleCreate',
AUTO_MODERATION_RULE_DELETE: 'autoModerationRuleDelete',
AUTO_MODERATION_RULE_UPDATE: 'autoModerationRuleUpdate',
CALL_CREATE: 'callCreate',
CALL_DELETE: 'callDelete',
CALL_UPDATE: 'callUpdate',
@@ -753,6 +761,7 @@ exports.MessageTypes = [
/**
* The name of an item to be swept in Sweepers
* * `applicationCommands` - both global and guild commands
* * `autoModerationRules`
* * `bans`
* * `emojis`
* * `invites` - accepts the `lifetime` property, using it will sweep based on expires timestamp
@@ -770,6 +779,7 @@ exports.MessageTypes = [
*/
exports.SweeperKeys = [
'applicationCommands',
'autoModerationRules',
'bans',
'emojis',
'invites',
@@ -1462,6 +1472,46 @@ exports.ApplicationCommandOptionTypes = createEnum([
*/
exports.ApplicationCommandPermissionTypes = createEnum([null, 'ROLE', 'USER']);
/**
* The type of an {@link AutoModerationRuleTriggerTypes} object:
* * KEYWORD
* * SPAM
* * KEYWORD_PRESET
* * MENTION_SPAM
* @typedef {string} AutoModerationRuleTriggerType
* @see {@link https://discord.com/developers/docs/resources/auto-moderation#auto-moderation-rule-object-trigger-types}
*/
exports.AutoModerationRuleTriggerTypes = createEnum([null, 'KEYWORD', null, 'SPAM', 'KEYWORD_PRESET', 'MENTION_SPAM']);
/**
* The type of an {@link AutoModerationRuleKeywordPresetTypes} object:
* * KEYWORD
* * SPAM
* * KEYWORD_PRESET
* * MENTION_SPAM
* @typedef {string} AutoModerationRuleKeywordPresetType
* @see {@link https://discord.com/developers/docs/resources/auto-moderation#auto-moderation-rule-object-keyword-preset-types}
*/
exports.AutoModerationRuleKeywordPresetTypes = createEnum([null, 'PROFANITY', 'SEXUAL_CONTENT', 'SLURS']);
/**
* The type of an {@link AutoModerationActionTypes} object:
* * BLOCK_MESSAGE
* * SEND_ALERT_MESSAGE
* * TIMEOUT
* @typedef {string} AutoModerationActionType
* @see {@link https://discord.com/developers/docs/resources/auto-moderation#auto-moderation-action-object-action-types}
*/
exports.AutoModerationActionTypes = createEnum([null, 'BLOCK_MESSAGE', 'SEND_ALERT_MESSAGE', 'TIMEOUT']);
/**
* The type of an {@link AutoModerationRuleEventTypes} object:
* * MESSAGE_SEND
* @typedef {string} AutoModerationRuleEventType
* @see {@link https://discord.com/developers/docs/resources/auto-moderation#auto-moderation-rule-object-event-types}
*/
exports.AutoModerationRuleEventTypes = createEnum([null, 'MESSAGE_SEND']);
/**
* The type of an {@link Interaction} object:
* * PING
@@ -1709,6 +1759,11 @@ function createEnum(keys) {
* The type of an {@link ApplicationCommandPermissions} object.
* @property {Object<ApplicationCommandType, number>} ApplicationCommandTypes
* The type of an {@link ApplicationCommand} object.
* @property {Object<AutoModerationRuleTriggerType, number>} AutoModerationRuleTriggerTypes Characterizes the type
* of contentwhich can trigger the rule.
* @property {Object<AutoModerationActionType, number>} AutoModerationActionTypes
* @property {Object<AutoModerationRuleKeywordPresetType, number>} AutoModerationRuleKeywordPresetTypes
* @property {Object<AutoModerationRuleEventType, number>} AutoModerationRuleEventTypes
* @property {Object<ChannelType, number>} ChannelTypes All available channel types.
* @property {ClientApplicationAssetTypes} ClientApplicationAssetTypes The types of an {@link ApplicationAsset} object.
* @property {Object<Color, number>} Colors An object with regularly used colors.

View File

@@ -42,6 +42,8 @@ class Intents extends BitField {}
* * `DIRECT_MESSAGE_TYPING`
* * `MESSAGE_CONTENT`
* * `GUILD_SCHEDULED_EVENTS`
* * `AUTO_MODERATION_CONFIGURATION`
* * `AUTO_MODERATION_EXECUTION`
* @type {Object}
* @see {@link https://discord.com/developers/docs/topics/gateway#list-of-intents}
*/
@@ -63,6 +65,8 @@ Intents.FLAGS = {
DIRECT_MESSAGE_TYPING: 1 << 14,
MESSAGE_CONTENT: 1 << 15,
GUILD_SCHEDULED_EVENTS: 1 << 16,
AUTO_MODERATION_CONFIGURATION: 1 << 20,
AUTO_MODERATION_EXECUTION: 1 << 21,
};
module.exports = Intents;

View File

@@ -77,6 +77,16 @@ class Sweepers {
return guildCommands + globalCommands;
}
/**
* Sweeps all auto moderation rules and removes the ones which are indicated by the filter.
* @param {Function} filter The function used to determine
* which auto moderation rules will be removed from the caches
* @returns {number} Amount of auto moderation rules that were removed from the caches
*/
sweepAutoModerationRules(filter) {
return this._sweepGuildDirectProp('autoModerationRules', filter).items;
}
/**
* Sweeps all guild bans and removes the ones which are indicated by the filter.
* @param {Function} filter The function used to determine which bans will be removed from the caches.