Skip to content
Merged
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
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -33,4 +33,5 @@ out/
/.nb-gradle/

### VS Code ###
.vscode/
.vscode/
/config/
14 changes: 14 additions & 0 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ val kotlin_version: String by project
val logback_version: String by project
val kmongo_version: String by project
val koin_version: String by project
val firebase_version: String by project

plugins {
application
Expand Down Expand Up @@ -47,6 +48,19 @@ dependencies {
// Koin
implementation("io.insert-koin:koin-ktor:$koin_version")
implementation("io.insert-koin:koin-logger-slf4j:$koin_version")

// Firebase
implementation("com.google.firebase:firebase-admin:$firebase_version")

// BCrypt
implementation("org.mindrot:jbcrypt:0.4")

// Google auth
implementation("com.google.api-client:google-api-client:2.1.1")

// JavaMail
implementation("javax.mail:javax.mail-api:1.6.2")
implementation("com.sun.mail:javax.mail:1.6.2")
}

ktor {
Expand Down
3 changes: 2 additions & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
ktor_version=2.1.3
ktor_version=2.2.1
kotlin_version=1.7.21
logback_version=1.4.4
kmongo_version=4.7.2
koin_version=3.2.2
firebase_version=9.1.1
kotlin.code.style=official
16 changes: 13 additions & 3 deletions src/main/kotlin/es/wokis/Application.kt
Original file line number Diff line number Diff line change
@@ -1,16 +1,26 @@
package es.wokis

import com.typesafe.config.ConfigFactory
import es.wokis.plugins.*
import io.ktor.server.application.*
import io.ktor.server.config.*
import io.ktor.server.engine.*
import io.ktor.server.netty.*
import es.wokis.plugins.*

fun main() {
embeddedServer(Netty, port = 8080, host = "0.0.0.0", module = Application::module)
.start(wait = true)
embeddedServer(Netty, environment = applicationEngineEnvironment {
config = HoconApplicationConfig(ConfigFactory.load("application.conf"))

connector {
host = config.host
port = config.port
}
}).start(wait = true)
}

fun Application.module() {
initConfig()
configureFirebase()
configureKoin()
configureSerialization()
configureMonitoring()
Expand Down
37 changes: 37 additions & 0 deletions src/main/kotlin/es/wokis/data/bo/invoice/InvoiceBO.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package es.wokis.data.bo.invoice

import es.wokis.data.constants.ServerConstants.EMPTY_TEXT
import java.util.*

data class InvoiceBO(
val id: String? = null,
val idApp: Long = 0L,
val title: String = EMPTY_TEXT,
val description: String = EMPTY_TEXT,
val quantity: Int = 0,
val date: Date = Date(),
val type: InvoiceType,
val userId: String,
val category: CategoryBO? = null,
val reactions: List<ReactionBO> = emptyList()
)

data class CategoryBO(
val id: Long,
val title: String,
val color: String,
)

data class ReactionBO(
val id: Long,
val unicode: String
)

enum class InvoiceType(val key: String) {
DEPOSIT("DEPOSIT"),
EXPENSE("EXPENSE");

companion object {
fun getFromKey(key: String) = values().find { it.key == key } ?: DEPOSIT
}
}
15 changes: 15 additions & 0 deletions src/main/kotlin/es/wokis/data/bo/user/UserBO.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package es.wokis.data.bo.user

import es.wokis.data.constants.ServerConstants.DEFAULT_LANG
import es.wokis.data.constants.ServerConstants.EMPTY_TEXT
import io.ktor.server.auth.*

data class UserBO(
val id: String? = null,
val username: String,
val email: String,
val password: String,
val image: String = EMPTY_TEXT,
val lang: String = DEFAULT_LANG,
val devices: List<String> = emptyList()
) : Principal
10 changes: 10 additions & 0 deletions src/main/kotlin/es/wokis/data/bo/verification/VerificationBO.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package es.wokis.data.bo.verification

import java.util.*

data class VerificationBO(
val id: Long? = null,
val email: String,
val verificationToken: String,
val timeStamp: Date = Date()
)
6 changes: 6 additions & 0 deletions src/main/kotlin/es/wokis/data/constants/ServerConstants.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package es.wokis.data.constants

object ServerConstants {
const val EMPTY_TEXT = ""
const val DEFAULT_LANG = "en"
}
30 changes: 30 additions & 0 deletions src/main/kotlin/es/wokis/data/database/AppDataBase.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package es.wokis.data.database

import com.mongodb.ConnectionString
import com.mongodb.MongoClientSettings
import com.mongodb.MongoCredential
import es.wokis.data.dbo.invoice.InvoiceDBO
import es.wokis.data.dbo.user.UserDBO
import es.wokis.plugins.config
import org.litote.kmongo.KMongo
import org.litote.kmongo.getCollection

class AppDataBase {
private val username = config.getString("db.user")
private val password = config.getString("db.password")
private val dataBaseUrl = "$MONGODB_PREFIX$username:$password@${config.getString("db.ip")}:${config.getString("db.port")}"
private val databaseName = config.getString("db.databaseName")
private val client = KMongo.createClient(
MongoClientSettings.builder()
.credential(MongoCredential.createCredential(username, databaseName, password.toCharArray()))
.applyConnectionString(ConnectionString(dataBaseUrl)).build()
)

val database by lazy { client.getDatabase(databaseName) }
val usersCollection by lazy { database.getCollection<UserDBO>("users") }
val invoicesCollection by lazy { database.getCollection<InvoiceDBO>("invoices") }

companion object {
private const val MONGODB_PREFIX = "mongodb://"
}
}
69 changes: 69 additions & 0 deletions src/main/kotlin/es/wokis/data/datasource/UserLocalDataSource.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
package es.wokis.data.datasource

import com.mongodb.client.MongoCollection
import es.wokis.data.bo.user.UserBO
import es.wokis.data.constants.ServerConstants.EMPTY_TEXT
import es.wokis.data.dbo.user.UserDBO
import es.wokis.data.mapper.user.toBO
import es.wokis.data.mapper.user.toDBO
import org.bson.types.ObjectId
import org.litote.kmongo.*
import org.litote.kmongo.id.toId
import java.util.regex.Pattern

interface UserLocalDataSource {
suspend fun getAllUsers(): List<UserBO>
suspend fun getUserById(id: String): UserBO?
suspend fun getUserByEmail(email: String): UserBO?
suspend fun getUserByUsername(username: String): UserBO?

suspend fun getUserByUsernameOrEmail(username: String, email: String = EMPTY_TEXT): UserBO?

suspend fun createUser(user: UserBO): Boolean
suspend fun updateUser(user: UserBO): Boolean
}

class UserLocalDataSourceImpl(private val userCollection: MongoCollection<UserDBO>) : UserLocalDataSource {

private val getCaseInsensitive: (element: String) -> Pattern = {
Pattern.compile(it, Pattern.CASE_INSENSITIVE)
}

override suspend fun getAllUsers(): List<UserBO> = userCollection.find().map {
it.toBO()
}.toList()

override suspend fun getUserById(id: String): UserBO? {
val bsonId: Id<UserDBO> = ObjectId(id).toId()
return userCollection.findOne(UserDBO::id eq bsonId)?.toBO()
}

override suspend fun getUserByEmail(email: String): UserBO? =
userCollection.findOne(UserDBO::email.regex(getCaseInsensitive(email)))?.toBO()

override suspend fun getUserByUsername(username: String): UserBO? =
userCollection.findOne(UserDBO::username.regex(getCaseInsensitive(username)))?.toBO()

override suspend fun getUserByUsernameOrEmail(username: String, email: String): UserBO? =
userCollection.findOne(
or(
UserDBO::username.regex(getCaseInsensitive(username)),
UserDBO::email.regex(getCaseInsensitive(email.takeIf { it.isNotBlank() } ?: username))
)
)?.toBO()

override suspend fun createUser(user: UserBO): Boolean {
return try {
userCollection.insertOne(user.toDBO()).wasAcknowledged()

} catch (e: Throwable) {
println(e.stackTraceToString())
false
}
}

override suspend fun updateUser(user: UserBO): Boolean {
val bsonId: Id<UserDBO> = ObjectId(user.id).toId()
return userCollection.updateOne(UserDBO::id eq bsonId, user.toDBO()).wasAcknowledged()
}
}
28 changes: 28 additions & 0 deletions src/main/kotlin/es/wokis/data/dbo/invoice/InvoiceDBO.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package es.wokis.data.dbo.invoice

import es.wokis.data.constants.ServerConstants
import org.litote.kmongo.Id

data class InvoiceDBO(
val id: Id<InvoiceDBO>? = null,
val idApp: Long = 0L,
val title: String = ServerConstants.EMPTY_TEXT,
val description: String = ServerConstants.EMPTY_TEXT,
val quantity: Int = 0,
val date: Long = 0L,
val type: String? = null,
val userId: String? = null,
val category: CategoryDBO? = null,
val reactions: List<ReactionDBO> = emptyList()
)

data class CategoryDBO(
val id: Long,
val title: String,
val color: String,
)

data class ReactionDBO(
val id: Long,
val unicode: String
)
16 changes: 16 additions & 0 deletions src/main/kotlin/es/wokis/data/dbo/user/UserDBO.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package es.wokis.data.dbo.user

import es.wokis.data.constants.ServerConstants
import org.bson.codecs.pojo.annotations.BsonId
import org.litote.kmongo.Id

data class UserDBO(
@BsonId
val id: Id<UserDBO>? = null,
val username: String,
val email: String,
val password: String,
val lang: String,
val image: String = ServerConstants.EMPTY_TEXT,
val devices: List<String> = emptyList()
)
43 changes: 43 additions & 0 deletions src/main/kotlin/es/wokis/data/dto/invoice/InvoiceDTO.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package es.wokis.data.dto.invoice

import com.google.gson.annotations.SerializedName
import es.wokis.data.constants.ServerConstants.EMPTY_TEXT

data class InvoiceDTO(
@SerializedName("server_id")
val id: String? = null,
@SerializedName("id")
val idApp: Long = 0L,
@SerializedName("title")
val title: String = EMPTY_TEXT,
@SerializedName("description")
val description: String = EMPTY_TEXT,
@SerializedName("quantity")
val quantity: Int = 0,
@SerializedName("date")
val date: Long = 0L,
@SerializedName("type")
val type: String? = null,
@SerializedName("userId")
val userId: String? = null,
@SerializedName("category")
val category: CategoryDTO? = null,
@SerializedName("reactions")
val reactions: List<ReactionDTO> = emptyList()
)

data class CategoryDTO(
@SerializedName("id")
val id: Long,
@SerializedName("title")
val title: String,
@SerializedName("color")
val color: String,
)

data class ReactionDTO(
@SerializedName("id")
val id: Long,
@SerializedName("unicode")
val unicode: String
)
12 changes: 12 additions & 0 deletions src/main/kotlin/es/wokis/data/dto/user/UserDTO.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package es.wokis.data.dto.user

import es.wokis.data.constants.ServerConstants

data class UserDTO(
val id: String,
val username: String,
val email: String,
val image: String = ServerConstants.EMPTY_TEXT,
val lang: String,
val devices: List<String> = emptyList()
)
17 changes: 17 additions & 0 deletions src/main/kotlin/es/wokis/data/dto/user/auth/Auth.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package es.wokis.data.dto.user.auth

import es.wokis.data.constants.ServerConstants.DEFAULT_LANG

data class LoginDTO(
val username: String,
val password: String,
val isGoogleAuth: Boolean = false
)

data class RegisterDTO(
val username: String,
val email: String,
val password: String,
val lang: String = DEFAULT_LANG,
val isGoogleAuth: Boolean = false
)
Loading