Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Auto Moderation #647

Merged
merged 65 commits into from
Aug 31, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
65 commits
Select commit Hold shift + click to select a range
b1607fb
Automod models [broken]
HopeBaron Jun 24, 2022
b733abf
Merge branch '0.8.x' into automod
lukellmann Jul 5, 2022
5ab959e
Fix Auto Moderation models
lukellmann Jul 6, 2022
85f6a0c
Add "Discord" prefix to Auto Moderation models
lukellmann Jul 6, 2022
cdf5451
Add Auto Moderation routes
lukellmann Jul 6, 2022
674e623
Add Auto Moderation requests
lukellmann Jul 6, 2022
1b587a2
Add AutoModerationService
lukellmann Jul 6, 2022
01ba306
Add Auto Moderation to Audit Log
lukellmann Jul 6, 2022
78da15b
Add `GuildFeature.AutoModeration`
lukellmann Jul 6, 2022
2f8b2ce
Add `MessageType.AutoModerationAction`
lukellmann Jul 6, 2022
52f9335
Add Auto Moderation Gateway Intents
lukellmann Jul 6, 2022
c8169bf
Add Auto Moderation Gateway Events
lukellmann Jul 6, 2022
4ff6296
Fix test
lukellmann Jul 6, 2022
c51dbe2
Rename `AutoModerationKeywordPresetType` to `AutoModerationRuleKeywor…
lukellmann Jul 7, 2022
3485fba
Remove TODOs, fields are indeed optional
lukellmann Jul 7, 2022
068c784
Add missing `Optional` default
lukellmann Jul 7, 2022
efcc54f
Add `DiscordAutoModerationRuleTriggerMetadata.allowList`
lukellmann Jul 8, 2022
4d03cf0
Add builders
lukellmann Jul 9, 2022
9591b4e
Add docs for builders
lukellmann Jul 9, 2022
790bd62
Merge branch '0.8.x' into automod
lukellmann Jul 9, 2022
2744416
Add builder-taking functions to AutoModerationService
lukellmann Jul 9, 2022
933f63b
Merge branch '0.8.x' into automod
lukellmann Jul 10, 2022
f4e861c
Add cache models
lukellmann Jul 11, 2022
058f7ce
Rename package
lukellmann Jul 12, 2022
307cf3c
Add `TypedAutoModerationRuleBuilder` and `UntypedAutoModerationRuleMo…
lukellmann Jul 12, 2022
9509d10
Start adding core models/functions
lukellmann Jul 12, 2022
b056320
Add missing properties to `AutoModerationRule`
lukellmann Jul 17, 2022
dd215aa
Add `AutoModerationAction`
lukellmann Jul 17, 2022
2c9e9a2
Add docs for `AutoModerationRule`
lukellmann Jul 17, 2022
1cdcf29
Add more documentation
lukellmann Jul 22, 2022
73e70ad
Add `AutoModerationRuleBehavior.delete`
lukellmann Jul 22, 2022
85087ed
Add @suppress to `assignX()` implementations
lukellmann Jul 28, 2022
23312da
Merge branch '0.8.x' into automod
lukellmann Jul 28, 2022
65fc3e7
Retrieve rules via suppliers
lukellmann Jul 29, 2022
4a85adf
Add `AutoModerationRuleBehavior.asAutoModerationRuleOrNull()` and `Au…
lukellmann Jul 31, 2022
7c1f35e
Add info to `@suppress` tags
lukellmann Jul 31, 2022
19b3a74
Add `AutoModerationRuleBehavior.getGuildOrNull()` and `AutoModeration…
lukellmann Jul 31, 2022
08933c5
Let `AutoModerationAction` implement `KordObject`
lukellmann Aug 1, 2022
b1c0b17
Document `ManageGuild` requirement for `asAutoModerationRule()`
lukellmann Aug 1, 2022
61785a3
Add convenience functions for keyword matching strategies
lukellmann Aug 1, 2022
d5e971c
Change some builder methods to extensions
lukellmann Aug 1, 2022
b9f3781
Add core events and Unsafe behavior creating functions
lukellmann Aug 3, 2022
b8e13a8
Merge branch '0.8.x' into automod
lukellmann Aug 7, 2022
bd864b6
Register `AutoModerationRuleData` for caching
lukellmann Aug 7, 2022
6cebbce
Add `MessageContent` intent to `AutoModerationActionExecutionEvent` i…
lukellmann Aug 7, 2022
624d93b
Add `autoModerationRules` to `AuditLog`
lukellmann Aug 7, 2022
310deee
Rename `allowList` to `allowedKeywords`
lukellmann Aug 7, 2022
315d892
Docs for builders
lukellmann Aug 7, 2022
5c3b526
Bound for type parameter of RequestBuilder
lukellmann Aug 7, 2022
fbff675
Add `MentionSpam` trigger type
lukellmann Aug 8, 2022
5a82ebb
Merge branch '0.8.x' into automod
lukellmann Aug 9, 2022
0b975a2
Merge branch '0.8.x' into automod
lukellmann Aug 19, 2022
e0d5a16
Fix after merge
lukellmann Aug 19, 2022
2025541
Forgot api dump for gateway
lukellmann Aug 19, 2022
7d002a6
Merge branch '0.8.x' into automod
lukellmann Aug 28, 2022
694a99d
Remove `AutoModerationRuleTriggerType.HarmfulLink`
lukellmann Aug 28, 2022
b9ca8c6
`@KordExperimental` for `Spam` and `MentionSpam` trigger types
lukellmann Aug 28, 2022
895d601
Allow `Timeout` actions for `MentionSpam` rules
lukellmann Aug 28, 2022
c1e7213
KDoc for `AutoModerationRuleKeywordPresetType`
lukellmann Aug 28, 2022
4a58bbe
KDoc for `AutoModerationActionType`
lukellmann Aug 28, 2022
c9cb627
Add missing removes in `removeKordData()`
lukellmann Aug 28, 2022
b1edada
Add `KordCacheBuilder.autoModerationRules`
lukellmann Aug 28, 2022
c7e548e
Add KDoc for automod methods in `EntitySupplier`
lukellmann Aug 28, 2022
9af4780
Adjust init blocks
lukellmann Aug 28, 2022
2ee9016
Rename user to member in `AutoModerationActionExecutionEvent`
lukellmann Aug 29, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
305 changes: 298 additions & 7 deletions common/api/common.api

Large diffs are not rendered by default.

10 changes: 10 additions & 0 deletions common/src/main/kotlin/entity/AuditLog.kt
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ public data class DiscordAuditLog(
val users: List<DiscordUser>,
@SerialName("audit_log_entries")
val auditLogEntries: List<DiscordAuditLogEntry>,
@SerialName("auto_moderation_rules")
val autoModerationRules: List<DiscordAutoModerationRule>,
val integrations: List<DiscordPartialIntegration>,
val threads: List<DiscordChannel>
)
Expand Down Expand Up @@ -486,6 +488,10 @@ public sealed class AuditLogEvent(public val value: Int) {
public object ThreadUpdate : AuditLogEvent(111)
public object ThreadDelete : AuditLogEvent(112)
public object ApplicationCommandPermissionUpdate : AuditLogEvent(121)
public object AutoModerationRuleCreate : AuditLogEvent(140)
public object AutoModerationRuleUpdate : AuditLogEvent(141)
public object AutoModerationRuleDelete : AuditLogEvent(142)
public object AutoModerationBlockMessage : AuditLogEvent(143)


internal object Serializer : KSerializer<AuditLogEvent> {
Expand Down Expand Up @@ -545,6 +551,10 @@ public sealed class AuditLogEvent(public val value: Int) {
111 -> ThreadUpdate
112 -> ThreadDelete
121 -> ApplicationCommandPermissionUpdate
140 -> AutoModerationRuleCreate
141 -> AutoModerationRuleUpdate
142 -> AutoModerationRuleDelete
143 -> AutoModerationBlockMessage
else -> Unknown(value)
}
}
Expand Down
232 changes: 232 additions & 0 deletions common/src/main/kotlin/entity/AutoModeration.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,232 @@
package dev.kord.common.entity

import dev.kord.common.annotation.KordExperimental
import dev.kord.common.entity.AutoModerationRuleTriggerType.Keyword
import dev.kord.common.entity.AutoModerationRuleTriggerType.MentionSpam
import dev.kord.common.entity.Permission.ModerateMembers
import dev.kord.common.entity.optional.Optional
import dev.kord.common.entity.optional.OptionalInt
import dev.kord.common.entity.optional.OptionalSnowflake
import dev.kord.common.serialization.DurationInSeconds
import kotlinx.serialization.KSerializer
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
import kotlinx.serialization.descriptors.PrimitiveKind
import kotlinx.serialization.descriptors.PrimitiveSerialDescriptor
import kotlinx.serialization.encoding.Decoder
import kotlinx.serialization.encoding.Encoder

@Serializable
public data class DiscordAutoModerationRule(
val id: Snowflake,
@SerialName("guild_id")
val guildId: Snowflake,
val name: String,
@SerialName("creator_id")
val creatorId: Snowflake,
@SerialName("event_type")
val eventType: AutoModerationRuleEventType,
@SerialName("trigger_type")
val triggerType: AutoModerationRuleTriggerType,
@SerialName("trigger_metadata")
val triggerMetadata: DiscordAutoModerationRuleTriggerMetadata,
val actions: List<DiscordAutoModerationAction>,
val enabled: Boolean,
@SerialName("exempt_roles")
val exemptRoles: List<Snowflake>,
@SerialName("exempt_channels")
val exemptChannels: List<Snowflake>,
)

/** Characterizes the type of content which can trigger the rule. */
@Serializable(with = AutoModerationRuleTriggerType.Serializer::class)
public sealed class AutoModerationRuleTriggerType(public val value: Int) {

final override fun equals(other: Any?): Boolean =
this === other || (other is AutoModerationRuleTriggerType && this.value == other.value)

final override fun hashCode(): Int = value


/** An unknown [AutoModerationRuleTriggerType]. */
public class Unknown(value: Int) : AutoModerationRuleTriggerType(value)

/** Check if content contains words from a user defined list of keywords. */
public object Keyword : AutoModerationRuleTriggerType(1)

/**
* Check if content represents generic spam.
*
* This [trigger type][AutoModerationRuleTriggerType] is not yet released, so it cannot be used in most servers.
*/
@KordExperimental
public object Spam : AutoModerationRuleTriggerType(3)

/** Check if content contains words from internal pre-defined wordsets. */
public object KeywordPreset : AutoModerationRuleTriggerType(4)

/**
* Check if content contains more mentions than allowed.
*
* This [trigger type][AutoModerationRuleTriggerType] is not yet released, so it cannot be used in most servers.
*/
@KordExperimental
public object MentionSpam : AutoModerationRuleTriggerType(5)


internal object Serializer : KSerializer<AutoModerationRuleTriggerType> {

override val descriptor =
PrimitiveSerialDescriptor("dev.kord.common.entity.AutoModerationRuleTriggerType", PrimitiveKind.INT)

override fun serialize(encoder: Encoder, value: AutoModerationRuleTriggerType) = encoder.encodeInt(value.value)

override fun deserialize(decoder: Decoder) = when (val value = decoder.decodeInt()) {
1 -> Keyword
3 -> Spam
4 -> KeywordPreset
5 -> MentionSpam
else -> Unknown(value)
}
}
}

@Serializable
public data class DiscordAutoModerationRuleTriggerMetadata(
@SerialName("keyword_filter")
val keywordFilter: Optional<List<String>> = Optional.Missing(),
val presets: Optional<List<AutoModerationRuleKeywordPresetType>> = Optional.Missing(),
@SerialName("allow_list")
val allowList: Optional<List<String>> = Optional.Missing(),
@SerialName("mention_total_limit")
val mentionTotalLimit: OptionalInt = OptionalInt.Missing,
)

/** An internally pre-defined wordset which will be searched for in content. */
@Serializable(with = AutoModerationRuleKeywordPresetType.Serializer::class)
public sealed class AutoModerationRuleKeywordPresetType(public val value: Int) {

final override fun equals(other: Any?): Boolean =
this === other || (other is AutoModerationRuleKeywordPresetType && this.value == other.value)

final override fun hashCode(): Int = value


/** An unknown [AutoModerationRuleKeywordPresetType]. */
public class Unknown(value: Int) : AutoModerationRuleKeywordPresetType(value)

/** Words that may be considered forms of swearing or cursing. */
public object Profanity : AutoModerationRuleKeywordPresetType(1)

/** Words that refer to sexually explicit behavior or activity. */
public object SexualContent : AutoModerationRuleKeywordPresetType(2)

/** Personal insults or words that may be considered hate speech. */
public object Slurs : AutoModerationRuleKeywordPresetType(3)


internal object Serializer : KSerializer<AutoModerationRuleKeywordPresetType> {

override val descriptor =
PrimitiveSerialDescriptor("dev.kord.common.entity.AutoModerationRuleKeywordPresetType", PrimitiveKind.INT)

override fun serialize(encoder: Encoder, value: AutoModerationRuleKeywordPresetType) =
encoder.encodeInt(value.value)

override fun deserialize(decoder: Decoder) = when (val value = decoder.decodeInt()) {
1 -> Profanity
2 -> SexualContent
3 -> Slurs
else -> Unknown(value)
}
}
}

/** Indicates in what event context a rule should be checked. */
@Serializable(with = AutoModerationRuleEventType.Serializer::class)
public sealed class AutoModerationRuleEventType(public val value: Int) {

final override fun equals(other: Any?): Boolean =
this === other || (other is AutoModerationRuleEventType && this.value == other.value)

final override fun hashCode(): Int = value


/** An unknown [AutoModerationRuleEventType]. */
public class Unknown(value: Int) : AutoModerationRuleEventType(value)

/** When a member sends or edits a message in the guild. */
public object MessageSend : AutoModerationRuleEventType(1)


internal object Serializer : KSerializer<AutoModerationRuleEventType> {

override val descriptor =
PrimitiveSerialDescriptor("dev.kord.common.entity.AutoModerationRuleEventType", PrimitiveKind.INT)

override fun serialize(encoder: Encoder, value: AutoModerationRuleEventType) = encoder.encodeInt(value.value)

override fun deserialize(decoder: Decoder) = when (val value = decoder.decodeInt()) {
1 -> MessageSend
else -> Unknown(value)
}
}
}

@Serializable
public data class DiscordAutoModerationAction(
val type: AutoModerationActionType,
val metadata: Optional<DiscordAutoModerationActionMetadata> = Optional.Missing(),
)

/** The type of action. */
@Serializable(with = AutoModerationActionType.Serializer::class)
public sealed class AutoModerationActionType(public val value: Int) {

final override fun equals(other: Any?): Boolean =
this === other || (other is AutoModerationActionType && this.value == other.value)

final override fun hashCode(): Int = value


/** An unknown [AutoModerationActionType]. */
public class Unknown(value: Int) : AutoModerationActionType(value)

/** Blocks the content of a message according to the rule. */
public object BlockMessage : AutoModerationActionType(1)

/** Logs user content to a specified channel. */
public object SendAlertMessage : AutoModerationActionType(2)

/**
* Timeout user for a specified duration.
*
* A [Timeout] action can only be set up for [Keyword] and [MentionSpam] rules. The [ModerateMembers] permission is
* required to use the [Timeout] action type.
*/
public object Timeout : AutoModerationActionType(3)


internal object Serializer : KSerializer<AutoModerationActionType> {

override val descriptor =
PrimitiveSerialDescriptor("dev.kord.common.entity.AutoModerationActionType", PrimitiveKind.INT)

override fun serialize(encoder: Encoder, value: AutoModerationActionType) = encoder.encodeInt(value.value)

override fun deserialize(decoder: Decoder) = when (val value = decoder.decodeInt()) {
1 -> BlockMessage
2 -> SendAlertMessage
3 -> Timeout
else -> Unknown(value)
}
}
}

@Serializable
public data class DiscordAutoModerationActionMetadata(
@SerialName("channel_id")
public val channelId: OptionalSnowflake = OptionalSnowflake.Missing,
@SerialName("duration_seconds")
public val durationSeconds: Optional<DurationInSeconds> = Optional.Missing(),
)
13 changes: 12 additions & 1 deletion common/src/main/kotlin/entity/DiscordGuild.kt
Original file line number Diff line number Diff line change
Expand Up @@ -183,13 +183,22 @@ public data class DiscordPartialGuild(
@Serializable(with = GuildFeature.Serializer::class)
public sealed class GuildFeature(public val value: String) {

override fun toString(): String = "GuildFeature(value=$value)"
final override fun equals(other: Any?): Boolean =
this === other || (other is GuildFeature && this.value == other.value)

final override fun hashCode(): Int = value.hashCode()
final override fun toString(): String = "GuildFeature(value=$value)"


/** An unknown [GuildFeature]. */
public class Unknown(value: String) : GuildFeature(value)

/** Guild has access to set an animated guild banner image. */
public object AnimatedBanner : GuildFeature("ANIMATED_BANNER")

/** Guild has set up auto moderation rules. */
public object AutoModeration : GuildFeature("AUTO_MODERATION")

/** Guild has access to set an invite splash background */
public object InviteSplash : GuildFeature("INVITE_SPLASH")

Expand Down Expand Up @@ -258,12 +267,14 @@ public sealed class GuildFeature(public val value: String) {
/** Guild is able to set role icons */
public object RoleIcons : GuildFeature("ROLE_ICONS")


internal object Serializer : KSerializer<GuildFeature> {
override val descriptor: SerialDescriptor
get() = PrimitiveSerialDescriptor("feature", PrimitiveKind.STRING)

override fun deserialize(decoder: Decoder): GuildFeature = when (val value = decoder.decodeString()) {
"ANIMATED_BANNER" -> AnimatedBanner
"AUTO_MODERATION" -> AutoModeration
"INVITE_SPLASH" -> InviteSplash
"VIP_REGIONS" -> VIPRegions
"VANITY_URL" -> VanityUrl
Expand Down
7 changes: 5 additions & 2 deletions common/src/main/kotlin/entity/DiscordMessage.kt
Original file line number Diff line number Diff line change
Expand Up @@ -775,10 +775,10 @@ public data class AllRemovedMessageReactions(
@Serializable(with = MessageType.MessageTypeSerializer::class)
public sealed class MessageType(public val code: Int) {

override fun equals(other: Any?): Boolean =
final override fun equals(other: Any?): Boolean =
this === other || (other is MessageType && this.code == other.code)

override fun hashCode(): Int = code
final override fun hashCode(): Int = code


/** The default code for unknown values. */
Expand Down Expand Up @@ -828,6 +828,8 @@ public sealed class MessageType(public val code: Int) {
public object ThreadStarterMessage : MessageType(21)
public object GuildInviteReminder : MessageType(22)
public object ContextMenuCommand : MessageType(23)
public object AutoModerationAction : MessageType(24)


internal object MessageTypeSerializer : KSerializer<MessageType> {

Expand Down Expand Up @@ -870,6 +872,7 @@ public sealed class MessageType(public val code: Int) {
ThreadStarterMessage,
GuildInviteReminder,
ContextMenuCommand,
AutoModerationAction,
)
}
}
Expand Down
Loading