Skip to content

Commit

Permalink
Revamp stickers (#473)
Browse files Browse the repository at this point in the history
* Fix collection in 1.6.0

* revamp message sticker model

* Add sticker endpoints and services

* Add core representation for Stickers

* implement suppliers for stickers and cache

* allow Stickers to be have a strategy

* Introduce a GuildSticker with behavior

* Fix compiler errors

* Fix compiler errors, again

* Fix modeling of description to packId
  • Loading branch information
HopeBaron authored Jan 12, 2022
1 parent f7e84be commit 3b9c5f5
Show file tree
Hide file tree
Showing 23 changed files with 614 additions and 241 deletions.
41 changes: 33 additions & 8 deletions common/src/main/kotlin/entity/DiscordMessage.kt
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,8 @@ data class DiscordMessage(
@SerialName("message_reference")
val messageReference: Optional<DiscordMessageReference> = Optional.Missing(),
val flags: Optional<MessageFlags> = Optional.Missing(),
val stickers: Optional<List<DiscordMessageSticker>> = Optional.Missing(),
@SerialName("sticker_items")
val stickers: Optional<List<DiscordStickerItem>> = Optional.Missing(),
@SerialName("referenced_message")
val referencedMessage: Optional<DiscordMessage?> = Optional.Missing(),
/*
Expand All @@ -126,16 +127,40 @@ data class DiscordMessage(
data class DiscordMessageSticker(
val id: Snowflake,
@SerialName("pack_id")
val packId: Snowflake,
val packId: OptionalSnowflake = OptionalSnowflake.Missing,
val name: String,
val description: String,
val description: String?,
val tags: Optional<String> = Optional.Missing(),
val asset: String,
@SerialName("preview_asset")
// https://github.com/kordlib/kord/issues/207
val previewAsset: Optional<String?> = Optional.Missing(),
@SerialName("format_type")
val formatType: MessageStickerType,
val available: OptionalBoolean = OptionalBoolean.Missing,
@SerialName("guild_id")
val guildId: OptionalSnowflake = OptionalSnowflake.Missing,
val user: Optional<DiscordUser> = Optional.Missing(),
@SerialName("sort_value")
val sortValue: OptionalInt = OptionalInt.Missing
)
@Serializable
data class DiscordStickerPack(
val id: Snowflake,
val stickers: List<DiscordMessageSticker>,
val name: String,
@SerialName("sku_id")
val skuId: Snowflake,
@SerialName("cover_sticker_id")
val coverStickerId: OptionalSnowflake = OptionalSnowflake.Missing,
val description: String,
@SerialName("banner_asset_id")
val bannerAssetId: Snowflake

)

@Serializable
data class DiscordStickerItem(
val id: Snowflake,
val name: String,
@SerialName("format_type")
val formatType: MessageStickerType
)

@Serializable(with = MessageStickerType.Serializer::class)
Expand Down Expand Up @@ -248,7 +273,7 @@ data class DiscordPartialMessage(
@SerialName("message_reference")
val messageReference: Optional<DiscordMessageReference> = Optional.Missing(),
val flags: Optional<MessageFlags> = Optional.Missing(),
val stickers: Optional<List<DiscordMessageSticker>> = Optional.Missing(),
val stickers: Optional<List<DiscordStickerItem>> = Optional.Missing(),
@SerialName("referenced_message")
val referencedMessage: Optional<DiscordMessage?> = Optional.Missing(),
val interaction: Optional<DiscordMessageInteraction> = Optional.Missing(),
Expand Down
16 changes: 7 additions & 9 deletions core/src/main/kotlin/Kord.kt
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,7 @@ import dev.kord.core.builder.kord.KordRestOnlyBuilder
import dev.kord.core.cache.data.ApplicationCommandData
import dev.kord.core.cache.data.GuildData
import dev.kord.core.cache.data.UserData
import dev.kord.core.entity.ApplicationInfo
import dev.kord.core.entity.Guild
import dev.kord.core.entity.GuildPreview
import dev.kord.core.entity.Invite
import dev.kord.core.entity.KordEntity
import dev.kord.core.entity.Region
import dev.kord.core.entity.Strategizable
import dev.kord.core.entity.User
import dev.kord.core.entity.Webhook
import dev.kord.core.entity.*
import dev.kord.core.entity.application.GlobalApplicationCommand
import dev.kord.core.entity.application.GlobalChatInputCommand
import dev.kord.core.entity.application.GlobalMessageCommand
Expand Down Expand Up @@ -106,6 +98,9 @@ public class Kord(
public val globalCommands: Flow<GlobalApplicationCommand>
get() = defaultSupplier.getGlobalApplicationCommands(resources.applicationId)

public val nitroStickerPacks: Flow<StickerPack>
get() = defaultSupplier.getNitroStickerPacks()


/**
* The default supplier, obtained through Kord's [resources] and configured through [KordBuilder.defaultStrategy].
Expand Down Expand Up @@ -368,6 +363,9 @@ public class Kord(
): Invite? =
EntitySupplyStrategy.rest.supply(this).getInviteOrNull(code, withCounts)

public suspend fun getSticker(id: Snowflake): Sticker = defaultSupplier.getSticker(id)



/**
* Requests to edit the presence of the bot user configured by the [builder].
Expand Down
62 changes: 21 additions & 41 deletions core/src/main/kotlin/behavior/GuildBehavior.kt
Original file line number Diff line number Diff line change
Expand Up @@ -11,42 +11,10 @@ import dev.kord.common.entity.optional.Optional
import dev.kord.common.entity.optional.unwrap
import dev.kord.common.exception.RequestException
import dev.kord.core.Kord
import dev.kord.core.cache.data.ChannelData
import dev.kord.core.cache.data.EmojiData
import dev.kord.core.cache.data.GuildData
import dev.kord.core.cache.data.GuildScheduledEventData
import dev.kord.core.cache.data.GuildWidgetData
import dev.kord.core.cache.data.IntegrationData
import dev.kord.core.cache.data.InviteData
import dev.kord.core.cache.data.MemberData
import dev.kord.core.cache.data.PresenceData
import dev.kord.core.cache.data.RoleData
import dev.kord.core.cache.data.UserData
import dev.kord.core.cache.data.VoiceStateData
import dev.kord.core.cache.data.WelcomeScreenData
import dev.kord.core.cache.data.*
import dev.kord.core.cache.idEq
import dev.kord.core.catchDiscordError
import dev.kord.core.entity.AuditLogEntry
import dev.kord.core.entity.Ban
import dev.kord.core.entity.Guild
import dev.kord.core.entity.GuildEmoji
import dev.kord.core.entity.GuildPreview
import dev.kord.core.entity.GuildScheduledEvent
import dev.kord.core.entity.GuildWidget
import dev.kord.core.entity.Integration
import dev.kord.core.entity.Invite
import dev.kord.core.entity.KordEntity
import dev.kord.core.entity.Member
import dev.kord.core.entity.PartialGuild
import dev.kord.core.entity.Presence
import dev.kord.core.entity.Region
import dev.kord.core.entity.Role
import dev.kord.core.entity.Strategizable
import dev.kord.core.entity.Template
import dev.kord.core.entity.User
import dev.kord.core.entity.VoiceState
import dev.kord.core.entity.Webhook
import dev.kord.core.entity.WelcomeScreen
import dev.kord.core.entity.*
import dev.kord.core.entity.application.GuildApplicationCommand
import dev.kord.core.entity.application.GuildChatInputCommand
import dev.kord.core.entity.application.GuildMessageCommand
Expand All @@ -62,19 +30,15 @@ import dev.kord.core.entity.channel.thread.ThreadChannel
import dev.kord.core.event.guild.MembersChunkEvent
import dev.kord.core.exception.EntityNotFoundException
import dev.kord.core.sorted
import dev.kord.core.supplier.EntitySupplier
import dev.kord.core.supplier.EntitySupplyStrategy
import dev.kord.core.supplier.*
import dev.kord.core.supplier.EntitySupplyStrategy.Companion.rest
import dev.kord.core.supplier.getChannelOf
import dev.kord.core.supplier.getChannelOfOrNull
import dev.kord.core.supplier.getGuildApplicationCommandOf
import dev.kord.core.supplier.getGuildApplicationCommandOfOrNull
import dev.kord.gateway.Gateway
import dev.kord.gateway.PrivilegedIntent
import dev.kord.gateway.RequestGuildMembers
import dev.kord.gateway.builder.RequestGuildMembersBuilder
import dev.kord.gateway.start
import dev.kord.rest.Image
import dev.kord.rest.NamedFile
import dev.kord.rest.builder.auditlog.AuditLogGetRequestBuilder
import dev.kord.rest.builder.ban.BanCreateBuilder
import dev.kord.rest.builder.channel.CategoryCreateBuilder
Expand All @@ -96,6 +60,8 @@ import dev.kord.rest.builder.role.RoleCreateBuilder
import dev.kord.rest.builder.role.RolePositionsModifyBuilder
import dev.kord.rest.json.JsonErrorCode
import dev.kord.rest.json.request.CurrentUserNicknameModifyRequest
import dev.kord.rest.json.request.GuildStickerCreateRequest
import dev.kord.rest.json.request.MultipartGuildStickerCreateRequest
import dev.kord.rest.request.RestRequestException
import dev.kord.rest.service.RestClient
import dev.kord.rest.service.createCategory
Expand Down Expand Up @@ -209,6 +175,9 @@ public interface GuildBehavior : KordEntity, Strategizable {
public val members: Flow<Member>
get() = supplier.getGuildMembers(id)

public val stickers: Flow<GuildSticker>
get() = supplier.getGuildStickers(id)

/**
* Requests to get the present voice regions for this guild.
*
Expand Down Expand Up @@ -632,6 +601,17 @@ public interface GuildBehavior : KordEntity, Strategizable {

public suspend fun getTemplateOrNull(code: String): Template? = supplier.getTemplateOrNull(code)

public suspend fun getSticker(stickerId: Snowflake): GuildSticker = supplier.getGuildSticker(id, stickerId)

public suspend fun getStickerOrNull(stickerId: Snowflake): GuildSticker? = supplier.getGuildStickerOrNull(id, stickerId)

public suspend fun createSticker(name: String, description: String, tags: String, file: NamedFile): GuildSticker {
val request = MultipartGuildStickerCreateRequest(GuildStickerCreateRequest(name, description, tags), file)
val response = kord.rest.sticker.createGuildSticker(id, request)
val data = StickerData.from(response)
return GuildSticker(data, kord)
}

/**
* Returns a new [GuildBehavior] with the given [strategy].
*/
Expand All @@ -643,7 +623,7 @@ public suspend inline fun <reified T : GuildApplicationCommand> GuildBehavior.ge
}


public suspend inline fun <reified T : GuildApplicationCommand> GuildBehavior.getApplicationCommandOf(commandId: Snowflake): T? {
public suspend inline fun <reified T : GuildApplicationCommand> GuildBehavior.getApplicationCommandOf(commandId: Snowflake): T {
return supplier.getGuildApplicationCommandOf(kord.resources.applicationId, id, commandId)
}

Expand Down
57 changes: 57 additions & 0 deletions core/src/main/kotlin/behavior/StickerBehavior.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package dev.kord.core.behavior

import dev.kord.common.entity.Snowflake
import dev.kord.core.Kord
import dev.kord.core.cache.data.StickerData
import dev.kord.core.entity.KordEntity
import dev.kord.core.entity.Sticker
import dev.kord.core.entity.Strategizable
import dev.kord.core.supplier.EntitySupplier
import dev.kord.core.supplier.EntitySupplyStrategy
import dev.kord.rest.builder.guild.StickerModifyBuilder
import kotlin.contracts.ExperimentalContracts
import kotlin.contracts.InvocationKind
import kotlin.contracts.contract

public interface StickerBehavior : KordEntity, Strategizable {

public val guildId: Snowflake

public suspend fun delete() {
return kord.rest.sticker.deleteSticker(guildId, id)
}

public suspend fun asSticker(): Sticker = supplier.getSticker(id)

public suspend fun asStickerOrNull(): Sticker? = supplier.getStickerOrNull(id)

public suspend fun fetchSticker(): Sticker = supplier.getSticker(id)

public suspend fun fetchStickerOrNull(): Sticker? = supplier.getStickerOrNull(id)

}

public fun StickerBehavior(guildId: Snowflake, id: Snowflake, kord: Kord, supplier: EntitySupplier): StickerBehavior =
object : StickerBehavior {
override val guildId: Snowflake
get() = guildId
override val id: Snowflake
get() = id
override val kord: Kord
get() = kord

override val supplier: EntitySupplier
get() = supplier

override fun withStrategy(strategy: EntitySupplyStrategy<*>): StickerBehavior =
StickerBehavior(guildId, id, kord, strategy.supply(kord))

}

@OptIn(ExperimentalContracts::class)
public suspend inline fun StickerBehavior.edit(builder: StickerModifyBuilder.() -> Unit): Sticker {
contract { callsInPlace(builder, InvocationKind.EXACTLY_ONCE) }
val response = kord.rest.sticker.modifyGuildSticker(guildId, id, builder)
val data = StickerData.from(response)
return Sticker(data, kord)
}
5 changes: 4 additions & 1 deletion core/src/main/kotlin/cache/DataCacheExtensions.kt
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,10 @@ internal suspend fun DataCache.registerKordData() = register(
PresenceData.description,
VoiceStateData.description,
ApplicationCommandData.description,
GuildApplicationCommandPermissionsData.description
GuildApplicationCommandPermissionsData.description,
StickerPackData.description,
StickerData.description,

)

/**
Expand Down
2 changes: 2 additions & 0 deletions core/src/main/kotlin/cache/KordCache.kt
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,8 @@ public class KordCacheBuilder {
*/
public fun users(generator: Generator<UserData, Snowflake>): Unit = forDescription(UserData.description, generator)

public fun stickers(generator: Generator<StickerData, Snowflake>): Unit = forDescription(StickerData.description, generator)


/**
* Configures the caching for [EmojiData].
Expand Down
6 changes: 3 additions & 3 deletions core/src/main/kotlin/cache/data/MessageData.kt
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ public data class MessageData(
val applicationId: OptionalSnowflake = OptionalSnowflake.Missing,
val messageReference: Optional<MessageReferenceData> = Optional.Missing(),
val flags: Optional<MessageFlags> = Optional.Missing(),
val stickers: Optional<List<MessageStickerData>> = Optional.Missing(),
val stickers: Optional<List<StickerItemData>> = Optional.Missing(),
val referencedMessage: Optional<MessageData?> = Optional.Missing(),
val interaction: Optional<MessageInteractionData> = Optional.Missing(),
val components: Optional<List<ComponentData>> = Optional.Missing()
Expand Down Expand Up @@ -73,7 +73,7 @@ public data class MessageData(
val mentionedChannels =
partialMessage.mentionedChannels.mapList { it.id }.switchOnMissing(mentionedChannels.value.orEmpty())
.coerceToMissing()
val stickers = partialMessage.stickers.mapList { MessageStickerData.from(it) }.switchOnMissing(this.stickers)
val stickers = partialMessage.stickers.mapList { StickerItemData.from(it) }.switchOnMissing(this.stickers)
val referencedMessage = partialMessage.referencedMessage.mapNullable { it?.toData() ?: referencedMessage.value }
val interaction =
partialMessage.interaction.map { MessageInteractionData.from(it) }.switchOnMissing(interaction)
Expand Down Expand Up @@ -139,7 +139,7 @@ public data class MessageData(
applicationId,
messageReference.map { MessageReferenceData.from(it) },
flags,
stickers.mapList { MessageStickerData.from(it) },
stickers.mapList { StickerItemData.from(it) },
referencedMessage.mapNotNull { from(it) },
interaction.map { MessageInteractionData.from(it) },
components = components.mapList { ComponentData.from(it) }
Expand Down
25 changes: 0 additions & 25 deletions core/src/main/kotlin/cache/data/MessageStickerData.kt

This file was deleted.

Loading

0 comments on commit 3b9c5f5

Please sign in to comment.