roles update and gradle scripts fixes

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

View File

@ -5,9 +5,9 @@ import dev.inmo.postssystem.features.auth.client.installClientAuthenticator
import dev.inmo.postssystem.features.auth.common.* import dev.inmo.postssystem.features.auth.common.*
import dev.inmo.postssystem.features.files.client.ClientFilesStorage import dev.inmo.postssystem.features.files.client.ClientFilesStorage
import dev.inmo.postssystem.features.files.common.storage.FilesStorage import dev.inmo.postssystem.features.files.common.storage.FilesStorage
import dev.inmo.postssystem.features.roles.common.UserRole import dev.inmo.postssystem.features.roles.common.Role
import dev.inmo.postssystem.features.roles.common.UsersRolesStorage import dev.inmo.postssystem.features.roles.common.RolesStorage
import dev.inmo.postssystem.features.roles.client.ClientUsersRolesStorage import dev.inmo.postssystem.features.roles.client.ClientRolesStorage
import dev.inmo.postssystem.features.roles.manager.common.RolesManagerRoleSerializer import dev.inmo.postssystem.features.roles.manager.common.RolesManagerRoleSerializer
import dev.inmo.postssystem.features.users.client.UsersStorageKtorClient import dev.inmo.postssystem.features.users.client.UsersStorageKtorClient
import dev.inmo.postssystem.features.users.common.ReadUsersStorage import dev.inmo.postssystem.features.users.common.ReadUsersStorage
@ -47,7 +47,7 @@ import org.koin.dsl.module
val UIScopeQualifier = StringQualifier("CoroutineScopeUI") val UIScopeQualifier = StringQualifier("CoroutineScopeUI")
val SettingsQualifier = StringQualifier("Settings") val SettingsQualifier = StringQualifier("Settings")
val UserRolesQualifier = StringQualifier("UserRoles") val RolesQualifier = StringQualifier("Roles")
private val FSMHandlersBuilderQualifier = StringQualifier("FSMHandlersBuilder") private val FSMHandlersBuilderQualifier = StringQualifier("FSMHandlersBuilder")
val defaultSerialFormat = Json { val defaultSerialFormat = Json {
@ -131,6 +131,6 @@ fun getAuthorizedFeaturesDIModule(
single<FilesStorage> { ClientFilesStorage(get(serverUrlQualifier), get(), get()) } single<FilesStorage> { ClientFilesStorage(get(serverUrlQualifier), get(), get()) }
single<ReadUsersStorage> { UsersStorageKtorClient(get(serverUrlQualifier), get()) } single<ReadUsersStorage> { UsersStorageKtorClient(get(serverUrlQualifier), get()) }
single<UsersRolesStorage<UserRole>> { ClientUsersRolesStorage(get(serverUrlQualifier), get(), UserRole.serializer()) } single<RolesStorage<Role>> { ClientRolesStorage(get(serverUrlQualifier), get(), Role.serializer()) }
} }
} }

View File

@ -2,7 +2,7 @@ package dev.inmo.postssystem.client.settings.auth
import dev.inmo.postssystem.features.auth.client.ui.AuthUIError import dev.inmo.postssystem.features.auth.client.ui.AuthUIError
import dev.inmo.postssystem.features.auth.common.AuthCreds import dev.inmo.postssystem.features.auth.common.AuthCreds
import dev.inmo.postssystem.features.roles.common.UserRole import dev.inmo.postssystem.features.roles.common.Role
import dev.inmo.postssystem.features.users.common.User import dev.inmo.postssystem.features.users.common.User
import kotlinx.coroutines.Job import kotlinx.coroutines.Job
import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.StateFlow
@ -11,7 +11,7 @@ import org.koin.core.module.Module
interface AuthSettings { interface AuthSettings {
val authorizedDIModule: StateFlow<Module?> val authorizedDIModule: StateFlow<Module?>
val user: StateFlow<User?> val user: StateFlow<User?>
val userRoles: StateFlow<List<UserRole>> val userRoles: StateFlow<List<Role>>
val loadingJob: Job val loadingJob: Job
suspend fun auth(serverUrl: String, creds: AuthCreds): AuthUIError? suspend fun auth(serverUrl: String, creds: AuthCreds): AuthUIError?

View File

@ -5,8 +5,8 @@ import dev.inmo.postssystem.client.getAuthorizedFeaturesDIModule
import dev.inmo.postssystem.features.auth.client.AuthUnavailableException import dev.inmo.postssystem.features.auth.client.AuthUnavailableException
import dev.inmo.postssystem.features.auth.client.ui.* import dev.inmo.postssystem.features.auth.client.ui.*
import dev.inmo.postssystem.features.auth.common.* import dev.inmo.postssystem.features.auth.common.*
import dev.inmo.postssystem.features.roles.common.UserRole import dev.inmo.postssystem.features.roles.common.Role
import dev.inmo.postssystem.features.roles.common.UsersRolesStorage import dev.inmo.postssystem.features.roles.common.RolesStorage
import dev.inmo.postssystem.features.status.client.StatusFeatureClient import dev.inmo.postssystem.features.status.client.StatusFeatureClient
import dev.inmo.postssystem.features.users.common.User import dev.inmo.postssystem.features.users.common.User
import dev.inmo.micro_utils.common.Either import dev.inmo.micro_utils.common.Either
@ -29,8 +29,8 @@ data class DefaultAuthSettings(
override val authorizedDIModule: StateFlow<Module?> = _authorizedDIModule.asStateFlow() override val authorizedDIModule: StateFlow<Module?> = _authorizedDIModule.asStateFlow()
private val _user = MutableStateFlow<User?>(null) private val _user = MutableStateFlow<User?>(null)
override val user: StateFlow<User?> = _user.asStateFlow() override val user: StateFlow<User?> = _user.asStateFlow()
private val _userRoles = MutableStateFlow<List<UserRole>>(emptyList()) private val _userRoles = MutableStateFlow<List<Role>>(emptyList())
override val userRoles: StateFlow<List<UserRole>> = _userRoles.asStateFlow() override val userRoles: StateFlow<List<Role>> = _userRoles.asStateFlow()
private suspend fun getCurrentServerURL() = repo.get(SERVER_URL_FIELD) as? String private suspend fun getCurrentServerURL() = repo.get(SERVER_URL_FIELD) as? String
private suspend fun getCurrentUsername() = repo.get(USERNAME_FIELD) as? String private suspend fun getCurrentUsername() = repo.get(USERNAME_FIELD) as? String
@ -48,7 +48,7 @@ data class DefaultAuthSettings(
if (user == null || authorizedDIModule.value == null) { if (user == null || authorizedDIModule.value == null) {
_userRoles.value = emptyList() _userRoles.value = emptyList()
} else { } else {
_userRoles.value = koin.get<UsersRolesStorage<UserRole>>().getRoles(user.id) _userRoles.value = koin.get<RolesStorage<Role>>().getRoles(user.id)
} }
println(user) println(user)
println(userRoles.value) println(userRoles.value)

View File

@ -4,14 +4,14 @@ import dev.inmo.postssystem.features.roles.common.*
import dev.inmo.micro_utils.ktor.client.UnifiedRequester import dev.inmo.micro_utils.ktor.client.UnifiedRequester
import kotlinx.serialization.KSerializer import kotlinx.serialization.KSerializer
class ClientUsersRolesStorage<T : UserRole>( class ClientRolesStorage<T : Role>(
private val baseUrl: String, private val baseUrl: String,
private val unifiedRequester: UnifiedRequester, private val unifiedRequester: UnifiedRequester,
private val serializer: KSerializer<T> private val serializer: KSerializer<T>
) : UsersRolesStorage<T>, ) : RolesStorage<T>,
ReadUsersRolesStorage<T> by ReadClientUsersRolesStorage( ReadRolesStorage<T> by ReadClientRolesStorage(
baseUrl, unifiedRequester, serializer baseUrl, unifiedRequester, serializer
), ),
WriteUsersRolesStorage<T> by WriteClientUsersRolesStorage( WriteRolesStorage<T> by WriteClientRolesStorage(
baseUrl, unifiedRequester, serializer baseUrl, unifiedRequester, serializer
) )

View File

@ -1,18 +1,17 @@
package dev.inmo.postssystem.features.roles.client package dev.inmo.postssystem.features.roles.client
import dev.inmo.postssystem.features.roles.common.* import dev.inmo.postssystem.features.roles.common.*
import dev.inmo.postssystem.features.users.common.UserId
import dev.inmo.micro_utils.ktor.client.UnifiedRequester import dev.inmo.micro_utils.ktor.client.UnifiedRequester
import dev.inmo.micro_utils.ktor.common.buildStandardUrl import dev.inmo.micro_utils.ktor.common.buildStandardUrl
import kotlinx.serialization.KSerializer import kotlinx.serialization.KSerializer
import kotlinx.serialization.builtins.ListSerializer import kotlinx.serialization.builtins.ListSerializer
import kotlinx.serialization.builtins.serializer import kotlinx.serialization.builtins.serializer
class ReadClientUsersRolesStorage<T : UserRole>( class ReadClientRolesStorage<T : Role>(
private val baseUrl: String, private val baseUrl: String,
private val unifiedRequester: UnifiedRequester, private val unifiedRequester: UnifiedRequester,
private val serializer: KSerializer<T> private val serializer: KSerializer<T>
) : ReadUsersRolesStorage<T> { ) : ReadRolesStorage<T> {
private val userRolesSerializer = ListSerializer(serializer) private val userRolesSerializer = ListSerializer(serializer)
private val userRolesFullUrl = buildStandardUrl( private val userRolesFullUrl = buildStandardUrl(
@ -20,50 +19,50 @@ class ReadClientUsersRolesStorage<T : UserRole>(
usersRolesRootPathPart usersRolesRootPathPart
) )
override suspend fun getUsers( override suspend fun getSubjects(
userRole: T role: T
): List<UserId> = unifiedRequester.uniget( ): List<RoleSubject> = unifiedRequester.uniget(
buildStandardUrl( buildStandardUrl(
userRolesFullUrl, userRolesFullUrl,
usersRolesGetUsersPathPart, usersRolesGetSubjectsPathPart,
usersRolesUserRoleQueryParameterName to unifiedRequester.encodeUrlQueryValue(serializer, userRole) usersRolesRoleQueryParameterName to unifiedRequester.encodeUrlQueryValue(serializer, role)
), ),
UsersIdsSerializer RoleSubjectsSerializer
) )
override suspend fun getRoles( override suspend fun getRoles(
userId: UserId subject: RoleSubject
): List<T> = unifiedRequester.uniget( ): List<T> = unifiedRequester.uniget(
buildStandardUrl( buildStandardUrl(
userRolesFullUrl, userRolesFullUrl,
usersRolesGetRolesPathPart, usersRolesGetRolesPathPart,
usersRolesUserIdQueryParameterName to unifiedRequester.encodeUrlQueryValue(UserId.serializer(), userId) usersRolesRoleSubjectQueryParameterName to unifiedRequester.encodeUrlQueryValue(RoleSubject.serializer(), subject)
), ),
userRolesSerializer userRolesSerializer
) )
override suspend fun contains( override suspend fun contains(
userId: UserId, subject: RoleSubject,
userRole: T role: T
): Boolean = unifiedRequester.uniget( ): Boolean = unifiedRequester.uniget(
buildStandardUrl( buildStandardUrl(
userRolesFullUrl, userRolesFullUrl,
usersRolesContainsPathPart, usersRolesContainsPathPart,
usersRolesUserIdQueryParameterName to unifiedRequester.encodeUrlQueryValue(UserId.serializer(), userId), usersRolesRoleSubjectQueryParameterName to unifiedRequester.encodeUrlQueryValue(RoleSubject.serializer(), subject),
usersRolesUserRoleQueryParameterName to unifiedRequester.encodeUrlQueryValue(serializer, userRole) usersRolesRoleQueryParameterName to unifiedRequester.encodeUrlQueryValue(serializer, role)
), ),
Boolean.serializer() Boolean.serializer()
) )
override suspend fun containsAny( override suspend fun containsAny(
userId: UserId, subject: RoleSubject,
userRoles: List<T> roles: List<T>
): Boolean = unifiedRequester.uniget( ): Boolean = unifiedRequester.uniget(
buildStandardUrl( buildStandardUrl(
userRolesFullUrl, userRolesFullUrl,
usersRolesContainsAnyPathPart, usersRolesContainsAnyPathPart,
usersRolesUserIdQueryParameterName to unifiedRequester.encodeUrlQueryValue(UserId.serializer(), userId), usersRolesRoleSubjectQueryParameterName to unifiedRequester.encodeUrlQueryValue(RoleSubject.serializer(), subject),
usersRolesUserRoleQueryParameterName to unifiedRequester.encodeUrlQueryValue(userRolesSerializer, userRoles) usersRolesRoleQueryParameterName to unifiedRequester.encodeUrlQueryValue(userRolesSerializer, roles)
), ),
Boolean.serializer() Boolean.serializer()
) )

View File

@ -1,18 +1,17 @@
package dev.inmo.postssystem.features.roles.client package dev.inmo.postssystem.features.roles.client
import dev.inmo.postssystem.features.roles.common.* import dev.inmo.postssystem.features.roles.common.*
import dev.inmo.postssystem.features.users.common.UserId
import dev.inmo.micro_utils.ktor.client.UnifiedRequester import dev.inmo.micro_utils.ktor.client.UnifiedRequester
import dev.inmo.micro_utils.ktor.common.buildStandardUrl import dev.inmo.micro_utils.ktor.common.buildStandardUrl
import kotlinx.serialization.KSerializer import kotlinx.serialization.KSerializer
import kotlinx.serialization.builtins.serializer import kotlinx.serialization.builtins.serializer
class WriteClientUsersRolesStorage<T : UserRole>( class WriteClientRolesStorage<T : Role>(
private val baseUrl: String, private val baseUrl: String,
private val unifiedRequester: UnifiedRequester, private val unifiedRequester: UnifiedRequester,
private val serializer: KSerializer<T> private val serializer: KSerializer<T>
) : WriteUsersRolesStorage<T> { ) : WriteRolesStorage<T> {
private val wrapperSerializer = UserRolesStorageIncludeExcludeWrapper.serializer( private val wrapperSerializer = RolesStorageIncludeExcludeWrapper.serializer(
serializer serializer
) )
private val userRolesFullUrl = buildStandardUrl( private val userRolesFullUrl = buildStandardUrl(
@ -29,23 +28,23 @@ class WriteClientUsersRolesStorage<T : UserRole>(
) )
override suspend fun include( override suspend fun include(
userId: UserId, subject: RoleSubject,
userRole: T role: T
): Boolean = unifiedRequester.unipost( ): Boolean = unifiedRequester.unipost(
includeFullUrl, includeFullUrl,
wrapperSerializer to UserRolesStorageIncludeExcludeWrapper( wrapperSerializer to RolesStorageIncludeExcludeWrapper(
userId, userRole subject, role
), ),
Boolean.serializer() Boolean.serializer()
) )
override suspend fun exclude( override suspend fun exclude(
userId: UserId, subject: RoleSubject,
userRole: T role: T
): Boolean = unifiedRequester.unipost( ): Boolean = unifiedRequester.unipost(
excludeFullUrl, excludeFullUrl,
wrapperSerializer to UserRolesStorageIncludeExcludeWrapper( wrapperSerializer to RolesStorageIncludeExcludeWrapper(
userId, userRole subject, role
), ),
Boolean.serializer() Boolean.serializer()
) )

View File

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

View File

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

View File

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

View File

@ -1,16 +1,42 @@
package dev.inmo.postssystem.features.roles.common package dev.inmo.postssystem.features.roles.common
import dev.inmo.postssystem.features.users.common.UserId import dev.inmo.postssystem.features.users.common.UserId
import kotlinx.serialization.Serializable
interface ReadUsersRolesStorage<T : UserRole> { @Serializable
suspend fun getUsers(userRole: T): List<UserId> sealed class RoleSubject
suspend fun getRoles(userId: UserId): List<T> @Serializable
suspend fun contains(userId: UserId, userRole: T): Boolean data class OtherRoleRoleSubject(@Serializable(RoleSerializer::class) val role: Role) : RoleSubject()
suspend fun containsAny(userId: UserId, userRoles: List<T>): Boolean @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 ReadRolesStorage<Role>.getUsers(
suspend fun include(userId: UserId, userRole: T): Boolean userRole: Role
suspend fun exclude(userId: UserId, userRole: T): Boolean ): 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>

View File

@ -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)

View File

@ -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)

View File

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

View File

@ -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
}
}

View File

@ -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
}
}

View File

@ -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 }
}
}

View File

@ -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 }
}
}

View File

@ -1,12 +1,12 @@
package dev.inmo.postssystem.features.roles.manager.common package dev.inmo.postssystem.features.roles.manager.common
import dev.inmo.postssystem.features.roles.common.UserRole import dev.inmo.postssystem.features.roles.common.Role
import dev.inmo.postssystem.features.roles.common.UserRoleSerializer import dev.inmo.postssystem.features.roles.common.RoleSerializer
import dev.inmo.micro_utils.serialization.typed_serializer.TypedSerializer import dev.inmo.micro_utils.serialization.typed_serializer.TypedSerializer
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
@Serializable(RolesManagerRoleSerializer::class) @Serializable(RolesManagerRoleSerializer::class)
interface RolesManagerRole : UserRole { interface RolesManagerRole : Role {
companion object { companion object {
fun serializer() = RolesManagerRoleSerializer fun serializer() = RolesManagerRoleSerializer
} }
@ -26,7 +26,7 @@ object RolesManagerRoleSerializer : TypedSerializer<RolesManagerRole>(
) )
) { ) {
init { init {
UserRoleSerializer.includeSerializer(KEY, RolesManagerRoleSerializer) RoleSerializer.includeSerializer(KEY, RolesManagerRoleSerializer)
serializers.forEach { (k, v) -> UserRoleSerializer.includeSerializer(k, v) } serializers.forEach { (k, v) -> RoleSerializer.includeSerializer(k, v) }
} }
} }

View File

@ -1,15 +1,15 @@
package dev.inmo.postssystem.features.roles.manager.common package dev.inmo.postssystem.features.roles.manager.common
import dev.inmo.postssystem.features.common.common.default import dev.inmo.postssystem.features.common.common.default
import dev.inmo.postssystem.features.roles.common.UsersRolesStorage import dev.inmo.postssystem.features.roles.common.RolesStorage
import dev.inmo.postssystem.features.roles.common.keyvalue.* import dev.inmo.postssystem.features.roles.common.keyvalue.*
import kotlinx.serialization.StringFormat import kotlinx.serialization.StringFormat
import kotlinx.serialization.json.Json import kotlinx.serialization.json.Json
class RolesManagerRoleStorage( class RolesManagerRoleStorage(
keyValuesRepo: KeyValuesUsersRolesOriginalRepo, keyValuesRepo: KeyValuesRolesOriginalRepo,
format: StringFormat = Json.default format: StringFormat = Json.default
) : UsersRolesStorage<RolesManagerRole>, KeyValueUsersRolesStorage<RolesManagerRole>( ) : RolesStorage<RolesManagerRole>, KeyValueRolesStorage<RolesManagerRole>(
keyValuesRepo, keyValuesRepo,
RolesManagerRole.serializer(), RolesManagerRole.serializer(),
format format

View File

@ -1,18 +1,17 @@
package dev.inmo.postssystem.features.roles.manager.server package dev.inmo.postssystem.features.roles.manager.server
import dev.inmo.postssystem.features.roles.common.ReadUsersRolesStorage import dev.inmo.postssystem.features.roles.common.*
import dev.inmo.postssystem.features.roles.common.UserRole
import dev.inmo.postssystem.features.roles.manager.common.GeneralRolesManagerRole import dev.inmo.postssystem.features.roles.manager.common.GeneralRolesManagerRole
import dev.inmo.postssystem.features.roles.server.RolesChecker import dev.inmo.postssystem.features.roles.server.RolesChecker
import dev.inmo.postssystem.features.users.common.User import dev.inmo.postssystem.features.users.common.User
import io.ktor.application.ApplicationCall import io.ktor.application.ApplicationCall
object RolesManagerRolesChecker : RolesChecker<UserRole> { object RolesManagerRolesChecker : RolesChecker<Role> {
override val key: String override val key: String
get() = "RolesManagerRolesChecker" get() = "RolesManagerRolesChecker"
override suspend fun ApplicationCall.invoke( override suspend fun ApplicationCall.invoke(
usersRolesStorage: ReadUsersRolesStorage<UserRole>, usersRolesStorage: ReadRolesStorage<Role>,
user: User user: User
): Boolean = usersRolesStorage.contains(user.id, GeneralRolesManagerRole) ): Boolean = usersRolesStorage.contains(user.id, GeneralRolesManagerRole)
} }

View File

@ -1,16 +1,16 @@
package dev.inmo.postssystem.features.roles.manager.server package dev.inmo.postssystem.features.roles.manager.server
import dev.inmo.micro_utils.ktor.server.UnifiedRouter import dev.inmo.micro_utils.ktor.server.UnifiedRouter
import dev.inmo.postssystem.features.roles.common.UsersRolesStorage import dev.inmo.postssystem.features.roles.common.RolesStorage
import dev.inmo.postssystem.features.roles.manager.common.RolesManagerRole import dev.inmo.postssystem.features.roles.manager.common.RolesManagerRole
import dev.inmo.postssystem.features.roles.manager.common.RolesManagerRoleSerializer import dev.inmo.postssystem.features.roles.manager.common.RolesManagerRoleSerializer
import dev.inmo.postssystem.features.roles.server.UsersRolesStorageWriteServerRoutesConfigurator import dev.inmo.postssystem.features.roles.server.RolesStorageWriteServerRoutesConfigurator
import dev.inmo.micro_utils.ktor.server.configurators.ApplicationRoutingConfigurator import dev.inmo.micro_utils.ktor.server.configurators.ApplicationRoutingConfigurator
class RolesManagerUsersRolesStorageServerRoutesConfigurator( class RolesManagerRolesStorageServerRoutesConfigurator(
storage: UsersRolesStorage<RolesManagerRole>, storage: RolesStorage<RolesManagerRole>,
unifiedRouter: UnifiedRouter unifiedRouter: UnifiedRouter
) : ApplicationRoutingConfigurator.Element by UsersRolesStorageWriteServerRoutesConfigurator( ) : ApplicationRoutingConfigurator.Element by RolesStorageWriteServerRoutesConfigurator(
storage, storage,
RolesManagerRoleSerializer, RolesManagerRoleSerializer,
RolesManagerRolesChecker.key, RolesManagerRolesChecker.key,

View File

@ -4,24 +4,24 @@ import dev.inmo.postssystem.features.roles.common.*
import dev.inmo.postssystem.features.users.common.User import dev.inmo.postssystem.features.users.common.User
import io.ktor.application.ApplicationCall import io.ktor.application.ApplicationCall
interface RolesChecker<T : UserRole> { interface RolesChecker<T : Role> {
val key: String val key: String
suspend operator fun ApplicationCall.invoke( suspend operator fun ApplicationCall.invoke(
usersRolesStorage: ReadUsersRolesStorage<T>, usersRolesStorage: ReadRolesStorage<T>,
user: User user: User
): Boolean ): Boolean
companion object { companion object {
fun <T : UserRole> default( fun default(
key: String, key: String,
role: T role: Role
): RolesChecker<T> = object : RolesChecker<T> { ): RolesChecker<Role> = object : RolesChecker<Role> {
override val key: String override val key: String
get() = key get() = key
override suspend fun ApplicationCall.invoke( override suspend fun ApplicationCall.invoke(
usersRolesStorage: ReadUsersRolesStorage<T>, usersRolesStorage: ReadRolesStorage<Role>,
user: User user: User
): Boolean = usersRolesStorage.contains(user.id, role) ): Boolean = usersRolesStorage.contains(user.id, role)
} }

View File

@ -9,19 +9,19 @@ import io.ktor.routing.*
import kotlinx.serialization.KSerializer import kotlinx.serialization.KSerializer
import kotlinx.serialization.builtins.serializer import kotlinx.serialization.builtins.serializer
class UsersRolesStorageWriteServerRoutesConfigurator<T : UserRole>( class RolesStorageWriteServerRoutesConfigurator<T : Role>(
private val storage: WriteUsersRolesStorage<T>, private val storage: WriteRolesStorage<T>,
private val serializer: KSerializer<T>, private val serializer: KSerializer<T>,
private val includeAuthKey: String, private val includeAuthKey: String,
private val excludeAuthKey: String = includeAuthKey, private val excludeAuthKey: String = includeAuthKey,
private val unifiedRouter: UnifiedRouter private val unifiedRouter: UnifiedRouter
) : ApplicationRoutingConfigurator.Element { ) : ApplicationRoutingConfigurator.Element {
override fun Route.invoke() { override fun Route.invoke() {
unifiedRouter.apply { route(usersRolesRootPathPart) {
route(usersRolesRootPathPart) { val wrapperSerializer = RolesStorageIncludeExcludeWrapper.serializer(
val wrapperSerializer = UserRolesStorageIncludeExcludeWrapper.serializer( serializer
serializer )
) unifiedRouter.apply {
authenticate(includeAuthKey) { authenticate(includeAuthKey) {
post(usersRolesIncludePathPart) { post(usersRolesIncludePathPart) {
val wrapper = uniload(wrapperSerializer) val wrapper = uniload(wrapperSerializer)
@ -29,7 +29,7 @@ class UsersRolesStorageWriteServerRoutesConfigurator<T : UserRole>(
unianswer( unianswer(
Boolean.serializer(), Boolean.serializer(),
storage.include( storage.include(
wrapper.userId, wrapper.subject,
wrapper.userRole wrapper.userRole
) )
) )
@ -42,7 +42,7 @@ class UsersRolesStorageWriteServerRoutesConfigurator<T : UserRole>(
unianswer( unianswer(
Boolean.serializer(), Boolean.serializer(),
storage.exclude( storage.exclude(
wrapper.userId, wrapper.subject,
wrapper.userRole wrapper.userRole
) )
) )

View File

@ -1,39 +1,37 @@
package dev.inmo.postssystem.features.roles.server package dev.inmo.postssystem.features.roles.server
import dev.inmo.postssystem.features.roles.common.UserRole import dev.inmo.postssystem.features.roles.common.*
import dev.inmo.postssystem.features.roles.common.UsersRolesStorage
import dev.inmo.postssystem.features.users.common.UserId
class UsersRolesAggregator( class RolesAggregator(
private val otherStorages: List<UsersRolesStorageHolder<*>> private val otherStorages: List<RolesStorageHolder<*>>
) : UsersRolesStorage<UserRole> { ) : RolesStorage<Role> {
private val otherStoragesByClass = otherStorages.associateBy { it.kclass } private val otherStoragesByClass = otherStorages.associateBy { it.kclass }
override suspend fun getUsers(userRole: UserRole): List<UserId> { override suspend fun getSubjects(role: Role): List<RoleSubject> {
return otherStoragesByClass[userRole::class] ?.getUsers(userRole) ?: emptyList() return otherStoragesByClass[role::class] ?.getUsers(role) ?: emptyList()
} }
override suspend fun getRoles(userId: UserId): List<UserRole> = otherStorages.flatMap { it.getRoles(userId) } override suspend fun getRoles(subject: RoleSubject): List<Role> = otherStorages.flatMap { it.getRoles(subject) }
override suspend fun contains(userId: UserId, userRole: UserRole): Boolean { override suspend fun contains(subject: RoleSubject, role: Role): Boolean {
return otherStoragesByClass[userRole::class] ?.contains(userId, userRole) ?: false return otherStoragesByClass[role::class] ?.contains(subject, role) ?: false
} }
override suspend fun containsAny(userId: UserId, userRoles: List<UserRole>): Boolean { override suspend fun containsAny(subject: RoleSubject, roles: List<Role>): Boolean {
return userRoles.any { return roles.any {
contains(userId, it) contains(subject, it)
} }
} }
override suspend fun include( override suspend fun include(
userId: UserId, subject: RoleSubject,
userRole: UserRole role: Role
): Boolean = otherStoragesByClass[userRole::class] ?.include(userId, userRole) ?: false ): Boolean = otherStoragesByClass[role::class] ?.include(subject, role) ?: false
override suspend fun exclude( override suspend fun exclude(
userId: UserId, subject: RoleSubject,
userRole: UserRole role: Role
): Boolean { ): Boolean {
return otherStoragesByClass[userRole::class] ?.exclude(userId, userRole) ?: false return otherStoragesByClass[role::class] ?.exclude(subject, role) ?: false
} }
} }

View File

@ -4,18 +4,18 @@ import dev.inmo.postssystem.features.auth.common.AuthToken
import dev.inmo.postssystem.features.auth.server.principal import dev.inmo.postssystem.features.auth.server.principal
import dev.inmo.postssystem.features.auth.server.tokens.AuthTokensService import dev.inmo.postssystem.features.auth.server.tokens.AuthTokensService
import dev.inmo.postssystem.features.common.server.sessions.ApplicationAuthenticationConfigurator import dev.inmo.postssystem.features.common.server.sessions.ApplicationAuthenticationConfigurator
import dev.inmo.postssystem.features.roles.common.UserRole import dev.inmo.postssystem.features.roles.common.Role
import dev.inmo.postssystem.features.roles.common.UsersRolesStorage import dev.inmo.postssystem.features.roles.common.RolesStorage
import io.ktor.application.call import io.ktor.application.call
import io.ktor.auth.Authentication import io.ktor.auth.Authentication
import io.ktor.auth.session import io.ktor.auth.session
import io.ktor.http.HttpStatusCode import io.ktor.http.HttpStatusCode
import io.ktor.response.respond import io.ktor.response.respond
class UsersRolesAuthenticationConfigurator<T : UserRole>( class RolesAuthenticationConfigurator<T : Role>(
private val usersRolesStorage: UsersRolesStorage<T>, private val usersRolesStorage: RolesStorage<T>,
private val authTokensService: AuthTokensService, private val authTokensService: AuthTokensService,
private val rolesCheckers: List<RolesChecker<T>>, private val rolesCheckers: List<RolesChecker<T>>
) : ApplicationAuthenticationConfigurator.Element { ) : ApplicationAuthenticationConfigurator.Element {
override fun Authentication.Configuration.invoke() { override fun Authentication.Configuration.invoke() {
rolesCheckers.forEach { checker -> rolesCheckers.forEach { checker ->

View File

@ -1,42 +1,40 @@
package dev.inmo.postssystem.features.roles.server package dev.inmo.postssystem.features.roles.server
import dev.inmo.postssystem.features.roles.common.UserRole import dev.inmo.postssystem.features.roles.common.*
import dev.inmo.postssystem.features.roles.common.UsersRolesStorage
import dev.inmo.postssystem.features.users.common.UserId
import dev.inmo.micro_utils.common.* import dev.inmo.micro_utils.common.*
import kotlin.reflect.KClass import kotlin.reflect.KClass
data class UsersRolesStorageHolder<T : UserRole>( data class RolesStorageHolder<T : Role>(
val kclass: KClass<T>, val kclass: KClass<T>,
val storage: UsersRolesStorage<T> val storage: RolesStorage<T>
) { ) {
private suspend fun <R> doIfRelevant( private suspend fun <R> doIfRelevant(
userRole: UserRole, role: Role,
block: suspend (T) -> R block: suspend (T) -> R
): Optional<R> = if (kclass.isInstance(userRole)) { ): Optional<R> = if (kclass.isInstance(role)) {
block(userRole as T).optional block(role as T).optional
} else { } else {
Optional.absent() Optional.absent()
} }
suspend fun getUsers(userRole: UserRole): List<UserId>? = doIfRelevant(userRole) { suspend fun getUsers(role: Role): List<RoleSubject>? = doIfRelevant(role) {
storage.getUsers(it) storage.getSubjects(it)
}.dataOrNull() }.dataOrNull()
suspend fun getRoles(userId: UserId): List<UserRole> = storage.getRoles(userId) suspend fun getRoles(subject: RoleSubject): List<Role> = storage.getRoles(subject)
suspend fun contains(userId: UserId, userRole: UserRole): Boolean? = doIfRelevant(userRole) { suspend fun contains(subject: RoleSubject, role: Role): Boolean? = doIfRelevant(role) {
storage.contains(userId, it) storage.contains(subject, it)
}.dataOrNull() }.dataOrNull()
suspend fun include( suspend fun include(
userId: UserId, subject: RoleSubject,
userRole: UserRole role: Role
): Boolean? = doIfRelevant(userRole) { ): Boolean? = doIfRelevant(role) {
storage.include(userId, it) storage.include(subject, it)
}.dataOrNull() }.dataOrNull()
suspend fun exclude(userId: UserId, userRole: UserRole): Boolean? = doIfRelevant(userRole) { suspend fun exclude(subject: RoleSubject, role: Role): Boolean? = doIfRelevant(role) {
storage.exclude(userId, it) storage.exclude(subject, it)
}.dataOrNull() }.dataOrNull()
} }

View File

@ -1,18 +1,16 @@
package dev.inmo.postssystem.features.roles.server package dev.inmo.postssystem.features.roles.server
import dev.inmo.postssystem.features.roles.common.* import dev.inmo.postssystem.features.roles.common.*
import dev.inmo.postssystem.features.users.common.UserId
import dev.inmo.micro_utils.ktor.server.* import dev.inmo.micro_utils.ktor.server.*
import dev.inmo.micro_utils.ktor.server.configurators.ApplicationRoutingConfigurator import dev.inmo.micro_utils.ktor.server.configurators.ApplicationRoutingConfigurator
import io.ktor.application.call
import io.ktor.auth.authenticate import io.ktor.auth.authenticate
import io.ktor.routing.* import io.ktor.routing.*
import kotlinx.serialization.KSerializer import kotlinx.serialization.KSerializer
import kotlinx.serialization.builtins.ListSerializer import kotlinx.serialization.builtins.ListSerializer
import kotlinx.serialization.builtins.serializer import kotlinx.serialization.builtins.serializer
class UsersRolesStorageReadServerRoutesConfigurator<T : UserRole>( class RolesStorageReadServerRoutesConfigurator<T : Role>(
private val storage: ReadUsersRolesStorage<T>, private val storage: ReadRolesStorage<T>,
private val serializer: KSerializer<T>, private val serializer: KSerializer<T>,
private val unifiedRouter: UnifiedRouter private val unifiedRouter: UnifiedRouter
) : ApplicationRoutingConfigurator.Element { ) : ApplicationRoutingConfigurator.Element {
@ -21,51 +19,53 @@ class UsersRolesStorageReadServerRoutesConfigurator<T : UserRole>(
unifiedRouter.apply { unifiedRouter.apply {
authenticate { authenticate {
route(usersRolesRootPathPart) { route(usersRolesRootPathPart) {
get(usersRolesGetUsersPathPart) { get(usersRolesGetSubjectsPathPart) {
val userRole = decodeUrlQueryValueOrSendError(usersRolesUserRoleQueryParameterName, serializer) val role = decodeUrlQueryValueOrSendError(usersRolesRoleQueryParameterName, serializer)
?: return@get ?: return@get
unianswer( unianswer(
UsersIdsSerializer, RoleSubjectsSerializer,
storage.getUsers(userRole) storage.getSubjects(role)
) )
} }
get(usersRolesGetRolesPathPart) { get(usersRolesGetRolesPathPart) {
val userId = decodeUrlQueryValueOrSendError(usersRolesUserIdQueryParameterName, UserId.serializer()) val subject = decodeUrlQueryValueOrSendError(
?: return@get usersRolesRoleSubjectQueryParameterName,
RoleSubject.serializer()
) ?: return@get
unianswer( unianswer(
userRolesSerializer, userRolesSerializer,
storage.getRoles(userId) storage.getRoles(subject)
) )
} }
get(usersRolesContainsPathPart) { get(usersRolesContainsPathPart) {
val userId = decodeUrlQueryValueOrSendError( val subject = decodeUrlQueryValueOrSendError(
usersRolesUserIdQueryParameterName, usersRolesRoleSubjectQueryParameterName,
UserId.serializer() RoleSubject.serializer()
) ?: return@get ) ?: return@get
val userRole = decodeUrlQueryValueOrSendError( val role = decodeUrlQueryValueOrSendError(
usersRolesUserRoleQueryParameterName, usersRolesRoleQueryParameterName,
serializer serializer
) ?: return@get ) ?: return@get
unianswer( unianswer(
Boolean.serializer(), Boolean.serializer(),
storage.contains(userId, userRole) storage.contains(subject, role)
) )
} }
get(usersRolesContainsAnyPathPart) { get(usersRolesContainsAnyPathPart) {
val userId = decodeUrlQueryValueOrSendError( val subject = decodeUrlQueryValueOrSendError(
usersRolesUserIdQueryParameterName, usersRolesRoleSubjectQueryParameterName,
UserId.serializer() RoleSubject.serializer()
) ?: return@get ) ?: return@get
val userRoles = decodeUrlQueryValueOrSendError( val userRoles = decodeUrlQueryValueOrSendError(
usersRolesUserRoleQueryParameterName, usersRolesRoleQueryParameterName,
userRolesSerializer userRolesSerializer
) ?: return@get ) ?: return@get
unianswer( unianswer(
Boolean.serializer(), Boolean.serializer(),
storage.containsAny(userId, userRoles) storage.containsAny(subject, userRoles)
) )
} }
} }

View File

@ -1,7 +1,7 @@
project.version = "$version" project.version = "$version"
project.group = "$group" project.group = "$group"
apply from: "$publishGradlePath" apply from: "$publishGradlePath"
kotlin { kotlin {
jvm().compilations.main { jvm().compilations.main {
@ -31,3 +31,8 @@ kotlin {
} }
} }
} }
java {
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
}

View File

@ -1,7 +1,7 @@
project.version = "$version" project.version = "$version"
project.group = "$group" project.group = "$group"
apply from: "$publishGradlePath" apply from: "$publishGradlePath"
kotlin { kotlin {
js (IR) { js (IR) {

View File

@ -1,7 +1,7 @@
project.version = "$version" project.version = "$version"
project.group = "$group" project.group = "$group"
apply from: "$publishGradlePath" apply from: "$publishGradlePath"
kotlin { kotlin {
jvm().compilations.main { jvm().compilations.main {
@ -53,3 +53,8 @@ kotlin {
} }
apply from: "$defaultAndroidSettingsPresetPath" apply from: "$defaultAndroidSettingsPresetPath"
java {
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
}

View File

@ -9,17 +9,16 @@ import dev.inmo.postssystem.features.files.common.storage.*
import dev.inmo.postssystem.features.files.common.storage.WriteFilesStorage import dev.inmo.postssystem.features.files.common.storage.WriteFilesStorage
import dev.inmo.postssystem.features.files.server.FilesRoutingConfigurator import dev.inmo.postssystem.features.files.server.FilesRoutingConfigurator
import dev.inmo.postssystem.features.roles.common.* import dev.inmo.postssystem.features.roles.common.*
import dev.inmo.postssystem.features.roles.common.keyvalue.KeyValuesUsersRolesOriginalRepo import dev.inmo.postssystem.features.roles.common.keyvalue.KeyValuesRolesOriginalRepo
import dev.inmo.postssystem.features.roles.manager.common.RolesManagerRole import dev.inmo.postssystem.features.roles.manager.common.RolesManagerRole
import dev.inmo.postssystem.features.roles.manager.common.RolesManagerRoleStorage import dev.inmo.postssystem.features.roles.manager.common.RolesManagerRoleStorage
import dev.inmo.postssystem.features.roles.manager.server.RolesManagerRolesChecker import dev.inmo.postssystem.features.roles.manager.server.RolesManagerRolesChecker
import dev.inmo.postssystem.features.roles.manager.server.RolesManagerUsersRolesStorageServerRoutesConfigurator import dev.inmo.postssystem.features.roles.manager.server.RolesManagerRolesStorageServerRoutesConfigurator
import dev.inmo.postssystem.features.roles.server.* import dev.inmo.postssystem.features.roles.server.*
import dev.inmo.postssystem.features.status.server.StatusRoutingConfigurator import dev.inmo.postssystem.features.status.server.StatusRoutingConfigurator
import dev.inmo.postssystem.features.users.common.ExposedUsersStorage import dev.inmo.postssystem.features.users.common.ExposedUsersStorage
import dev.inmo.postssystem.features.users.server.UsersStorageServerRoutesConfigurator import dev.inmo.postssystem.features.users.server.UsersStorageServerRoutesConfigurator
import dev.inmo.micro_utils.coroutines.LinkedSupervisorScope import dev.inmo.micro_utils.coroutines.LinkedSupervisorScope
import dev.inmo.micro_utils.ktor.common.standardKtorSerialFormat
import dev.inmo.micro_utils.ktor.server.UnifiedRouter import dev.inmo.micro_utils.ktor.server.UnifiedRouter
import dev.inmo.micro_utils.ktor.server.configurators.* import dev.inmo.micro_utils.ktor.server.configurators.*
import dev.inmo.micro_utils.ktor.server.createKtorServer import dev.inmo.micro_utils.ktor.server.createKtorServer
@ -113,23 +112,23 @@ fun getDIModule(
singleWithBinds { ExposedUsersStorage(get()) } singleWithBinds { ExposedUsersStorage(get()) }
singleWithBinds { exposedUsersAuthenticator(get(), get()) } singleWithBinds { exposedUsersAuthenticator(get(), get()) }
factory<KeyValuesUsersRolesOriginalRepo>(usersRolesKeyValueFactoryQualifier) { (tableName: String) -> factory<KeyValuesRolesOriginalRepo>(usersRolesKeyValueFactoryQualifier) { (tableName: String) ->
ExposedOneToManyKeyValueRepo(get(), { long("userId") }, { text("role") }, tableName) ExposedOneToManyKeyValueRepo(get(), { text("subject") }, { text("role") }, tableName)
} }
single { single {
RolesManagerRoleStorage(get(usersRolesKeyValueFactoryQualifier) { ParametersHolder(mutableListOf("rolesManager")) }) RolesManagerRoleStorage(get(usersRolesKeyValueFactoryQualifier) { ParametersHolder(mutableListOf("rolesManager")) })
} }
single<UsersRolesStorage<RolesManagerRole>>(StringQualifier("RolesManagerRoleStorage")) { get<RolesManagerRoleStorage>() } single<RolesStorage<RolesManagerRole>>(StringQualifier("RolesManagerRoleStorage")) { get<RolesManagerRoleStorage>() }
singleWithBinds { singleWithBinds {
UsersRolesStorageHolder( RolesStorageHolder(
RolesManagerRole::class, RolesManagerRole::class,
get<RolesManagerRoleStorage>() get<RolesManagerRoleStorage>()
) )
} }
singleWithBinds<UsersRolesStorage<UserRole>> { UsersRolesAggregator(getAll()) } singleWithBinds<RolesStorage<Role>> { RolesAggregator(getAll()) }
// Roles checkers // Roles checkers
single<RolesChecker<UserRole>>(StringQualifier(RolesManagerRolesChecker.key)) { RolesManagerRolesChecker } single<RolesChecker<Role>>(StringQualifier(RolesManagerRolesChecker.key)) { RolesManagerRolesChecker }
factory<CoroutineScope> { baseScope.LinkedSupervisorScope() } factory<CoroutineScope> { baseScope.LinkedSupervisorScope() }
@ -137,12 +136,12 @@ fun getDIModule(
singleWithBinds { FilesRoutingConfigurator(get(), null, get()) } singleWithBinds { FilesRoutingConfigurator(get(), null, get()) }
singleWithBinds { StatusRoutingConfigurator } singleWithBinds { StatusRoutingConfigurator }
singleWithBinds { UsersStorageServerRoutesConfigurator(get(), get()) } singleWithBinds { UsersStorageServerRoutesConfigurator(get(), get()) }
singleWithBinds { UsersRolesStorageReadServerRoutesConfigurator<UserRole>(get(), UserRoleSerializer, get()) } singleWithBinds { RolesStorageReadServerRoutesConfigurator<Role>(get(), RoleSerializer, get()) }
singleWithBinds { RolesManagerUsersRolesStorageServerRoutesConfigurator(get(), get()) } singleWithBinds { RolesManagerRolesStorageServerRoutesConfigurator(get(), get()) }
singleWithBinds { ClientStaticRoutingConfiguration(get<Config>().clientStatic) } singleWithBinds { ClientStaticRoutingConfiguration(get<Config>().clientStatic) }
singleWithBinds { singleWithBinds {
UsersRolesAuthenticationConfigurator<UserRole>( RolesAuthenticationConfigurator<Role>(
get(), get(),
get(), get(),
getAll() getAll()