Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -73,8 +73,11 @@ dependencies {

// Tests
testImplementation(libs.ktor.server.tests)
testImplementation(libs.kotlin.test.junit)
testImplementation(libs.kotlin.test)
testImplementation(libs.ktor.client.mock)
testImplementation(libs.mockk)
testImplementation(libs.kotlin.coroutines.test)
testImplementation(libs.junit.jupiter)
}

val shadowJarTask = tasks.named("shadowJar")
Expand Down
8 changes: 7 additions & 1 deletion gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ bcrypt = "0.4"
slf4j = "2.0.17"
sonarqube = "6.0.1.5171"
jacoco = "0.8.12"
mockk = "1.14.2"
kotlin-coroutines-test = "1.10.1"
junit-jupiter = "5.11.4"

[libraries]
# Ktor Server dependencies
Expand Down Expand Up @@ -44,7 +47,10 @@ micrometer-registry-prometheus = { module = "io.micrometer:micrometer-registry-p

# Test dependencies
ktor-server-tests = { module = "io.ktor:ktor-server-tests-jvm", version.ref = "ktor-server-test" }
kotlin-test-junit = { module = "org.jetbrains.kotlin:kotlin-test-junit", version.ref = "kotlin" }
kotlin-test = { module = "org.jetbrains.kotlin:kotlin-test", version.ref = "kotlin" }
mockk = { module = "io.mockk:mockk", version.ref = "mockk" }
kotlin-coroutines-test = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-test", version.ref = "kotlin-coroutines-test" }
junit-jupiter = { module = "org.junit.jupiter:junit-jupiter", version.ref = "junit-jupiter" }

# Logs
logback-classic = { module = "ch.qos.logback:logback-classic", version.ref = "logback" }
Expand Down
12 changes: 9 additions & 3 deletions src/main/kotlin/es/wokis/data/bo/sound/SoundBO.kt
Original file line number Diff line number Diff line change
@@ -1,19 +1,25 @@
package es.wokis.data.bo.sound

import es.wokis.data.bo.user.UserBO

data class SoundBO(
val id: Long? = null,
val displayId: String,
val title: String,
val description: String = "",
val soundUrl: String,
val createdBy: String,
val thumbsUp: List<UserBO>,
val thumbsDown: List<UserBO>,
val thumbsUp: List<SoundUserBO> = emptyList(),
val thumbsDown: List<SoundUserBO> = emptyList(),
val createdOn: Long,
val status: String = "pending",
val reactions: List<ReactionBO> = emptyList()
)

data class SoundUserBO(
val id: String,
val displayName: String
)

data class ReactionBO(
val unicode: String,
val addedBy: String
Expand Down
2 changes: 2 additions & 0 deletions src/main/kotlin/es/wokis/data/database/AppDataBase.kt
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import com.mongodb.MongoClientSettings
import com.mongodb.MongoCredential
import com.mongodb.kotlin.client.coroutine.MongoClient
import com.mongodb.kotlin.client.coroutine.MongoDatabase
import es.wokis.data.dbo.SoundDBO
import es.wokis.data.dbo.radio.RadioCollectionDBO
import es.wokis.data.dbo.radio.RadioDBO
import es.wokis.data.dbo.recover.RecoverDBO
Expand Down Expand Up @@ -35,6 +36,7 @@ class AppDataBase {
val recoverCollection by lazy { database.getCollection<RecoverDBO>("recover") }
val statsCollection by lazy { database.getCollection<FullStatDBO>("stats") }
val radioCollection by lazy { database.getCollection<RadioCollectionDBO>("radios") }
val soundsCollection by lazy { database.getCollection<SoundDBO>("sounds") }

companion object {
private const val MONGODB_PREFIX = "mongodb://"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
package es.wokis.data.datasource.local.sound

import com.mongodb.client.model.Filters
import com.mongodb.client.model.Sorts
import com.mongodb.kotlin.client.coroutine.MongoCollection
import es.wokis.data.bo.sound.SoundBO
import es.wokis.data.dbo.SoundDBO
import es.wokis.data.mapper.sound.toBO
import es.wokis.data.mapper.sound.toDBO
import kotlinx.coroutines.flow.firstOrNull
import kotlinx.coroutines.flow.toList
import org.slf4j.LoggerFactory

interface SoundsLocalDataSource {
suspend fun getAllSounds(page: Int, limit: Int, status: String? = null): List<SoundBO>
suspend fun getSoundsCount(status: String? = null): Long
suspend fun getSoundByDisplayId(displayId: String): SoundBO?
suspend fun getSoundsByCreatedBy(userId: String, page: Int, limit: Int): List<SoundBO>
suspend fun getSoundsByCreatedByCount(userId: String): Long
suspend fun createSound(sound: SoundBO): Boolean
suspend fun updateSound(sound: SoundBO): Boolean
suspend fun deleteSound(displayId: String): Boolean
}

class SoundsLocalDataSourceImpl(
private val soundsCollection: MongoCollection<SoundDBO>
) : SoundsLocalDataSource {
private val logger = LoggerFactory.getLogger(SoundsLocalDataSourceImpl::class.java)

override suspend fun getAllSounds(page: Int, limit: Int, status: String?): List<SoundBO> {
val skip = (page - 1) * limit
val filter = status?.let { Filters.eq(SoundDBO::status.name, it) } ?: Filters.empty()
return soundsCollection.find(filter)
.sort(Sorts.descending(SoundDBO::createdOn.name))
.skip(skip)
.limit(limit)
.toList()
.map { it.toBO() }
}

override suspend fun getSoundsCount(status: String?): Long {
val filter = status?.let { Filters.eq(SoundDBO::status.name, it) } ?: Filters.empty()
return soundsCollection.countDocuments(filter)
}

override suspend fun getSoundByDisplayId(displayId: String): SoundBO? {
val filter = Filters.eq(SoundDBO::displayId.name, displayId)
return soundsCollection.find(filter).firstOrNull()?.toBO()
}

override suspend fun getSoundsByCreatedBy(userId: String, page: Int, limit: Int): List<SoundBO> {
val skip = (page - 1) * limit
val filter = Filters.eq(SoundDBO::createdBy.name, userId)
return soundsCollection.find(filter)
.sort(Sorts.descending(SoundDBO::createdOn.name))
.skip(skip)
.limit(limit)
.toList()
.map { it.toBO() }
}

override suspend fun getSoundsByCreatedByCount(userId: String): Long {
val filter = Filters.eq(SoundDBO::createdBy.name, userId)
return soundsCollection.countDocuments(filter)
}

override suspend fun createSound(sound: SoundBO): Boolean = try {
soundsCollection.insertOne(sound.toDBO()).wasAcknowledged()
} catch (e: Throwable) {
logger.error("Failed to create sound", e)
false
}

override suspend fun updateSound(sound: SoundBO): Boolean {
val filter = Filters.eq(SoundDBO::displayId.name, sound.displayId)
return soundsCollection.replaceOne(filter, sound.toDBO()).wasAcknowledged()
}

override suspend fun deleteSound(displayId: String): Boolean = try {
soundsCollection.deleteOne(Filters.eq(SoundDBO::displayId.name, displayId)).wasAcknowledged()
} catch (e: Throwable) {
logger.error("Failed to delete sound", e)
false
}
}
12 changes: 9 additions & 3 deletions src/main/kotlin/es/wokis/data/dbo/SoundDBO.kt
Original file line number Diff line number Diff line change
@@ -1,21 +1,27 @@
package es.wokis.data.dbo

import es.wokis.data.dbo.user.UserDBO
import org.bson.codecs.pojo.annotations.BsonId

data class SoundDBO(
@BsonId
val id: Long? = null,
val displayId: String,
val title: String,
val description: String = "",
val soundUrl: String,
val createdBy: String,
val thumbsUp: List<UserDBO>,
val thumbsDown: List<UserDBO>,
val thumbsUp: List<SoundUserDBO> = emptyList(),
val thumbsDown: List<SoundUserDBO> = emptyList(),
val createdOn: Long,
val status: String = "pending",
val reactions: List<ReactionDBO> = emptyList()
)

data class SoundUserDBO(
val id: String,
val displayName: String
)

data class ReactionDBO(
val unicode: String,
val addedBy: String
Expand Down
35 changes: 31 additions & 4 deletions src/main/kotlin/es/wokis/data/dto/sound/SoundDTO.kt
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package es.wokis.data.dto.sound

import es.wokis.data.dto.user.UserDTO
import es.wokis.utils.HashGenerator.generateHashWithSeed
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
Expand All @@ -13,18 +12,30 @@ data class SoundDTO(
val displayId: String = generateHashWithSeed(),
@SerialName("title")
val title: String,
@SerialName("description")
val description: String = "",
@SerialName("sound")
val soundUrl: String,
@SerialName("createdBy")
val createdBy: String,
@SerialName("thumbsUp")
val thumbsUp: List<UserDTO>,
val thumbsUp: List<SoundUserDTO> = emptyList(),
@SerialName("thumbsDown")
val thumbsDown: List<UserDTO>,
val thumbsDown: List<SoundUserDTO> = emptyList(),
@SerialName("createdOn")
val createdOn: Long,
@SerialName("status")
val status: String = "pending",
@SerialName("reactions")
val reactions: List<ReactionDTO>
val reactions: List<ReactionDTO> = emptyList()
)

@Serializable
data class SoundUserDTO(
@SerialName("id")
val id: String,
@SerialName("displayName")
val displayName: String
)

@Serializable
Expand All @@ -39,6 +50,22 @@ data class ReactionDTO(
data class SoundRequestDTO(
@SerialName("title")
Comment thread
Wikijito7 marked this conversation as resolved.
val title: String,
@SerialName("description")
val description: String = "",
@SerialName("sound")
val sound: String
)

@Serializable
data class VoteRequestDTO(
@SerialName("vote")
val vote: String
)

@Serializable
data class UpdateSoundRequestDTO(
@SerialName("title")
val title: String? = null,
@SerialName("description")
val description: String? = null
)
4 changes: 3 additions & 1 deletion src/main/kotlin/es/wokis/data/exception/CustomExceptions.kt
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,6 @@ object TotpNotFoundException : IllegalStateException()

object RecoverCodeNotFoundException : IllegalStateException()

object UserNotFoundException : IllegalStateException()
object UserNotFoundException : IllegalStateException()

object SoundNotFoundException : IllegalStateException()
Loading
Loading