diff --git a/core/shared/src/main/scala/works/iterative/core/Action.scala b/core/shared/src/main/scala/works/iterative/core/Action.scala new file mode 100644 index 0000000..834a945 --- /dev/null +++ b/core/shared/src/main/scala/works/iterative/core/Action.scala @@ -0,0 +1,14 @@ +package works.iterative.core + +import works.iterative.core.auth.PermissionOp +import works.iterative.core.auth.PermissionTarget + +final case class Action( + op: PermissionOp, + target: PermissionTarget +) + +object Action: + def apply(op: String, target: String): Validated[Action] = + for t <- PermissionTarget(target) + yield Action(PermissionOp(op), t) diff --git a/core/shared/src/main/scala/works/iterative/core/Action.scala b/core/shared/src/main/scala/works/iterative/core/Action.scala new file mode 100644 index 0000000..834a945 --- /dev/null +++ b/core/shared/src/main/scala/works/iterative/core/Action.scala @@ -0,0 +1,14 @@ +package works.iterative.core + +import works.iterative.core.auth.PermissionOp +import works.iterative.core.auth.PermissionTarget + +final case class Action( + op: PermissionOp, + target: PermissionTarget +) + +object Action: + def apply(op: String, target: String): Validated[Action] = + for t <- PermissionTarget(target) + yield Action(PermissionOp(op), t) diff --git a/core/shared/src/main/scala/works/iterative/core/auth/PermissionService.scala b/core/shared/src/main/scala/works/iterative/core/auth/PermissionService.scala index 6edb8e4..37818a8 100644 --- a/core/shared/src/main/scala/works/iterative/core/auth/PermissionService.scala +++ b/core/shared/src/main/scala/works/iterative/core/auth/PermissionService.scala @@ -1,6 +1,9 @@ package works.iterative.core.auth import zio.* +import works.iterative.core.Validated +import zio.prelude.Validation +import works.iterative.core.UserMessage opaque type PermissionOp = String object PermissionOp: @@ -10,7 +13,33 @@ opaque type PermissionTarget = String object PermissionTarget: - def apply(namespace: String, id: String): PermissionTarget = + def apply(target: String): Validated[PermissionTarget] = + target.split(":", 2) match + case Array(n, i) => apply(n, i) + case _ => Validation.fail(UserMessage("error.target.format")) + + def apply(namespace: String, id: String): Validated[PermissionTarget] = + for + n <- Validation.fromPredicateWith(UserMessage("error.namespace.empty"))( + namespace + )(_.trim.nonEmpty) + i <- Validation.fromPredicateWith(UserMessage("error.id.empty"))(id)( + _.trim.nonEmpty + ) + _ <- Validation.fromPredicateWith(UserMessage("error.namespace.colon"))( + n + )(_.indexOf(':') == -1) + _ <- Validation.fromPredicateWith(UserMessage("error.id.colon"))(i)( + _.indexOf(':') == -1 + ) + yield s"$n:$i" + + def unsafe(target: String): PermissionTarget = + require(target.trim.nonEmpty, "Target must be defined") + require(target.indexOf(':') != -1, "Target must contain ':'") + target + + def unsafe(namespace: String, id: String): PermissionTarget = require( namespace.trim.nonEmpty && id.trim.nonEmpty, "Both namespace and id must be defined" @@ -19,7 +48,7 @@ namespace.indexOf(':') == -1 && id.indexOf(':') == -1, "Neither namespace nor id can contain ':'" ) - s"$namespace:$id" + s"${namespace}:${id}" extension (target: PermissionTarget) def namespace: String = target.split(":", 2).head