roles update and gradle scripts fixes

This commit is contained in:
2021-11-28 01:11:04 +06:00
parent 9a7272b976
commit 0e1a7adb04
31 changed files with 324 additions and 297 deletions

@ -6,13 +6,13 @@ import kotlinx.serialization.builtins.ListSerializer
const val usersRolesRootPathPart = "roles"
val UsersIdsSerializer = ListSerializer(UserId.serializer())
val RoleSubjectsSerializer = ListSerializer(RoleSubject.serializer())
const val usersRolesUserRoleQueryParameterName = "userRole"
const val usersRolesUserIdQueryParameterName = "userId"
const val usersRolesRoleQueryParameterName = "userRole"
const val usersRolesRoleSubjectQueryParameterName = "subject"
const val usersRolesGetUsersPathPart = "getUsersByRole"
const val usersRolesGetRolesPathPart = "getUserRoles"
const val usersRolesGetSubjectsPathPart = "getSubjectsByRole"
const val usersRolesGetRolesPathPart = "getSubjectRoles"
const val usersRolesContainsPathPart = "contains"
const val usersRolesContainsAnyPathPart = "containsAny"
@ -20,7 +20,7 @@ const val usersRolesIncludePathPart = "include"
const val usersRolesExcludePathPart = "exclude"
@Serializable
data class UserRolesStorageIncludeExcludeWrapper<T : UserRole>(
val userId: UserId,
data class RolesStorageIncludeExcludeWrapper<T : Role>(
val subject: RoleSubject,
val userRole: T
)

@ -6,31 +6,31 @@ import kotlinx.serialization.descriptors.SerialDescriptor
import kotlinx.serialization.encoding.*
import kotlinx.serialization.json.*
@Serializable(UserRoleSerializer::class)
interface UserRole { // temporarily made as class while interfaces are bugged
@Serializable(RoleSerializer::class)
interface Role {
companion object {
fun serializer() = UserRoleSerializer
fun serializer() = RoleSerializer
}
}
@Serializable
data class UnknownUserRole(val originalJson: JsonElement) : UserRole
data class UnknownRole(val originalJson: JsonElement) : Role
@Serializer(UserRole::class)
object UserRoleSerializer : KSerializer<UserRole> {
@Serializer(Role::class)
object RoleSerializer : KSerializer<Role> {
private val userRoleFormat = Json { ignoreUnknownKeys = true }
private const val keyField = "key"
private const val valueField = "value"
private val serializers = mutableMapOf<String, KSerializer<out UserRole>>()
private val serializers = mutableMapOf<String, KSerializer<out Role>>()
override val descriptor: SerialDescriptor = String.serializer().descriptor
@InternalSerializationApi
override fun deserialize(decoder: Decoder): UserRole {
override fun deserialize(decoder: Decoder): Role {
return if (decoder is JsonDecoder) {
val originalJson = decoder.decodeJsonElement().jsonObject
val type = originalJson[keyField]?.jsonPrimitive ?.content
return if (type == null || !serializers.containsKey(type)) {
UnknownUserRole(originalJson)
UnknownRole(originalJson)
} else {
userRoleFormat.decodeFromJsonElement(
serializers.getValue(type),
@ -44,14 +44,14 @@ object UserRoleSerializer : KSerializer<UserRole> {
}
@InternalSerializationApi
private fun <T : UserRole> T.toJson(): JsonElement {
private fun <T : Role> T.toJson(): JsonElement {
return userRoleFormat.encodeToJsonElement(this::class.serializer() as KSerializer<T>, this)
}
@InternalSerializationApi
override fun serialize(encoder: Encoder, value: UserRole) {
override fun serialize(encoder: Encoder, value: Role) {
if (encoder is JsonEncoder) {
if (value is UnknownUserRole) {
if (value is UnknownRole) {
encoder.encodeJsonElement(value.originalJson)
} else {
val valueSerializer = value::class.serializer()
@ -70,7 +70,7 @@ object UserRoleSerializer : KSerializer<UserRole> {
}
}
fun <T : UserRole> includeSerializer(
fun <T : Role> includeSerializer(
type: String,
kSerializer: KSerializer<T>
) { serializers[type] = kSerializer }

@ -2,4 +2,4 @@ package dev.inmo.postssystem.features.roles.common
import kotlinx.serialization.builtins.ListSerializer
val UserRolesSerializer = ListSerializer(UserRole.serializer())
val RolesSerializer = ListSerializer(Role.serializer())

@ -1,16 +1,42 @@
package dev.inmo.postssystem.features.roles.common
import dev.inmo.postssystem.features.users.common.UserId
import kotlinx.serialization.Serializable
interface ReadUsersRolesStorage<T : UserRole> {
suspend fun getUsers(userRole: T): List<UserId>
suspend fun getRoles(userId: UserId): List<T>
suspend fun contains(userId: UserId, userRole: T): Boolean
suspend fun containsAny(userId: UserId, userRoles: List<T>): Boolean
@Serializable
sealed class RoleSubject
@Serializable
data class OtherRoleRoleSubject(@Serializable(RoleSerializer::class) val role: Role) : RoleSubject()
@Serializable
data class UserRoleSubject(val userId: UserId) : RoleSubject()
interface ReadRolesStorage<T : Role> {
suspend fun getSubjects(role: T): List<RoleSubject>
suspend fun getRoles(subject: RoleSubject): List<T>
suspend fun getRoles(userId: UserId): List<T> = getRoles(UserRoleSubject(userId))
suspend fun contains(subject: RoleSubject, role: T): Boolean
suspend fun containsAny(subject: RoleSubject, roles: List<T>): Boolean
}
interface WriteUsersRolesStorage<T : UserRole> {
suspend fun include(userId: UserId, userRole: T): Boolean
suspend fun exclude(userId: UserId, userRole: T): Boolean
suspend fun ReadRolesStorage<Role>.getUsers(
userRole: Role
): List<UserId> = getSubjects(userRole).flatMap {
when (it) {
is OtherRoleRoleSubject -> getUsers(it.role)
is UserRoleSubject -> listOf(it.userId)
}
}
suspend fun ReadRolesStorage<Role>.contains(
userId: UserId,
userRole: Role
): Boolean = getSubjects(userRole).any {
when (it) {
is OtherRoleRoleSubject -> contains(userId, it.role)
is UserRoleSubject -> userId == it.userId
}
}
interface WriteRolesStorage<T : Role> {
suspend fun include(subject: RoleSubject, role: T): Boolean
suspend fun exclude(subject: RoleSubject, role: T): Boolean
}
interface UsersRolesStorage<T : UserRole> : ReadUsersRolesStorage<T>, WriteUsersRolesStorage<T>
interface RolesStorage<T : Role> : ReadRolesStorage<T>, WriteRolesStorage<T>

@ -0,0 +1,13 @@
package dev.inmo.postssystem.features.roles.common.keyvalue
import dev.inmo.postssystem.features.roles.common.*
import kotlinx.serialization.KSerializer
import kotlinx.serialization.StringFormat
open class KeyValueRolesStorage<T : Role>(
private val keyValuesRepo: KeyValuesRolesOriginalRepo,
private val serializer: KSerializer<T>,
private val format: StringFormat = ReadKeyValueRolesStorage.defaultJson
) : RolesStorage<T>,
ReadRolesStorage<T> by ReadKeyValueRolesStorage(keyValuesRepo, serializer, format),
WriteRolesStorage<T> by WriteKeyValueRolesStorage(keyValuesRepo, serializer, format)

@ -1,13 +0,0 @@
package dev.inmo.postssystem.features.roles.common.keyvalue
import dev.inmo.postssystem.features.roles.common.*
import kotlinx.serialization.KSerializer
import kotlinx.serialization.StringFormat
open class KeyValueUsersRolesStorage<T : UserRole>(
private val keyValuesRepo: KeyValuesUsersRolesOriginalRepo,
private val serializer: KSerializer<T>,
private val format: StringFormat = ReadKeyValueUsersRolesStorage.defaultJson
) : UsersRolesStorage<T>,
ReadUsersRolesStorage<T> by ReadKeyValueUsersRolesStorage(keyValuesRepo, serializer, format),
WriteUsersRolesStorage<T> by WriteKeyValueUsersRolesStorage(keyValuesRepo, serializer, format)

@ -2,4 +2,4 @@ package dev.inmo.postssystem.features.roles.common.keyvalue
import dev.inmo.micro_utils.repos.KeyValuesRepo
typealias KeyValuesUsersRolesOriginalRepo = KeyValuesRepo<Long, String>
typealias KeyValuesRolesOriginalRepo = KeyValuesRepo<String, String>

@ -0,0 +1,60 @@
package dev.inmo.postssystem.features.roles.common.keyvalue
import dev.inmo.postssystem.features.common.common.default
import dev.inmo.postssystem.features.roles.common.*
import dev.inmo.micro_utils.pagination.changeResults
import dev.inmo.micro_utils.pagination.utils.getAllByWithNextPaging
import dev.inmo.micro_utils.repos.ReadKeyValuesRepo
import kotlinx.serialization.KSerializer
import kotlinx.serialization.StringFormat
import kotlinx.serialization.json.Json
open class ReadKeyValueRolesStorage<T : Role>(
private val keyValuesRepo: ReadKeyValuesRepo<String, String>,
private val serializer: KSerializer<T>,
private val format: StringFormat = defaultJson
) : ReadRolesStorage<T> {
override suspend fun getSubjects(role: T): List<RoleSubject> {
val serialized = format.encodeToString(serializer, role)
return keyValuesRepo.getAllByWithNextPaging {
keys(serialized, it).let { paginationResult ->
paginationResult.changeResults(
paginationResult.results.map { serializedSubject -> format.decodeFromString(RoleSubject.serializer(), serializedSubject) }
)
}
}
}
override suspend fun getRoles(subject: RoleSubject): List<T> {
val subjectString = format.encodeToString(RoleSubject.serializer(), subject)
return keyValuesRepo.getAllByWithNextPaging {
get(subjectString, it).let { paginationResult ->
paginationResult.changeResults(
paginationResult.results.map { serialized ->
format.decodeFromString(serializer, serialized)
}
)
}
}
}
override suspend fun contains(subject: RoleSubject, role: T): Boolean {
val serialized = format.encodeToString(serializer, role)
val subjectString = format.encodeToString(RoleSubject.serializer(), subject)
return keyValuesRepo.contains(subjectString, serialized)
}
override suspend fun containsAny(subject: RoleSubject, roles: List<T>): Boolean {
val subjectString = format.encodeToString(RoleSubject.serializer(), subject)
return roles.any {
val serialized = format.encodeToString(serializer, it)
keyValuesRepo.contains(subjectString, serialized)
}
}
companion object {
internal val defaultJson = Json.default
}
}

@ -1,59 +0,0 @@
package dev.inmo.postssystem.features.roles.common.keyvalue
import dev.inmo.postssystem.features.common.common.default
import dev.inmo.postssystem.features.roles.common.ReadUsersRolesStorage
import dev.inmo.postssystem.features.roles.common.UserRole
import dev.inmo.postssystem.features.users.common.UserId
import dev.inmo.micro_utils.pagination.changeResults
import dev.inmo.micro_utils.pagination.utils.getAllByWithNextPaging
import dev.inmo.micro_utils.repos.ReadKeyValuesRepo
import kotlinx.serialization.KSerializer
import kotlinx.serialization.StringFormat
import kotlinx.serialization.json.Json
open class ReadKeyValueUsersRolesStorage<T : UserRole>(
private val keyValuesRepo: ReadKeyValuesRepo<Long, String>,
private val serializer: KSerializer<T>,
private val format: StringFormat = defaultJson
) : ReadUsersRolesStorage<T> {
override suspend fun getUsers(userRole: T): List<UserId> {
val serialized = format.encodeToString(serializer, userRole)
return keyValuesRepo.getAllByWithNextPaging {
keys(serialized, it).let { paginationResult ->
paginationResult.changeResults(
paginationResult.results.map { UserId(it) }
)
}
}
}
override suspend fun getRoles(userId: UserId): List<T> {
return keyValuesRepo.getAllByWithNextPaging {
get(userId.long, it).let { paginationResult ->
paginationResult.changeResults(
paginationResult.results.map { serialized ->
format.decodeFromString(serializer, serialized)
}
)
}
}
}
override suspend fun contains(userId: UserId, userRole: T): Boolean {
val serialized = format.encodeToString(serializer, userRole)
return keyValuesRepo.contains(userId.long, serialized)
}
override suspend fun containsAny(userId: UserId, userRoles: List<T>): Boolean {
return userRoles.any {
contains(userId, it)
}
}
companion object {
internal val defaultJson = Json.default
}
}

@ -0,0 +1,32 @@
package dev.inmo.postssystem.features.roles.common.keyvalue
import dev.inmo.postssystem.features.roles.common.*
import dev.inmo.micro_utils.repos.*
import kotlinx.serialization.KSerializer
import kotlinx.serialization.StringFormat
open class WriteKeyValueRolesStorage<T : Role>(
private val keyValuesRepo: WriteKeyValuesRepo<String, String>,
private val serializer: KSerializer<T>,
private val format: StringFormat = ReadKeyValueRolesStorage.defaultJson
) : WriteRolesStorage<T> {
override suspend fun include(subject: RoleSubject, role: T): Boolean {
return runCatching {
keyValuesRepo.add(
format.encodeToString(RoleSubject.serializer(), subject),
format.encodeToString(serializer, role)
)
true
}.getOrElse { false }
}
override suspend fun exclude(subject: RoleSubject, role: T): Boolean {
return runCatching {
keyValuesRepo.remove(
format.encodeToString(RoleSubject.serializer(), subject),
format.encodeToString(serializer, role)
)
true
}.getOrElse { false }
}
}

@ -1,34 +0,0 @@
package dev.inmo.postssystem.features.roles.common.keyvalue
import dev.inmo.postssystem.features.roles.common.UserRole
import dev.inmo.postssystem.features.roles.common.WriteUsersRolesStorage
import dev.inmo.postssystem.features.users.common.UserId
import dev.inmo.micro_utils.repos.*
import kotlinx.serialization.KSerializer
import kotlinx.serialization.StringFormat
open class WriteKeyValueUsersRolesStorage<T : UserRole>(
private val keyValuesRepo: WriteKeyValuesRepo<Long, String>,
private val serializer: KSerializer<T>,
private val format: StringFormat = ReadKeyValueUsersRolesStorage.defaultJson
) : WriteUsersRolesStorage<T> {
override suspend fun include(userId: UserId, userRole: T): Boolean {
return runCatching {
keyValuesRepo.add(
userId.long,
format.encodeToString(serializer, userRole)
)
true
}.getOrElse { false }
}
override suspend fun exclude(userId: UserId, userRole: T): Boolean {
return runCatching {
keyValuesRepo.remove(
userId.long,
format.encodeToString(serializer, userRole)
)
true
}.getOrElse { false }
}
}