Compare commits
1 Commits
master
...
0f983d9286
| Author | SHA1 | Date | |
|---|---|---|---|
| 0f983d9286 |
14
README.md
14
README.md
@@ -1,14 +1,12 @@
|
|||||||
## Структура проекта
|
## Структура проекта
|
||||||
|
|
||||||
* **Features** - набор **законченных** фич проекта. Считается, что любая фича, находящаяся в мастере может быть добавлена в
|
* **Features** - набор **законченных** фич проекта. Считается, что любая фича, находящаяся в мастере может быть добавлена в
|
||||||
клиент и использована в нем. Исключением является `common` - это набор вещей, используемых везде.
|
клиент и использована в нем. Исключением является `common` - это набор вещей, используемых везде. В подпунктах представлены
|
||||||
* Части, на которые *обычно* разделяется фича
|
части, на которые *обычно* разделяется фича
|
||||||
* Common - общая для фичи часть. Тут, как правило, хранятся конвенции путей для сетевых соединений, общие типы и пр.
|
* Common - общая для фичи часть. Тут, как правило, хранятся конвенции путей для сетевых соединений, общие типы и пр.
|
||||||
* Server - часть, включаемая в сервер для подключения фичи. Обычно содержит работу с бд, определение модулей сервера и пр.
|
* Server - часть, включаемая в сервер для подключения фичи. Обычно содержит работу с бд, определение модулей сервера и пр.
|
||||||
* Client - часть с клиентским кодом. В большинстве своём включает работу с сервером, MVVM часть (View при этом должны
|
* Client - часть с клиентским кодом. В большинстве своём включает работу с сервером, MVVM часть (View при этом должны
|
||||||
находиться в платформенной части, если их нельзя вынести в сommon часть клиента)
|
находиться в платформенной части, если их нельзя вынести в сommon часть клиента)
|
||||||
* Также существует фича `client`, которая не является фичей самой по-себе. Фактически, это набор разных фич, который системно
|
|
||||||
отсутствуют в бэке и используются в основном для пробрасывания удобных `API` и `View` для клиента
|
|
||||||
* **Services** - модули, отвечающие за клиент-серверную работу фич с точки зрения их взаимодействия. Например, в рамках сервисов
|
* **Services** - модули, отвечающие за клиент-серверную работу фич с точки зрения их взаимодействия. Например, в рамках сервисов
|
||||||
должен быть добавлен модуль для постов - именно через сервисы будет происходить создание поста, его редактирование и удаление
|
должен быть добавлен модуль для постов - именно через сервисы будет происходить создание поста, его редактирование и удаление
|
||||||
* **Client** - итоговый клиент. На момент написания этой доки (`Пн окт 25 12:56:41 +06 2021`) предполагается два варианта:
|
* **Client** - итоговый клиент. На момент написания этой доки (`Пн окт 25 12:56:41 +06 2021`) предполагается два варианта:
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import dev.inmo.postssystem.features.auth.client.ui.*
|
|||||||
import dev.inmo.postssystem.features.common.common.baseKoin
|
import dev.inmo.postssystem.features.common.common.baseKoin
|
||||||
import dev.inmo.postssystem.features.common.common.getAllDistinct
|
import dev.inmo.postssystem.features.common.common.getAllDistinct
|
||||||
import dev.inmo.postssystem.features.common.common.ui.fsm.UIFSMHandler
|
import dev.inmo.postssystem.features.common.common.ui.fsm.UIFSMHandler
|
||||||
|
import dev.inmo.postssystem.features.common.common.ui.fsm.UIFSMStateSerializer
|
||||||
import dev.inmo.postssystem.services.posts.client.ui.list.PostsListUIFSMState
|
import dev.inmo.postssystem.services.posts.client.ui.list.PostsListUIFSMState
|
||||||
import dev.inmo.postssystem.services.posts.client.ui.list.PostsListUIState
|
import dev.inmo.postssystem.services.posts.client.ui.list.PostsListUIState
|
||||||
import kotlinx.browser.*
|
import kotlinx.browser.*
|
||||||
@@ -28,7 +29,8 @@ val defaultTypedSerializer = TypedSerializer<Any>(
|
|||||||
"Short" to Short.serializer(),
|
"Short" to Short.serializer(),
|
||||||
"Byte" to Byte.serializer(),
|
"Byte" to Byte.serializer(),
|
||||||
"Float" to Float.serializer(),
|
"Float" to Float.serializer(),
|
||||||
"Double" to Double.serializer()
|
"Double" to Double.serializer(),
|
||||||
|
"UIFSMState" to UIFSMStateSerializer
|
||||||
)
|
)
|
||||||
val defaultSerialFormat = Json {
|
val defaultSerialFormat = Json {
|
||||||
ignoreUnknownKeys = true
|
ignoreUnknownKeys = true
|
||||||
|
|||||||
@@ -8,9 +8,8 @@ import dev.inmo.postssystem.features.auth.client.ui.*
|
|||||||
import dev.inmo.postssystem.features.common.common.*
|
import dev.inmo.postssystem.features.common.common.*
|
||||||
import dev.inmo.postssystem.features.common.common.ui.fsm.UIFSMExceptionHandler
|
import dev.inmo.postssystem.features.common.common.ui.fsm.UIFSMExceptionHandler
|
||||||
import dev.inmo.postssystem.features.common.common.ui.fsm.UIFSMState
|
import dev.inmo.postssystem.features.common.common.ui.fsm.UIFSMState
|
||||||
import kotlin.js.JsExport
|
|
||||||
|
|
||||||
internal fun CommonAuthModuleLoader() = DefaultModuleLoader {
|
val defaultModuleLoader = DefaultModuleLoader {
|
||||||
single<AuthSettings> { DefaultAuthSettings(get(DefaultQualifiers.SettingsQualifier), get(), getKoin(), get()) }
|
single<AuthSettings> { DefaultAuthSettings(get(DefaultQualifiers.SettingsQualifier), get(), getKoin(), get()) }
|
||||||
|
|
||||||
singleWithRandomQualifier {
|
singleWithRandomQualifier {
|
||||||
|
|||||||
@@ -4,9 +4,9 @@ import kotlinx.serialization.Serializable
|
|||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
sealed interface AuthUIError {
|
sealed interface AuthUIError {
|
||||||
// @Serializable
|
@Serializable
|
||||||
object ServerUnavailable : AuthUIError
|
object ServerUnavailable : AuthUIError
|
||||||
// @Serializable
|
@Serializable
|
||||||
object AuthIncorrect : AuthUIError
|
object AuthIncorrect : AuthUIError
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -14,9 +14,9 @@ sealed interface AuthUIError {
|
|||||||
sealed interface AuthUIState {
|
sealed interface AuthUIState {
|
||||||
@Serializable
|
@Serializable
|
||||||
data class Init(val showError: AuthUIError? = null) : AuthUIState
|
data class Init(val showError: AuthUIError? = null) : AuthUIState
|
||||||
// @Serializable
|
@Serializable
|
||||||
object Loading : AuthUIState
|
object Loading : AuthUIState
|
||||||
// @Serializable
|
@Serializable
|
||||||
object Authorized : AuthUIState
|
object Authorized : AuthUIState
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ val loader = DefaultModuleLoader {
|
|||||||
strictlyOn(get<AuthView>())
|
strictlyOn(get<AuthView>())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} + CommonAuthModuleLoader()
|
}
|
||||||
|
|
||||||
class AuthView(
|
class AuthView(
|
||||||
private val viewModel: AuthUIViewModel,
|
private val viewModel: AuthUIViewModel,
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ package dev.inmo.postssystem.features.auth.server
|
|||||||
|
|
||||||
import dev.inmo.postssystem.features.auth.common.*
|
import dev.inmo.postssystem.features.auth.common.*
|
||||||
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.ApplicationAuthenticationConfigurator
|
import dev.inmo.postssystem.features.common.server.sessions.ApplicationAuthenticationConfigurator
|
||||||
import dev.inmo.postssystem.features.users.common.User
|
import dev.inmo.postssystem.features.users.common.User
|
||||||
import dev.inmo.micro_utils.coroutines.safely
|
import dev.inmo.micro_utils.coroutines.safely
|
||||||
import dev.inmo.micro_utils.ktor.server.*
|
import dev.inmo.micro_utils.ktor.server.*
|
||||||
@@ -10,7 +10,6 @@ import dev.inmo.micro_utils.ktor.server.configurators.*
|
|||||||
import io.ktor.http.HttpStatusCode
|
import io.ktor.http.HttpStatusCode
|
||||||
import io.ktor.server.application.call
|
import io.ktor.server.application.call
|
||||||
import io.ktor.server.auth.*
|
import io.ktor.server.auth.*
|
||||||
import io.ktor.server.request.receive
|
|
||||||
import io.ktor.server.response.respond
|
import io.ktor.server.response.respond
|
||||||
import io.ktor.server.routing.*
|
import io.ktor.server.routing.*
|
||||||
import io.ktor.server.sessions.sessions
|
import io.ktor.server.sessions.sessions
|
||||||
@@ -25,72 +24,84 @@ fun User.principal() = AuthUserPrincipal(this)
|
|||||||
|
|
||||||
class AuthenticationRoutingConfigurator(
|
class AuthenticationRoutingConfigurator(
|
||||||
private val authFeature: AuthFeature,
|
private val authFeature: AuthFeature,
|
||||||
private val authTokensService: AuthTokensService
|
private val authTokensService: AuthTokensService,
|
||||||
|
private val unifiedRouter: UnifiedRouter
|
||||||
) : ApplicationRoutingConfigurator.Element, ApplicationAuthenticationConfigurator.Element {
|
) : ApplicationRoutingConfigurator.Element, ApplicationAuthenticationConfigurator.Element {
|
||||||
override fun Route.invoke() {
|
override fun Route.invoke() {
|
||||||
route(authRootPathPart) {
|
unifiedRouter.apply {
|
||||||
post(authAuthPathPart) {
|
route(authRootPathPart) {
|
||||||
safely(
|
post(authAuthPathPart) {
|
||||||
{
|
safely(
|
||||||
// TODO:: add error info
|
{
|
||||||
it.printStackTrace()
|
// TODO:: add error info
|
||||||
call.respond(
|
it.printStackTrace()
|
||||||
HttpStatusCode.InternalServerError,
|
call.respond(
|
||||||
"Something went wrong"
|
HttpStatusCode.InternalServerError,
|
||||||
)
|
"Something went wrong"
|
||||||
}
|
)
|
||||||
) {
|
}
|
||||||
val creds = call.receive<AuthCreds>()
|
) {
|
||||||
|
val creds = uniload(AuthCreds.serializer())
|
||||||
val tokenInfo = authFeature.auth(creds)
|
|
||||||
|
val tokenInfo = authFeature.auth(creds)
|
||||||
if (tokenInfo == null) {
|
|
||||||
if (call.response.status() == null) {
|
if (tokenInfo == null) {
|
||||||
call.respond(HttpStatusCode.Forbidden)
|
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.respond(tokenInfo)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
post (authRefreshPathPart) {
|
||||||
post (authRefreshPathPart) {
|
safely(
|
||||||
safely(
|
{
|
||||||
{
|
// TODO:: add error info
|
||||||
// TODO:: add error info
|
call.respond(
|
||||||
call.respond(
|
HttpStatusCode.InternalServerError,
|
||||||
HttpStatusCode.InternalServerError,
|
"Something went wrong"
|
||||||
"Something went wrong"
|
)
|
||||||
)
|
}
|
||||||
}
|
) {
|
||||||
) {
|
val refreshToken = uniload(RefreshToken.serializer())
|
||||||
val refreshToken = call.receive<RefreshToken>()
|
|
||||||
|
val tokenInfo = authFeature.refresh(refreshToken)
|
||||||
val tokenInfo = authFeature.refresh(refreshToken)
|
|
||||||
|
if (tokenInfo == null) {
|
||||||
if (tokenInfo == null) {
|
if (call.response.status() == null) {
|
||||||
if (call.response.status() == null) {
|
call.respond(HttpStatusCode.Forbidden)
|
||||||
call.respond(HttpStatusCode.Forbidden)
|
}
|
||||||
|
} else {
|
||||||
|
call.sessions.set(tokenSessionKey, tokenInfo.token)
|
||||||
|
unianswer(
|
||||||
|
AuthTokenInfo.serializer().nullable,
|
||||||
|
tokenInfo
|
||||||
|
)
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
call.sessions.set(tokenSessionKey, tokenInfo.token)
|
|
||||||
call.respond(tokenInfo)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
post(authGetMePathPart) {
|
||||||
post(authGetMePathPart) {
|
safely(
|
||||||
safely(
|
{
|
||||||
{
|
// TODO:: add error info
|
||||||
// TODO:: add error info
|
call.respond(
|
||||||
call.respond(
|
HttpStatusCode.InternalServerError,
|
||||||
HttpStatusCode.InternalServerError,
|
"Something went wrong"
|
||||||
"Something went wrong"
|
)
|
||||||
|
}
|
||||||
|
) {
|
||||||
|
unianswer(
|
||||||
|
User.serializer().nullable,
|
||||||
|
authFeature.getMe(
|
||||||
|
uniload(AuthToken.serializer())
|
||||||
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
) {
|
|
||||||
call.respond(
|
|
||||||
authFeature.getMe(call.receive()) ?: HttpStatusCode.NoContent
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,18 +0,0 @@
|
|||||||
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.client.template.common")
|
|
||||||
api project(":postssystem.features.common.client")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
<manifest package="dev.inmo.postssystem.features.client.template.client"/>
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
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")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
<manifest package="dev.inmo.postssystem.features.client.template.common"/>
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
plugins {
|
|
||||||
id "org.jetbrains.kotlin.multiplatform"
|
|
||||||
id "org.jetbrains.kotlin.plugin.serialization"
|
|
||||||
}
|
|
||||||
|
|
||||||
apply from: "$mppJavaProjectPresetPath"
|
|
||||||
|
|
||||||
kotlin {
|
|
||||||
sourceSets {
|
|
||||||
commonMain {
|
|
||||||
dependencies {
|
|
||||||
api project(":postssystem.features.client.template.common")
|
|
||||||
api project(":postssystem.features.common.server")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -49,16 +49,12 @@ fun baseKoin(
|
|||||||
single { repoFactory() }
|
single { repoFactory() }
|
||||||
single { defaultScope }
|
single { defaultScope }
|
||||||
single(DefaultQualifiers.UIScopeQualifier) { get<CoroutineScope>().LinkedSupervisorScope(Dispatchers.Main) }
|
single(DefaultQualifiers.UIScopeQualifier) { get<CoroutineScope>().LinkedSupervisorScope(Dispatchers.Main) }
|
||||||
single<StatesMachine<UIFSMState>>(DefaultQualifiers.UIFSMQualifier) {
|
single<StatesMachine<UIFSMState>>(UIFSMQualifier) { UIFSM(get()) { (this@single to this@UIFSM).apply(get(
|
||||||
UIFSM(get()) {
|
DefaultQualifiers.FSMHandlersBuilderQualifier
|
||||||
(this@single to this@UIFSM).apply(get(DefaultQualifiers.FSMHandlersBuilderQualifier))
|
)) } }
|
||||||
}
|
|
||||||
}
|
AdditionalModules.Default.modules.forEach {
|
||||||
} + AdditionalModules.Default.modules.map {
|
it.apply { load() }
|
||||||
module {
|
|
||||||
with(it) {
|
|
||||||
load()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -6,5 +6,5 @@ object DefaultQualifiers {
|
|||||||
val SettingsQualifier = StringQualifier("Settings")
|
val SettingsQualifier = StringQualifier("Settings")
|
||||||
val FSMHandlersBuilderQualifier = StringQualifier("FSMHandlersBuilder")
|
val FSMHandlersBuilderQualifier = StringQualifier("FSMHandlersBuilder")
|
||||||
val UIScopeQualifier = StringQualifier("CoroutineScopeUI")
|
val UIScopeQualifier = StringQualifier("CoroutineScopeUI")
|
||||||
val UIFSMQualifier = StringQualifier("UIFSM")
|
val UIFSMQualifier = StringQualifier("FSM")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,15 +12,6 @@ interface ModuleLoader {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
operator fun ModuleLoader.plus(other: ModuleLoader) = ModuleLoader.ByCallback {
|
|
||||||
with(this@plus) {
|
|
||||||
load()
|
|
||||||
}
|
|
||||||
with (other) {
|
|
||||||
load()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun DefaultModuleLoader(loadingBlock: Module.() -> Unit): ModuleLoader.ByCallback {
|
fun DefaultModuleLoader(loadingBlock: Module.() -> Unit): ModuleLoader.ByCallback {
|
||||||
val newModuleLoader = ModuleLoader.ByCallback(loadingBlock)
|
val newModuleLoader = ModuleLoader.ByCallback(loadingBlock)
|
||||||
AdditionalModules.Default.addModule(newModuleLoader)
|
AdditionalModules.Default.addModule(newModuleLoader)
|
||||||
|
|||||||
@@ -6,6 +6,8 @@ import dev.inmo.micro_utils.fsm.common.managers.DefaultStatesManager
|
|||||||
import dev.inmo.micro_utils.fsm.common.managers.DefaultStatesManagerRepo
|
import dev.inmo.micro_utils.fsm.common.managers.DefaultStatesManagerRepo
|
||||||
import org.koin.core.qualifier.StringQualifier
|
import org.koin.core.qualifier.StringQualifier
|
||||||
|
|
||||||
|
val UIFSMQualifier = StringQualifier("UIFSM")
|
||||||
|
|
||||||
fun UIFSM(
|
fun UIFSM(
|
||||||
repo: DefaultStatesManagerRepo<UIFSMState>,
|
repo: DefaultStatesManagerRepo<UIFSMState>,
|
||||||
handlersSetter: FSMBuilder<UIFSMState>.() -> Unit
|
handlersSetter: FSMBuilder<UIFSMState>.() -> Unit
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
package dev.inmo.postssystem.features.common.server
|
package dev.inmo.postssystem.features.common.server.sessions
|
||||||
|
|
||||||
import dev.inmo.micro_utils.ktor.server.configurators.KtorApplicationConfigurator
|
import dev.inmo.micro_utils.ktor.server.configurators.KtorApplicationConfigurator
|
||||||
import io.ktor.server.application.Application
|
import io.ktor.server.application.Application
|
||||||
@@ -1,9 +1,8 @@
|
|||||||
package dev.inmo.postssystem.features.common.server
|
package dev.inmo.postssystem.features.common.server.sessions
|
||||||
|
|
||||||
import org.koin.core.qualifier.StringQualifier
|
import org.koin.core.qualifier.StringQualifier
|
||||||
|
|
||||||
object Qualifiers {
|
object Qualifiers {
|
||||||
val filesFolderQualifier = StringQualifier("filesFolder")
|
val filesFolderQualifier = StringQualifier("filesFolder")
|
||||||
val commonFilesFolderQualifier = StringQualifier("commonFilesFolder")
|
|
||||||
val usersRolesKeyValueFactoryQualifier = StringQualifier("usersRolesKeyValueFactory")
|
val usersRolesKeyValueFactoryQualifier = StringQualifier("usersRolesKeyValueFactory")
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package dev.inmo.postssystem.features.common.server
|
package dev.inmo.postssystem.features.common.server.sessions
|
||||||
|
|
||||||
import kotlinx.serialization.json.JsonObject
|
import kotlinx.serialization.json.JsonObject
|
||||||
import org.koin.core.module.Module
|
import org.koin.core.module.Module
|
||||||
@@ -3,8 +3,8 @@ package dev.inmo.postssystem.features.content.binary.server
|
|||||||
import dev.inmo.micro_utils.repos.exposed.keyvalue.ExposedKeyValueRepo
|
import dev.inmo.micro_utils.repos.exposed.keyvalue.ExposedKeyValueRepo
|
||||||
import dev.inmo.postssystem.features.common.common.singleWithBinds
|
import dev.inmo.postssystem.features.common.common.singleWithBinds
|
||||||
import dev.inmo.postssystem.features.common.common.singleWithRandomQualifier
|
import dev.inmo.postssystem.features.common.common.singleWithRandomQualifier
|
||||||
import dev.inmo.postssystem.features.common.server.Qualifiers
|
import dev.inmo.postssystem.features.common.server.sessions.Qualifiers
|
||||||
import dev.inmo.postssystem.features.common.server.ServerModuleLoader
|
import dev.inmo.postssystem.features.common.server.sessions.ServerModuleLoader
|
||||||
import dev.inmo.postssystem.features.content.common.BinaryContent
|
import dev.inmo.postssystem.features.content.common.BinaryContent
|
||||||
import dev.inmo.postssystem.features.content.server.ServerContentStorageWrapper
|
import dev.inmo.postssystem.features.content.server.ServerContentStorageWrapper
|
||||||
import dev.inmo.postssystem.features.files.common.*
|
import dev.inmo.postssystem.features.files.common.*
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package dev.inmo.postssystem.features.content.common
|
package dev.inmo.postssystem.features.content.common
|
||||||
|
|
||||||
import dev.inmo.micro_utils.common.*
|
import dev.inmo.micro_utils.common.FileName
|
||||||
|
import dev.inmo.micro_utils.common.MPPFile
|
||||||
import dev.inmo.micro_utils.mime_types.MimeType
|
import dev.inmo.micro_utils.mime_types.MimeType
|
||||||
import dev.inmo.postssystem.features.common.common.SimpleInputProvider
|
import dev.inmo.postssystem.features.common.common.SimpleInputProvider
|
||||||
import kotlinx.serialization.PolymorphicSerializer
|
import kotlinx.serialization.PolymorphicSerializer
|
||||||
@@ -29,18 +30,6 @@ data class BinaryContent(
|
|||||||
) : Content
|
) : Content
|
||||||
|
|
||||||
val ContentSerializer = PolymorphicSerializer(Content::class)
|
val ContentSerializer = PolymorphicSerializer(Content::class)
|
||||||
@Serializable
|
|
||||||
data class ContentWrapper(
|
|
||||||
val content: Content
|
|
||||||
)
|
|
||||||
@Serializable
|
|
||||||
data class ContentsWrapper(
|
|
||||||
val content: List<Content>
|
|
||||||
)
|
|
||||||
@Serializable
|
|
||||||
data class ContentsEithersWrapper(
|
|
||||||
val content: List<Either<ContentId, Content>>
|
|
||||||
)
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Content which is already registered in database. Using its [id] you can retrieve all known
|
* Content which is already registered in database. Using its [id] you can retrieve all known
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
package dev.inmo.postssystem.features.content.text.server
|
package dev.inmo.postssystem.features.content.text.server
|
||||||
|
|
||||||
import dev.inmo.postssystem.features.common.common.singleWithRandomQualifier
|
import dev.inmo.postssystem.features.common.common.singleWithRandomQualifier
|
||||||
import dev.inmo.postssystem.features.common.server.ServerModuleLoader
|
import dev.inmo.postssystem.features.common.server.sessions.ServerModuleLoader
|
||||||
import dev.inmo.postssystem.features.content.common.ContentSerializersModuleConfigurator
|
import dev.inmo.postssystem.features.content.common.ContentSerializersModuleConfigurator
|
||||||
import dev.inmo.postssystem.features.content.server.ServerContentStorageWrapper
|
import dev.inmo.postssystem.features.content.server.ServerContentStorageWrapper
|
||||||
import dev.inmo.postssystem.features.content.text.common.TextContent
|
import dev.inmo.postssystem.features.content.text.common.TextContent
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ class ClientReadFilesStorage(
|
|||||||
MetaFileInfoStorageWrapper.serializer().nullable,
|
MetaFileInfoStorageWrapper.serializer().nullable,
|
||||||
FileId.serializer()
|
FileId.serializer()
|
||||||
) {
|
) {
|
||||||
|
private val unifiedRequester = UnifiedRequester(client, serialFormat)
|
||||||
private val fullFilesPath = buildStandardUrl(baseUrl, filesRootPathPart)
|
private val fullFilesPath = buildStandardUrl(baseUrl, filesRootPathPart)
|
||||||
private val fullFilesGetBytesPath = buildStandardUrl(
|
private val fullFilesGetBytesPath = buildStandardUrl(
|
||||||
fullFilesPath,
|
fullFilesPath,
|
||||||
|
|||||||
@@ -4,13 +4,10 @@ import dev.inmo.postssystem.features.files.common.*
|
|||||||
import dev.inmo.postssystem.features.files.common.storage.*
|
import dev.inmo.postssystem.features.files.common.storage.*
|
||||||
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 dev.inmo.micro_utils.repos.ktor.server.crud.*
|
import dev.inmo.micro_utils.repos.ktor.server.crud.configureReadStandardCrudRepoRoutes
|
||||||
import io.ktor.http.HttpStatusCode
|
import dev.inmo.micro_utils.repos.ktor.server.crud.configureWriteStandardCrudRepoRoutes
|
||||||
import io.ktor.http.decodeURLQueryComponent
|
|
||||||
import io.ktor.server.application.call
|
import io.ktor.server.application.call
|
||||||
import io.ktor.server.auth.authenticate
|
import io.ktor.server.auth.authenticate
|
||||||
import io.ktor.server.request.receive
|
|
||||||
import io.ktor.server.response.respond
|
|
||||||
import io.ktor.server.response.respondBytes
|
import io.ktor.server.response.respondBytes
|
||||||
import io.ktor.server.routing.*
|
import io.ktor.server.routing.*
|
||||||
import kotlinx.serialization.builtins.nullable
|
import kotlinx.serialization.builtins.nullable
|
||||||
@@ -18,33 +15,47 @@ import kotlinx.serialization.builtins.nullable
|
|||||||
class FilesRoutingConfigurator(
|
class FilesRoutingConfigurator(
|
||||||
private val filesStorage: ReadFilesStorage,
|
private val filesStorage: ReadFilesStorage,
|
||||||
private val writeFilesStorage: WriteFilesStorage?,
|
private val writeFilesStorage: WriteFilesStorage?,
|
||||||
|
private val unifierRouter: UnifiedRouter
|
||||||
) : ApplicationRoutingConfigurator.Element {
|
) : ApplicationRoutingConfigurator.Element {
|
||||||
constructor(filesStorage: FilesStorage) : this(filesStorage, filesStorage)
|
constructor(filesStorage: FilesStorage, unifierRouter: UnifiedRouter) : this(filesStorage, filesStorage, unifierRouter)
|
||||||
|
|
||||||
override fun Route.invoke() {
|
override fun Route.invoke() {
|
||||||
authenticate {
|
authenticate {
|
||||||
route(filesRootPathPart) {
|
route(filesRootPathPart) {
|
||||||
configureReadCRUDRepoRoutes(
|
configureReadStandardCrudRepoRoutes(
|
||||||
filesStorage,
|
filesStorage,
|
||||||
::FileId
|
MetaFileInfoStorageWrapper.serializer(),
|
||||||
|
MetaFileInfoStorageWrapper.serializer().nullable,
|
||||||
|
FileId.serializer(),
|
||||||
|
unifierRouter
|
||||||
)
|
)
|
||||||
writeFilesStorage ?.let {
|
writeFilesStorage ?.let {
|
||||||
configureWriteCRUDRepoRoutes(writeFilesStorage)
|
configureWriteStandardCrudRepoRoutes(
|
||||||
|
writeFilesStorage,
|
||||||
|
FullFileInfoStorageWrapper.serializer(),
|
||||||
|
FullFileInfoStorageWrapper.serializer().nullable,
|
||||||
|
FullFileInfo.serializer(),
|
||||||
|
FileId.serializer(),
|
||||||
|
unifierRouter
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
post(filesGetFilesPathPart) {
|
unifierRouter.apply {
|
||||||
call.respondBytes(
|
post(filesGetFilesPathPart) {
|
||||||
filesStorage.getBytes(
|
call.respondBytes(
|
||||||
call.receive()
|
filesStorage.getBytes(
|
||||||
|
uniload(FileId.serializer())
|
||||||
|
)
|
||||||
)
|
)
|
||||||
)
|
}
|
||||||
}
|
get(filesGetFullFileInfoPathPart) {
|
||||||
get(filesGetFullFileInfoPathPart) {
|
unianswer(
|
||||||
call.respond(
|
FullFileInfoStorageWrapper.serializer().nullable,
|
||||||
filesStorage.getFullFileInfo(
|
filesStorage.getFullFileInfo(
|
||||||
FileId(call.getParameterOrSendError(filesFileIdParameter) ?.decodeURLQueryComponent() ?: return@get)
|
decodeUrlQueryValueOrSendError(filesFileIdParameter, FileId.serializer()) ?: return@get
|
||||||
) ?: HttpStatusCode.NoContent
|
)
|
||||||
)
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,8 +25,8 @@ typealias ContentIds = List<ContentId>
|
|||||||
* @see RegisteredPost
|
* @see RegisteredPost
|
||||||
*/
|
*/
|
||||||
@Serializable
|
@Serializable
|
||||||
sealed interface Post {
|
sealed class Post {
|
||||||
val content: ContentIds
|
abstract val content: ContentIds
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -35,7 +35,7 @@ sealed interface Post {
|
|||||||
@Serializable
|
@Serializable
|
||||||
data class NewPost(
|
data class NewPost(
|
||||||
override val content: ContentIds
|
override val content: ContentIds
|
||||||
) : Post
|
) : Post()
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Registered [Post]
|
* Registered [Post]
|
||||||
@@ -46,12 +46,12 @@ data class RegisteredPost(
|
|||||||
override val content: ContentIds,
|
override val content: ContentIds,
|
||||||
@Serializable(DateTimeSerializer::class)
|
@Serializable(DateTimeSerializer::class)
|
||||||
val creationDate: DateTime
|
val creationDate: DateTime
|
||||||
) : Post
|
) : Post()
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
data class PostWithContent(
|
data class PostWithContent(
|
||||||
val post: Post,
|
val post: Post,
|
||||||
val content: List<@Polymorphic Content>
|
val content: List<Content>
|
||||||
)
|
)
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
|
|||||||
@@ -6,12 +6,12 @@ import kotlinx.serialization.KSerializer
|
|||||||
|
|
||||||
class ClientRolesStorage<T : Role>(
|
class ClientRolesStorage<T : Role>(
|
||||||
private val baseUrl: String,
|
private val baseUrl: String,
|
||||||
private val client: HttpClient,
|
private val unifiedRequester: UnifiedRequester,
|
||||||
private val serializer: KSerializer<T>
|
private val serializer: KSerializer<T>
|
||||||
) : RolesStorage<T>,
|
) : RolesStorage<T>,
|
||||||
ReadRolesStorage<T> by ReadClientRolesStorage(
|
ReadRolesStorage<T> by ReadClientRolesStorage(
|
||||||
baseUrl, client, serializer
|
baseUrl, unifiedRequester, serializer
|
||||||
),
|
),
|
||||||
WriteRolesStorage<T> by WriteClientRolesStorage(
|
WriteRolesStorage<T> by WriteClientRolesStorage(
|
||||||
baseUrl, client, serializer
|
baseUrl, unifiedRequester, serializer
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -3,15 +3,13 @@ package dev.inmo.postssystem.features.roles.client
|
|||||||
import dev.inmo.postssystem.features.roles.common.*
|
import dev.inmo.postssystem.features.roles.common.*
|
||||||
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 io.ktor.client.HttpClient
|
|
||||||
import io.ktor.client.request.get
|
|
||||||
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 ReadClientRolesStorage<T : Role>(
|
class ReadClientRolesStorage<T : Role>(
|
||||||
private val baseUrl: String,
|
private val baseUrl: String,
|
||||||
private val client: HttpClient,
|
private val unifiedRequester: UnifiedRequester,
|
||||||
private val serializer: KSerializer<T>
|
private val serializer: KSerializer<T>
|
||||||
) : ReadRolesStorage<T> {
|
) : ReadRolesStorage<T> {
|
||||||
private val userRolesSerializer = ListSerializer(serializer)
|
private val userRolesSerializer = ListSerializer(serializer)
|
||||||
@@ -23,13 +21,14 @@ class ReadClientRolesStorage<T : Role>(
|
|||||||
|
|
||||||
override suspend fun getSubjects(
|
override suspend fun getSubjects(
|
||||||
role: T
|
role: T
|
||||||
): List<RoleSubject> = client.get(
|
): List<RoleSubject> = unifiedRequester.uniget(
|
||||||
buildStandardUrl(
|
buildStandardUrl(
|
||||||
userRolesFullUrl,
|
userRolesFullUrl,
|
||||||
usersRolesGetSubjectsPathPart,
|
usersRolesGetSubjectsPathPart,
|
||||||
usersRolesRoleQueryParameterName to unifiedRequester.encodeUrlQueryValue(serializer, role)
|
usersRolesRoleQueryParameterName to unifiedRequester.encodeUrlQueryValue(serializer, role)
|
||||||
)
|
),
|
||||||
).body()
|
RoleSubjectsSerializer
|
||||||
|
)
|
||||||
|
|
||||||
override suspend fun getRoles(
|
override suspend fun getRoles(
|
||||||
subject: RoleSubject
|
subject: RoleSubject
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import kotlinx.serialization.builtins.serializer
|
|||||||
|
|
||||||
class WriteClientRolesStorage<T : Role>(
|
class WriteClientRolesStorage<T : Role>(
|
||||||
private val baseUrl: String,
|
private val baseUrl: String,
|
||||||
private val client: HttpClient,
|
private val unifiedRequester: UnifiedRequester,
|
||||||
private val serializer: KSerializer<T>
|
private val serializer: KSerializer<T>
|
||||||
) : WriteRolesStorage<T> {
|
) : WriteRolesStorage<T> {
|
||||||
private val wrapperSerializer = RolesStorageIncludeExcludeWrapper.serializer(
|
private val wrapperSerializer = RolesStorageIncludeExcludeWrapper.serializer(
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import kotlinx.serialization.descriptors.SerialDescriptor
|
|||||||
import kotlinx.serialization.encoding.*
|
import kotlinx.serialization.encoding.*
|
||||||
import kotlinx.serialization.json.*
|
import kotlinx.serialization.json.*
|
||||||
|
|
||||||
@Polymorphic
|
@Serializable(RoleSerializer::class)
|
||||||
interface Role {
|
interface Role {
|
||||||
companion object {
|
companion object {
|
||||||
fun serializer(): KSerializer<Role> = RoleSerializer
|
fun serializer(): KSerializer<Role> = RoleSerializer
|
||||||
|
|||||||
@@ -1,14 +1,17 @@
|
|||||||
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.postssystem.features.roles.common.RolesStorage
|
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.server.RolesStorageWriteServerRoutesConfigurator
|
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 RolesManagerRolesStorageServerRoutesConfigurator(
|
class RolesManagerRolesStorageServerRoutesConfigurator(
|
||||||
storage: RolesStorage<RolesManagerRole>
|
storage: RolesStorage<RolesManagerRole>,
|
||||||
|
unifiedRouter: UnifiedRouter
|
||||||
) : ApplicationRoutingConfigurator.Element by RolesStorageWriteServerRoutesConfigurator(
|
) : ApplicationRoutingConfigurator.Element by RolesStorageWriteServerRoutesConfigurator(
|
||||||
storage,
|
storage,
|
||||||
RolesManagerRole.serializer(),
|
RolesManagerRole.serializer(),
|
||||||
RolesManagerRolesChecker.key
|
RolesManagerRolesChecker.key,
|
||||||
|
unifiedRouter = unifiedRouter
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -12,7 +12,8 @@ class RolesStorageWriteServerRoutesConfigurator<T : Role>(
|
|||||||
private val storage: WriteRolesStorage<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
|
||||||
) : ApplicationRoutingConfigurator.Element {
|
) : ApplicationRoutingConfigurator.Element {
|
||||||
override fun Route.invoke() {
|
override fun Route.invoke() {
|
||||||
route(usersRolesRootPathPart) {
|
route(usersRolesRootPathPart) {
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ package dev.inmo.postssystem.features.roles.server
|
|||||||
import dev.inmo.postssystem.features.auth.common.AuthToken
|
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.ApplicationAuthenticationConfigurator
|
import dev.inmo.postssystem.features.common.server.sessions.ApplicationAuthenticationConfigurator
|
||||||
import dev.inmo.postssystem.features.roles.common.Role
|
import dev.inmo.postssystem.features.roles.common.Role
|
||||||
import dev.inmo.postssystem.features.roles.common.RolesStorage
|
import dev.inmo.postssystem.features.roles.common.RolesStorage
|
||||||
import io.ktor.http.HttpStatusCode
|
import io.ktor.http.HttpStatusCode
|
||||||
|
|||||||
@@ -11,7 +11,8 @@ import kotlinx.serialization.builtins.serializer
|
|||||||
|
|
||||||
class RolesStorageReadServerRoutesConfigurator<T : Role>(
|
class RolesStorageReadServerRoutesConfigurator<T : Role>(
|
||||||
private val storage: ReadRolesStorage<T>,
|
private val storage: ReadRolesStorage<T>,
|
||||||
private val serializer: KSerializer<T>
|
private val serializer: KSerializer<T>,
|
||||||
|
private val unifiedRouter: UnifiedRouter
|
||||||
) : ApplicationRoutingConfigurator.Element {
|
) : ApplicationRoutingConfigurator.Element {
|
||||||
private val userRolesSerializer = ListSerializer(serializer)
|
private val userRolesSerializer = ListSerializer(serializer)
|
||||||
override fun Route.invoke() {
|
override fun Route.invoke() {
|
||||||
|
|||||||
@@ -9,10 +9,10 @@ import kotlinx.serialization.builtins.nullable
|
|||||||
|
|
||||||
class UsersStorageKtorClient(
|
class UsersStorageKtorClient(
|
||||||
baseUrl: String,
|
baseUrl: String,
|
||||||
client: HttpClient
|
unifiedRequester: UnifiedRequester
|
||||||
) : ReadUsersStorage, ReadCRUDRepo<User, UserId> by KtorReadStandardCrudRepo(
|
) : ReadUsersStorage, ReadCRUDRepo<User, UserId> by KtorReadStandardCrudRepo(
|
||||||
buildStandardUrl(baseUrl, usersServerPathPart),
|
buildStandardUrl(baseUrl, usersServerPathPart),
|
||||||
client,
|
unifiedRequester,
|
||||||
User.serializer(),
|
User.serializer(),
|
||||||
User.serializer().nullable,
|
User.serializer().nullable,
|
||||||
UserId.serializer()
|
UserId.serializer()
|
||||||
|
|||||||
@@ -1,21 +1,28 @@
|
|||||||
package dev.inmo.postssystem.features.users.server
|
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.postssystem.features.users.common.*
|
||||||
import dev.inmo.micro_utils.ktor.server.configurators.ApplicationRoutingConfigurator
|
import dev.inmo.micro_utils.ktor.server.configurators.ApplicationRoutingConfigurator
|
||||||
import dev.inmo.micro_utils.repos.ktor.server.crud.configureReadCRUDRepoRoutes
|
import dev.inmo.micro_utils.repos.ktor.server.crud.configureReadStandardCrudRepoRoutes
|
||||||
import io.ktor.server.auth.authenticate
|
import io.ktor.server.auth.authenticate
|
||||||
import io.ktor.server.routing.Route
|
import io.ktor.server.routing.Route
|
||||||
import io.ktor.server.routing.route
|
import io.ktor.server.routing.route
|
||||||
|
import kotlinx.serialization.builtins.nullable
|
||||||
|
|
||||||
class UsersStorageServerRoutesConfigurator(
|
class UsersStorageServerRoutesConfigurator(
|
||||||
private val usersStorage: ReadUsersStorage
|
private val usersStorage: ReadUsersStorage,
|
||||||
|
private val unifiedRouter: UnifiedRouter
|
||||||
) : ApplicationRoutingConfigurator.Element {
|
) : ApplicationRoutingConfigurator.Element {
|
||||||
override fun Route.invoke() {
|
override fun Route.invoke() {
|
||||||
authenticate {
|
authenticate {
|
||||||
route(usersServerPathPart) {
|
route(usersServerPathPart) {
|
||||||
configureReadCRUDRepoRoutes(
|
configureReadStandardCrudRepoRoutes(
|
||||||
usersStorage
|
usersStorage,
|
||||||
) { UserId(it.toLong()) }
|
User.serializer(),
|
||||||
|
User.serializer().nullable,
|
||||||
|
UserId.serializer(),
|
||||||
|
unifiedRouter
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
kotlin.code.style=official
|
kotlin.code.style=official
|
||||||
org.gradle.parallel=true
|
org.gradle.parallel=true
|
||||||
org.gradle.jvmargs=-Xmx2g
|
org.gradle.jvmargs=-Xmx4g
|
||||||
kotlin.js.generate.externals=true
|
kotlin.js.generate.externals=true
|
||||||
kotlin.incremental=true
|
kotlin.incremental=true
|
||||||
kotlin.incremental.js=true
|
kotlin.incremental.js=true
|
||||||
|
|||||||
@@ -2,25 +2,25 @@
|
|||||||
|
|
||||||
kotlin = "1.6.21"
|
kotlin = "1.6.21"
|
||||||
kotlin-serialization = "1.3.3"
|
kotlin-serialization = "1.3.3"
|
||||||
jsuikit = "0.1.7"
|
jsuikit = "0.1.1"
|
||||||
compose = "1.2.0-alpha01-dev731"
|
compose = "1.2.0-alpha01-dev686"
|
||||||
microutils = "0.11.12"
|
microutils = "0.10.4"
|
||||||
tgbotapi = "2.1.2"
|
tgbotapi = "1.1.1"
|
||||||
ktor = "2.0.3"
|
ktor = "2.0.1"
|
||||||
klock = "2.7.0"
|
klock = "2.7.0"
|
||||||
koin = "3.2.0"
|
koin = "3.2.0"
|
||||||
exposed = "0.38.2"
|
exposed = "0.38.2"
|
||||||
psql = "42.3.6"
|
psql = "42.3.0"
|
||||||
scrimage = "4.0.31"
|
scrimage = "4.0.31"
|
||||||
dokka = "1.6.21"
|
dokka = "1.6.21"
|
||||||
logback = "1.2.10"
|
logback = "1.2.10"
|
||||||
uuid = "0.4.1"
|
uuid = "0.4.0"
|
||||||
|
|
||||||
android-junit = "4.12"
|
android-junit = "4.12"
|
||||||
android-test-junit = "1.1.2"
|
android-test-junit = "1.1.2"
|
||||||
android-espresso-core = "3.3.0"
|
android-espresso-core = "3.3.0"
|
||||||
|
|
||||||
gh-release = "2.4.1"
|
gh-release = "2.3.7"
|
||||||
|
|
||||||
android-gradle = "7.0.4"
|
android-gradle = "7.0.4"
|
||||||
dexcount = "3.1.0"
|
dexcount = "3.1.0"
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import kotlinx.serialization.builtins.serializer
|
|||||||
|
|
||||||
class SimplePublicatorServiceClient(
|
class SimplePublicatorServiceClient(
|
||||||
baseUrl: String,
|
baseUrl: String,
|
||||||
private val client: HttpClient
|
private val unifiedRequester: UnifiedRequester
|
||||||
) : SimplePublicatorService {
|
) : SimplePublicatorService {
|
||||||
private val fullUrl = buildStandardUrl(
|
private val fullUrl = buildStandardUrl(
|
||||||
baseUrl,
|
baseUrl,
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ package dev.inmo.postssystem.publicators.simple.server
|
|||||||
|
|
||||||
import dev.inmo.micro_utils.ktor.server.configurators.ApplicationRoutingConfigurator
|
import dev.inmo.micro_utils.ktor.server.configurators.ApplicationRoutingConfigurator
|
||||||
import dev.inmo.postssystem.features.common.common.singleWithRandomQualifier
|
import dev.inmo.postssystem.features.common.common.singleWithRandomQualifier
|
||||||
import dev.inmo.postssystem.features.common.server.ServerModuleLoader
|
import dev.inmo.postssystem.features.common.server.sessions.ServerModuleLoader
|
||||||
import kotlinx.serialization.json.JsonObject
|
import kotlinx.serialization.json.JsonObject
|
||||||
import org.koin.core.module.Module
|
import org.koin.core.module.Module
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
package dev.inmo.postssystem.server
|
package dev.inmo.postssystem.server
|
||||||
|
|
||||||
import dev.inmo.postssystem.features.common.server.ServerModuleLoader
|
import dev.inmo.postssystem.features.common.server.sessions.ServerModuleLoader
|
||||||
import kotlinx.serialization.SerialName
|
import kotlinx.serialization.SerialName
|
||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
|||||||
@@ -3,9 +3,10 @@ package dev.inmo.postssystem.server
|
|||||||
import dev.inmo.postssystem.features.auth.server.AuthenticationRoutingConfigurator
|
import dev.inmo.postssystem.features.auth.server.AuthenticationRoutingConfigurator
|
||||||
import dev.inmo.postssystem.features.auth.server.SessionAuthenticationConfigurator
|
import dev.inmo.postssystem.features.auth.server.SessionAuthenticationConfigurator
|
||||||
import dev.inmo.postssystem.features.auth.server.tokens.*
|
import dev.inmo.postssystem.features.auth.server.tokens.*
|
||||||
import dev.inmo.postssystem.features.common.server.ApplicationAuthenticationConfigurator
|
import dev.inmo.postssystem.features.common.server.sessions.ApplicationAuthenticationConfigurator
|
||||||
import dev.inmo.postssystem.features.files.common.*
|
import dev.inmo.postssystem.features.files.common.*
|
||||||
import dev.inmo.postssystem.features.files.common.storage.*
|
import dev.inmo.postssystem.features.files.common.storage.*
|
||||||
|
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.KeyValuesRolesOriginalRepo
|
import dev.inmo.postssystem.features.roles.common.keyvalue.KeyValuesRolesOriginalRepo
|
||||||
@@ -18,19 +19,20 @@ 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.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
|
||||||
import dev.inmo.micro_utils.repos.exposed.keyvalue.ExposedKeyValueRepo
|
import dev.inmo.micro_utils.repos.exposed.keyvalue.ExposedKeyValueRepo
|
||||||
import dev.inmo.micro_utils.repos.exposed.onetomany.ExposedKeyValuesRepo
|
import dev.inmo.micro_utils.repos.exposed.onetomany.ExposedOneToManyKeyValueRepo
|
||||||
import dev.inmo.postssystem.features.common.common.*
|
import dev.inmo.postssystem.features.common.common.*
|
||||||
import dev.inmo.postssystem.features.common.server.Qualifiers
|
import dev.inmo.postssystem.features.common.server.sessions.Qualifiers
|
||||||
import dev.inmo.postssystem.features.content.common.*
|
import dev.inmo.postssystem.features.content.common.*
|
||||||
import dev.inmo.postssystem.features.content.server.ServerContentStorageAggregator
|
import dev.inmo.postssystem.features.content.server.ServerContentStorageAggregator
|
||||||
import dev.inmo.postssystem.features.content.server.storage.*
|
import dev.inmo.postssystem.features.content.server.storage.*
|
||||||
import dev.inmo.postssystem.features.posts.server.*
|
import dev.inmo.postssystem.features.posts.server.*
|
||||||
import dev.inmo.postssystem.features.publication.server.PublicationManager
|
import dev.inmo.postssystem.features.publication.server.PublicationManager
|
||||||
import dev.inmo.postssystem.services.posts.server.*
|
import dev.inmo.postssystem.services.posts.server.*
|
||||||
import io.ktor.server.application.pluginOrNull
|
import io.ktor.server.application.featureOrNull
|
||||||
import io.ktor.server.application.log
|
import io.ktor.server.application.log
|
||||||
import io.ktor.server.routing.Route
|
import io.ktor.server.routing.Route
|
||||||
import io.ktor.server.routing.Routing
|
import io.ktor.server.routing.Routing
|
||||||
@@ -47,7 +49,6 @@ import org.jetbrains.exposed.sql.Database
|
|||||||
import org.koin.core.module.Module
|
import org.koin.core.module.Module
|
||||||
import org.koin.core.parameter.ParametersHolder
|
import org.koin.core.parameter.ParametersHolder
|
||||||
import org.koin.core.qualifier.StringQualifier
|
import org.koin.core.qualifier.StringQualifier
|
||||||
import org.koin.core.qualifier.named
|
|
||||||
import org.koin.dsl.*
|
import org.koin.dsl.*
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
|
||||||
@@ -87,18 +88,19 @@ fun getDIModule(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
single { UnifiedRouter(get()) }
|
||||||
|
|
||||||
singleWithBinds { config }
|
singleWithBinds { config }
|
||||||
singleWithBinds { get<Config>().databaseConfig }
|
singleWithBinds { get<Config>().databaseConfig }
|
||||||
singleWithBinds { get<Config>().authConfig }
|
singleWithBinds { get<Config>().authConfig }
|
||||||
singleWithBinds(Qualifiers.filesFolderQualifier) { get<Config>().filesFolderFile }
|
singleWithBinds(Qualifiers.filesFolderQualifier) { get<Config>().filesFolderFile }
|
||||||
singleWithBinds(Qualifiers.commonFilesFolderQualifier) { File(get<Config>().filesFolderFile, "common").apply { mkdirs() } }
|
|
||||||
|
|
||||||
singleWithBinds { get<DatabaseConfig>().database }
|
singleWithBinds { get<DatabaseConfig>().database }
|
||||||
singleWithBinds { ExposedUsersStorage(get()) }
|
singleWithBinds { ExposedUsersStorage(get()) }
|
||||||
singleWithBinds { exposedUsersAuthenticator(get(), get()) }
|
singleWithBinds { exposedUsersAuthenticator(get(), get()) }
|
||||||
|
|
||||||
factory<KeyValuesRolesOriginalRepo>(Qualifiers.usersRolesKeyValueFactoryQualifier) { (tableName: String) ->
|
factory<KeyValuesRolesOriginalRepo>(Qualifiers.usersRolesKeyValueFactoryQualifier) { (tableName: String) ->
|
||||||
ExposedKeyValuesRepo(get(), { text("subject") }, { text("role") }, tableName)
|
ExposedOneToManyKeyValueRepo(get(), { text("subject") }, { text("role") }, tableName)
|
||||||
}
|
}
|
||||||
single {
|
single {
|
||||||
RolesManagerRoleStorage(get(Qualifiers.usersRolesKeyValueFactoryQualifier) { ParametersHolder(mutableListOf("rolesManager")) })
|
RolesManagerRoleStorage(get(Qualifiers.usersRolesKeyValueFactoryQualifier) { ParametersHolder(mutableListOf("rolesManager")) })
|
||||||
@@ -139,24 +141,13 @@ fun getDIModule(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
singleWithBinds<FilesStorage> {
|
|
||||||
val metasRepo = MetasKeyValueRepo(
|
|
||||||
get(),
|
|
||||||
ExposedKeyValueRepo(get(), { text("fileid") }, { text("metaInfo") }, "CommonFilesMetaInfoTable")
|
|
||||||
)
|
|
||||||
DefaultFilesStorage(
|
|
||||||
DiskReadFilesStorage(get(Qualifiers.commonFilesFolderQualifier), metasRepo),
|
|
||||||
WriteDistFilesStorage(get(Qualifiers.commonFilesFolderQualifier), metasRepo)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Routing configurators
|
// Routing configurators
|
||||||
singleWithBinds { FilesRoutingConfigurator(get(), null) }
|
singleWithBinds { FilesRoutingConfigurator(get(), null, get()) }
|
||||||
singleWithBinds { StatusRoutingConfigurator }
|
singleWithBinds { StatusRoutingConfigurator }
|
||||||
singleWithBinds { UsersStorageServerRoutesConfigurator(get()) }
|
singleWithBinds { UsersStorageServerRoutesConfigurator(get(), get()) }
|
||||||
singleWithBinds { RolesStorageReadServerRoutesConfigurator<Role>(get(), RoleSerializer) }
|
singleWithBinds { RolesStorageReadServerRoutesConfigurator<Role>(get(), RoleSerializer, get()) }
|
||||||
singleWithBinds { RolesManagerRolesStorageServerRoutesConfigurator(get()) }
|
singleWithBinds { RolesManagerRolesStorageServerRoutesConfigurator(get(), get()) }
|
||||||
singleWithBinds { ServerPostsServiceRoutingConfigurator(get(), get(), get()) }
|
singleWithBinds { ServerPostsServiceRoutingConfigurator(get(), get(), get(), get()) }
|
||||||
|
|
||||||
singleWithBinds { ClientStaticRoutingConfiguration("web") }
|
singleWithBinds { ClientStaticRoutingConfiguration("web") }
|
||||||
singleWithBinds {
|
singleWithBinds {
|
||||||
@@ -178,7 +169,7 @@ fun getDIModule(
|
|||||||
get()
|
get()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
singleWithBinds { AuthenticationRoutingConfigurator(get(), get()) }
|
singleWithBinds { AuthenticationRoutingConfigurator(get(), get(), get()) }
|
||||||
singleWithBinds { NotFoundStatusPageRedirectToIndex("/") }
|
singleWithBinds { NotFoundStatusPageRedirectToIndex("/") }
|
||||||
|
|
||||||
if (config.debugMode) {
|
if (config.debugMode) {
|
||||||
@@ -203,7 +194,7 @@ fun getDIModule(
|
|||||||
it.apply { configure() }
|
it.apply { configure() }
|
||||||
}
|
}
|
||||||
if (config.debugMode) {
|
if (config.debugMode) {
|
||||||
pluginOrNull(Routing) ?.print()
|
featureOrNull(Routing) ?.print()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ data class NotFoundStatusPageRedirectToIndex(
|
|||||||
val redirectTo: String
|
val redirectTo: String
|
||||||
) : StatusPagesConfigurator.Element {
|
) : StatusPagesConfigurator.Element {
|
||||||
override fun StatusPagesConfig.invoke() {
|
override fun StatusPagesConfig.invoke() {
|
||||||
status(HttpStatusCode.NotFound) { _ ->
|
status(HttpStatusCode.NotFound) {
|
||||||
call.respondRedirect(redirectTo)
|
call.respondRedirect(redirectTo)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import dev.inmo.postssystem.services.posts.common.*
|
|||||||
|
|
||||||
class ClientPostsService(
|
class ClientPostsService(
|
||||||
baseUrl: String,
|
baseUrl: String,
|
||||||
client: HttpClient
|
unifiedRequester: UnifiedRequester
|
||||||
) : PostsService,
|
) : PostsService,
|
||||||
ReadPostsService by ClientReadPostsService(baseUrl, client),
|
ReadPostsService by ClientReadPostsService(baseUrl, unifiedRequester),
|
||||||
WritePostsService by ClientWritePostsService(baseUrl, client)
|
WritePostsService by ClientWritePostsService(baseUrl, unifiedRequester)
|
||||||
|
|||||||
@@ -12,10 +12,10 @@ import kotlinx.serialization.builtins.nullable
|
|||||||
|
|
||||||
class ClientReadPostsService(
|
class ClientReadPostsService(
|
||||||
private val baseUrl: String,
|
private val baseUrl: String,
|
||||||
private val client: HttpClient
|
private val unifiedRequester: UnifiedRequester
|
||||||
) : ReadPostsService, ReadCRUDRepo<RegisteredPost, PostId> by KtorReadStandardCrudRepo(
|
) : ReadPostsService, ReadCRUDRepo<RegisteredPost, PostId> by KtorReadStandardCrudRepo(
|
||||||
buildStandardUrl(baseUrl, postsRootPath),
|
buildStandardUrl(baseUrl, postsRootPath),
|
||||||
client,
|
unifiedRequester,
|
||||||
RegisteredPost.serializer(),
|
RegisteredPost.serializer(),
|
||||||
RegisteredPost.serializer().nullable,
|
RegisteredPost.serializer().nullable,
|
||||||
PostId.serializer()
|
PostId.serializer()
|
||||||
|
|||||||
@@ -25,17 +25,17 @@ import kotlinx.serialization.modules.polymorphic
|
|||||||
|
|
||||||
class ClientWritePostsService(
|
class ClientWritePostsService(
|
||||||
private val baseUrl: String,
|
private val baseUrl: String,
|
||||||
client: HttpClient
|
unifiedRequester: UnifiedRequester
|
||||||
) : WritePostsService {
|
) : WritePostsService {
|
||||||
private val root = buildStandardUrl(baseUrl, postsRootPath)
|
private val root = buildStandardUrl(baseUrl, postsRootPath)
|
||||||
// private val unifiedRequester = UnifiedRequester(
|
private val unifiedRequester = UnifiedRequester(
|
||||||
// unifiedRequester.client,
|
unifiedRequester.client,
|
||||||
// unifiedRequester.serialFormat.createWithSerializerModuleExtension {
|
unifiedRequester.serialFormat.createWithSerializerModuleExtension {
|
||||||
// polymorphic(Content::class) {
|
polymorphic(Content::class) {
|
||||||
// subclass(BinaryContent::class, BinaryContentSerializer(TempFileIdentifierInputProvider::class, TempFileIdentifierInputProvider.serializer()))
|
subclass(BinaryContent::class, BinaryContentSerializer(TempFileIdentifierInputProvider::class, TempFileIdentifierInputProvider.serializer()))
|
||||||
// }
|
}
|
||||||
// }
|
}
|
||||||
// )
|
)
|
||||||
|
|
||||||
private val contentEitherSerializer = EitherSerializer(ContentId.serializer(), ContentSerializer)
|
private val contentEitherSerializer = EitherSerializer(ContentId.serializer(), ContentSerializer)
|
||||||
private val contentsEitherSerializer = ListSerializer(contentEitherSerializer)
|
private val contentsEitherSerializer = ListSerializer(contentEitherSerializer)
|
||||||
@@ -58,7 +58,7 @@ class ClientWritePostsService(
|
|||||||
return (content as? BinaryContent) ?.let {
|
return (content as? BinaryContent) ?.let {
|
||||||
when (val provider = it.inputProvider) {
|
when (val provider = it.inputProvider) {
|
||||||
is FileBasedInputProvider -> {
|
is FileBasedInputProvider -> {
|
||||||
val fileId = client.tempUpload(
|
val fileId = unifiedRequester.tempUpload(
|
||||||
tempUploadFullPath,
|
tempUploadFullPath,
|
||||||
provider.file
|
provider.file
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -3,14 +3,14 @@ package dev.inmo.postssystem.services.posts.client.ui.create
|
|||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
sealed interface PostCreateUIState {
|
sealed class PostCreateUIState {
|
||||||
// @Serializable
|
@Serializable
|
||||||
object Init : PostCreateUIState
|
object Init : PostCreateUIState()
|
||||||
// @Serializable
|
@Serializable
|
||||||
object Uploading : PostCreateUIState
|
object Uploading : PostCreateUIState()
|
||||||
// @Serializable
|
@Serializable
|
||||||
object Fail : PostCreateUIState
|
object Fail : PostCreateUIState()
|
||||||
// @Serializable
|
@Serializable
|
||||||
object Completed : PostCreateUIState
|
object Completed : PostCreateUIState()
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,13 +4,13 @@ import dev.inmo.postssystem.features.posts.common.RegisteredPostWithContent
|
|||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
sealed interface PostsListUIState {
|
sealed class PostsListUIState {
|
||||||
// @Serializable
|
@Serializable
|
||||||
object Loading : PostsListUIState
|
object Loading : PostsListUIState()
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
data class Show(
|
data class Show(
|
||||||
val posts: List<RegisteredPostWithContent>
|
val posts: List<RegisteredPostWithContent>
|
||||||
) : PostsListUIState
|
) : PostsListUIState()
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,19 +10,18 @@ import dev.inmo.micro_utils.mime_types.findBuiltinMimeType
|
|||||||
import dev.inmo.micro_utils.repos.ktor.common.crud.createRouting
|
import dev.inmo.micro_utils.repos.ktor.common.crud.createRouting
|
||||||
import dev.inmo.micro_utils.repos.ktor.common.crud.updateRouting
|
import dev.inmo.micro_utils.repos.ktor.common.crud.updateRouting
|
||||||
import dev.inmo.micro_utils.repos.ktor.common.one_to_many.removeRoute
|
import dev.inmo.micro_utils.repos.ktor.common.one_to_many.removeRoute
|
||||||
import dev.inmo.micro_utils.repos.ktor.server.crud.configureReadCRUDRepoRoutes
|
import dev.inmo.micro_utils.repos.ktor.server.crud.configureReadStandardCrudRepoRoutes
|
||||||
import dev.inmo.postssystem.features.common.common.FileBasedInputProvider
|
import dev.inmo.postssystem.features.common.common.FileBasedInputProvider
|
||||||
import dev.inmo.postssystem.features.content.common.*
|
import dev.inmo.postssystem.features.content.common.*
|
||||||
import dev.inmo.postssystem.features.files.common.FileId
|
import dev.inmo.postssystem.features.files.common.FileId
|
||||||
import dev.inmo.postssystem.features.posts.common.*
|
import dev.inmo.postssystem.features.posts.common.*
|
||||||
import dev.inmo.postssystem.services.posts.common.*
|
import dev.inmo.postssystem.services.posts.common.*
|
||||||
import io.ktor.http.HttpStatusCode
|
import io.ktor.http.HttpStatusCode
|
||||||
import io.ktor.http.content.PartData
|
import io.ktor.http.server.content.PartData
|
||||||
import io.ktor.http.content.streamProvider
|
import io.ktor.http.server.content.streamProvider
|
||||||
import io.ktor.server.application.ApplicationCall
|
import io.ktor.server.application.ApplicationCall
|
||||||
import io.ktor.server.application.call
|
import io.ktor.server.application.call
|
||||||
import io.ktor.server.auth.authenticate
|
import io.ktor.server.auth.authenticate
|
||||||
import io.ktor.server.request.receive
|
|
||||||
import io.ktor.server.request.receiveMultipart
|
import io.ktor.server.request.receiveMultipart
|
||||||
import io.ktor.server.response.respond
|
import io.ktor.server.response.respond
|
||||||
import io.ktor.server.routing.*
|
import io.ktor.server.routing.*
|
||||||
@@ -33,6 +32,8 @@ import io.ktor.utils.io.streams.asInput
|
|||||||
import kotlinx.coroutines.*
|
import kotlinx.coroutines.*
|
||||||
import kotlinx.coroutines.sync.Mutex
|
import kotlinx.coroutines.sync.Mutex
|
||||||
import kotlinx.coroutines.sync.withLock
|
import kotlinx.coroutines.sync.withLock
|
||||||
|
import kotlinx.serialization.builtins.*
|
||||||
|
import kotlinx.serialization.modules.polymorphic
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.nio.file.Files
|
import java.nio.file.Files
|
||||||
import java.nio.file.attribute.FileTime
|
import java.nio.file.attribute.FileTime
|
||||||
@@ -41,8 +42,19 @@ import java.util.concurrent.TimeUnit
|
|||||||
class ServerPostsServiceRoutingConfigurator(
|
class ServerPostsServiceRoutingConfigurator(
|
||||||
private val readPostsService: ReadPostsService,
|
private val readPostsService: ReadPostsService,
|
||||||
private val writePostsService: WritePostsService? = readPostsService as? WritePostsService,
|
private val writePostsService: WritePostsService? = readPostsService as? WritePostsService,
|
||||||
private val scope: CoroutineScope
|
private val scope: CoroutineScope,
|
||||||
|
unifiedRouter: UnifiedRouter
|
||||||
) : ApplicationRoutingConfigurator.Element {
|
) : ApplicationRoutingConfigurator.Element {
|
||||||
|
private val unifiedRouter = UnifiedRouter(
|
||||||
|
serialFormat = unifiedRouter.serialFormat.createWithSerializerModuleExtension {
|
||||||
|
polymorphic(Content::class) {
|
||||||
|
subclass(BinaryContent::class, BinaryContentSerializer(TempFileIdentifierInputProvider::class, TempFileIdentifierInputProvider.serializer()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
private val contentEitherSerializer = EitherSerializer(ContentId.serializer(), ContentSerializer)
|
||||||
|
private val contentsEitherSerializer = ListSerializer(contentEitherSerializer)
|
||||||
|
private val contentsSerializer = ListSerializer(ContentSerializer)
|
||||||
|
|
||||||
private val temporalFilesMap = mutableMapOf<FileId, MPPFile>()
|
private val temporalFilesMap = mutableMapOf<FileId, MPPFile>()
|
||||||
private val temporalFilesMutex = Mutex()
|
private val temporalFilesMutex = Mutex()
|
||||||
@@ -85,16 +97,20 @@ class ServerPostsServiceRoutingConfigurator(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun PipelineContext<Unit, ApplicationCall>.receiveContents(): List<Content> {
|
private suspend fun PipelineContext<Unit, ApplicationCall>.receiveContents(): List<Content> {
|
||||||
return call.receive<ContentsWrapper>().content.mapNotNull {
|
return unifiedRouter.run {
|
||||||
mapBinary(it as? BinaryContent ?: return@mapNotNull it)
|
uniload(contentsSerializer).mapNotNull {
|
||||||
|
mapBinary(it as? BinaryContent ?: return@mapNotNull it)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun PipelineContext<Unit, ApplicationCall>.receiveContentsEithers(): List<Either<ContentId, Content>> {
|
private suspend fun PipelineContext<Unit, ApplicationCall>.receiveContentsEithers(): List<Either<ContentId, Content>> {
|
||||||
return call.receive<ContentsEithersWrapper>().content.mapNotNull {
|
return unifiedRouter.run {
|
||||||
it.mapOnSecond {
|
uniload(contentsEitherSerializer).mapNotNull {
|
||||||
mapBinary(it as? BinaryContent ?: return@mapOnSecond null) ?.either()
|
it.mapOnSecond {
|
||||||
} ?: it
|
mapBinary(it as? BinaryContent ?: return@mapOnSecond null) ?.either()
|
||||||
|
} ?: it
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -103,69 +119,83 @@ class ServerPostsServiceRoutingConfigurator(
|
|||||||
override fun Route.invoke() {
|
override fun Route.invoke() {
|
||||||
authenticate {
|
authenticate {
|
||||||
route(postsRootPath) {
|
route(postsRootPath) {
|
||||||
configureReadCRUDRepoRoutes(
|
configureReadStandardCrudRepoRoutes(
|
||||||
readPostsService
|
readPostsService,
|
||||||
) { PostId(it.toLong()) }
|
RegisteredPost.serializer(),
|
||||||
|
RegisteredPost.serializer().nullable,
|
||||||
|
PostId.serializer(),
|
||||||
|
unifiedRouter
|
||||||
|
)
|
||||||
|
|
||||||
writePostsService ?.let {
|
writePostsService ?.let {
|
||||||
|
|
||||||
post(createRouting) {
|
unifiedRouter.apply {
|
||||||
val data = receiveContents()
|
|
||||||
|
|
||||||
call.respond(
|
post(createRouting) {
|
||||||
writePostsService.create(FullNewPost(data)) ?: HttpStatusCode.NoContent
|
val data = receiveContents()
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
post(updateRouting) {
|
unianswer(
|
||||||
call.respond(
|
RegisteredPost.serializer().nullable,
|
||||||
writePostsService.update(
|
writePostsService.create(FullNewPost(data))
|
||||||
call.getQueryParameterOrSendError(postsPostIdParameter)?.toLong()?.let(::PostId) ?: return@post,
|
|
||||||
receiveContentsEithers()
|
|
||||||
) ?: HttpStatusCode.NoContent
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
post(removeRoute) {
|
|
||||||
call.respond(
|
|
||||||
writePostsService.remove(
|
|
||||||
call.receive()
|
|
||||||
)
|
)
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
post(postsCreateTempPathPart) {
|
|
||||||
val multipart = call.receiveMultipart()
|
|
||||||
|
|
||||||
var fileInfo: Pair<FileId, MPPFile>? = null
|
|
||||||
var part = multipart.readPart()
|
|
||||||
while (part != null) {
|
|
||||||
if (part is PartData.FileItem) {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
part = multipart.readPart()
|
|
||||||
}
|
}
|
||||||
part ?.let {
|
|
||||||
if (it is PartData.FileItem) {
|
post(updateRouting) {
|
||||||
val fileId = FileId(uuid4().toString())
|
val postId = call.decodeUrlQueryValueOrSendError(postsPostIdParameter, PostId.serializer()) ?: return@post
|
||||||
val fileName = it.originalFileName ?.let { FileName(it) } ?: return@let
|
val data = receiveContentsEithers()
|
||||||
fileInfo = fileId to File.createTempFile(fileId.string, ".${fileName.extension}").apply {
|
|
||||||
outputStream().use { outputStream ->
|
unianswer(
|
||||||
it.streamProvider().use {
|
RegisteredPost.serializer().nullable,
|
||||||
it.copyTo(outputStream)
|
writePostsService.update(
|
||||||
|
postId,
|
||||||
|
data
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
post(removeRoute) {
|
||||||
|
val postId = uniload(PostId.serializer())
|
||||||
|
|
||||||
|
unianswer(
|
||||||
|
Unit.serializer(),
|
||||||
|
writePostsService.remove(postId)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
post(postsCreateTempPathPart) {
|
||||||
|
val multipart = call.receiveMultipart()
|
||||||
|
|
||||||
|
var fileInfo: Pair<FileId, MPPFile>? = null
|
||||||
|
var part = multipart.readPart()
|
||||||
|
while (part != null) {
|
||||||
|
if (part is PartData.FileItem) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
part = multipart.readPart()
|
||||||
|
}
|
||||||
|
part ?.let {
|
||||||
|
if (it is PartData.FileItem) {
|
||||||
|
val fileId = FileId(uuid4().toString())
|
||||||
|
val fileName = it.originalFileName ?.let { FileName(it) } ?: return@let
|
||||||
|
fileInfo = fileId to File.createTempFile(fileId.string, ".${fileName.extension}").apply {
|
||||||
|
outputStream().use { outputStream ->
|
||||||
|
it.streamProvider().use {
|
||||||
|
it.copyTo(outputStream)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
deleteOnExit()
|
||||||
}
|
}
|
||||||
deleteOnExit()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
fileInfo ?.also { (fileId, file) ->
|
fileInfo ?.also { (fileId, file) ->
|
||||||
temporalFilesMutex.withLock {
|
temporalFilesMutex.withLock {
|
||||||
temporalFilesMap[fileId] = file
|
temporalFilesMap[fileId] = file
|
||||||
}
|
}
|
||||||
call.respond(fileId.string)
|
call.respond(fileId.string)
|
||||||
} ?: call.respond(HttpStatusCode.BadRequest)
|
} ?: call.respond(HttpStatusCode.BadRequest)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
package dev.inmo.postssystem.targets.telegram.loader.server
|
package dev.inmo.postssystem.targets.telegram.loader.server
|
||||||
|
|
||||||
import dev.inmo.postssystem.features.common.common.singleWithRandomQualifier
|
import dev.inmo.postssystem.features.common.common.singleWithRandomQualifier
|
||||||
import dev.inmo.postssystem.features.common.server.ServerModuleLoader
|
import dev.inmo.postssystem.features.common.server.sessions.ServerModuleLoader
|
||||||
import dev.inmo.postssystem.features.content.common.ContentSerializersModuleConfigurator
|
import dev.inmo.postssystem.features.content.common.ContentSerializersModuleConfigurator
|
||||||
import dev.inmo.postssystem.features.publication.server.PublicationTarget
|
import dev.inmo.postssystem.features.publication.server.PublicationTarget
|
||||||
import dev.inmo.postssystem.targets.telegram.content.polls.common.PollContent
|
import dev.inmo.postssystem.targets.telegram.content.polls.common.PollContent
|
||||||
|
|||||||
Reference in New Issue
Block a user