feat: Safety alerts channel and mention raid protection (#9073)

* feat: safety alerts channel and mention raid protection

* feat: add raw types

* Apply suggestions from code review

Co-authored-by: Jiralite <33201955+Jiralite@users.noreply.github.com>

* docs: update guild features

---------

Co-authored-by: Jiralite <33201955+Jiralite@users.noreply.github.com>
This commit is contained in:
Jaw0r3k 2023-05-07 14:44:44 +02:00 committed by GitHub
parent c5a42ed5ec
commit 5057f04304
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 119 additions and 1 deletions

View file

@ -58,6 +58,7 @@ class AutoModerationRuleManager extends CachedManager {
* @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
* @property {boolean} [mentionRaidProtectionEnabled] Whether to automatically detect mention raids
*/
/**
@ -126,6 +127,7 @@ class AutoModerationRuleManager extends CachedManager {
),
allow_list: triggerMetadata.allowList,
mention_total_limit: triggerMetadata.mentionTotalLimit,
mention_raid_protection_enabled: triggerMetadata.mentionRaidProtectionEnabled,
},
actions: actions.map(action => ({
type: typeof action.type === 'number' ? action.type : AutoModerationActionTypes[action.type],
@ -188,6 +190,7 @@ class AutoModerationRuleManager extends CachedManager {
),
allow_list: triggerMetadata.allowList,
mention_total_limit: triggerMetadata.mentionTotalLimit,
mention_raid_protection_enabled: triggerMetadata.mentionRaidProtectionEnabled,
},
actions: actions?.map(action => ({
type: typeof action.type === 'number' ? action.type : AutoModerationActionTypes[action.type],

View file

@ -73,6 +73,7 @@ class AutoModerationRule extends Base {
* @property {string[]} allowList The substrings that will be exempt from triggering
* {@link AutoModerationRuleTriggerTypes.KEYWORD} and {@link AutoModerationRuleTriggerTypes.KEYWORD_PRESET}
* @property {?number} mentionTotalLimit The total number of role & user mentions allowed per message
* @property {boolean} mentionRaidProtectionEnabled Whether mention raid protection is enabled
*/
/**
@ -85,6 +86,7 @@ class AutoModerationRule extends Base {
presets: data.trigger_metadata.presets?.map(preset => AutoModerationRuleKeywordPresetTypes[preset]) ?? [],
allowList: data.trigger_metadata.allow_list ?? [],
mentionTotalLimit: data.trigger_metadata.mention_total_limit ?? null,
mentionRaidProtectionEnabled: data.trigger_metadata.mention_raid_protection_enabled ?? false,
};
}
@ -236,6 +238,17 @@ class AutoModerationRule extends Base {
return this.edit({ triggerMetadata: { ...this.triggerMetadata, mentionTotalLimit }, reason });
}
/**
* Sets whether to enable mention raid protection for this auto moderation rule.
* @param {boolean} mentionRaidProtectionEnabled
* Whether to enable mention raid protection for this auto moderation rule
* @param {string} [reason] The reason for changing the mention raid protection of this auto moderation rule
* @returns {Promise<AutoModerationRule>}
*/
setMentionRaidProtectionEnabled(mentionRaidProtectionEnabled, reason) {
return this.edit({ triggerMetadata: { ...this.triggerMetadata, mentionRaidProtectionEnabled }, reason });
}
/**
* Sets the actions for this auto moderation rule.
* @param {AutoModerationActionOptions[]} actions The actions of this auto moderation rule

View file

@ -255,6 +255,7 @@ class Guild extends AnonymousGuild {
* * SEVEN_DAY_THREAD_ARCHIVE
* * PRIVATE_THREADS
* * ROLE_ICONS
* * RAID_ALERTS_DISABLED
* * ROLE_SUBSCRIPTIONS_AVAILABLE_FOR_PURCHASE
* * ROLE_SUBSCRIPTIONS_ENABLED
* @typedef {string} Features
@ -442,6 +443,16 @@ class Guild extends AnonymousGuild {
this.preferredLocale = data.preferred_locale;
}
if ('safety_alerts_channel_id' in data) {
/**
* The safety alerts channel's id for the guild
* @type {?Snowflake}
*/
this.safetyAlertsChannelId = data.safety_alerts_channel_id;
} else {
this.safetyAlertsChannelId ??= null;
}
if (data.channels) {
this.channels.cache.clear();
for (const rawChannel of data.channels) {
@ -575,6 +586,15 @@ class Guild extends AnonymousGuild {
return this.client.channels.resolve(this.systemChannelId);
}
/**
* Safety alerts channel for this guild
* @type {?TextChannel}
* @readonly
*/
get safetyAlertsChannel() {
return this.client.channels.resolve(this.safetyAlertsChannelId);
}
/**
* Widget channel for this guild
* @type {?(TextChannel|NewsChannel|VoiceChannel|StageChannel|ForumChannel)}
@ -839,6 +859,7 @@ class Guild extends AnonymousGuild {
* @property {?TextChannelResolvable} [rulesChannel] The rules channel of the guild
* @property {?TextChannelResolvable} [publicUpdatesChannel] The community updates channel of the guild
* @property {?string} [preferredLocale] The preferred locale of the guild
* @property {?TextChannelResolvable} [safetyAlertsChannel] The safety alerts channel of the guild
* @property {boolean} [premiumProgressBarEnabled] Whether the guild's premium progress bar is enabled
* @property {?string} [description] The discovery description of the guild
* @property {Features[]} [features] The features of the guild
@ -922,6 +943,9 @@ class Guild extends AnonymousGuild {
_data.description = data.description;
}
if (typeof data.preferredLocale !== 'undefined') _data.preferred_locale = data.preferredLocale;
if (typeof data.safetyAlertsChannel !== 'undefined') {
_data.safety_alerts_channel_id = this.client.channels.resolveId(data.safetyAlertsChannel);
}
if ('premiumProgressBarEnabled' in data) _data.premium_progress_bar_enabled = data.premiumProgressBarEnabled;
const newData = await this.client.api.guilds(this.id).patch({ data: _data, reason });
return this.client.actions.GuildUpdate.handle(newData).updated;
@ -1224,6 +1248,21 @@ class Guild extends AnonymousGuild {
return this.edit({ preferredLocale }, reason);
}
/**
* Edits the safety alerts channel of the guild.
* @param {?TextChannelResolvable} safetyAlertsChannel The new safety alerts channel
* @param {string} [reason] Reason for changing the guild's safety alerts channel
* @returns {Promise<Guild>}
* @example
* // Edit the guild safety alerts channel
* guild.setSafetyAlertsChannel(channel)
* .then(updated => console.log(`Updated guild safety alerts channel to ${updated.safetyAlertsChannel.name}`))
* .catch(console.error);
*/
setSafetyAlertsChannel(safetyAlertsChannel, reason) {
return this.edit({ safetyAlertsChannel }, reason);
}
/**
* Edits the enabled state of the guild's premium progress bar
* @param {boolean} [enabled=true] The new enabled state of the guild's premium progress bar

10
typings/index.d.ts vendored
View file

@ -1013,6 +1013,8 @@ export class Guild extends AnonymousGuild {
public roles: RoleManager;
public readonly rulesChannel: TextChannel | null;
public rulesChannelId: Snowflake | null;
public readonly safetyAlertsChannel: TextChannel | null;
public safetyAlertsChannelId: Snowflake | null;
public scheduledEvents: GuildScheduledEventManager;
public readonly shard: WebSocketShard;
public shardId: number;
@ -1073,6 +1075,7 @@ export class Guild extends AnonymousGuild {
/** @deprecated Use {@link RoleManager.setPositions} instead */
public setRolePositions(rolePositions: readonly RolePosition[]): Promise<Guild>;
public setRulesChannel(rulesChannel: TextChannelResolvable | null, reason?: string): Promise<Guild>;
public setSafetyAlertsChannel(safetyAlertsChannel: TextChannelResolvable | null, reason?: string): Promise<Guild>;
public setSplash(splash: BufferResolvable | Base64Resolvable | null, reason?: string): Promise<Guild>;
public setSystemChannel(systemChannel: TextChannelResolvable | null, reason?: string): Promise<Guild>;
public setSystemChannelFlags(systemChannelFlags: SystemChannelFlagsResolvable, reason?: string): Promise<Guild>;
@ -4227,6 +4230,10 @@ export class AutoModerationRule extends Base {
public setRegexPatterns(regexPatterns: string[], reason?: string): Promise<AutoModerationRule>;
public setPresets(presets: AutoModerationRuleKeywordPresetType[], reason?: string): Promise<AutoModerationRule>;
public setAllowList(allowList: string[], reason?: string): Promise<AutoModerationRule>;
public setMentionRaidProtectionEnabled(
mentionRaidProtectionEnabled: boolean,
reason?: string,
): Promise<AutoModerationRule>;
public setMentionTotalLimit(mentionTotalLimit: number, reason?: string): Promise<AutoModerationRule>;
public setActions(actions: AutoModerationActionOptions[], reason?: string): Promise<AutoModerationRule>;
public setEnabled(enabled?: boolean, reason?: string): Promise<AutoModerationRule>;
@ -4315,6 +4322,7 @@ export interface AutoModerationTriggerMetadata {
regexPatterns: string[];
presets: (AutoModerationRuleKeywordPresetType | AutoModerationRuleKeywordPresetTypes)[];
allowList: string[];
mentionRaidProtectionEnabled: boolean;
mentionTotalLimit: number | null;
}
@ -5419,6 +5427,7 @@ export interface GuildEditData {
rulesChannel?: TextChannelResolvable | null;
publicUpdatesChannel?: TextChannelResolvable | null;
preferredLocale?: string | null;
safetyAlertsChannel?: TextChannelResolvable | null;
premiumProgressBarEnabled?: boolean;
description?: string | null;
features?: GuildFeatures[];
@ -5471,6 +5480,7 @@ export type GuildFeatures =
| 'SEVEN_DAY_THREAD_ARCHIVE'
| 'PRIVATE_THREADS'
| 'ROLE_ICONS'
| 'RAID_ALERTS_DISABLED'
| 'ROLE_SUBSCRIPTIONS_AVAILABLE_FOR_PURCHASE'
| 'ROLE_SUBSCRIPTIONS_ENABLED';

View file

@ -11,7 +11,6 @@ import {
APIChannel,
APIEmoji,
APIExtendedInvite,
APIGuild,
APIGuildIntegration,
APIGuildIntegrationApplication,
APIGuildMember,
@ -79,6 +78,16 @@ import {
APITextInputComponent,
APIModalActionRowComponent,
APIModalSubmitInteraction,
Permissions,
GuildDefaultMessageNotifications,
GuildExplicitContentFilter,
GuildMFALevel,
GuildSystemChannelFlags,
GuildPremiumTier,
GuildNSFWLevel,
GuildHubType,
GuildVerificationLevel,
GuildFeature,
LocalizationMap
} from 'discord-api-types/v9';
import { GuildChannel, Guild, PermissionOverwrites, InteractionType } from '.';
@ -282,6 +291,50 @@ export interface APIAutoModerationRuleTriggerMetadata {
allow_list?: string[];
regex_patterns?: string[];
mention_total_limit?: number;
mention_raid_protection_enabled?: boolean;
}
export interface APIGuild extends APIPartialGuild {
icon_hash?: string | null;
discovery_splash: string | null;
owner?: boolean;
owner_id: Snowflake;
permissions?: Permissions;
region: string;
afk_channel_id: Snowflake | null;
afk_timeout: number;
widget_enabled?: boolean;
widget_channel_id?: Snowflake | null;
verification_level: GuildVerificationLevel;
default_message_notifications: GuildDefaultMessageNotifications;
explicit_content_filter: GuildExplicitContentFilter;
roles: APIRole[];
emojis: APIEmoji[];
features: GuildFeature[];
mfa_level: GuildMFALevel;
application_id: Snowflake | null;
system_channel_id: Snowflake | null;
system_channel_flags: GuildSystemChannelFlags;
rules_channel_id: Snowflake | null;
max_presences?: number | null;
max_members?: number;
vanity_url_code: string | null;
description: string | null;
banner: string | null;
premium_tier: GuildPremiumTier;
premium_subscription_count?: number;
preferred_locale: string;
public_updates_channel_id: Snowflake | null;
max_video_channel_users?: number;
approximate_member_count?: number;
approximate_presence_count?: number;
welcome_screen?: APIGuildWelcomeScreen;
nsfw_level: GuildNSFWLevel;
stickers: APISticker[];
premium_progress_bar_enabled: boolean;
hub_type: GuildHubType | null;
safety_alerts_channel_id: Snowflake | null;
}
export interface APIApplicationRoleConnectionMetadata {