diff --git a/.github/workflows/tag.yml b/.github/workflows/tag.yml index bc91d142aa..5a22846961 100644 --- a/.github/workflows/tag.yml +++ b/.github/workflows/tag.yml @@ -72,16 +72,19 @@ jobs: run: echo ::set-output name=NAME::${GITHUB_REF#refs/tags/} - name: Create Release - uses: softprops/action-gh-release@v1 + uses: softprops/action-gh-release@2 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: body_path: release.md - files: build/libs/*.jar name: Release ${{ steps.get_tag.outputs.NAME }} + files: | + build/libs/*.jar + **/build/libs/*.jar + - name: Release webhook run: kotlin .github/release.main.kts diff --git a/web/backend/src/main/kotlin/dev/kordex/extra/web/routes/Route.kt b/web/backend/src/main/kotlin/dev/kordex/extra/web/routes/Route.kt index ea6e384ee0..9af10257d1 100644 --- a/web/backend/src/main/kotlin/dev/kordex/extra/web/routes/Route.kt +++ b/web/backend/src/main/kotlin/dev/kordex/extra/web/routes/Route.kt @@ -8,12 +8,16 @@ package dev.kordex.extra.web.routes import dev.kordex.extra.web.errors.MethodNotAllowedError import dev.kordex.extra.web.errors.error +import dev.kordex.extra.web.routes.utils.allow import io.ktor.server.application.* @Suppress("StringLiteralDuplication") public abstract class Route(public val extension: String) { public abstract val path: String + public open suspend fun beforeRequest(verb: Verb, call: ApplicationCall): Boolean = + call.allow() + public open suspend fun delete(call: ApplicationCall) { call.error(MethodNotAllowedError) } diff --git a/web/backend/src/main/kotlin/dev/kordex/extra/web/routes/RouteRegistry.kt b/web/backend/src/main/kotlin/dev/kordex/extra/web/routes/RouteRegistry.kt index ffeae6034c..cc63218136 100644 --- a/web/backend/src/main/kotlin/dev/kordex/extra/web/routes/RouteRegistry.kt +++ b/web/backend/src/main/kotlin/dev/kordex/extra/web/routes/RouteRegistry.kt @@ -26,14 +26,16 @@ public class RouteRegistry : KordExKoinComponent { val route = routes[path] ?: return call.respond(HttpStatusCode.NotFound) - when (verb) { - Verb.DELETE -> route.delete(call) - Verb.GET -> route.get(call) - Verb.HEAD -> route.head(call) - Verb.OPTIONS -> route.options(call) - Verb.PATCH -> route.patch(call) - Verb.POST -> route.post(call) - Verb.PUT -> route.put(call) + if (route.beforeRequest(verb, call)) { + when (verb) { + Verb.DELETE -> route.delete(call) + Verb.GET -> route.get(call) + Verb.HEAD -> route.head(call) + Verb.OPTIONS -> route.options(call) + Verb.PATCH -> route.patch(call) + Verb.POST -> route.post(call) + Verb.PUT -> route.put(call) + } } } diff --git a/web/backend/src/main/kotlin/dev/kordex/extra/web/routes/utils/_Permissions.kt b/web/backend/src/main/kotlin/dev/kordex/extra/web/routes/utils/_Permissions.kt new file mode 100644 index 0000000000..9e05178809 --- /dev/null +++ b/web/backend/src/main/kotlin/dev/kordex/extra/web/routes/utils/_Permissions.kt @@ -0,0 +1,113 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +package dev.kordex.extra.web.routes.utils + +import com.kotlindiscord.kord.extensions.koin.KordExKoinComponent +import dev.kord.common.entity.Permission +import dev.kord.common.entity.Permissions +import dev.kord.common.entity.Snowflake +import dev.kord.core.Kord +import dev.kord.core.entity.Guild +import dev.kord.core.entity.Role +import io.ktor.http.HttpStatusCode +import io.ktor.server.application.ApplicationCall +import io.ktor.server.response.respond +import kotlinx.serialization.Serializable +import org.koin.core.component.inject +import kotlin.collections.map +import kotlin.collections.toTypedArray + +@Suppress("FunctionOnlyReturningConstant") +public suspend fun ApplicationCall.allow(): Boolean = + true + +public suspend fun ApplicationCall.deny(body: DenyBuilder.() -> Unit): Boolean { + response.status(HttpStatusCode.Unauthorized) + + val builder = DenyBuilder() + + body(builder) + respond(builder) + + return false +} + +@Serializable +public class DenyBuilder : KordExKoinComponent { + private val kord: Kord by inject() + + public var reasonKey: String? = null + public var reasonPlaceholders: Array = arrayOf() + + public var missingGuilds: MutableList? = null + public var missingPermissions: Permissions? = null + public var missingRoles: MutableList? = null + + public fun reason(key: String, placeholders: Array = arrayOf()) { + reasonKey = key + + reasonPlaceholders = placeholders + .map { it.toString() } + .toTypedArray() + } + + public fun missingGuild(guild: Guild) { + if (missingGuilds == null) { + missingGuilds = mutableListOf() + } + + missingGuilds!!.add(EntityInfo(guild.id, guild.name)) + } + + public suspend fun missingGuild(id: Snowflake) { + if (missingGuilds == null) { + missingGuilds = mutableListOf() + } + + val guild = kord.getGuildOrNull(id) + + missingGuilds!!.add(EntityInfo(id, guild?.name)) + } + + public fun missingPermission(perm: Permission) { + if (missingPermissions == null) { + missingPermissions = Permissions() + } + + missingPermissions = missingPermissions!! + perm + } + + public suspend fun missingPermissions(perms: Permissions) { + if (missingPermissions == null) { + missingPermissions = Permissions() + } + + missingPermissions = missingPermissions!! + perms + } + + public fun missingRole(role: Role) { + if (missingRoles == null) { + missingRoles = mutableListOf() + } + + missingRoles!!.add(EntityInfo(role.id, role.name)) + } + + public suspend fun missingRole(guildId: Snowflake, id: Snowflake) { + if (missingRoles == null) { + missingRoles = mutableListOf() + } + + val guild = kord.getGuildOrNull(guildId) + val role = guild?.getRoleOrNull(id) + + missingRoles!!.add(EntityInfo(id, role?.name)) + } + + @Serializable + public data class EntityInfo(val id: Snowflake, val name: String?) +}