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

Implement Role Icons #402

Merged
merged 12 commits into from
Oct 1, 2021
6 changes: 6 additions & 0 deletions common/src/main/kotlin/entity/DiscordRole.kt
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ data class DiscordRole(
val name: String,
val color: Int,
val hoist: Boolean,
val icon: Optional<String?>,
@SerialName("unicode_emoji")
val unicodeEmoji: Optional<String?>,
val position: Int,
val permissions: Permissions,
val managed: Boolean,
Expand All @@ -41,6 +44,9 @@ data class DiscordPartialRole(
val name: Optional<String> = Optional.Missing(),
val color: OptionalInt = OptionalInt.Missing,
val hoist: OptionalBoolean = OptionalBoolean.Missing,
val icon: Optional<String?> = Optional.Missing(),
@SerialName("unicode_emoji")
val unicodeEmoji: Optional<String?> = Optional.Missing(),
val position: OptionalInt = OptionalInt.Missing,
val permissions: Optional<Permissions> = Optional.Missing(),
val managed: OptionalBoolean = OptionalBoolean.Missing,
Expand Down
4 changes: 4 additions & 0 deletions core/src/main/kotlin/cache/data/RoleData.kt
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ data class RoleData(
val name: String,
val color: Int,
val hoisted: Boolean,
val icon: Optional<String?>,
val unicodeEmoji: Optional<String?>,
val position: Int,
val permissions: Permissions,
val managed: Boolean,
Expand All @@ -32,6 +34,8 @@ data class RoleData(
name,
color,
hoist,
icon,
unicodeEmoji,
position,
permissions,
managed,
Expand Down
4 changes: 4 additions & 0 deletions core/src/main/kotlin/entity/Icon.kt
Original file line number Diff line number Diff line change
Expand Up @@ -51,4 +51,8 @@ sealed class Icon(val animated: Boolean, val cdnUrl: CdnUrl, override val kord:

class MemberAvatar(guildId: Snowflake, userId: Snowflake, avatarHash: String, kord: Kord) :
Icon(avatarHash.startsWith("a_"), DiscordCdn.memberAvatar(guildId, userId, avatarHash), kord)

class RoleIcon(roleId: Snowflake, iconHash: String, kord: Kord) :
Icon(iconHash.startsWith("a_"), DiscordCdn.roleIcon(roleId, iconHash), kord)

}
4 changes: 4 additions & 0 deletions core/src/main/kotlin/entity/Role.kt
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,10 @@ data class Role(

val hoisted: Boolean get() = data.hoisted

val icon: Icon? get() = data.icon.value?.let { Icon.RoleIcon(data.id, it, kord) }

val unicodeEmoji: String? = data.unicodeEmoji.value

val managed: Boolean get() = data.managed

val mentionable: Boolean get() = data.mentionable
Expand Down
4 changes: 4 additions & 0 deletions core/src/test/kotlin/live/LiveGuildTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,8 @@ class LiveGuildTest : AbstractLiveEntityTest<LiveGuild>() {
name = "",
color = 0,
hoist = false,
icon = Optional.Missing(),
unicodeEmoji = Optional.Missing(),
position = 0,
permissions = Permissions(Permission.BanMembers),
managed = false,
Expand Down Expand Up @@ -285,6 +287,8 @@ class LiveGuildTest : AbstractLiveEntityTest<LiveGuild>() {
name = "",
color = 0,
hoist = false,
icon = Optional.Missing(),
unicodeEmoji = Optional.Missing(),
position = 0,
permissions = Permissions(Permission.BanMembers),
managed = false,
Expand Down
5 changes: 5 additions & 0 deletions core/src/test/kotlin/live/LiveRoleTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package live

import dev.kord.common.annotation.KordPreview
import dev.kord.common.entity.*
import dev.kord.common.entity.optional.Optional
import dev.kord.core.cache.data.RoleData
import dev.kord.core.entity.Role
import dev.kord.core.event.guild.GuildDeleteEvent
Expand Down Expand Up @@ -46,6 +47,8 @@ class LiveRoleTest : AbstractLiveEntityTest<LiveRole>() {
name = "test",
color = 0,
hoisted = false,
icon = Optional.Missing(),
unicodeEmoji = Optional.Missing(),
position = 0,
permissions = Permissions(Permission.CreateInstantInvite),
managed = false,
Expand All @@ -72,6 +75,8 @@ class LiveRoleTest : AbstractLiveEntityTest<LiveRole>() {
name = "",
color = 0,
hoist = false,
icon = Optional.Missing(),
unicodeEmoji = Optional.Missing(),
position = 0,
permissions = Permissions(Permission.BanMembers),
managed = false,
Expand Down
28 changes: 28 additions & 0 deletions core/src/test/kotlin/rest/RestTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,9 @@ fun imageBinary(path: String): Image {
@EnabledIfEnvironmentVariable(named = "KORD_TEST_TOKEN", matches = ".+")
class RestServiceTest {

// should we run checks which require boosts on the public guild?
private val boostEnabled = System.getenv("KORD_BOOST_ENABLED")?.equals("true", ignoreCase = true) ?: false

private val publicGuildId = Snowflake(322850917248663552u)

private val token = System.getenv("KORD_TEST_TOKEN")
Expand Down Expand Up @@ -545,4 +548,29 @@ class RestServiceTest {
Unit
}

@Test
fun `create role with image icon`() = runBlocking {
if (!boostEnabled)
return@runBlocking Unit
val guild = kord.getGuild(publicGuildId)!!
guild.createRole {
name = "Test Image Icon"
hoist = true
icon = imageBinary("images/kord_icon.png")
}
return@runBlocking Unit
}

@Test
fun `create role with unicode icon`() = runBlocking {
if (!boostEnabled)
return@runBlocking Unit
val guild = kord.getGuild(publicGuildId)!!
guild.createRole {
name = "Test Unicode Icon"
hoist = true
unicodeEmoji = "\uD83D\uDE04"
}
return@runBlocking Unit
}
}
Binary file added core/src/test/resources/images/kord_icon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
10 changes: 10 additions & 0 deletions rest/src/main/kotlin/builder/role/RoleCreateBuilder.kt
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import dev.kord.common.entity.Permissions
import dev.kord.common.entity.optional.Optional
import dev.kord.common.entity.optional.OptionalBoolean
import dev.kord.common.entity.optional.delegate.delegate
import dev.kord.common.entity.optional.map
import dev.kord.rest.Image
import dev.kord.rest.builder.AuditRequestBuilder
import dev.kord.rest.json.request.GuildRoleCreateRequest

Expand All @@ -19,6 +21,12 @@ class RoleCreateBuilder : AuditRequestBuilder<GuildRoleCreateRequest> {
private var _hoist: OptionalBoolean = OptionalBoolean.Missing
var hoist: Boolean? by ::_hoist.delegate()

private var _icon: Optional<Image> = Optional.Missing()
var icon: Image? by ::_icon.delegate()

private var _unicodeEmoji: Optional<String> = Optional.Missing()
var unicodeEmoji: String? by ::_unicodeEmoji.delegate()

private var _name: Optional<String> = Optional.Missing()
var name: String? by ::_name.delegate()

Expand All @@ -31,6 +39,8 @@ class RoleCreateBuilder : AuditRequestBuilder<GuildRoleCreateRequest> {
override fun toRequest(): GuildRoleCreateRequest = GuildRoleCreateRequest(
color = _color,
separate = _hoist,
icon = _icon.map { it.dataUri },
unicodeEmoji = _unicodeEmoji,
name = _name,
mentionable = _mentionable,
permissions = _permissions
Expand Down
10 changes: 10 additions & 0 deletions rest/src/main/kotlin/builder/role/RoleModifyBuilder.kt
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import dev.kord.common.entity.Permissions
import dev.kord.common.entity.optional.Optional
import dev.kord.common.entity.optional.OptionalBoolean
import dev.kord.common.entity.optional.delegate.delegate
import dev.kord.common.entity.optional.map
import dev.kord.rest.Image
import dev.kord.rest.builder.AuditRequestBuilder
import dev.kord.rest.json.request.GuildRoleModifyRequest

Expand All @@ -19,6 +21,12 @@ class RoleModifyBuilder : AuditRequestBuilder<GuildRoleModifyRequest> {
private var _hoist: OptionalBoolean? = OptionalBoolean.Missing
var hoist: Boolean? by ::_hoist.delegate()

private var _icon: Optional<Image> = Optional.Missing()
var icon: Image? by ::_icon.delegate()

private var _unicodeEmoji: Optional<String> = Optional.Missing()
var unicodeEmoji: String? by ::_unicodeEmoji.delegate()

private var _name: Optional<String?> = Optional.Missing()
var name: String? by ::_name.delegate()

Expand All @@ -32,6 +40,8 @@ class RoleModifyBuilder : AuditRequestBuilder<GuildRoleModifyRequest> {
name = _name,
color = _color,
separate = _hoist,
icon = _icon.map { it.dataUri },
unicodeEmoji = _unicodeEmoji,
mentionable = _mentionable,
permissions = _permissions
)
Expand Down
6 changes: 6 additions & 0 deletions rest/src/main/kotlin/json/request/GuildRequests.kt
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,9 @@ data class GuildRoleCreateRequest(
val color: Optional<Color> = Optional.Missing(),
@SerialName("hoist")
val separate: OptionalBoolean = OptionalBoolean.Missing,
val icon: Optional<String> = Optional.Missing(),
@SerialName("unicode_emoji")
val unicodeEmoji: Optional<String> = Optional.Missing(),
val mentionable: OptionalBoolean = OptionalBoolean.Missing,
val id: OptionalSnowflake = OptionalSnowflake.Missing,
)
Expand Down Expand Up @@ -160,6 +163,9 @@ data class GuildRoleModifyRequest(
val color: Optional<Color?> = Optional.Missing(),
@SerialName("hoist")
val separate: OptionalBoolean? = OptionalBoolean.Missing,
val icon: Optional<String> = Optional.Missing(),
@SerialName("unicode_emoji")
val unicodeEmoji: Optional<String> = Optional.Missing(),
val mentionable: OptionalBoolean? = OptionalBoolean.Missing,
)

Expand Down
1 change: 1 addition & 0 deletions rest/src/main/kotlin/route/DiscordCdn.kt
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,5 @@ object DiscordCdn {
fun memberAvatar(guildId: Snowflake, userId: Snowflake, hash: String) =
CdnUrl("$BASE_URL/guilds/${guildId.asString}/users/${userId.asString}/avatars/$hash")

fun roleIcon(roleId: Snowflake, hash: String) = CdnUrl("$BASE_URL/role-icons/${roleId.asString}/$hash")
}