Skip to content

Commit

Permalink
Implement Stage events (#421)
Browse files Browse the repository at this point in the history
* Add common entities

* Add gateway events

* Add low-level rest requests

* Add request builders

* Update existing entities

* Add core representation

* Add proper event handling
- Fix caching

* Add new AuditLog changes

* Update GuildScheduledEvent models to new PR changes

* Update rest endpoints

* Add support for event members
  • Loading branch information
DRSchlaubi committed Nov 25, 2021
1 parent 93c6366 commit 4f30665
Show file tree
Hide file tree
Showing 35 changed files with 1,801 additions and 98 deletions.
57 changes: 51 additions & 6 deletions common/src/main/kotlin/entity/AuditLog.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,25 @@ package dev.kord.common.entity
import dev.kord.common.entity.optional.Optional
import dev.kord.common.entity.optional.OptionalSnowflake
import dev.kord.common.entity.optional.orEmpty
import kotlinx.serialization.*
import kotlinx.serialization.Contextual
import kotlinx.serialization.KSerializer
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
import kotlinx.serialization.SerializationException
import kotlinx.serialization.builtins.serializer
import kotlinx.serialization.descriptors.*
import kotlinx.serialization.encoding.*
import kotlinx.serialization.descriptors.PrimitiveKind
import kotlinx.serialization.descriptors.PrimitiveSerialDescriptor
import kotlinx.serialization.descriptors.SerialDescriptor
import kotlinx.serialization.descriptors.buildClassSerialDescriptor
import kotlinx.serialization.descriptors.element
import kotlinx.serialization.encoding.CompositeDecoder
import kotlinx.serialization.encoding.Decoder
import kotlinx.serialization.encoding.Encoder
import kotlinx.serialization.encoding.decodeStructure
import kotlinx.serialization.encoding.encodeStructure
import kotlinx.serialization.json.Json
import kotlinx.serialization.json.JsonElement
import kotlinx.serialization.serializer
import dev.kord.common.Color as CommonColor
import dev.kord.common.entity.DefaultMessageNotificationLevel as CommonDefaultMessageNotificationLevel
import dev.kord.common.entity.ExplicitContentFilter as CommonExplicitContentFilter
Expand Down Expand Up @@ -92,7 +105,7 @@ data class AuditLogEntryOptionalInfo(
2020-11-12 field is described as present but is in fact optional
*/
@SerialName("role_name")
val roleName: Optional<String> = Optional.Missing(),
val roleName: Optional<String> = Optional.Missing()
)

@Serializable(with = AuditLogChange.Serializer::class)
Expand Down Expand Up @@ -263,6 +276,9 @@ sealed class AuditLogChangeKey<T>(val name: String, val serializer: KSerializer<
@SerialName("inviter_id")
object InviterId : AuditLogChangeKey<Snowflake>("inviter_id", serializer())

@SerialName("location")
object Location : AuditLogChangeKey<String>("location", serializer())

@SerialName("max_uses")
object MaxUses : AuditLogChangeKey<Int>("max_uses", serializer())

Expand Down Expand Up @@ -315,7 +331,26 @@ sealed class AuditLogChangeKey<T>(val name: String, val serializer: KSerializer<
object AutoArchiveDuration : AuditLogChangeKey<ArchiveDuration>("auto_archive_duration", serializer())

@SerialName("default_auto_archive_duration")
object DefaultAutoArchiveDuration : AuditLogChangeKey<ArchiveDuration>("default_auto_archive_duration", serializer())
object DefaultAutoArchiveDuration :
AuditLogChangeKey<ArchiveDuration>("default_auto_archive_duration", serializer())

@SerialName("entity_type")
object EntityType : AuditLogChangeKey<ScheduledEntityType>(
"entity_type",
serializer()
)

@SerialName("status")
object Status : AuditLogChangeKey<GuildScheduledEventStatus>(
"status",
serializer()
)

@SerialName("sku_ids")
object SkuIds : AuditLogChangeKey<List<Snowflake>>(
"sku_ids",
serializer()
)

internal class Serializer<T>(val type: KSerializer<T>) : KSerializer<AuditLogChangeKey<T>> {
override val descriptor: SerialDescriptor
Expand Down Expand Up @@ -363,6 +398,7 @@ sealed class AuditLogChangeKey<T>(val name: String, val serializer: KSerializer<
"code" -> Code
"channel_id" -> ChannelId
"inviter_id" -> InviterId
"location" -> Location
"max_uses" -> MaxUses
"uses" -> Uses
"max_age" -> MaxAges
Expand All @@ -381,6 +417,9 @@ sealed class AuditLogChangeKey<T>(val name: String, val serializer: KSerializer<
"archived" -> Archived
"auto_archive_duration" -> AutoArchiveDuration
"default_auto_archive_duration" -> DefaultAutoArchiveDuration
"entity_type" -> EntityType
"status" -> Status
"sku_ids" -> SkuIds
else -> Unknown(name)
} as AuditLogChangeKey<T>
}
Expand Down Expand Up @@ -431,6 +470,9 @@ sealed class AuditLogEvent(val value: Int) {
object StickerCreate : AuditLogEvent(90)
object StickerUpdate : AuditLogEvent(91)
object StickerDelete : AuditLogEvent(92)
object GuildScheduledEventCreate : AuditLogEvent(100)
object GuildScheduledEventUpdate : AuditLogEvent(101)
object GuildScheduledEventDelete : AuditLogEvent(102)
object ThreadCreate : AuditLogEvent(110)
object ThreadUpdate : AuditLogEvent(111)
object ThreadDelete : AuditLogEvent(112)
Expand Down Expand Up @@ -486,11 +528,14 @@ sealed class AuditLogEvent(val value: Int) {
90 -> StickerCreate
91 -> StickerUpdate
92 -> StickerDelete
100 -> GuildScheduledEventCreate
101 -> GuildScheduledEventUpdate
102 -> GuildScheduledEventDelete
110 -> ThreadCreate
111 -> ThreadUpdate
112 -> ThreadDelete
else -> Unknown(value)
}
}

}
}
2 changes: 1 addition & 1 deletion common/src/main/kotlin/entity/DiscordGuild.kt
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ data class DiscordUnavailableGuild(
)

/**
* A representation of a [Discord Guild structure](https://discord.com/developers/docs/resources/guild#guild-object
* A representation of a [Discord Guild structure](https://discord.com/developers/docs/resources/guild#guild-object)
*
* @param id The guild id.
* @param name The guild name (2-100 characters, excluding trailing and leading whitespace)
Expand Down
124 changes: 124 additions & 0 deletions common/src/main/kotlin/entity/DiscordGuildScheduledEvent.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
package dev.kord.common.entity

import dev.kord.common.entity.optional.Optional
import dev.kord.common.entity.optional.OptionalSnowflake
import kotlinx.datetime.Instant
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.descriptors.SerialDescriptor
import kotlinx.serialization.encoding.Decoder
import kotlinx.serialization.encoding.Encoder

/**
* Representation of a [Guild Scheduled Event Structure](ADD LINK).
*
* @property id the id of the event
* @property guildId the id of the guild the event is on
* @property channelId the id of the channel the event is in
* @property creatorId the id of the user that created the scheduled event
* @property name the name of the event
* @property description the description of the event
* @property scheduledStartTime the [Instant] in which the event will start
* @property scheduledEndTime the [Instant] in which the event wil stop, if any
* @property privacyLevel the [event privacy level][StageInstancePrivacyLevel]
* @property status the [event status][GuildScheduledEventStatus]
* @property entityType the [ScheduledEntityType] of the event
* @property entityId entity id
* @property entityMetadata [metadata][GuildScheduledEventEntityMetadata] for the event
* @property creator the [user][DiscordUser] that created the scheduled event
* @property userCount users subscribed to the event
*/
@Serializable
data class DiscordGuildScheduledEvent(
val id: Snowflake,
@SerialName("guild_id")
val guildId: Snowflake,
val channelId: Snowflake?,
@SerialName("creator_id")
val creatorId: OptionalSnowflake,
val name: String,
val description: Optional<String> = Optional.Missing(),
@SerialName("scheduled_start_time")
val scheduledStartTime: Instant,
@SerialName("scheduled_end_time")
val scheduledEndTime: Instant?,
@SerialName("privacy_level")
val privacyLevel: StageInstancePrivacyLevel,
val status: GuildScheduledEventStatus,
@SerialName("entity_type")
val entityType: ScheduledEntityType,
@SerialName("entity_id")
val entityId: Snowflake?,
@SerialName("entity_metadata")
val entityMetadata: GuildScheduledEventEntityMetadata,
val creator: Optional<DiscordUser>,
@SerialName("user_count")
val userCount: Int
)

@Serializable(with = ScheduledEntityType.Serializer::class)
sealed class ScheduledEntityType(val value: Int) {
object None : ScheduledEntityType(0)
object StageInstance : ScheduledEntityType(1)
object Voice : ScheduledEntityType(2)
object External : ScheduledEntityType(3)
class Unknown(value: Int) : ScheduledEntityType(value)

companion object Serializer : KSerializer<ScheduledEntityType> {
override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor("ScheduledEntityType", PrimitiveKind.INT)

override fun deserialize(decoder: Decoder): ScheduledEntityType {
return when (val value = decoder.decodeInt()) {
0 -> None
1 -> StageInstance
2 -> Voice
3 -> External
else -> Unknown(value)
}
}

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

}
}

@Serializable(with = GuildScheduledEventStatus.Serializer::class)
sealed class GuildScheduledEventStatus(val value: Int) {
object Scheduled : GuildScheduledEventStatus(1)
object Active : GuildScheduledEventStatus(2)
object Completed : GuildScheduledEventStatus(3)
object Cancelled : GuildScheduledEventStatus(4)
class Unknown(value: Int) : GuildScheduledEventStatus(value)

companion object Serializer : KSerializer<GuildScheduledEventStatus> {
override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor("GuildScheduledEventStatus", PrimitiveKind.INT)

override fun deserialize(decoder: Decoder): GuildScheduledEventStatus {
return when (val value = decoder.decodeInt()) {
1 -> Scheduled
2 -> Active
3 -> Completed
4 -> Cancelled
else -> Unknown(value)
}
}

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

}
}

/**
* Entity metadata for [DiscordGuildScheduledEvent].
*
* @property speakerIds the speakers of the stage channel
* @property location location of the event
*/
@Serializable
data class GuildScheduledEventEntityMetadata(
val speakerIds: Optional<List<Snowflake>> = Optional.Missing(),
val location: Optional<String> = Optional.Missing()
)
9 changes: 8 additions & 1 deletion common/src/main/kotlin/entity/DiscordInvite.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package dev.kord.common.entity

import dev.kord.common.entity.optional.Optional
import dev.kord.common.entity.optional.OptionalInt
import kotlinx.datetime.Instant
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable

Expand All @@ -19,6 +20,12 @@ data class DiscordInvite(
val approximatePresenceCount: OptionalInt = OptionalInt.Missing,
@SerialName("approximate_member_count")
val approximateMemberCount: OptionalInt = OptionalInt.Missing,
@SerialName("expires_at")
val expiresAt: Optional<Instant?> = Optional.Missing(),
@SerialName("stage_instance")
val stageInstance: Optional<DiscordStageInstance> = Optional.Missing(),
@SerialName("guild_scheduled_event")
val guildScheduledEvent: Optional<DiscordGuildScheduledEvent> = Optional.Missing(),
)

@Serializable
Expand All @@ -42,4 +49,4 @@ data class DiscordInviteMetadata(
val temporary: Boolean,
@SerialName("created_at")
val createdAt: String,
)
)
50 changes: 49 additions & 1 deletion common/src/main/kotlin/entity/DiscordStageInstance.kt
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@
package dev.kord.common.entity

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.descriptors.SerialDescriptor
import kotlinx.serialization.encoding.Decoder
import kotlinx.serialization.encoding.Encoder


/**
Expand All @@ -11,6 +17,8 @@ import kotlinx.serialization.Serializable
* @property guildId The guild id of the associated Stage channel
* @property channelId The id of the associated Stage channel
* @property topic The topic of the Stage instance (1-120 characters)
* @property privacyLevel The [privacy level][StageInstancePrivacyLevel] of the Stage instance
* @property discoverableDisabled Whether or not Stage Discovery is disabled
*/
@Serializable
data class DiscordStageInstance(
Expand All @@ -19,5 +27,45 @@ data class DiscordStageInstance(
val guildId: Snowflake,
@SerialName("channel_id")
val channelId: Snowflake,
val topic: String
val topic: String,
@SerialName("privacy_level")
val privacyLevel: StageInstancePrivacyLevel,
@SerialName("discoverable_disabled")
val discoverableDisabled: Boolean
)

/**
* Privacy level of a [DiscordStageInstance].
*/
@Serializable(with = StageInstancePrivacyLevel.Serializer::class)
sealed class StageInstancePrivacyLevel(val value: Int) {
/**
* The Stage instance is visible publicly, such as on Stage Discovery.
*/
object Public : StageInstancePrivacyLevel(1)

/**
* The Stage instance is visible to only guild members.
*/
object GuildOnly : StageInstancePrivacyLevel(2)

/**
* An unknown privacy level.
*/
class Unknown(value: Int) : StageInstancePrivacyLevel(value)

companion object Serializer : KSerializer<StageInstancePrivacyLevel> {
override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor("StageInstancePrivacyLevel", PrimitiveKind.INT)

override fun deserialize(decoder: Decoder): StageInstancePrivacyLevel {
return when (val value = decoder.decodeInt()) {
1 -> Public
2 -> GuildOnly
else -> Unknown(value)
}
}

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

}
}
6 changes: 5 additions & 1 deletion common/src/main/kotlin/entity/DiscordUser.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package dev.kord.common.entity

import dev.kord.common.entity.optional.Optional
import dev.kord.common.entity.optional.OptionalBoolean
import kotlinx.serialization.ExperimentalSerializationApi
import kotlinx.serialization.KSerializer
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
Expand All @@ -10,6 +11,7 @@ import kotlinx.serialization.descriptors.PrimitiveSerialDescriptor
import kotlinx.serialization.descriptors.SerialDescriptor
import kotlinx.serialization.encoding.Decoder
import kotlinx.serialization.encoding.Encoder
import kotlinx.serialization.json.JsonNames
import kotlin.contracts.ExperimentalContracts
import kotlin.contracts.InvocationKind
import kotlin.contracts.contract
Expand Down Expand Up @@ -72,6 +74,7 @@ data class DiscordUser(
* @param premiumType The type of Nitro subscription on a user's account.
* @param publicFlags The public flags on a user's account. Unlike [flags], these **are** visible ot other users.
*/
@OptIn(ExperimentalSerializationApi::class)
@Serializable
data class DiscordOptionallyMemberUser(
val id: Snowflake,
Expand All @@ -90,6 +93,7 @@ data class DiscordOptionallyMemberUser(
val premiumType: Optional<UserPremium> = Optional.Missing(),
@SerialName("public_flags")
val publicFlags: Optional<UserFlags> = Optional.Missing(),
@JsonNames("member", "guild_member")
val member: Optional<DiscordGuildMember> = Optional.Missing(),
)

Expand Down Expand Up @@ -207,4 +211,4 @@ sealed class UserPremium(val value: Int) {
encoder.encodeInt(value.value)
}
}
}
}
Loading

0 comments on commit 4f30665

Please sign in to comment.