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 forum channels #592

Closed
wants to merge 19 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
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
68 changes: 63 additions & 5 deletions common/api/common.api

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,11 @@ public sealed class ChannelType(
*/
public object GuildDirectory : ChannelType(14)

/**
* A channel that can only contain threads.
*/
public object GuildForum : ChannelType(15)

/**
* A channel in which game developers can sell their game on Discord.
*
Expand Down Expand Up @@ -139,6 +144,7 @@ public sealed class ChannelType(
12 -> PrivateThread
13 -> GuildStageVoice
14 -> GuildDirectory
15 -> GuildForum
else -> Unknown(value)
}
}
Expand All @@ -161,6 +167,7 @@ public sealed class ChannelType(
PrivateThread,
GuildStageVoice,
GuildDirectory,
GuildForum,
)
}

Expand Down
103 changes: 101 additions & 2 deletions common/src/main/kotlin/entity/DiscordChannel.kt
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
kDoc = "The channel in a [hub](https://support.discord.com/hc/en-us/articles/4406046651927-Discord-" +
"Student-Hubs-FAQ) containing the listed servers.",
),
Entry("GuildForum", intValue = 15, kDoc = "A channel that can only contain threads."),
],
deprecatedEntries = [
Entry(
Expand Down Expand Up @@ -78,7 +79,12 @@ import kotlinx.serialization.descriptors.SerialDescriptor
import kotlinx.serialization.encoding.Decoder
import kotlinx.serialization.encoding.Encoder
import kotlin.DeprecationLevel.ERROR
import kotlin.contracts.InvocationKind
import kotlin.contracts.contract
import kotlin.time.Duration
import dev.kord.common.entity.ChannelType.GuildForum
import kotlinx.serialization.descriptors.PrimitiveKind
import kotlinx.serialization.descriptors.PrimitiveSerialDescriptor
import kotlin.time.Duration.Companion.minutes

/**
Expand All @@ -92,7 +98,8 @@ import kotlin.time.Duration.Companion.minutes
* @param name The name of the channel.
* @param topic The channel topic.
* @param nsfw Whether the channel is nsfw.
* @param lastMessageId The id of the last message sent in this channel (may not point to an existing or valid message).
* @param lastMessageId The id of the last message sent in this channel (or thread for
* [GuildForum][ChannelType.GuildForum] channels) (may not point to an existing or valid message or thread).
* @param bitrate The bitrate (in bits) of the voice channel.
* @param userLimit The user limit of the voice channel.
* @param rateLimitPerUser amount of time a user has to wait before sending another message; bots,
Expand All @@ -103,6 +110,7 @@ import kotlin.time.Duration.Companion.minutes
* @param applicationId The application id of the group DM creator if it is bot-created.
* @param parentId The id of the parent category for a channel.
* @param lastPinTimestamp When the last pinned message was pinned.
* @param flags The channel flags.
*/
@Serializable
public data class DiscordChannel(
Expand Down Expand Up @@ -146,9 +154,100 @@ public data class DiscordChannel(
val threadMetadata: Optional<DiscordThreadMetadata> = Optional.Missing(),
@SerialName("default_auto_archive_duration")
val defaultAutoArchiveDuration: Optional<ArchiveDuration> = Optional.Missing(),
val member: Optional<DiscordThreadMember> = Optional.Missing()
val member: Optional<DiscordThreadMember> = Optional.Missing(),
val flags: Optional<ChannelFlags> = Optional.Missing(),
)

public enum class ChannelFlag(public val code: Int) {

/** This thread is pinned to the top of its parent [GuildForum] channel. */
Pinned(1 shl 1),

/** Whether a tag is required to be specified when creating a thread in a [GuildForum] channel. */
RequireTag(1 shl 4);


public operator fun plus(flag: ChannelFlag): ChannelFlags = ChannelFlags(this.code or flag.code)

public operator fun plus(flags: ChannelFlags): ChannelFlags = flags + this
}

@Serializable(with = ChannelFlags.Serializer::class)
public data class ChannelFlags internal constructor(public val code: Int) {

public val flags: List<ChannelFlag> get() = ChannelFlag.values().filter { it in this }

public operator fun contains(flag: ChannelFlag): Boolean = this.code and flag.code == flag.code

public operator fun contains(flags: ChannelFlags): Boolean = this.code and flags.code == flags.code

public operator fun plus(flag: ChannelFlag): ChannelFlags = ChannelFlags(this.code or flag.code)

public operator fun plus(flags: ChannelFlags): ChannelFlags = ChannelFlags(this.code or flags.code)

public operator fun minus(flag: ChannelFlag): ChannelFlags = ChannelFlags(this.code and flag.code.inv())

public operator fun minus(flags: ChannelFlags): ChannelFlags = ChannelFlags(this.code and flags.code.inv())


public inline fun copy(builder: Builder.() -> Unit): ChannelFlags {
contract { callsInPlace(builder, InvocationKind.EXACTLY_ONCE) }
return Builder(code).apply(builder).build()
}


internal object Serializer : KSerializer<ChannelFlags> {

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

override fun deserialize(decoder: Decoder): ChannelFlags {
val code = decoder.decodeInt()
return ChannelFlags(code)
}

override fun serialize(encoder: Encoder, value: ChannelFlags) {
encoder.encodeInt(value.code)
}
}


public class Builder(private var code: Int = 0) {

public operator fun ChannelFlag.unaryPlus() {
[email protected] = [email protected] or this.code
}

public operator fun ChannelFlags.unaryPlus() {
[email protected] = [email protected] or this.code
}

public operator fun ChannelFlag.unaryMinus() {
[email protected] = [email protected] and this.code.inv()
}

public operator fun ChannelFlags.unaryMinus() {
[email protected] = [email protected] and this.code.inv()
}

public fun build(): ChannelFlags = ChannelFlags(code)
}
}

public inline fun ChannelFlags(builder: ChannelFlags.Builder.() -> Unit): ChannelFlags {
contract { callsInPlace(builder, InvocationKind.EXACTLY_ONCE) }
return ChannelFlags.Builder().apply(builder).build()
}

public fun ChannelFlags(vararg flags: ChannelFlag): ChannelFlags = ChannelFlags { flags.forEach { +it } }

public fun ChannelFlags(vararg flags: ChannelFlags): ChannelFlags = ChannelFlags { flags.forEach { +it } }

public fun ChannelFlags(flags: Iterable<ChannelFlag>): ChannelFlags = ChannelFlags { flags.forEach { +it } }

@JvmName("ChannelFlags0")
public fun ChannelFlags(flags: Iterable<ChannelFlags>): ChannelFlags = ChannelFlags { flags.forEach { +it } }

@Serializable
public data class Overwrite(
val id: Snowflake,
Expand Down
5 changes: 4 additions & 1 deletion common/src/main/kotlin/entity/Permission.kt
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,10 @@ public sealed class Permission(public val code: DiscordBitSet) {
*/
public object ViewChannel : Permission(1L shl 10)

/** Allows for sending messages in a channel (does not allow sending messages in threads). */
/**
* Allows for sending messages in a channel and creating threads in a forum (does not allow sending messages in
* threads).
*/
public object SendMessages : Permission(1L shl 11)

/** Allows for sending of `/tts` messages. */
Expand Down
Loading