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

Top channels #353

Merged
merged 12 commits into from
Aug 2, 2021
16 changes: 8 additions & 8 deletions core/src/main/kotlin/Unsafe.kt
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,11 @@ class Unsafe(private val kord: Kord) {
fun messageChannel(id: Snowflake): MessageChannelBehavior =
MessageChannelBehavior(id, kord)

fun guildChannel(guildId: Snowflake, id: Snowflake): GuildChannelBehavior =
GuildChannelBehavior(guildId = guildId, id = id, kord = kord)
fun guildChannel(guildId: Snowflake, id: Snowflake): TopGuildChannelBehavior =
TopGuildChannelBehavior(guildId = guildId, id = id, kord = kord)

fun guildMessageChannel(guildId: Snowflake, id: Snowflake): GuildMessageChannelBehavior =
GuildMessageChannelBehavior(guildId = guildId, id = id, kord = kord)
fun guildMessageChannel(guildId: Snowflake, id: Snowflake): TopGuildMessageChannelBehavior =
TopGuildMessageChannelBehavior(guildId = guildId, id = id, kord = kord)
Copy link
Contributor

Choose a reason for hiding this comment

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

For correctness, I think these should include top in their name.


fun newsChannel(guildId: Snowflake, id: Snowflake): NewsChannelBehavior =
NewsChannelBehavior(guildId = guildId, id = id, kord = kord)
Expand All @@ -61,8 +61,8 @@ class Unsafe(private val kord: Kord) {
fun privateThreadParent(guildId: Snowflake, id: Snowflake): PrivateThreadParentChannelBehavior =
PrivateThreadParentChannelBehavior(guildId, id, kord)

fun thread(id: Snowflake): ThreadChannelBehavior =
ThreadChannelBehavior(id, kord)
fun thread(guildId: Snowflake, parentId: Snowflake, id: Snowflake): ThreadChannelBehavior =
ThreadChannelBehavior(guildId, parentId, id, kord)


fun guild(id: Snowflake): GuildBehavior =
Expand All @@ -77,8 +77,8 @@ class Unsafe(private val kord: Kord) {
fun user(id: Snowflake): UserBehavior =
UserBehavior(id, kord)

fun threadUser(id: Snowflake, threadId: Snowflake) =
ThreadUserBehavior(id, threadId, kord)
fun threadMember(id: Snowflake, threadId: Snowflake) =
ThreadMemberBehavior(id, threadId, kord)

fun member(guildId: Snowflake, id: Snowflake): MemberBehavior =
MemberBehavior(guildId = guildId, id = id, kord = kord)
Expand Down
10 changes: 5 additions & 5 deletions core/src/main/kotlin/behavior/GuildBehavior.kt
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ interface GuildBehavior : KordEntity, Strategizable {
* The returned flow is lazily executed, any [RequestException] will be thrown on
* [terminal operators](https://kotlinlang.org/docs/reference/coroutines/flow.html#terminal-flow-operators) instead.
*/
val channels: Flow<GuildChannel>
val channels: Flow<TopGuildChannel>
get() = supplier.getGuildChannels(id)

/**
Expand Down Expand Up @@ -395,11 +395,11 @@ interface GuildBehavior : KordEntity, Strategizable {
suspend fun getBanOrNull(userId: Snowflake): Ban? = supplier.getGuildBanOrNull(id, userId)

/**
* Requests to get the [GuildChannel] represented by the [channelId].
* Requests to get the [TopGuildChannel] represented by the [channelId].
*
* @throws [RequestException] if anything went wrong during the request.
* @throws [EntityNotFoundException] if the [GuildChannel] wasn't present.
* @throws [ClassCastException] if the channel is not a [GuildChannel].
* @throws [EntityNotFoundException] if the [TopGuildChannel] wasn't present.
* @throws [ClassCastException] if the channel is not a [TopGuildChannel].
* @throws [IllegalArgumentException] if the channel is not part of this guild.
*/
suspend fun getChannel(channelId: Snowflake): GuildChannel {
Expand All @@ -413,7 +413,7 @@ interface GuildBehavior : KordEntity, Strategizable {
* returns null if the [GuildChannel] isn't present.
*
* @throws [RequestException] if anything went wrong during the request.
* @throws [ClassCastException] if the channel is not a [GuildChannel].
* @throws [ClassCastException] if the channel is not a [TopGuildChannel].
* @throws [IllegalArgumentException] if the channel is not part of this guild.
*/
suspend fun getChannelOrNull(channelId: Snowflake): GuildChannel? {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,36 +2,33 @@ package dev.kord.core.behavior

import dev.kord.common.entity.Snowflake
import dev.kord.core.Kord
import dev.kord.core.behavior.channel.threads.ThreadChannelBehavior
import dev.kord.core.entity.channel.thread.ThreadChannel
import dev.kord.core.supplier.EntitySupplier
import dev.kord.core.supplier.EntitySupplyStrategy
import dev.kord.core.supplier.getChannelOf
import dev.kord.core.supplier.getChannelOfOrNull

interface ThreadUserBehavior : UserBehavior {
interface ThreadMemberBehavior : UserBehavior {

val threadId: Snowflake

val thread: ThreadChannelBehavior get() = ThreadChannelBehavior(threadId, kord)

suspend fun getThread(): ThreadChannel = supplier.getChannelOf(threadId)

suspend fun getThreadOrNull(): ThreadChannel? = supplier.getChannelOfOrNull(threadId)

override fun withStrategy(strategy: EntitySupplyStrategy<*>): UserBehavior {
return ThreadUserBehavior(id, threadId, kord, strategy.supply(kord))
return ThreadMemberBehavior(id, threadId, kord, strategy.supply(kord))

}
}

fun ThreadUserBehavior(
fun ThreadMemberBehavior(
id: Snowflake,
threadId: Snowflake,
kord: Kord,
supplier: EntitySupplier = kord.defaultSupplier
): ThreadUserBehavior {
return object : ThreadUserBehavior {
): ThreadMemberBehavior {
return object : ThreadMemberBehavior {
override val id: Snowflake
get() = id
override val threadId: Snowflake
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import dev.kord.core.entity.VoiceState
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.map

interface BaseVoiceChannelBehavior : GuildChannelBehavior {
interface BaseVoiceChannelBehavior : TopGuildChannelBehavior {

/**
* Requests to retrieve the present voice states of this channel.
Expand Down
6 changes: 2 additions & 4 deletions core/src/main/kotlin/behavior/channel/CategoryBehavior.kt
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
package dev.kord.core.behavior.channel

import dev.kord.common.annotation.DeprecatedSinceKord
import dev.kord.common.entity.Snowflake
import dev.kord.common.exception.RequestException
import dev.kord.core.Kord
import dev.kord.core.behavior.GuildBehavior
import dev.kord.core.cache.data.ChannelData
import dev.kord.core.entity.channel.*
import dev.kord.core.exception.EntityNotFoundException
Expand All @@ -31,7 +29,7 @@ import kotlin.contracts.contract
/**
* The behavior of a Discord category associated to a [guild].
*/
interface CategoryBehavior : GuildChannelBehavior {
interface CategoryBehavior : TopGuildChannelBehavior {

/**
* Requests to get this behavior as a [Category].
Expand Down Expand Up @@ -89,7 +87,7 @@ fun CategoryBehavior(
override fun hashCode(): Int = Objects.hash(id, guildId)

override fun equals(other: Any?): Boolean = when (other) {
is GuildChannelBehavior -> other.id == id && other.guildId == guildId
is TopGuildChannelBehavior -> other.id == id && other.guildId == guildId
is ChannelBehavior -> other.id == id
else -> false
}
Expand Down
94 changes: 5 additions & 89 deletions core/src/main/kotlin/behavior/channel/GuildChannelBehavior.kt
Original file line number Diff line number Diff line change
Expand Up @@ -4,25 +4,13 @@ import dev.kord.common.entity.Snowflake
import dev.kord.common.exception.RequestException
import dev.kord.core.Kord
import dev.kord.core.behavior.GuildBehavior
import dev.kord.core.cache.data.InviteData
import dev.kord.core.entity.*
import dev.kord.core.entity.channel.GuildChannel
import dev.kord.core.entity.channel.TopGuildChannel
import dev.kord.core.exception.EntityNotFoundException
import dev.kord.core.supplier.EntitySupplier
import dev.kord.core.supplier.EntitySupplyStrategy
import dev.kord.rest.builder.channel.ChannelPermissionModifyBuilder
import dev.kord.rest.request.RestRequestException
import dev.kord.rest.service.RestClient
import dev.kord.rest.service.editMemberPermissions
import dev.kord.rest.service.editRolePermission
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.flow.withIndex
import java.util.*
import kotlin.contracts.ExperimentalContracts
import kotlin.contracts.InvocationKind
import kotlin.contracts.contract

/**
* The behavior of a Discord channel associated to a [guild].
Expand All @@ -40,26 +28,7 @@ interface GuildChannelBehavior : ChannelBehavior, Strategizable {
val guild: GuildBehavior get() = GuildBehavior(guildId, kord)

/**
* Requests to get the invites of this channel.
*
* This property is not resolvable through cache and will always use the [RestClient] instead.
*
* The returned flow is lazily executed, any [RequestException] will be thrown on
* [terminal operators](https://kotlinlang.org/docs/reference/coroutines/flow.html#terminal-flow-operators) instead.
*/
val invites: Flow<Invite>
get() = flow {
val responses = kord.rest.channel.getChannelInvites(id)

for (response in responses) {
val data = InviteData.from(response)

emit(Invite(data, kord))
}
}

/**
* Requests to get this behavior as a [GuildChannel].
* Requests to get this behavior as a [TopGuildChannel].
*
* @throws [RequestException] if something went wrong during the request.
* @throws [EntityNotFoundException] if the channel wasn't present.
Expand All @@ -68,7 +37,7 @@ interface GuildChannelBehavior : ChannelBehavior, Strategizable {
override suspend fun asChannel(): GuildChannel = super.asChannel() as GuildChannel

/**
* Requests to get this behavior as a [GuildChannel],
* Requests to get this behavior as a [TopGuildChannel],
* returns null if the channel isn't present or if the channel isn't a guild channel.
*
* @throws [RequestException] if something went wrong during the request.
Expand All @@ -91,40 +60,18 @@ interface GuildChannelBehavior : ChannelBehavior, Strategizable {
*/
suspend fun getGuildOrNull(): Guild? = supplier.getGuildOrNull(guildId)

/**
* Requests to add or replace a [PermissionOverwrite] to this entity.
*
* @param reason the reason showing up in the audit log
* @throws [RestRequestException] if something went wrong during the request.
*/
suspend fun addOverwrite(overwrite: PermissionOverwrite, reason: String?) {
kord.rest.channel.editChannelPermissions(
channelId = id,
overwriteId = overwrite.target,
permissions = overwrite.asRequest(),
reason = reason
)
}

/**
* Requests to get the position of this channel in the [guild], as displayed in Discord,
*.
*
* @throws [RequestException] if something went wrong during the request.
*/
suspend fun getPosition(): Int = supplier.getGuildChannels(guildId).withIndex().first { it.value.id == id }.index

override fun compareTo(other: Entity): Int {
if (other !is GuildChannelBehavior) return super.compareTo(other)
val discordOrder = compareBy<GuildChannelBehavior> { it.guildId }
.thenBy { (it as? GuildChannel)?.guildId }
.thenBy { (it as? TopGuildChannel)?.guildId }
.thenBy { it.id }

return discordOrder.compare(this, other)
}

/**
* Returns a new [GuildChannelBehavior] with the given [strategy].
* Returns a new [TopGuildChannelBehavior] with the given [strategy].
*/
override fun withStrategy(
strategy: EntitySupplyStrategy<*>
Expand Down Expand Up @@ -157,34 +104,3 @@ fun GuildChannelBehavior(
}
}

/**
* Requests to add or replace a [PermissionOverwrite] for the [roleId].
*
* @throws [RestRequestException] if something went wrong during the request.
*/
@OptIn(ExperimentalContracts::class)
suspend inline fun GuildChannelBehavior.editRolePermission(
roleId: Snowflake,
builder: ChannelPermissionModifyBuilder.() -> Unit
) {
contract {
callsInPlace(builder, InvocationKind.EXACTLY_ONCE)
}
kord.rest.channel.editRolePermission(channelId = id, roleId = roleId, builder = builder)
}

/**
* Requests to add or replace a [PermissionOverwrite] for the [memberId].
*
* @throws [RestRequestException] if something went wrong during the request.
*/
@OptIn(ExperimentalContracts::class)
suspend inline fun GuildChannelBehavior.editMemberPermission(
memberId: Snowflake,
builder: ChannelPermissionModifyBuilder.() -> Unit
) {
contract {
callsInPlace(builder, InvocationKind.EXACTLY_ONCE)
}
kord.rest.channel.editMemberPermissions(channelId = id, memberId = memberId, builder = builder)
}
Loading