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

Add Auto Moderation #647

merged 65 commits into from
Aug 31, 2022

Conversation

lukellmann
Copy link
Member

@lukellmann lukellmann commented Jul 6, 2022

This PR adds support for Discord's Auto Moderation feature.

The DSL for creating and editing AutoModerationRules looks like this:

// or other type instead of `Keyword`
// or rule.edit { ... }
val rule = guild.createKeywordAutoModerationRule("name") {

    // for `Keword` rules:
    // select one or multiple keywords that will trigger the rule
    keyword("cat")
    prefixKeyword("dog")
    suffixKeyword("owl")
    anywhereKeyword("fish")

    // for `KeywordPreset` rules:
    // select one or multiple presets
    preset(Profanity)
    // exempt substrings from triggering presets (optional)
    allowKeyword("hamster")

    // for `MentionSpam` rules:
    mentionLimit = 11

    // select one or multiple actions
    blockMessage()
    sendAlertMessage(channelId)
    timeout(42.minutes) // can only be used for `Keyword` and `MentionSpam` rules

    // optional
    eventType = MessageSend
    enabled = true
    exemptRole(roleId)
    exemptChannel(channelId)
}

relevant doc commits / PRs / pages:

@lukellmann lukellmann marked this pull request as draft July 6, 2022 00:29
@lukellmann lukellmann force-pushed the 0.8.x branch 2 times, most recently from a1bb076 to 1e6718a Compare August 17, 2022 12:47
# Conflicts:
#	core/src/main/kotlin/event/Event.kt
#	core/src/main/kotlin/gateway/handler/BaseGatewayEventHandler.kt
#	core/src/main/kotlin/gateway/handler/DefaultGatewayEventInterceptor.kt
#	core/src/main/kotlin/gateway/handler/InteractionEventHandler.kt
#	core/src/main/kotlin/gateway/handler/ThreadEventHandler.kt

public class AuditLogService(requestHandler: RequestHandler) : RestService(requestHandler) {

public suspend inline fun getAuditLogs(
guildId: Snowflake,
builder: AuditLogGetRequestBuilder.() -> Unit,
): DiscordAuditLog {
contract { callsInPlace(builder, EXACTLY_ONCE) }
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

doesn't have anything to do with automod but contract was missing

@@ -32,7 +32,7 @@ public interface Gateway : CoroutineScope {
public val events: SharedFlow<Event>

/**
* The duration between the last [Heartbeat] and [HeartbeatACK].
* The duration between the last [Heartbeat][Command.Heartbeat] and [HeartbeatACK].
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

doesn't have anything to do with automod but link was wrong

Comment on lines -93 to +94
"Identify(token=hunter2,properties=$properties,compress=$compress,largeThreshold=$largeThreshold," +
"shard=$shard,presence=$presence"
"Identify(token=hunter2, properties=$properties, compress=$compress, largeThreshold=$largeThreshold, " +
"shard=$shard, presence=$presence, intents=$intents)"
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

doesn't have anything to do with automod

override fun toString(): String = "Resume(token=hunter2,sessionId=$sessionId,sequenceNumber:$sequenceNumber)"
override fun toString(): String = "Resume(token=hunter2, sessionId=$sessionId, sequenceNumber=$sequenceNumber)"
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

doesn't have anything to do with automod

Comment on lines -69 to +76
public abstract interface class dev/kord/rest/builder/AuditRequestBuilder : dev/kord/rest/builder/RequestBuilder {
public abstract interface class dev/kord/rest/builder/AuditBuilder {
public abstract fun getReason ()Ljava/lang/String;
public abstract fun setReason (Ljava/lang/String;)V
}

public abstract interface class dev/kord/rest/builder/AuditRequestBuilder : dev/kord/rest/builder/AuditBuilder, dev/kord/rest/builder/RequestBuilder {
}

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a binary compatible change, AuditRequestBuilder doesn't lose or get new members (they are just inherited now).

Comment on lines 5 to +19
@KordDsl
public interface RequestBuilder<T> {
public fun toRequest(): T
}

@KordDsl
public interface AuditRequestBuilder<T> : RequestBuilder<T> {
public interface AuditBuilder {
/**
* The reason for this request, this will be displayed in the audit log.
*/
public var reason: String?
}

@KordDsl
public interface RequestBuilder<out T : Any> {
public fun toRequest(): T
}

@KordDsl
public interface AuditRequestBuilder<out T : Any> : AuditBuilder, RequestBuilder<T>
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This allows supertypes of create and modify builders to implement AuditBuilder. They can't implement AuditRequestBuilder since create and modify builders usually have different return types for toRequest.

Comment on lines -29 to +34
public val description: DataDescription<UserData, Snowflake>
get() = description(UserData::id) {
link(UserData::id to MemberData::userId)
link(UserData::id to WebhookData::nullableUserId)
link(UserData::id to VoiceStateData::userId)
link(UserData::id to PresenceData::userId)
}
public val description: DataDescription<UserData, Snowflake> = description(UserData::id) {
link(UserData::id to MemberData::userId)
link(UserData::id to WebhookData::nullableUserId)
link(UserData::id to VoiceStateData::userId)
link(UserData::id to PresenceData::userId)
}
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

removed the getter and replaced it with an initializer

Comment on lines +38 to +47
query<ThreadMemberData>().remove()
query<MessageData>().remove()
query<EmojiData>().remove()
query<WebhookData>().remove()
query<PresenceData>().remove()
query<VoiceStateData>().remove()
query<ApplicationCommandData>().remove()
query<GuildApplicationCommandPermissionsData>().remove()
query<StickerPackData>().remove()
query<StickerData>().remove()
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added these because they were missing, is this right?

Comment on lines +86 to +88
override fun equals(other: Any?): Boolean
override fun hashCode(): Int
override fun toString(): String
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this forces overrides in subtypes

/**
* The Gateway that spawned this event.
*/
public val gateway: Gateway get() = kord.gateway.gateways.getValue(shard)

public val kord: Kord
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

KordObject has this property too

@OptIn(FlowPreview::class)
override val events: Flow<ShardEvent> = gateways.entries.asFlow()
override val events: Flow<ShardEvent> = gateways.entries
.map { (shard, gateway) -> gateway.events.map { ShardEvent(it, gateway, shard) } }
.flattenMerge(gateways.size.coerceAtLeast(1))
.merge()
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

merge() has no limit on concurrency (we used the max with flattenMerge before anyway) and isn't marked with @FlowPreview

Comment on lines -10196 to 10659
public abstract interface class dev/kord/core/event/Event {
public abstract interface class dev/kord/core/event/Event : dev/kord/core/KordObject {
public abstract fun getCustomContext ()Ljava/lang/Object;
public abstract fun getGateway ()Ldev/kord/gateway/Gateway;
public abstract fun getKord ()Ldev/kord/core/Kord;
public abstract fun getShard ()I
}
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a binary compatible change, Event doesn't lose or get new members (getKord() is just inherited now).

@lukellmann lukellmann marked this pull request as ready for review August 29, 2022 00:23
@lukellmann
Copy link
Member Author

This should now be ready for review 🥳

@lukellmann lukellmann requested a review from HopeBaron August 29, 2022 00:24
@HopeBaron
Copy link
Member

The overall PR looks good; tho it could've been easier if we used smaller PRs this would've helped splitting tasks to contributors as well

Great job tho 👍

@lukellmann
Copy link
Member Author

The overall PR looks good; tho it could've been easier if we used smaller PRs this would've helped splitting tasks to contributors as well

Yeah, didn't anticipate that it would be this big.

Copy link
Member

@HopeBaron HopeBaron left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would be nice to have some tests before we merge this

@lukellmann
Copy link
Member Author

What kind of tests are you thinking of? Automated tests with the api are hard in this case as automod is only available in community guilds (I did some manual api tests).

@HopeBaron
Copy link
Member

This is enough then

@HopeBaron HopeBaron merged commit a2bfc1f into 0.8.x Aug 31, 2022
@lukellmann lukellmann deleted the automod branch September 12, 2022 13:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants