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

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

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

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

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

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

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