diff --git a/client/build.gradle b/client/build.gradle index b6313f8d..3227d2ea 100644 --- a/client/build.gradle +++ b/client/build.gradle @@ -20,6 +20,7 @@ kotlin { api project(":postssystem.features.auth.client") api project(":postssystem.features.roles.client") api project(":postssystem.features.roles.manager.client") + api project(":postssystem.features.content.client") api "dev.inmo:micro_utils.fsm.common:$microutils_version" api "dev.inmo:micro_utils.fsm.repos.common:$microutils_version" api "dev.inmo:micro_utils.crypto:$microutils_version" diff --git a/client/src/commonMain/kotlin/dev/inmo/postssystem/client/DI.kt b/client/src/commonMain/kotlin/dev/inmo/postssystem/client/DI.kt index d3a5b027..b0f61bed 100644 --- a/client/src/commonMain/kotlin/dev/inmo/postssystem/client/DI.kt +++ b/client/src/commonMain/kotlin/dev/inmo/postssystem/client/DI.kt @@ -24,13 +24,19 @@ import dev.inmo.postssystem.client.settings.DefaultSettings import dev.inmo.postssystem.client.settings.Settings import dev.inmo.postssystem.client.settings.auth.AuthSettings import dev.inmo.postssystem.client.settings.auth.DefaultAuthSettings +import dev.inmo.postssystem.features.common.common.SerializersModuleConfigurator +import dev.inmo.postssystem.features.common.common.singleWithRandomQualifier +import dev.inmo.postssystem.features.content.common.ContentSerializersModuleConfigurator +import dev.inmo.postssystem.features.content.common.OtherContentSerializerModuleConfigurator import dev.inmo.postssystem.features.status.client.StatusFeatureClient import io.ktor.client.HttpClient import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.serialization.BinaryFormat import kotlinx.serialization.StringFormat +import kotlinx.serialization.cbor.Cbor import kotlinx.serialization.json.Json +import kotlinx.serialization.modules.SerializersModule import org.koin.core.Koin import org.koin.core.context.startKoin import org.koin.core.module.Module @@ -41,7 +47,6 @@ import org.koin.dsl.module val UIScopeQualifier = StringQualifier("CoroutineScopeUI") val SettingsQualifier = StringQualifier("Settings") val UserRolesQualifier = StringQualifier("UserRoles") -private val DBDropperQualifier = StringQualifier("DBDropper") private val FSMHandlersBuilderQualifier = StringQualifier("FSMHandlersBuilder") val defaultSerialFormat = Json { @@ -61,7 +66,18 @@ fun baseKoin( ): Koin = startKoin { modules( module { - single { defaultSerialFormat } + singleWithRandomQualifier { OtherContentSerializerModuleConfigurator } + singleWithRandomQualifier { ContentSerializersModuleConfigurator(getAll()) } + single { SerializersModuleConfigurator(getAll()) } + + single { + Json { + ignoreUnknownKeys = true + serializersModule = SerializersModule { get().apply { invoke() } } + } + } + single { get() } + single(SettingsQualifier) { settingsFactory() } single { DBDropper(get(SettingsQualifier)) } single(FSMHandlersBuilderQualifier) { handlersSetter } @@ -102,7 +118,11 @@ fun getAuthorizedFeaturesDIModule( } single(credsQualifier) { initialAuthKey } single(serverUrlQualifier) { serverUrl } - single { standardKtorSerialFormat } + single { + Cbor { + serializersModule = SerializersModule { get().apply { invoke() } } + } + } single { UnifiedRequester(get(), get()) } single { StatusFeatureClient(get(serverUrlQualifier), get()) } diff --git a/features/auth/server/src/jvmMain/kotlin/dev/inmo/postssystem/features/auth/server/AuthenticationRoutingConfigurator.kt b/features/auth/server/src/jvmMain/kotlin/dev/inmo/postssystem/features/auth/server/AuthenticationRoutingConfigurator.kt index 74ee9d7a..a4fb4827 100644 --- a/features/auth/server/src/jvmMain/kotlin/dev/inmo/postssystem/features/auth/server/AuthenticationRoutingConfigurator.kt +++ b/features/auth/server/src/jvmMain/kotlin/dev/inmo/postssystem/features/auth/server/AuthenticationRoutingConfigurator.kt @@ -5,9 +5,8 @@ import dev.inmo.postssystem.features.auth.server.tokens.AuthTokensService import dev.inmo.postssystem.features.common.server.sessions.ApplicationAuthenticationConfigurator import dev.inmo.postssystem.features.users.common.User import dev.inmo.micro_utils.coroutines.safely +import dev.inmo.micro_utils.ktor.server.* import dev.inmo.micro_utils.ktor.server.configurators.* -import dev.inmo.micro_utils.ktor.server.unianswer -import dev.inmo.micro_utils.ktor.server.uniload import io.ktor.application.* import io.ktor.auth.* import io.ktor.http.HttpStatusCode @@ -25,81 +24,84 @@ fun User.principal() = AuthUserPrincipal(this) class AuthenticationRoutingConfigurator( private val authFeature: AuthFeature, - private val authTokensService: AuthTokensService + private val authTokensService: AuthTokensService, + private val unifiedRouter: UnifiedRouter ) : ApplicationRoutingConfigurator.Element, ApplicationAuthenticationConfigurator.Element { override fun Route.invoke() { - route(authRootPathPart) { - post(authAuthPathPart) { - safely( - { - // TODO:: add error info - it.printStackTrace() - call.respond( - HttpStatusCode.InternalServerError, - "Something went wrong" - ) - } - ) { - val creds = call.uniload(AuthCreds.serializer()) - - val tokenInfo = authFeature.auth(creds) - - if (tokenInfo == null) { - if (call.response.status() == null) { - call.respond(HttpStatusCode.Forbidden) + unifiedRouter.apply { + route(authRootPathPart) { + post(authAuthPathPart) { + safely( + { + // TODO:: add error info + it.printStackTrace() + call.respond( + HttpStatusCode.InternalServerError, + "Something went wrong" + ) + } + ) { + val creds = uniload(AuthCreds.serializer()) + + val tokenInfo = authFeature.auth(creds) + + if (tokenInfo == null) { + if (call.response.status() == null) { + call.respond(HttpStatusCode.Forbidden) + } + } else { + call.sessions.set(tokenSessionKey, tokenInfo.token) + unianswer( + AuthTokenInfo.serializer().nullable, + tokenInfo + ) } - } else { - call.sessions.set(tokenSessionKey, tokenInfo.token) - call.unianswer( - AuthTokenInfo.serializer().nullable, - tokenInfo - ) } } - } - post(authRefreshPathPart) { - safely( - { - // TODO:: add error info - call.respond( - HttpStatusCode.InternalServerError, - "Something went wrong" - ) - } - ) { - val refreshToken = call.uniload(RefreshToken.serializer()) - - val tokenInfo = authFeature.refresh(refreshToken) - - if (tokenInfo == null) { - if (call.response.status() == null) { - call.respond(HttpStatusCode.Forbidden) + post(authRefreshPathPart) { + safely( + { + // TODO:: add error info + call.respond( + HttpStatusCode.InternalServerError, + "Something went wrong" + ) + } + ) { + val refreshToken = uniload(RefreshToken.serializer()) + + val tokenInfo = authFeature.refresh(refreshToken) + + if (tokenInfo == null) { + if (call.response.status() == null) { + call.respond(HttpStatusCode.Forbidden) + } + } else { + call.sessions.set(tokenSessionKey, tokenInfo.token) + unianswer( + AuthTokenInfo.serializer().nullable, + tokenInfo + ) } - } else { - call.sessions.set(tokenSessionKey, tokenInfo.token) - call.unianswer( - AuthTokenInfo.serializer().nullable, - tokenInfo - ) } } - } - post(authGetMePathPart) { - safely( - { - // TODO:: add error info - call.respond( - HttpStatusCode.InternalServerError, - "Something went wrong" + post(authGetMePathPart) { + safely( + { + // TODO:: add error info + call.respond( + HttpStatusCode.InternalServerError, + "Something went wrong" + ) + } + ) { + unianswer( + User.serializer().nullable, + authFeature.getMe( + uniload(AuthToken.serializer()) + ) ) } - ) { - call.unianswer( - User.serializer().nullable, - authFeature.getMe( - call.uniload(AuthToken.serializer()) - ) - ) } } } diff --git a/features/common/common/src/commonMain/kotlin/dev/inmo/postssystem/features/common/common/KoinSingleWithAutoQualifier.kt b/features/common/common/src/commonMain/kotlin/dev/inmo/postssystem/features/common/common/KoinSingleWithAutoQualifier.kt new file mode 100644 index 00000000..490eae17 --- /dev/null +++ b/features/common/common/src/commonMain/kotlin/dev/inmo/postssystem/features/common/common/KoinSingleWithAutoQualifier.kt @@ -0,0 +1,16 @@ +package dev.inmo.postssystem.features.common.common + +import com.benasher44.uuid.uuid4 +import org.koin.core.definition.Definition +import org.koin.core.instance.InstanceFactory +import org.koin.core.module.Module +import org.koin.core.qualifier.StringQualifier + +/** + * Will be useful in case you need to declare some singles with one type several types, but need to separate them and do + * not care about how :) + */ +inline fun Module.singleWithRandomQualifier( + createdAtStart: Boolean = false, + noinline definition: Definition +) = single(uuid4().toString(), createdAtStart, definition) diff --git a/features/common/common/src/commonMain/kotlin/dev/inmo/postssystem/features/common/common/KoinSingleWithStringQualifier.kt b/features/common/common/src/commonMain/kotlin/dev/inmo/postssystem/features/common/common/KoinSingleWithStringQualifier.kt new file mode 100644 index 00000000..769a12b9 --- /dev/null +++ b/features/common/common/src/commonMain/kotlin/dev/inmo/postssystem/features/common/common/KoinSingleWithStringQualifier.kt @@ -0,0 +1,11 @@ +package dev.inmo.postssystem.features.common.common + +import org.koin.core.definition.Definition +import org.koin.core.module.Module +import org.koin.core.qualifier.StringQualifier + +inline fun Module.single( + qualifier: String, + createdAtStart: Boolean = false, + noinline definition: Definition +) = single(StringQualifier(qualifier), createdAtStart, definition) diff --git a/features/common/common/src/commonMain/kotlin/dev/inmo/postssystem/features/common/common/SerializersModuleConfigurator.kt b/features/common/common/src/commonMain/kotlin/dev/inmo/postssystem/features/common/common/SerializersModuleConfigurator.kt new file mode 100644 index 00000000..5f9490e3 --- /dev/null +++ b/features/common/common/src/commonMain/kotlin/dev/inmo/postssystem/features/common/common/SerializersModuleConfigurator.kt @@ -0,0 +1,14 @@ +package dev.inmo.postssystem.features.common.common + +import kotlinx.serialization.modules.SerializersModuleBuilder + +class SerializersModuleConfigurator( + private val elements: List +) { + fun interface Element { + operator fun SerializersModuleBuilder.invoke() + } + operator fun SerializersModuleBuilder.invoke() { + elements.forEach { it.apply { invoke() } } + } +} diff --git a/features/common/common/src/jvmMain/kotlin/dev/inmo/postssystem/features/common/common/KoinSingleWithBinds.kt b/features/common/common/src/jvmMain/kotlin/dev/inmo/postssystem/features/common/common/KoinSingleWithBinds.kt index 8e9a026b..08c5b8a5 100644 --- a/features/common/common/src/jvmMain/kotlin/dev/inmo/postssystem/features/common/common/KoinSingleWithBinds.kt +++ b/features/common/common/src/jvmMain/kotlin/dev/inmo/postssystem/features/common/common/KoinSingleWithBinds.kt @@ -11,6 +11,6 @@ inline fun Module.singleWithBinds( qualifier: Qualifier? = null, createdAtStart: Boolean = false, noinline definition: Definition -): Pair> { - return single(qualifier, createdAtStart, definition) binds (T::class.allSuperclasses.toTypedArray()) +): Pair> { + return single(qualifier, createdAtStart, definition) } diff --git a/features/content/client/build.gradle b/features/content/client/build.gradle new file mode 100644 index 00000000..54bea44c --- /dev/null +++ b/features/content/client/build.gradle @@ -0,0 +1,18 @@ +plugins { + id "org.jetbrains.kotlin.multiplatform" + id "org.jetbrains.kotlin.plugin.serialization" + id "com.android.library" +} + +apply from: "$mppProjectWithSerializationPresetPath" + +kotlin { + sourceSets { + commonMain { + dependencies { + api project(":postssystem.features.content.common") + api project(":postssystem.features.common.client") + } + } + } +} diff --git a/features/content/client/src/main/AndroidManifest.xml b/features/content/client/src/main/AndroidManifest.xml new file mode 100644 index 00000000..2990cb1e --- /dev/null +++ b/features/content/client/src/main/AndroidManifest.xml @@ -0,0 +1 @@ + diff --git a/features/content/common/build.gradle b/features/content/common/build.gradle new file mode 100644 index 00000000..d4a562e5 --- /dev/null +++ b/features/content/common/build.gradle @@ -0,0 +1,17 @@ +plugins { + id "org.jetbrains.kotlin.multiplatform" + id "org.jetbrains.kotlin.plugin.serialization" + id "com.android.library" +} + +apply from: "$mppProjectWithSerializationPresetPath" + +kotlin { + sourceSets { + commonMain { + dependencies { + api project(":postssystem.features.common.common") + } + } + } +} diff --git a/features/content/common/src/commonMain/kotlin/dev/inmo/postssystem/features/content/common/Content.kt b/features/content/common/src/commonMain/kotlin/dev/inmo/postssystem/features/content/common/Content.kt new file mode 100644 index 00000000..d8214e74 --- /dev/null +++ b/features/content/common/src/commonMain/kotlin/dev/inmo/postssystem/features/content/common/Content.kt @@ -0,0 +1,24 @@ +package dev.inmo.postssystem.features.content.common + +import kotlinx.serialization.Serializable + +typealias ContentId = String + +/** + * Content which is planned to be registered in database + * + * @see ContentSerializersModuleConfigurator.Element + * @see ContentSerializersModuleConfigurator + */ +interface Content + +/** + * Content which is already registered in database. Using its [id] you can retrieve all known + * [dev.inmo.postssystem.core.post.RegisteredPost]s by using + * [dev.inmo.postssystem.core.post.repo.ReadPostsRepo.getPostsByContent] + */ +@Serializable +data class RegisteredContent( + val id: ContentId, + val content: Content +) diff --git a/features/content/common/src/commonMain/kotlin/dev/inmo/postssystem/features/content/common/ContentSerializersModuleConfigurator.kt b/features/content/common/src/commonMain/kotlin/dev/inmo/postssystem/features/content/common/ContentSerializersModuleConfigurator.kt new file mode 100644 index 00000000..0e5681f7 --- /dev/null +++ b/features/content/common/src/commonMain/kotlin/dev/inmo/postssystem/features/content/common/ContentSerializersModuleConfigurator.kt @@ -0,0 +1,18 @@ +package dev.inmo.postssystem.features.content.common + +import dev.inmo.postssystem.features.common.common.SerializersModuleConfigurator +import kotlinx.serialization.modules.* + +class ContentSerializersModuleConfigurator( + private val subconfigurators: List +) : SerializersModuleConfigurator.Element { + fun interface Element { + operator fun PolymorphicModuleBuilder.invoke() + } + + override fun SerializersModuleBuilder.invoke() { + polymorphic(Content::class) { + subconfigurators.forEach { it.apply { invoke() } } + } + } +} diff --git a/features/content/common/src/commonMain/kotlin/dev/inmo/postssystem/features/content/common/OtherContentLinkContent.kt b/features/content/common/src/commonMain/kotlin/dev/inmo/postssystem/features/content/common/OtherContentLinkContent.kt new file mode 100644 index 00000000..ef8c1470 --- /dev/null +++ b/features/content/common/src/commonMain/kotlin/dev/inmo/postssystem/features/content/common/OtherContentLinkContent.kt @@ -0,0 +1,19 @@ +package dev.inmo.postssystem.features.content.common + +import kotlinx.serialization.Serializable +import kotlinx.serialization.modules.PolymorphicModuleBuilder + +/** + * That is a content which in fact just a link to another content. It would be useful in case when user wish to reuse + * some content + */ +@Serializable +data class OtherContentLinkContent( + val otherId: ContentId +) : Content + +object OtherContentSerializerModuleConfigurator : ContentSerializersModuleConfigurator.Element { + override fun PolymorphicModuleBuilder.invoke() { + subclass(OtherContentLinkContent::class, OtherContentLinkContent.serializer()) + } +} diff --git a/features/content/common/src/main/AndroidManifest.xml b/features/content/common/src/main/AndroidManifest.xml new file mode 100644 index 00000000..07feef75 --- /dev/null +++ b/features/content/common/src/main/AndroidManifest.xml @@ -0,0 +1 @@ + diff --git a/features/content/server/build.gradle b/features/content/server/build.gradle new file mode 100644 index 00000000..eaa12f15 --- /dev/null +++ b/features/content/server/build.gradle @@ -0,0 +1,17 @@ +plugins { + id "org.jetbrains.kotlin.multiplatform" + id "org.jetbrains.kotlin.plugin.serialization" +} + +apply from: "$mppJavaProjectPresetPath" + +kotlin { + sourceSets { + commonMain { + dependencies { + api project(":postssystem.features.content.common") + api project(":postssystem.features.common.server") + } + } + } +} diff --git a/features/files/server/src/jvmMain/kotlin/dev/inmo/postssystem/features/files/server/FilesRoutingConfigurator.kt b/features/files/server/src/jvmMain/kotlin/dev/inmo/postssystem/features/files/server/FilesRoutingConfigurator.kt index 76cd54ca..04df8b57 100644 --- a/features/files/server/src/jvmMain/kotlin/dev/inmo/postssystem/features/files/server/FilesRoutingConfigurator.kt +++ b/features/files/server/src/jvmMain/kotlin/dev/inmo/postssystem/features/files/server/FilesRoutingConfigurator.kt @@ -14,9 +14,10 @@ import kotlinx.serialization.builtins.nullable class FilesRoutingConfigurator( private val filesStorage: FilesStorage, - private val writeFilesStorage: WriteFilesStorage? + private val writeFilesStorage: WriteFilesStorage?, + private val unifierRouter: UnifiedRouter ) : ApplicationRoutingConfigurator.Element { - constructor(fullFilesStorage: FullFilesStorage) : this(fullFilesStorage, fullFilesStorage) + constructor(fullFilesStorage: FullFilesStorage, unifierRouter: UnifiedRouter) : this(fullFilesStorage, fullFilesStorage, unifierRouter) override fun Route.invoke() { authenticate { @@ -25,7 +26,8 @@ class FilesRoutingConfigurator( filesStorage, MetaFileInfoStorageWrapper.serializer(), MetaFileInfoStorageWrapper.serializer().nullable, - FileId.serializer() + FileId.serializer(), + unifierRouter ) writeFilesStorage ?.let { configureWriteStandardCrudRepoRoutes( @@ -33,23 +35,27 @@ class FilesRoutingConfigurator( FullFileInfoStorageWrapper.serializer(), FullFileInfoStorageWrapper.serializer().nullable, FullFileInfo.serializer(), - FileId.serializer() + FileId.serializer(), + unifierRouter ) } - post(filesGetFilesPathPart) { - call.respondBytes( - filesStorage.getBytes( - call.uniload(FileId.serializer()) + + unifierRouter.apply { + post(filesGetFilesPathPart) { + call.respondBytes( + filesStorage.getBytes( + uniload(FileId.serializer()) + ) ) - ) - } - get(filesGetFullFileInfoPathPart) { - call.unianswer( - FullFileInfoStorageWrapper.serializer().nullable, - filesStorage.getFullFileInfo( - call.decodeUrlQueryValueOrSendError(filesFileIdParameter, FileId.serializer()) ?: return@get + } + get(filesGetFullFileInfoPathPart) { + unianswer( + FullFileInfoStorageWrapper.serializer().nullable, + filesStorage.getFullFileInfo( + decodeUrlQueryValueOrSendError(filesFileIdParameter, FileId.serializer()) ?: return@get + ) ) - ) + } } } } diff --git a/features/roles/manager/server/src/jvmMain/kotlin/dev/inmo/postssystem/features/roles/manager/server/RolesManagerUsersRolesStorageServerRoutesConfigurator.kt b/features/roles/manager/server/src/jvmMain/kotlin/dev/inmo/postssystem/features/roles/manager/server/RolesManagerUsersRolesStorageServerRoutesConfigurator.kt index 7a9f4481..f28dc4c2 100644 --- a/features/roles/manager/server/src/jvmMain/kotlin/dev/inmo/postssystem/features/roles/manager/server/RolesManagerUsersRolesStorageServerRoutesConfigurator.kt +++ b/features/roles/manager/server/src/jvmMain/kotlin/dev/inmo/postssystem/features/roles/manager/server/RolesManagerUsersRolesStorageServerRoutesConfigurator.kt @@ -1,5 +1,6 @@ package dev.inmo.postssystem.features.roles.manager.server +import dev.inmo.micro_utils.ktor.server.UnifiedRouter import dev.inmo.postssystem.features.roles.common.UsersRolesStorage import dev.inmo.postssystem.features.roles.manager.common.RolesManagerRole import dev.inmo.postssystem.features.roles.manager.common.RolesManagerRoleSerializer @@ -7,9 +8,11 @@ import dev.inmo.postssystem.features.roles.server.UsersRolesStorageWriteServerRo import dev.inmo.micro_utils.ktor.server.configurators.ApplicationRoutingConfigurator class RolesManagerUsersRolesStorageServerRoutesConfigurator( - storage: UsersRolesStorage + storage: UsersRolesStorage, + unifiedRouter: UnifiedRouter ) : ApplicationRoutingConfigurator.Element by UsersRolesStorageWriteServerRoutesConfigurator( storage, RolesManagerRoleSerializer, - RolesManagerRolesChecker.key + RolesManagerRolesChecker.key, + unifiedRouter = unifiedRouter ) diff --git a/features/roles/server/src/jvmMain/kotlin/dev/inmo/postssystem/features/roles/server/UsersRolesAuthenticationConfigurator.kt b/features/roles/server/src/jvmMain/kotlin/dev/inmo/postssystem/features/roles/server/UsersRolesAuthenticationConfigurator.kt index 48e4347b..a38eaae6 100644 --- a/features/roles/server/src/jvmMain/kotlin/dev/inmo/postssystem/features/roles/server/UsersRolesAuthenticationConfigurator.kt +++ b/features/roles/server/src/jvmMain/kotlin/dev/inmo/postssystem/features/roles/server/UsersRolesAuthenticationConfigurator.kt @@ -15,7 +15,7 @@ import io.ktor.response.respond class UsersRolesAuthenticationConfigurator( private val usersRolesStorage: UsersRolesStorage, private val authTokensService: AuthTokensService, - private val rolesCheckers: List> + private val rolesCheckers: List>, ) : ApplicationAuthenticationConfigurator.Element { override fun Authentication.Configuration.invoke() { rolesCheckers.forEach { checker -> diff --git a/features/roles/server/src/jvmMain/kotlin/dev/inmo/postssystem/features/roles/server/UsersRolesStorageReadServerRoutesConfigurator.kt b/features/roles/server/src/jvmMain/kotlin/dev/inmo/postssystem/features/roles/server/UsersRolesStorageReadServerRoutesConfigurator.kt index 4b7ff250..33a6219f 100644 --- a/features/roles/server/src/jvmMain/kotlin/dev/inmo/postssystem/features/roles/server/UsersRolesStorageReadServerRoutesConfigurator.kt +++ b/features/roles/server/src/jvmMain/kotlin/dev/inmo/postssystem/features/roles/server/UsersRolesStorageReadServerRoutesConfigurator.kt @@ -13,59 +13,61 @@ import kotlinx.serialization.builtins.serializer class UsersRolesStorageReadServerRoutesConfigurator( private val storage: ReadUsersRolesStorage, - private val serializer: KSerializer + private val serializer: KSerializer, + private val unifiedRouter: UnifiedRouter ) : ApplicationRoutingConfigurator.Element { private val userRolesSerializer = ListSerializer(serializer) override fun Route.invoke() { - authenticate { - route(usersRolesRootPathPart) { - get(usersRolesGetUsersPathPart) { - val userRole = call.decodeUrlQueryValueOrSendError(usersRolesUserRoleQueryParameterName, serializer) - ?: return@get - call.unianswer( - UsersIdsSerializer, - storage.getUsers(userRole) - ) - } - - get(usersRolesGetRolesPathPart) { - val userId = - call.decodeUrlQueryValueOrSendError(usersRolesUserIdQueryParameterName, UserId.serializer()) + unifiedRouter.apply { + authenticate { + route(usersRolesRootPathPart) { + get(usersRolesGetUsersPathPart) { + val userRole = decodeUrlQueryValueOrSendError(usersRolesUserRoleQueryParameterName, serializer) ?: return@get - call.unianswer( - userRolesSerializer, - storage.getRoles(userId) - ) - } + unianswer( + UsersIdsSerializer, + storage.getUsers(userRole) + ) + } - get(usersRolesContainsPathPart) { - val userId = call.decodeUrlQueryValueOrSendError( - usersRolesUserIdQueryParameterName, - UserId.serializer() - ) ?: return@get - val userRole = call.decodeUrlQueryValueOrSendError( - usersRolesUserRoleQueryParameterName, - serializer - ) ?: return@get - call.unianswer( - Boolean.serializer(), - storage.contains(userId, userRole) - ) - } + get(usersRolesGetRolesPathPart) { + val userId = decodeUrlQueryValueOrSendError(usersRolesUserIdQueryParameterName, UserId.serializer()) + ?: return@get + unianswer( + userRolesSerializer, + storage.getRoles(userId) + ) + } - get(usersRolesContainsAnyPathPart) { - val userId = call.decodeUrlQueryValueOrSendError( - usersRolesUserIdQueryParameterName, - UserId.serializer() - ) ?: return@get - val userRoles = call.decodeUrlQueryValueOrSendError( - usersRolesUserRoleQueryParameterName, - userRolesSerializer - ) ?: return@get - call.unianswer( - Boolean.serializer(), - storage.containsAny(userId, userRoles) - ) + get(usersRolesContainsPathPart) { + val userId = decodeUrlQueryValueOrSendError( + usersRolesUserIdQueryParameterName, + UserId.serializer() + ) ?: return@get + val userRole = decodeUrlQueryValueOrSendError( + usersRolesUserRoleQueryParameterName, + serializer + ) ?: return@get + unianswer( + Boolean.serializer(), + storage.contains(userId, userRole) + ) + } + + get(usersRolesContainsAnyPathPart) { + val userId = decodeUrlQueryValueOrSendError( + usersRolesUserIdQueryParameterName, + UserId.serializer() + ) ?: return@get + val userRoles = decodeUrlQueryValueOrSendError( + usersRolesUserRoleQueryParameterName, + userRolesSerializer + ) ?: return@get + unianswer( + Boolean.serializer(), + storage.containsAny(userId, userRoles) + ) + } } } } diff --git a/features/roles/server/src/jvmMain/kotlin/dev/inmo/postssystem/features/roles/server/UsersRolesStorageWriteServerRoutesConfigurator.kt b/features/roles/server/src/jvmMain/kotlin/dev/inmo/postssystem/features/roles/server/UsersRolesStorageWriteServerRoutesConfigurator.kt index b9e14417..c87fdd61 100644 --- a/features/roles/server/src/jvmMain/kotlin/dev/inmo/postssystem/features/roles/server/UsersRolesStorageWriteServerRoutesConfigurator.kt +++ b/features/roles/server/src/jvmMain/kotlin/dev/inmo/postssystem/features/roles/server/UsersRolesStorageWriteServerRoutesConfigurator.kt @@ -13,37 +13,40 @@ class UsersRolesStorageWriteServerRoutesConfigurator( private val storage: WriteUsersRolesStorage, private val serializer: KSerializer, private val includeAuthKey: String, - private val excludeAuthKey: String = includeAuthKey + private val excludeAuthKey: String = includeAuthKey, + private val unifiedRouter: UnifiedRouter ) : ApplicationRoutingConfigurator.Element { override fun Route.invoke() { - route(usersRolesRootPathPart) { - val wrapperSerializer = UserRolesStorageIncludeExcludeWrapper.serializer( - serializer - ) - authenticate(includeAuthKey) { - post(usersRolesIncludePathPart) { - val wrapper = call.uniload(wrapperSerializer) + unifiedRouter.apply { + route(usersRolesRootPathPart) { + val wrapperSerializer = UserRolesStorageIncludeExcludeWrapper.serializer( + serializer + ) + authenticate(includeAuthKey) { + post(usersRolesIncludePathPart) { + val wrapper = uniload(wrapperSerializer) - call.unianswer( - Boolean.serializer(), - storage.include( - wrapper.userId, - wrapper.userRole + unianswer( + Boolean.serializer(), + storage.include( + wrapper.userId, + wrapper.userRole + ) ) - ) + } } - } - authenticate(excludeAuthKey) { - post(usersRolesExcludePathPart) { - val wrapper = call.uniload(wrapperSerializer) + authenticate(excludeAuthKey) { + post(usersRolesExcludePathPart) { + val wrapper = uniload(wrapperSerializer) - call.unianswer( - Boolean.serializer(), - storage.exclude( - wrapper.userId, - wrapper.userRole + unianswer( + Boolean.serializer(), + storage.exclude( + wrapper.userId, + wrapper.userRole + ) ) - ) + } } } } diff --git a/features/users/server/src/jvmMain/kotlin/dev/inmo/postssystem/features/users/server/UsersStorageServerRoutesConfigurator.kt b/features/users/server/src/jvmMain/kotlin/dev/inmo/postssystem/features/users/server/UsersStorageServerRoutesConfigurator.kt index 6edac1bd..4335cafb 100644 --- a/features/users/server/src/jvmMain/kotlin/dev/inmo/postssystem/features/users/server/UsersStorageServerRoutesConfigurator.kt +++ b/features/users/server/src/jvmMain/kotlin/dev/inmo/postssystem/features/users/server/UsersStorageServerRoutesConfigurator.kt @@ -1,5 +1,6 @@ package dev.inmo.postssystem.features.users.server +import dev.inmo.micro_utils.ktor.server.UnifiedRouter import dev.inmo.postssystem.features.users.common.* import dev.inmo.micro_utils.ktor.server.configurators.ApplicationRoutingConfigurator import dev.inmo.micro_utils.repos.ktor.server.crud.configureReadStandardCrudRepoRoutes @@ -9,7 +10,8 @@ import io.ktor.routing.route import kotlinx.serialization.builtins.nullable class UsersStorageServerRoutesConfigurator( - private val usersStorage: ReadUsersStorage + private val usersStorage: ReadUsersStorage, + private val unifiedRouter: UnifiedRouter ) : ApplicationRoutingConfigurator.Element { override fun Route.invoke() { authenticate { @@ -18,7 +20,8 @@ class UsersStorageServerRoutesConfigurator( usersStorage, User.serializer(), User.serializer().nullable, - UserId.serializer() + UserId.serializer(), + unifiedRouter ) } } diff --git a/server/build.gradle b/server/build.gradle index 51b4017e..b386be3c 100644 --- a/server/build.gradle +++ b/server/build.gradle @@ -18,6 +18,7 @@ dependencies { api project(":postssystem.features.auth.server") api project(":postssystem.features.roles.server") api project(":postssystem.features.roles.manager.server") + api project(":postssystem.features.content.server") api "io.ktor:ktor-server-netty:$ktor_version" api "io.ktor:ktor-websockets:$ktor_version" api "org.jetbrains.exposed:exposed-jdbc:$kotlin_exposed_version" diff --git a/server/src/main/java/dev/inmo/postssystem/server/DI.kt b/server/src/main/java/dev/inmo/postssystem/server/DI.kt index 3cc506c3..7f2bd0df 100644 --- a/server/src/main/java/dev/inmo/postssystem/server/DI.kt +++ b/server/src/main/java/dev/inmo/postssystem/server/DI.kt @@ -3,8 +3,6 @@ package dev.inmo.postssystem.server import dev.inmo.postssystem.features.auth.server.AuthenticationRoutingConfigurator import dev.inmo.postssystem.features.auth.server.SessionAuthenticationConfigurator import dev.inmo.postssystem.features.auth.server.tokens.* -import dev.inmo.postssystem.features.common.common.getAllDistinct -import dev.inmo.postssystem.features.common.common.singleWithBinds import dev.inmo.postssystem.features.common.server.sessions.ApplicationAuthenticationConfigurator import dev.inmo.postssystem.features.files.common.* import dev.inmo.postssystem.features.files.common.storage.* @@ -21,10 +19,15 @@ import dev.inmo.postssystem.features.status.server.StatusRoutingConfigurator import dev.inmo.postssystem.features.users.common.ExposedUsersStorage import dev.inmo.postssystem.features.users.server.UsersStorageServerRoutesConfigurator 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.configurators.* import dev.inmo.micro_utils.ktor.server.createKtorServer import dev.inmo.micro_utils.repos.exposed.keyvalue.ExposedKeyValueRepo import dev.inmo.micro_utils.repos.exposed.onetomany.ExposedOneToManyKeyValueRepo +import dev.inmo.postssystem.features.common.common.* +import dev.inmo.postssystem.features.content.common.ContentSerializersModuleConfigurator +import dev.inmo.postssystem.features.content.common.OtherContentSerializerModuleConfigurator import io.ktor.application.featureOrNull import io.ktor.application.log import io.ktor.routing.Route @@ -33,8 +36,11 @@ import io.ktor.server.engine.ApplicationEngine import io.ktor.server.netty.Netty import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers +import kotlinx.serialization.BinaryFormat import kotlinx.serialization.StringFormat +import kotlinx.serialization.cbor.Cbor import kotlinx.serialization.json.Json +import kotlinx.serialization.modules.SerializersModule import org.jetbrains.exposed.sql.Database import org.koin.core.module.Module import org.koin.core.parameter.ParametersHolder @@ -54,21 +60,36 @@ fun getDIModule( vararg args: String, baseScope: CoroutineScope = CoroutineScope(Dispatchers.IO) ): Module { - val json = Json { + val configJson = Json { ignoreUnknownKeys = true } - val config = json.decodeFromString(Config.serializer(), File(args.first()).readText()) + val config = configJson.decodeFromString(Config.serializer(), File(args.first()).readText()) val originalFilesMetasKeyValueRepoQualifier = StringQualifier("OriginalFilesMetaKV") val filesMetasKeyValueRepoQualifier = StringQualifier("FilesMetaKV") val filesFolderQualifier = StringQualifier("filesFolder") - val reviewVersionsQualifier = StringQualifier("reviewVersions") - val releaseVersionsQualifier = StringQualifier("releaseVersions") val usersRolesKeyValueFactoryQualifier = StringQualifier("usersRolesKeyValueFactory") return module { - single { json } + singleWithRandomQualifier { OtherContentSerializerModuleConfigurator } + singleWithRandomQualifier { ContentSerializersModuleConfigurator(getAll()) } + single { SerializersModuleConfigurator(getAll()) } + + single { + Json { + ignoreUnknownKeys = true + serializersModule = SerializersModule { get().apply { invoke() } } + } + } single { get() } + single { + Cbor { + serializersModule = SerializersModule { get().apply { invoke() } } + } + } + + single { UnifiedRouter(get()) } + singleWithBinds { config } singleWithBinds { get().databaseConfig } singleWithBinds { get().authConfig } @@ -111,11 +132,11 @@ fun getDIModule( factory { baseScope.LinkedSupervisorScope() } // Routing configurators - singleWithBinds { FilesRoutingConfigurator(get(), null) } + singleWithBinds { FilesRoutingConfigurator(get(), null, get()) } singleWithBinds { StatusRoutingConfigurator } - singleWithBinds { UsersStorageServerRoutesConfigurator(get()) } - singleWithBinds { UsersRolesStorageReadServerRoutesConfigurator(get(), UserRoleSerializer) } - singleWithBinds { RolesManagerUsersRolesStorageServerRoutesConfigurator(get()) } + singleWithBinds { UsersStorageServerRoutesConfigurator(get(), get()) } + singleWithBinds { UsersRolesStorageReadServerRoutesConfigurator(get(), UserRoleSerializer, get()) } + singleWithBinds { RolesManagerUsersRolesStorageServerRoutesConfigurator(get(), get()) } singleWithBinds { ClientStaticRoutingConfiguration(get().clientStatic) } singleWithBinds { @@ -137,7 +158,7 @@ fun getDIModule( get() ) } - singleWithBinds { AuthenticationRoutingConfigurator(get(), get()) } + singleWithBinds { AuthenticationRoutingConfigurator(get(), get(), get()) } if (config.debugMode) { single(StringQualifier("Tracer")) { ApplicationRoutingConfigurator.Element {(this as Routing).trace { application.log.trace(it.buildText()) } } } diff --git a/settings.gradle b/settings.gradle index fa6429f7..97e556aa 100644 --- a/settings.gradle +++ b/settings.gradle @@ -29,6 +29,10 @@ String[] includes = [ ":features:auth:client", ":features:auth:server", + ":features:content:common", + ":features:content:client", + ":features:content:server", + ":server", ":client", ]