feat: 構造ノードの定義を可能に
This commit is contained in:
parent
a4f6e8e236
commit
58ad0e67c9
52
README.md
52
README.md
|
|
@ -8,17 +8,20 @@ instances and keep `PermissionAttachment`s in sync.
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
```kotlin
|
```kotlin
|
||||||
|
import net.hareworks.permits_lib.domain.NodeRegistration
|
||||||
|
|
||||||
class ExamplePlugin : JavaPlugin() {
|
class ExamplePlugin : JavaPlugin() {
|
||||||
private val permits = PermitsLib.session(this)
|
private val permits = PermitsLib.session(this)
|
||||||
|
|
||||||
override fun onEnable() {
|
override fun onEnable() {
|
||||||
val tree = permissionTree("example") {
|
val tree = permissionTree("example") {
|
||||||
node("command") {
|
node("command", NodeRegistration.STRUCTURAL) {
|
||||||
description = "Access to all example commands"
|
description = "Access to all example commands"
|
||||||
defaultValue = PermissionDefault.OP
|
defaultValue = PermissionDefault.OP
|
||||||
|
|
||||||
node("reload") {
|
node("reload", NodeRegistration.PERMISSION) {
|
||||||
description = "Allows /example reload (permission example.command.reload)"
|
description = "Allows /example reload (permission example.command.reload)"
|
||||||
|
wildcard = true // include reload in example.command.*
|
||||||
}
|
}
|
||||||
|
|
||||||
// Link to a helper node defined elsewhere under the command branch:
|
// Link to a helper node defined elsewhere under the command branch:
|
||||||
|
|
@ -27,17 +30,17 @@ class ExamplePlugin : JavaPlugin() {
|
||||||
// Link to a permission outside the current branch (must be fully-qualified):
|
// Link to a permission outside the current branch (must be fully-qualified):
|
||||||
childAbsolute("example.tools.repair")
|
childAbsolute("example.tools.repair")
|
||||||
|
|
||||||
node("cooldown") {
|
node("cooldown", NodeRegistration.PERMISSION) {
|
||||||
description = "Allows /example cooldown tweaks"
|
description = "Allows /example cooldown tweaks"
|
||||||
wildcard = false // opt-out if you do not want example.command.* to include it
|
wildcard = true // opt in so example.command.* grants cooldown
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
node("command.helper") {
|
node("command.helper", NodeRegistration.PERMISSION) {
|
||||||
description = "Allows /example helper (referenced via child(\"helper\"))"
|
description = "Allows /example helper (referenced via child(\"helper\"))"
|
||||||
}
|
}
|
||||||
|
|
||||||
node("tools.repair") {
|
node("tools.repair", NodeRegistration.PERMISSION) {
|
||||||
description = "Allows /example tools repair (linked with childAbsolute(\"example.tools.repair\"))"
|
description = "Allows /example tools repair (linked with childAbsolute(\"example.tools.repair\"))"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -47,7 +50,7 @@ class ExamplePlugin : JavaPlugin() {
|
||||||
// The tree above materializes as permissions such as:
|
// The tree above materializes as permissions such as:
|
||||||
// example.command, example.command.reload, example.command.helper, example.command.cooldown,
|
// example.command, example.command.reload, example.command.helper, example.command.cooldown,
|
||||||
// example.tools.repair,
|
// example.tools.repair,
|
||||||
// plus the auto-generated example.command.* wildcard that references every child (visible if you
|
// plus the auto-generated example.command.* wildcard (because reload/cooldown set wildcard = true)
|
||||||
// export to plugin.yml or inspect Bukkit's /permissions output).
|
// export to plugin.yml or inspect Bukkit's /permissions output).
|
||||||
|
|
||||||
configureRuntimePermissions()
|
configureRuntimePermissions()
|
||||||
|
|
@ -61,15 +64,15 @@ class ExamplePlugin : JavaPlugin() {
|
||||||
// Later in runtime you can mutate the previously applied structure without rebuilding it:
|
// Later in runtime you can mutate the previously applied structure without rebuilding it:
|
||||||
permits.edit("example") {
|
permits.edit("example") {
|
||||||
// Update an existing node and link it to new children
|
// Update an existing node and link it to new children
|
||||||
node("command") {
|
node("command", NodeRegistration.STRUCTURAL) {
|
||||||
description = "Admins for every command path"
|
description = "Admins for every command path"
|
||||||
node("debug") {
|
node("debug", NodeRegistration.PERMISSION) {
|
||||||
description = "Allows /example debug"
|
description = "Allows /example debug"
|
||||||
defaultValue = PermissionDefault.OP
|
defaultValue = PermissionDefault.OP
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Remove deprecated permissions entirely
|
// Remove deprecated permissions entirely
|
||||||
remove("command.cooldown")
|
removeNode("command.cooldown")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -82,12 +85,14 @@ mutate it procedurally, and then apply the result:
|
||||||
|
|
||||||
```kotlin
|
```kotlin
|
||||||
val baseTree = permissionTree("example") {
|
val baseTree = permissionTree("example") {
|
||||||
node("command") { node("reload") }
|
node("command", NodeRegistration.STRUCTURAL) {
|
||||||
|
node("reload", NodeRegistration.PERMISSION)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val mutable = MutablePermissionTree.from(baseTree)
|
val mutable = MutablePermissionTree.from(baseTree)
|
||||||
mutable.node("command") {
|
mutable.node("command", NodeRegistration.STRUCTURAL) {
|
||||||
node("debug") {
|
node("debug", NodeRegistration.PERMISSION) {
|
||||||
description = "Allows /example debug"
|
description = "Allows /example debug"
|
||||||
defaultValue = PermissionDefault.OP
|
defaultValue = PermissionDefault.OP
|
||||||
}
|
}
|
||||||
|
|
@ -104,24 +109,25 @@ stage edits procedurally before ever touching `MutationSession`.
|
||||||
### Concepts
|
### Concepts
|
||||||
|
|
||||||
- **Permission tree** – immutable graph of `PermissionNode`s. Nodes specify description, default value,
|
- **Permission tree** – immutable graph of `PermissionNode`s. Nodes specify description, default value,
|
||||||
boolean children map, optional tags, and the `wildcard` flag (enabled by default) that makes the library
|
boolean children map, optional tags, and the `wildcard` flag (disabled by default) that, when enabled,
|
||||||
create/update `namespace.path.*` aggregate permissions automatically.
|
makes the library create/update `namespace.path.*` aggregate permissions automatically.
|
||||||
- **DSL** – `permissionTree("namespace") { ... }` ensures consistent prefixes and validation (no cycles). Top-level `node("command")` / `remove("command")` treat `command` as relative to that namespace, so you never include the namespace manually at the root.
|
- **DSL** – `permissionTree("namespace") { ... }` ensures consistent prefixes and validation (no cycles). Every `node("command", NodeRegistration.PERMISSION)` (or `.STRUCTURAL`) is relative to that namespace, so you never include the namespace manually at the root.
|
||||||
- **Nested nodes** – `node("command") { node("reload") { ... } }` automatically produces
|
- **Nested nodes** – `node("command", NodeRegistration.STRUCTURAL) { node("reload", NodeRegistration.PERMISSION) { ... } }` automatically produces
|
||||||
`namespace.command` and `namespace.command.reload` plus wires the parent/child relationship so you don't
|
`namespace.command` and `namespace.command.reload` plus wires the parent/child relationship so you don't
|
||||||
have to repeat the full id.
|
have to repeat the full id.
|
||||||
- **Flexible references** – `child("reload")`, `node("command") { node("reload") { ... } }`, or
|
- **Flexible references** – `child("reload")`, `node("command", NodeRegistration.STRUCTURAL) { node("reload", NodeRegistration.PERMISSION) { ... } }`, or
|
||||||
even `node("command.reload")` inside `edit` all resolve to the same node; children are auto-created on
|
even `node("command.reload", NodeRegistration.PERMISSION)` inside `edit` all resolve to the same node; children are auto-created on
|
||||||
first reference but you can demand explicit nodes by adding a `node` block later, and you can unlink
|
first reference but you can demand explicit nodes by adding a `node` block later, and you can unlink
|
||||||
specific children via `node("command") { removeNode("cooldown") }` and the entire subtree disappears.
|
specific children via `node("command", NodeRegistration.STRUCTURAL) { removeNode("cooldown") }` and the entire subtree disappears.
|
||||||
|
- **Node registration** – `NodeRegistration.PERMISSION` materializes the node as a Bukkit permission, while `NodeRegistration.STRUCTURAL` keeps it purely for grouping (still participates in wildcard aggregation) so you can avoid ambiguous intermediate permissions like `hoge.command`.
|
||||||
Nested `child(...)` calls are relative to the current node by default, while `childAbsolute(...)` now
|
Nested `child(...)` calls are relative to the current node by default, while `childAbsolute(...)` now
|
||||||
expects a fully-qualified permission ID (e.g., `example.tools.repair`) so you can also point at nodes in
|
expects a fully-qualified permission ID (e.g., `example.tools.repair`) so you can also point at nodes in
|
||||||
other namespaces.
|
other namespaces.
|
||||||
- **PermissionRegistry** – calculates a diff between snapshots and performs the minimum additions,
|
- **PermissionRegistry** – calculates a diff between snapshots and performs the minimum additions,
|
||||||
removals, or updates via Bukkit's `PluginManager`.
|
removals, or updates via Bukkit's `PluginManager`.
|
||||||
- **Wildcards** – with `wildcard = true`, the generated `namespace.command.*` child always exists and stays
|
- **Wildcards** – opt-in via `wildcard = true` to have the generated `namespace.command.*` child kept in sync,
|
||||||
in sync so granting `example.command.*` automatically grants every nested node; set it to `false` to opt
|
so granting `example.command.*` automatically grants every nested node you marked; leave it `false` (default)
|
||||||
out for specific permissions.
|
to keep nodes out of the wildcard.
|
||||||
- **Mutable edits** – `permits.edit { ... }` clones the currently registered tree, lets you mutate nodes
|
- **Mutable edits** – `permits.edit { ... }` clones the currently registered tree, lets you mutate nodes
|
||||||
imperatively, re-validates, and only pushes the structural diff to Bukkit.
|
imperatively, re-validates, and only pushes the structural diff to Bukkit.
|
||||||
- **AttachmentSynchronizer** – manages identity-based `PermissionAttachment`s and exposes high-level
|
- **AttachmentSynchronizer** – manages identity-based `PermissionAttachment`s and exposes high-level
|
||||||
|
|
|
||||||
|
|
@ -10,10 +10,11 @@ class MutablePermissionTree internal constructor(
|
||||||
private val namespace: String,
|
private val namespace: String,
|
||||||
private val drafts: MutableMap<PermissionId, PermissionNodeDraft>
|
private val drafts: MutableMap<PermissionId, PermissionNodeDraft>
|
||||||
) {
|
) {
|
||||||
fun node(id: String, block: MutableNode.() -> Unit = {}): MutableNode {
|
fun node(id: String, registration: NodeRegistration, block: MutableNode.() -> Unit = {}): MutableNode {
|
||||||
require(id.isNotBlank()) { "Node id must not be blank." }
|
require(id.isNotBlank()) { "Node id must not be blank." }
|
||||||
val permissionId = PermissionId.of("$namespace.${id.lowercase()}")
|
val permissionId = PermissionId.of("$namespace.${id.lowercase()}")
|
||||||
val draft = drafts.getOrPut(permissionId) { PermissionNodeDraft(permissionId) }
|
val draft = drafts.getOrPut(permissionId) { PermissionNodeDraft(permissionId) }
|
||||||
|
draft.registration = registration
|
||||||
return MutableNode(permissionId, draft).apply(block)
|
return MutableNode(permissionId, draft).apply(block)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -63,6 +64,12 @@ class MutablePermissionTree internal constructor(
|
||||||
draft.wildcard = value
|
draft.wildcard = value
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var registration: NodeRegistration
|
||||||
|
get() = draft.registration
|
||||||
|
set(value) {
|
||||||
|
draft.registration = value
|
||||||
|
}
|
||||||
|
|
||||||
val tags: MutableSet<String>
|
val tags: MutableSet<String>
|
||||||
get() = draft.tags
|
get() = draft.tags
|
||||||
|
|
||||||
|
|
@ -83,11 +90,12 @@ class MutablePermissionTree internal constructor(
|
||||||
draft.children[permissionId] = value
|
draft.children[permissionId] = value
|
||||||
}
|
}
|
||||||
|
|
||||||
fun node(id: String, block: MutableNode.() -> Unit = {}) {
|
fun node(id: String, registration: NodeRegistration, block: MutableNode.() -> Unit = {}) {
|
||||||
require(id.isNotBlank()) { "Node id must not be blank." }
|
require(id.isNotBlank()) { "Node id must not be blank." }
|
||||||
val permissionId = PermissionId.of("${this.id.value}.${id.lowercase()}")
|
val permissionId = PermissionId.of("${this.id.value}.${id.lowercase()}")
|
||||||
draft.children[permissionId] = true
|
draft.children[permissionId] = true
|
||||||
val childDraft = drafts.getOrPut(permissionId) { PermissionNodeDraft(permissionId) }
|
val childDraft = drafts.getOrPut(permissionId) { PermissionNodeDraft(permissionId) }
|
||||||
|
childDraft.registration = registration
|
||||||
MutableNode(permissionId, childDraft).apply(block)
|
MutableNode(permissionId, childDraft).apply(block)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -151,7 +159,8 @@ class MutablePermissionTree internal constructor(
|
||||||
defaultValue = draft.defaultValue,
|
defaultValue = draft.defaultValue,
|
||||||
children = draft.children.toMutableMap(),
|
children = draft.children.toMutableMap(),
|
||||||
tags = draft.tags.toMutableSet(),
|
tags = draft.tags.toMutableSet(),
|
||||||
wildcard = draft.wildcard
|
wildcard = draft.wildcard,
|
||||||
|
registration = draft.registration
|
||||||
)
|
)
|
||||||
drafts[newId] = newDraft
|
drafts[newId] = newDraft
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,10 @@
|
||||||
|
package net.hareworks.permits_lib.domain
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Declares whether a DSL node should materialize as an actual Bukkit permission or behave as a
|
||||||
|
* purely structural placeholder (still participates in relationships/wildcards).
|
||||||
|
*/
|
||||||
|
enum class NodeRegistration(val registersPermission: Boolean) {
|
||||||
|
PERMISSION(true),
|
||||||
|
STRUCTURAL(false)
|
||||||
|
}
|
||||||
|
|
@ -14,7 +14,8 @@ data class PermissionNode(
|
||||||
val defaultValue: PermissionDefault = PermissionDefault.FALSE,
|
val defaultValue: PermissionDefault = PermissionDefault.FALSE,
|
||||||
val children: Map<PermissionId, Boolean> = emptyMap(),
|
val children: Map<PermissionId, Boolean> = emptyMap(),
|
||||||
val tags: Set<String> = emptySet(),
|
val tags: Set<String> = emptySet(),
|
||||||
val wildcard: Boolean = true
|
val wildcard: Boolean = false,
|
||||||
|
val registration: NodeRegistration = NodeRegistration.PERMISSION
|
||||||
) {
|
) {
|
||||||
init {
|
init {
|
||||||
require(children.keys.none { it == id }) { "Permission node cannot be a child of itself." }
|
require(children.keys.none { it == id }) { "Permission node cannot be a child of itself." }
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,8 @@ internal data class PermissionNodeDraft(
|
||||||
var defaultValue: PermissionDefault = PermissionDefault.FALSE,
|
var defaultValue: PermissionDefault = PermissionDefault.FALSE,
|
||||||
val children: MutableMap<PermissionId, Boolean> = linkedMapOf(),
|
val children: MutableMap<PermissionId, Boolean> = linkedMapOf(),
|
||||||
val tags: MutableSet<String> = linkedSetOf(),
|
val tags: MutableSet<String> = linkedSetOf(),
|
||||||
var wildcard: Boolean = true
|
var wildcard: Boolean = false,
|
||||||
|
var registration: NodeRegistration = NodeRegistration.PERMISSION
|
||||||
) {
|
) {
|
||||||
fun toNode(): PermissionNode =
|
fun toNode(): PermissionNode =
|
||||||
PermissionNode(
|
PermissionNode(
|
||||||
|
|
@ -17,7 +18,8 @@ internal data class PermissionNodeDraft(
|
||||||
defaultValue = defaultValue,
|
defaultValue = defaultValue,
|
||||||
children = children.toMap(),
|
children = children.toMap(),
|
||||||
tags = tags.toSet(),
|
tags = tags.toSet(),
|
||||||
wildcard = wildcard
|
wildcard = wildcard,
|
||||||
|
registration = registration
|
||||||
)
|
)
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|
@ -28,7 +30,8 @@ internal data class PermissionNodeDraft(
|
||||||
defaultValue = node.defaultValue,
|
defaultValue = node.defaultValue,
|
||||||
children = node.children.toMutableMap(),
|
children = node.children.toMutableMap(),
|
||||||
tags = node.tags.toMutableSet(),
|
tags = node.tags.toMutableSet(),
|
||||||
wildcard = node.wildcard
|
wildcard = node.wildcard,
|
||||||
|
registration = node.registration
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,8 @@ class PermissionTree internal constructor(
|
||||||
|
|
||||||
operator fun get(id: PermissionId): PermissionNode? = nodes[id]
|
operator fun get(id: PermissionId): PermissionNode? = nodes[id]
|
||||||
|
|
||||||
fun toSnapshot(): TreeSnapshot = TreeSnapshot(nodes)
|
fun toSnapshot(): TreeSnapshot =
|
||||||
|
TreeSnapshot(nodes.filterValues { it.registration.registersPermission })
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
fun empty(namespace: String): PermissionTree = PermissionTree(namespace, emptyMap())
|
fun empty(namespace: String): PermissionTree = PermissionTree(namespace, emptyMap())
|
||||||
|
|
|
||||||
|
|
@ -29,6 +29,7 @@ class TreeSnapshot internal constructor(
|
||||||
digest.update(tag.toByteArray())
|
digest.update(tag.toByteArray())
|
||||||
}
|
}
|
||||||
digest.update(if (node.wildcard) 1 else 0)
|
digest.update(if (node.wildcard) 1 else 0)
|
||||||
|
digest.update(node.registration.name.toByteArray())
|
||||||
}
|
}
|
||||||
return digest.digest().joinToString("") { "%02x".format(it) }
|
return digest.digest().joinToString("") { "%02x".format(it) }
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
package net.hareworks.permits_lib.dsl
|
package net.hareworks.permits_lib.dsl
|
||||||
|
|
||||||
|
import net.hareworks.permits_lib.domain.NodeRegistration
|
||||||
import net.hareworks.permits_lib.domain.PermissionId
|
import net.hareworks.permits_lib.domain.PermissionId
|
||||||
import net.hareworks.permits_lib.domain.PermissionNodeDraft
|
import net.hareworks.permits_lib.domain.PermissionNodeDraft
|
||||||
import org.bukkit.permissions.PermissionDefault
|
import org.bukkit.permissions.PermissionDefault
|
||||||
|
|
@ -27,6 +28,12 @@ class PermissionNodeBuilder internal constructor(
|
||||||
draft.wildcard = value
|
draft.wildcard = value
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var registration: NodeRegistration
|
||||||
|
get() = draft.registration
|
||||||
|
set(value) {
|
||||||
|
draft.registration = value
|
||||||
|
}
|
||||||
|
|
||||||
fun tag(value: String) {
|
fun tag(value: String) {
|
||||||
if (value.isNotBlank()) {
|
if (value.isNotBlank()) {
|
||||||
draft.tags += value.trim()
|
draft.tags += value.trim()
|
||||||
|
|
@ -52,12 +59,16 @@ class PermissionNodeBuilder internal constructor(
|
||||||
* Declares a nested node whose id is derived from the current node:
|
* Declares a nested node whose id is derived from the current node:
|
||||||
*
|
*
|
||||||
* ```
|
* ```
|
||||||
* node("command") {
|
* node("command", NodeRegistration.STRUCTURAL) {
|
||||||
* node("reload") { ... } // -> namespace.command.reload
|
* node("reload", NodeRegistration.PERMISSION) { ... } // -> namespace.command.reload
|
||||||
* }
|
* }
|
||||||
* ```
|
* ```
|
||||||
*/
|
*/
|
||||||
fun node(id: String, block: PermissionNodeBuilder.() -> Unit = {}) {
|
fun node(
|
||||||
treeBuilder.nestedNode(draft, id, block)
|
id: String,
|
||||||
|
registration: NodeRegistration,
|
||||||
|
block: PermissionNodeBuilder.() -> Unit = {}
|
||||||
|
) {
|
||||||
|
treeBuilder.nestedNode(draft, id, registration, block)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
package net.hareworks.permits_lib.dsl
|
package net.hareworks.permits_lib.dsl
|
||||||
|
|
||||||
|
import net.hareworks.permits_lib.domain.NodeRegistration
|
||||||
import net.hareworks.permits_lib.domain.PermissionId
|
import net.hareworks.permits_lib.domain.PermissionId
|
||||||
import net.hareworks.permits_lib.domain.PermissionNodeDraft
|
import net.hareworks.permits_lib.domain.PermissionNodeDraft
|
||||||
import net.hareworks.permits_lib.domain.PermissionTree
|
import net.hareworks.permits_lib.domain.PermissionTree
|
||||||
|
|
@ -10,10 +11,15 @@ class PermissionTreeBuilder internal constructor(
|
||||||
) {
|
) {
|
||||||
private val drafts = linkedMapOf<PermissionId, PermissionNodeDraft>()
|
private val drafts = linkedMapOf<PermissionId, PermissionNodeDraft>()
|
||||||
|
|
||||||
fun node(id: String, block: PermissionNodeBuilder.() -> Unit = {}) {
|
fun node(
|
||||||
|
id: String,
|
||||||
|
registration: NodeRegistration,
|
||||||
|
block: PermissionNodeBuilder.() -> Unit = {}
|
||||||
|
) {
|
||||||
require(id.isNotBlank()) { "Node id must not be blank." }
|
require(id.isNotBlank()) { "Node id must not be blank." }
|
||||||
val permissionId = PermissionId.of("$namespace.${id.lowercase()}")
|
val permissionId = PermissionId.of("$namespace.${id.lowercase()}")
|
||||||
val draft = drafts.getOrPut(permissionId) { PermissionNodeDraft(permissionId) }
|
val draft = drafts.getOrPut(permissionId) { PermissionNodeDraft(permissionId) }
|
||||||
|
draft.registration = registration
|
||||||
PermissionNodeBuilder(this, draft).apply(block)
|
PermissionNodeBuilder(this, draft).apply(block)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -27,7 +33,7 @@ class PermissionTreeBuilder internal constructor(
|
||||||
require(id.isNotBlank()) { "Child id must not be blank." }
|
require(id.isNotBlank()) { "Child id must not be blank." }
|
||||||
"${parent.id.value}.${id.lowercase()}"
|
"${parent.id.value}.${id.lowercase()}"
|
||||||
} else {
|
} else {
|
||||||
id.lowercase()
|
normalizeAbsolute(id)
|
||||||
}
|
}
|
||||||
val permissionId = PermissionId.of(target)
|
val permissionId = PermissionId.of(target)
|
||||||
parent.children[permissionId] = value
|
parent.children[permissionId] = value
|
||||||
|
|
@ -48,17 +54,24 @@ class PermissionTreeBuilder internal constructor(
|
||||||
internal fun nestedNode(
|
internal fun nestedNode(
|
||||||
parent: PermissionNodeDraft,
|
parent: PermissionNodeDraft,
|
||||||
id: String,
|
id: String,
|
||||||
|
registration: NodeRegistration,
|
||||||
block: PermissionNodeBuilder.() -> Unit
|
block: PermissionNodeBuilder.() -> Unit
|
||||||
) {
|
) {
|
||||||
require(id.isNotBlank()) { "Nested node id must not be blank." }
|
require(id.isNotBlank()) { "Nested node id must not be blank." }
|
||||||
val composedId = PermissionId.of("${parent.id.value}.${id.lowercase()}")
|
val composedId = PermissionId.of("${parent.id.value}.${id.lowercase()}")
|
||||||
parent.children[composedId] = true
|
parent.children[composedId] = true
|
||||||
val draft = drafts.getOrPut(composedId) { PermissionNodeDraft(composedId) }
|
val draft = drafts.getOrPut(composedId) { PermissionNodeDraft(composedId) }
|
||||||
|
draft.registration = registration
|
||||||
PermissionNodeBuilder(this, draft).apply(block)
|
PermissionNodeBuilder(this, draft).apply(block)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun build(): PermissionTree =
|
fun build(): PermissionTree =
|
||||||
PermissionTree.from(namespace, drafts.mapValues { it.value.toNode() })
|
PermissionTree.from(namespace, drafts.mapValues { it.value.toNode() })
|
||||||
|
|
||||||
|
private fun normalizeAbsolute(id: String): String {
|
||||||
|
require(id.isNotBlank()) { "Absolute permission id must not be blank." }
|
||||||
|
return id.lowercase()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun permissionTree(namespace: String, block: PermissionTreeBuilder.() -> Unit): PermissionTree =
|
fun permissionTree(namespace: String, block: PermissionTreeBuilder.() -> Unit): PermissionTree =
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user