add integration with posts creating
This commit is contained in:
client
features/content
binary
common
src
commonMain
kotlin
dev
inmo
postssystem
features
content
server
src
jvmMain
kotlin
dev
inmo
postssystem
features
content
binary
common
src
commonMain
kotlin
dev
inmo
postssystem
features
content
common
server
services/posts
client
src
commonMain
kotlin
dev
inmo
postssystem
services
common
server
11
services/posts/client/src/commonMain/kotlin/dev/inmo/postssystem/services/posts/client/ClientPostsService.kt
Normal file
11
services/posts/client/src/commonMain/kotlin/dev/inmo/postssystem/services/posts/client/ClientPostsService.kt
Normal file
@ -0,0 +1,11 @@
|
||||
package dev.inmo.postssystem.services.posts.client
|
||||
|
||||
import dev.inmo.micro_utils.ktor.client.UnifiedRequester
|
||||
import dev.inmo.postssystem.services.posts.common.*
|
||||
|
||||
class ClientPostsService(
|
||||
baseUrl: String,
|
||||
unifiedRequester: UnifiedRequester
|
||||
) : PostsService,
|
||||
ReadPostsService by ClientReadPostsService(baseUrl, unifiedRequester),
|
||||
WritePostsService by ClientWritePostsService(baseUrl, unifiedRequester)
|
22
services/posts/client/src/commonMain/kotlin/dev/inmo/postssystem/services/posts/client/ClientReadPostsService.kt
Normal file
22
services/posts/client/src/commonMain/kotlin/dev/inmo/postssystem/services/posts/client/ClientReadPostsService.kt
Normal file
@ -0,0 +1,22 @@
|
||||
package dev.inmo.postssystem.services.posts.client
|
||||
|
||||
import dev.inmo.micro_utils.ktor.client.UnifiedRequester
|
||||
import dev.inmo.micro_utils.ktor.common.buildStandardUrl
|
||||
import dev.inmo.micro_utils.repos.ReadCRUDRepo
|
||||
import dev.inmo.micro_utils.repos.ktor.client.crud.KtorReadStandardCrudRepo
|
||||
import dev.inmo.postssystem.features.posts.common.PostId
|
||||
import dev.inmo.postssystem.features.posts.common.RegisteredPost
|
||||
import dev.inmo.postssystem.services.posts.common.ReadPostsService
|
||||
import dev.inmo.postssystem.services.posts.common.postsRootPath
|
||||
import kotlinx.serialization.builtins.nullable
|
||||
|
||||
class ClientReadPostsService(
|
||||
private val baseUrl: String,
|
||||
private val unifiedRequester: UnifiedRequester
|
||||
) : ReadPostsService, ReadCRUDRepo<RegisteredPost, PostId> by KtorReadStandardCrudRepo(
|
||||
buildStandardUrl(baseUrl, postsRootPath),
|
||||
unifiedRequester,
|
||||
RegisteredPost.serializer(),
|
||||
RegisteredPost.serializer().nullable,
|
||||
PostId.serializer()
|
||||
)
|
123
services/posts/client/src/commonMain/kotlin/dev/inmo/postssystem/services/posts/client/ClientWritePostsService.kt
Normal file
123
services/posts/client/src/commonMain/kotlin/dev/inmo/postssystem/services/posts/client/ClientWritePostsService.kt
Normal file
@ -0,0 +1,123 @@
|
||||
package dev.inmo.postssystem.services.posts.client
|
||||
|
||||
import dev.inmo.micro_utils.common.*
|
||||
import dev.inmo.micro_utils.ktor.client.UnifiedRequester
|
||||
import dev.inmo.micro_utils.ktor.common.buildStandardUrl
|
||||
import dev.inmo.micro_utils.ktor.common.encodeHex
|
||||
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.one_to_many.removeRoute
|
||||
import dev.inmo.postssystem.features.content.common.*
|
||||
import dev.inmo.postssystem.features.posts.common.PostId
|
||||
import dev.inmo.postssystem.features.posts.common.RegisteredPost
|
||||
import dev.inmo.postssystem.services.posts.common.*
|
||||
import io.ktor.client.request.forms.InputProvider
|
||||
import io.ktor.client.request.forms.formData
|
||||
import io.ktor.client.request.headers
|
||||
import io.ktor.client.request.post
|
||||
import io.ktor.http.HttpHeaders
|
||||
import kotlinx.serialization.builtins.*
|
||||
|
||||
class ClientWritePostsService(
|
||||
private val baseUrl: String,
|
||||
private val unifiedRequester: UnifiedRequester
|
||||
) : WritePostsService {
|
||||
private val root = buildStandardUrl(baseUrl, postsRootPath)
|
||||
|
||||
private val contentEitherSerializer = EitherSerializer(ContentId.serializer(), ContentSerializer)
|
||||
private val contentsEitherSerializer = ListSerializer(contentEitherSerializer)
|
||||
private val contentsSerializer = ListSerializer(ContentSerializer)
|
||||
|
||||
private val createFullPath = buildStandardUrl(
|
||||
root,
|
||||
createRouting
|
||||
)
|
||||
private val removeFullPath = buildStandardUrl(
|
||||
root,
|
||||
removeRoute
|
||||
)
|
||||
|
||||
override suspend fun create(newPost: FullNewPost): RegisteredPost? {
|
||||
return if (newPost.content.any { it is BinaryContent }) {
|
||||
val answer = unifiedRequester.client.post<ByteArray>(createFullPath) {
|
||||
formData {
|
||||
newPost.content.forEachIndexed { i, content ->
|
||||
when (content) {
|
||||
is BinaryContent -> append(
|
||||
i.toString(),
|
||||
InputProvider(block = content.inputProvider),
|
||||
headers {
|
||||
append(HttpHeaders.ContentType, content.mimeType.raw)
|
||||
append(HttpHeaders.ContentDisposition, "filename=\"${content.filename.name}\"")
|
||||
}.build()
|
||||
)
|
||||
else -> append(
|
||||
i.toString(),
|
||||
unifiedRequester.serialFormat.encodeHex(ContentSerializer, content)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
unifiedRequester.serialFormat.decodeFromByteArray(RegisteredPost.serializer().nullable, answer)
|
||||
} else {
|
||||
unifiedRequester.unipost(
|
||||
createFullPath,
|
||||
contentsSerializer to newPost.content,
|
||||
RegisteredPost.serializer().nullable
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun update(
|
||||
postId: PostId,
|
||||
content: List<Either<ContentId, Content>>
|
||||
): RegisteredPost? {
|
||||
return if (content.any { it.optionalT2.data is BinaryContent }) {
|
||||
val answer = unifiedRequester.client.post<ByteArray>(createFullPath) {
|
||||
formData {
|
||||
content.forEachIndexed { i, eitherContent ->
|
||||
eitherContent.onFirst {
|
||||
append(
|
||||
i.toString(),
|
||||
unifiedRequester.serialFormat.encodeHex(contentEitherSerializer, it.either())
|
||||
)
|
||||
}.onSecond {
|
||||
when (it) {
|
||||
is BinaryContent -> append(
|
||||
i.toString(),
|
||||
InputProvider(block = it.inputProvider),
|
||||
headers {
|
||||
append(HttpHeaders.ContentType, it.mimeType.raw)
|
||||
append(HttpHeaders.ContentDisposition, "filename=\"${it.filename.name}\"")
|
||||
}.build()
|
||||
)
|
||||
else -> append(
|
||||
i.toString(),
|
||||
unifiedRequester.serialFormat.encodeHex(contentEitherSerializer, it.either())
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
unifiedRequester.serialFormat.decodeFromByteArray(RegisteredPost.serializer().nullable, answer)
|
||||
} else {
|
||||
unifiedRequester.unipost(
|
||||
buildStandardUrl(
|
||||
root,
|
||||
updateRouting,
|
||||
postsPostIdParameter to unifiedRequester.encodeUrlQueryValue(PostId.serializer(), postId)
|
||||
),
|
||||
contentsEitherSerializer to content,
|
||||
RegisteredPost.serializer().nullable
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun remove(postId: PostId) = unifiedRequester.unipost(
|
||||
removeFullPath,
|
||||
PostId.serializer() to postId,
|
||||
Unit.serializer()
|
||||
)
|
||||
}
|
@ -12,6 +12,8 @@ kotlin {
|
||||
dependencies {
|
||||
api project(":postssystem.features.common.common")
|
||||
api project(":postssystem.features.posts.common")
|
||||
api "dev.inmo:micro_utils.repos.common:$microutils_version"
|
||||
api "dev.inmo:micro_utils.repos.ktor.client:$microutils_version"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
2
services/posts/common/src/commonMain/kotlin/dev/inmo/postssystem/services/posts/common/Constants.kt
2
services/posts/common/src/commonMain/kotlin/dev/inmo/postssystem/services/posts/common/Constants.kt
@ -1,3 +1,5 @@
|
||||
package dev.inmo.postssystem.services.posts.common
|
||||
|
||||
const val postsRootPath = "posts"
|
||||
|
||||
const val postsPostIdParameter = "postId"
|
||||
|
9
services/posts/common/src/commonMain/kotlin/dev/inmo/postssystem/services/posts/common/FullNewPost.kt
Normal file
9
services/posts/common/src/commonMain/kotlin/dev/inmo/postssystem/services/posts/common/FullNewPost.kt
Normal file
@ -0,0 +1,9 @@
|
||||
package dev.inmo.postssystem.services.posts.common
|
||||
|
||||
import dev.inmo.postssystem.features.content.common.Content
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
data class FullNewPost(
|
||||
val content: List<Content>
|
||||
)
|
3
services/posts/common/src/commonMain/kotlin/dev/inmo/postssystem/services/posts/common/PostsService.kt
Normal file
3
services/posts/common/src/commonMain/kotlin/dev/inmo/postssystem/services/posts/common/PostsService.kt
Normal file
@ -0,0 +1,3 @@
|
||||
package dev.inmo.postssystem.services.posts.common
|
||||
|
||||
interface PostsService : ReadPostsService, WritePostsService
|
7
services/posts/common/src/commonMain/kotlin/dev/inmo/postssystem/services/posts/common/ReadPostsService.kt
Normal file
7
services/posts/common/src/commonMain/kotlin/dev/inmo/postssystem/services/posts/common/ReadPostsService.kt
Normal file
@ -0,0 +1,7 @@
|
||||
package dev.inmo.postssystem.services.posts.common
|
||||
|
||||
import dev.inmo.micro_utils.repos.ReadCRUDRepo
|
||||
import dev.inmo.postssystem.features.posts.common.PostId
|
||||
import dev.inmo.postssystem.features.posts.common.RegisteredPost
|
||||
|
||||
interface ReadPostsService : ReadCRUDRepo<RegisteredPost, PostId>
|
16
services/posts/common/src/commonMain/kotlin/dev/inmo/postssystem/services/posts/common/WritePostsService.kt
Normal file
16
services/posts/common/src/commonMain/kotlin/dev/inmo/postssystem/services/posts/common/WritePostsService.kt
Normal file
@ -0,0 +1,16 @@
|
||||
package dev.inmo.postssystem.services.posts.common
|
||||
|
||||
import dev.inmo.micro_utils.common.Either
|
||||
import dev.inmo.postssystem.features.content.common.Content
|
||||
import dev.inmo.postssystem.features.content.common.ContentId
|
||||
import dev.inmo.postssystem.features.posts.common.PostId
|
||||
import dev.inmo.postssystem.features.posts.common.RegisteredPost
|
||||
|
||||
interface WritePostsService {
|
||||
suspend fun create(newPost: FullNewPost): RegisteredPost?
|
||||
suspend fun update(
|
||||
postId: PostId,
|
||||
content: List<Either<ContentId, Content>>
|
||||
): RegisteredPost?
|
||||
suspend fun remove(postId: PostId)
|
||||
}
|
@ -14,6 +14,8 @@ kotlin {
|
||||
api project(":postssystem.features.content.server")
|
||||
api project(":postssystem.features.posts.server")
|
||||
api project(":postssystem.features.users.server")
|
||||
api "dev.inmo:micro_utils.common:$microutils_version"
|
||||
api "org.jetbrains.kotlinx:kotlinx-serialization-properties:$kotlin_serialisation_core_version"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
49
services/posts/server/src/jvmMain/kotlin/dev/inmo/postssystem/services/posts/server/DefaultWritePostsService.kt
Normal file
49
services/posts/server/src/jvmMain/kotlin/dev/inmo/postssystem/services/posts/server/DefaultWritePostsService.kt
Normal file
@ -0,0 +1,49 @@
|
||||
package dev.inmo.postssystem.services.posts.server
|
||||
|
||||
import dev.inmo.micro_utils.common.*
|
||||
import dev.inmo.micro_utils.repos.create
|
||||
import dev.inmo.micro_utils.repos.deleteById
|
||||
import dev.inmo.postssystem.features.content.common.Content
|
||||
import dev.inmo.postssystem.features.content.common.ContentId
|
||||
import dev.inmo.postssystem.features.content.server.storage.ServerContentStorage
|
||||
import dev.inmo.postssystem.features.posts.common.*
|
||||
import dev.inmo.postssystem.features.posts.server.ServerPostsStorage
|
||||
import dev.inmo.postssystem.services.posts.common.FullNewPost
|
||||
import dev.inmo.postssystem.services.posts.common.WritePostsService
|
||||
|
||||
class DefaultWritePostsService(
|
||||
private val postsStorage: ServerPostsStorage,
|
||||
private val contentStorage: ServerContentStorage<Content>
|
||||
) : WritePostsService {
|
||||
override suspend fun create(newPost: FullNewPost): RegisteredPost? {
|
||||
val contentIds = contentStorage.create(newPost.content).map { it.id }
|
||||
|
||||
return postsStorage.create(NewPost(contentIds)).firstOrNull()
|
||||
}
|
||||
|
||||
override suspend fun update(postId: PostId, content: List<Either<ContentId, Content>>): RegisteredPost? {
|
||||
if (!postsStorage.contains(postId)) {
|
||||
return null
|
||||
}
|
||||
|
||||
val newContent = content.mapNotNull {
|
||||
when (it) {
|
||||
is EitherFirst -> {
|
||||
it.t1
|
||||
}
|
||||
is EitherSecond -> {
|
||||
contentStorage.create(it.t2).firstOrNull() ?.id
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return postsStorage.update(
|
||||
postId,
|
||||
NewPost(newContent)
|
||||
)
|
||||
}
|
||||
|
||||
override suspend fun remove(postId: PostId) {
|
||||
return postsStorage.deleteById(postId)
|
||||
}
|
||||
}
|
61
services/posts/server/src/jvmMain/kotlin/dev/inmo/postssystem/services/posts/server/DownloadFullNewPost.kt
Normal file
61
services/posts/server/src/jvmMain/kotlin/dev/inmo/postssystem/services/posts/server/DownloadFullNewPost.kt
Normal file
@ -0,0 +1,61 @@
|
||||
package dev.inmo.postssystem.services.posts.server
|
||||
|
||||
import dev.inmo.micro_utils.common.FileName
|
||||
import dev.inmo.micro_utils.common.MPPFile
|
||||
import dev.inmo.micro_utils.ktor.common.StandardKtorSerialFormat
|
||||
import dev.inmo.micro_utils.ktor.common.decodeHex
|
||||
import dev.inmo.postssystem.features.content.common.ContentSerializer
|
||||
import dev.inmo.postssystem.services.posts.common.FullNewPost
|
||||
import io.ktor.application.ApplicationCall
|
||||
import io.ktor.application.call
|
||||
import io.ktor.http.content.PartData
|
||||
import io.ktor.request.receiveMultipart
|
||||
import io.ktor.util.asStream
|
||||
import io.ktor.util.pipeline.PipelineContext
|
||||
import io.ktor.utils.io.core.use
|
||||
|
||||
suspend fun PipelineContext<Unit, ApplicationCall>.downloadFullNewPost(
|
||||
serialFormat: StandardKtorSerialFormat
|
||||
): FullNewPost {
|
||||
val multipart = call.receiveMultipart()
|
||||
val map = mutableMapOf<String, Any>()
|
||||
|
||||
var part = multipart.readPart()
|
||||
|
||||
while (part != null) {
|
||||
val name = part.name
|
||||
val capturedPart = part
|
||||
when {
|
||||
name == null -> {}
|
||||
capturedPart is PartData.FormItem -> {
|
||||
map[name] = serialFormat.decodeHex(
|
||||
ContentSerializer,
|
||||
capturedPart.value
|
||||
)
|
||||
}
|
||||
capturedPart is PartData.FileItem -> {
|
||||
val filename = FileName(capturedPart.originalFileName ?: error("File name is unknown for default part"))
|
||||
val resultInput = MPPFile.createTempFile(
|
||||
filename.nameWithoutExtension.let {
|
||||
var resultName = it
|
||||
while (resultName.length < 3) {
|
||||
resultName += "_"
|
||||
}
|
||||
resultName
|
||||
},
|
||||
".${filename.extension}"
|
||||
).apply {
|
||||
outputStream().use { fileStream ->
|
||||
capturedPart.provider().asStream().copyTo(fileStream)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
else -> {}
|
||||
}
|
||||
|
||||
part = multipart.readPart()
|
||||
}
|
||||
|
||||
|
||||
}
|
211
services/posts/server/src/jvmMain/kotlin/dev/inmo/postssystem/services/posts/server/ServerPostsServiceRoutingConfigurator.kt
Normal file
211
services/posts/server/src/jvmMain/kotlin/dev/inmo/postssystem/services/posts/server/ServerPostsServiceRoutingConfigurator.kt
Normal file
@ -0,0 +1,211 @@
|
||||
package dev.inmo.postssystem.services.posts.server
|
||||
|
||||
import dev.inmo.micro_utils.common.*
|
||||
import dev.inmo.micro_utils.ktor.common.decodeHex
|
||||
import dev.inmo.micro_utils.ktor.server.*
|
||||
import dev.inmo.micro_utils.ktor.server.configurators.ApplicationRoutingConfigurator
|
||||
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.updateRouting
|
||||
import dev.inmo.micro_utils.repos.ktor.common.one_to_many.removeRoute
|
||||
import dev.inmo.micro_utils.repos.ktor.server.crud.configureReadStandardCrudRepoRoutes
|
||||
import dev.inmo.postssystem.features.content.common.*
|
||||
import dev.inmo.postssystem.features.posts.common.*
|
||||
import dev.inmo.postssystem.services.posts.common.*
|
||||
import io.ktor.application.ApplicationCall
|
||||
import io.ktor.application.call
|
||||
import io.ktor.auth.authenticate
|
||||
import io.ktor.http.content.PartData
|
||||
import io.ktor.request.isMultipart
|
||||
import io.ktor.request.receiveMultipart
|
||||
import io.ktor.routing.*
|
||||
import io.ktor.util.asStream
|
||||
import io.ktor.util.pipeline.PipelineContext
|
||||
import io.ktor.utils.io.core.use
|
||||
import io.ktor.utils.io.streams.asInput
|
||||
import kotlinx.serialization.builtins.*
|
||||
|
||||
class ServerPostsServiceRoutingConfigurator(
|
||||
private val readPostsService: ReadPostsService,
|
||||
private val writePostsService: WritePostsService? = readPostsService as? WritePostsService,
|
||||
private val unifiedRouter: UnifiedRouter
|
||||
) : ApplicationRoutingConfigurator.Element {
|
||||
private val contentEitherSerializer = EitherSerializer(ContentId.serializer(), ContentSerializer)
|
||||
private val contentsEitherSerializer = ListSerializer(contentEitherSerializer)
|
||||
private val contentsSerializer = ListSerializer(ContentSerializer)
|
||||
|
||||
private suspend fun PipelineContext<Unit, ApplicationCall>.receiveContents(): List<Content> {
|
||||
return unifiedRouter.run {
|
||||
if (call.request.isMultipart()) {
|
||||
val multipart = call.receiveMultipart()
|
||||
val list = mutableListOf<Pair<String, Content>>()
|
||||
|
||||
var part = multipart.readPart()
|
||||
|
||||
while (part != null) {
|
||||
val name = part.name
|
||||
val capturedPart = part
|
||||
when {
|
||||
name == null -> {}
|
||||
capturedPart is PartData.FormItem -> {
|
||||
list.add(
|
||||
name to unifiedRouter.serialFormat.decodeHex(
|
||||
ContentSerializer,
|
||||
capturedPart.value
|
||||
)
|
||||
)
|
||||
}
|
||||
capturedPart is PartData.FileItem -> {
|
||||
val filename = capturedPart.originalFileName ?.let(::FileName) ?: error("File name is unknown for default part")
|
||||
val mimeType = capturedPart.contentType ?.let {
|
||||
findBuiltinMimeType("${it.contentType}/${it.contentSubtype}")
|
||||
} ?: error("File type is unknown for default part")
|
||||
val resultInput = MPPFile.createTempFile(
|
||||
filename.nameWithoutExtension.let {
|
||||
var resultName = it
|
||||
while (resultName.length < 3) {
|
||||
resultName += "_"
|
||||
}
|
||||
resultName
|
||||
},
|
||||
".${filename.extension}"
|
||||
).apply {
|
||||
outputStream().use { fileStream ->
|
||||
capturedPart.provider().asStream().copyTo(fileStream)
|
||||
}
|
||||
}
|
||||
|
||||
list.add(
|
||||
name to BinaryContent(
|
||||
filename,
|
||||
mimeType
|
||||
) { resultInput.inputStream().asInput() }
|
||||
)
|
||||
}
|
||||
else -> {}
|
||||
}
|
||||
|
||||
part = multipart.readPart()
|
||||
}
|
||||
|
||||
list.sortedBy { it.first }.map { it.second }
|
||||
} else {
|
||||
uniload(contentsSerializer)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun PipelineContext<Unit, ApplicationCall>.receiveContentsEithers(): List<Either<ContentId, Content>> {
|
||||
return unifiedRouter.run {
|
||||
if (call.request.isMultipart()) {
|
||||
val multipart = call.receiveMultipart()
|
||||
val list = mutableListOf<Pair<String, Either<ContentId, Content>>>()
|
||||
|
||||
var part = multipart.readPart()
|
||||
|
||||
while (part != null) {
|
||||
val name = part.name
|
||||
val capturedPart = part
|
||||
when {
|
||||
name == null -> {}
|
||||
capturedPart is PartData.FormItem -> {
|
||||
list.add(
|
||||
name to unifiedRouter.serialFormat.decodeHex(
|
||||
contentEitherSerializer,
|
||||
capturedPart.value
|
||||
)
|
||||
)
|
||||
}
|
||||
capturedPart is PartData.FileItem -> {
|
||||
val filename = capturedPart.originalFileName ?.let(::FileName) ?: error("File name is unknown for default part")
|
||||
val mimeType = capturedPart.contentType ?.let {
|
||||
findBuiltinMimeType("${it.contentType}/${it.contentSubtype}")
|
||||
} ?: error("File type is unknown for default part")
|
||||
val resultInput = MPPFile.createTempFile(
|
||||
filename.nameWithoutExtension.let {
|
||||
var resultName = it
|
||||
while (resultName.length < 3) {
|
||||
resultName += "_"
|
||||
}
|
||||
resultName
|
||||
},
|
||||
".${filename.extension}"
|
||||
).apply {
|
||||
outputStream().use { fileStream ->
|
||||
capturedPart.provider().asStream().copyTo(fileStream)
|
||||
}
|
||||
}
|
||||
|
||||
list.add(
|
||||
name to BinaryContent(
|
||||
filename,
|
||||
mimeType
|
||||
) { resultInput.inputStream().asInput() }.either()
|
||||
)
|
||||
}
|
||||
else -> {}
|
||||
}
|
||||
|
||||
part = multipart.readPart()
|
||||
}
|
||||
|
||||
list.sortedBy { it.first }.map { it.second }
|
||||
} else {
|
||||
uniload(contentsEitherSerializer)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun Route.invoke() {
|
||||
authenticate {
|
||||
route(postsRootPath) {
|
||||
configureReadStandardCrudRepoRoutes(
|
||||
readPostsService,
|
||||
RegisteredPost.serializer(),
|
||||
RegisteredPost.serializer().nullable,
|
||||
PostId.serializer(),
|
||||
unifiedRouter
|
||||
)
|
||||
|
||||
writePostsService ?.let {
|
||||
|
||||
unifiedRouter.apply {
|
||||
|
||||
post(createRouting) {
|
||||
val data = receiveContents()
|
||||
|
||||
unianswer(
|
||||
RegisteredPost.serializer().nullable,
|
||||
writePostsService.create(FullNewPost(data))
|
||||
)
|
||||
}
|
||||
|
||||
post(updateRouting) {
|
||||
val postId = call.decodeUrlQueryValueOrSendError(postsPostIdParameter, PostId.serializer()) ?: return@post
|
||||
val data = receiveContentsEithers()
|
||||
|
||||
unianswer(
|
||||
RegisteredPost.serializer().nullable,
|
||||
writePostsService.update(
|
||||
postId,
|
||||
data
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
post(removeRoute) {
|
||||
val postId = uniload(PostId.serializer())
|
||||
|
||||
unianswer(
|
||||
Unit.serializer(),
|
||||
writePostsService.remove(postId)
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user