From e291e0064bc1c857716add40dced8fb070f91aba Mon Sep 17 00:00:00 2001 From: luevard <99143550+saucepommefrite@users.noreply.github.com> Date: Thu, 30 May 2024 12:39:18 +0200 Subject: [PATCH] :sparkles: [no_ci] Add routes for inject,get and remove image of a user. Update pom.xml dependencies. --- Sources/pom.xml | 16 +++-- Sources/src/main/kotlin/allin/Application.kt | 4 +- .../main/kotlin/allin/data/UserDataSource.kt | 3 + .../allin/data/mock/MockUserDataSource.kt | 15 ++++- .../data/postgres/PostgresUserDataSource.kt | 18 +++++- .../data/postgres/entities/UserImageEntity.kt | 29 +++++++++ Sources/src/main/kotlin/allin/dto/UserDTO.kt | 2 +- Sources/src/main/kotlin/allin/model/User.kt | 6 ++ .../main/kotlin/allin/routing/basicRouter.kt | 31 +--------- .../main/kotlin/allin/routing/userRouter.kt | 62 +++++++++++++++++++ .../src/test/kotlin/allin/ApplicationTest.kt | 1 + 11 files changed, 145 insertions(+), 42 deletions(-) create mode 100644 Sources/src/main/kotlin/allin/data/postgres/entities/UserImageEntity.kt diff --git a/Sources/pom.xml b/Sources/pom.xml index 9536a23..897fde2 100644 --- a/Sources/pom.xml +++ b/Sources/pom.xml @@ -10,7 +10,7 @@ 1.9.10 1.5.0 - 2.3.4 + 2.3.11 official 1.4.14 2.0.9 @@ -34,7 +34,7 @@ org.postgresql postgresql - 42.7.1 + 42.7.3 io.ktor @@ -44,7 +44,7 @@ io.github.smiley4 ktor-swagger-ui - 2.7.4 + 2.10.0 io.ktor @@ -142,12 +142,12 @@ io.ktor ktor-server-auth-jwt-jvm - 2.3.4 + 2.3.11 io.swagger.codegen.v3 swagger-codegen-generators - 1.0.38 + 1.0.50 @@ -155,6 +155,12 @@ hamcrest-core 1.3 + + org.junit.jupiter + junit-jupiter + RELEASE + test + ${project.basedir}/src/main/kotlin diff --git a/Sources/src/main/kotlin/allin/Application.kt b/Sources/src/main/kotlin/allin/Application.kt index 7b5a97d..cbc89f6 100644 --- a/Sources/src/main/kotlin/allin/Application.kt +++ b/Sources/src/main/kotlin/allin/Application.kt @@ -27,6 +27,8 @@ val BET_VERIFY_DELAY = 1.minutes val data_source = System.getenv()["DATA_SOURCE"] val isCodeFirstContainer = System.getenv()["CODEFIRST_CONTAINER"].orEmpty() +val hostIP = "0.0.0.0" +val hostPort = 8080 private val allInDataSource: AllInDataSource = when (data_source) { "mock" -> MockDataSource() @@ -38,7 +40,7 @@ val Application.dataSource: AllInDataSource get() = allInDataSource fun main() { - embeddedServer(Netty, port = 8080, host = "0.0.0.0") { + embeddedServer(Netty, port = hostPort, host = hostIP) { extracted() }.start(wait = true) } diff --git a/Sources/src/main/kotlin/allin/data/UserDataSource.kt b/Sources/src/main/kotlin/allin/data/UserDataSource.kt index ba4d54a..273de87 100644 --- a/Sources/src/main/kotlin/allin/data/UserDataSource.kt +++ b/Sources/src/main/kotlin/allin/data/UserDataSource.kt @@ -12,4 +12,7 @@ interface UserDataSource { fun userExists(username: String): Boolean fun emailExists(email: String): Boolean fun canHaveDailyGift(username: String): Boolean + fun addImage(userid: String, image: ByteArray) + fun removeImage(userid: String) + fun getImage(userid: String): ByteArray? } \ No newline at end of file diff --git a/Sources/src/main/kotlin/allin/data/mock/MockUserDataSource.kt b/Sources/src/main/kotlin/allin/data/mock/MockUserDataSource.kt index 454357f..03a63b2 100644 --- a/Sources/src/main/kotlin/allin/data/mock/MockUserDataSource.kt +++ b/Sources/src/main/kotlin/allin/data/mock/MockUserDataSource.kt @@ -3,8 +3,6 @@ package allin.data.mock import allin.data.UserDataSource import allin.dto.UserDTO import allin.model.User -import org.ktorm.dsl.eq -import org.ktorm.dsl.or import java.time.ZonedDateTime class MockUserDataSource(private val mockData: MockDataSource.MockData) : UserDataSource { @@ -57,4 +55,17 @@ class MockUserDataSource(private val mockData: MockDataSource.MockData) : UserDa lastGifts[username] = ZonedDateTime.now() return value } + + override fun addImage(userid: String, image: ByteArray) { + TODO("Not yet implemented") + } + + override fun removeImage(userid: String) { + TODO("Not yet implemented") + } + + override fun getImage(userid: String): ByteArray? { + TODO("Not yet implemented") + } + } \ No newline at end of file diff --git a/Sources/src/main/kotlin/allin/data/postgres/PostgresUserDataSource.kt b/Sources/src/main/kotlin/allin/data/postgres/PostgresUserDataSource.kt index 31a51f8..c9e858f 100644 --- a/Sources/src/main/kotlin/allin/data/postgres/PostgresUserDataSource.kt +++ b/Sources/src/main/kotlin/allin/data/postgres/PostgresUserDataSource.kt @@ -1,9 +1,7 @@ package allin.data.postgres import allin.data.UserDataSource -import allin.data.postgres.entities.UserEntity -import allin.data.postgres.entities.UsersEntity -import allin.data.postgres.entities.users +import allin.data.postgres.entities.* import allin.dto.UserDTO import allin.ext.executeWithResult import allin.model.User @@ -83,4 +81,18 @@ class PostgresUserDataSource(private val database: Database) : UserDataSource { return false } + override fun addImage(userid: String, image: ByteArray) { + database.usersimage.add(UserImageEntity { + id = userid + this.image = image + }) + } + + override fun removeImage(userid: String) { + database.usersimage.removeIf { it.id eq userid } + } + + override fun getImage(userid: String): ByteArray? = + database.usersimage.find { it.id eq userid }?.image + } \ No newline at end of file diff --git a/Sources/src/main/kotlin/allin/data/postgres/entities/UserImageEntity.kt b/Sources/src/main/kotlin/allin/data/postgres/entities/UserImageEntity.kt new file mode 100644 index 0000000..64a47eb --- /dev/null +++ b/Sources/src/main/kotlin/allin/data/postgres/entities/UserImageEntity.kt @@ -0,0 +1,29 @@ +package allin.data.postgres.entities + +import allin.model.UserImage +import org.ktorm.database.Database +import org.ktorm.entity.Entity +import org.ktorm.entity.sequenceOf +import org.ktorm.schema.Table +import org.ktorm.schema.bytes +import org.ktorm.schema.varchar + +interface UserImageEntity : Entity { + companion object : Entity.Factory() + + var id: String + var image: ByteArray + + fun toUserImage() = + UserImage( + id = id, + image = image, + ) +} + +object UsersImageEntity : Table("userimage") { + val id = varchar("user_id").primaryKey().bindTo { it.id } + val image = bytes("image").bindTo { it.image } +} + +val Database.usersimage get() = this.sequenceOf(UsersImageEntity) diff --git a/Sources/src/main/kotlin/allin/dto/UserDTO.kt b/Sources/src/main/kotlin/allin/dto/UserDTO.kt index c34686f..b4cc2bf 100644 --- a/Sources/src/main/kotlin/allin/dto/UserDTO.kt +++ b/Sources/src/main/kotlin/allin/dto/UserDTO.kt @@ -9,4 +9,4 @@ data class UserDTO( val email: String, val nbCoins: Int, var token: String? -) +) \ No newline at end of file diff --git a/Sources/src/main/kotlin/allin/model/User.kt b/Sources/src/main/kotlin/allin/model/User.kt index 423986e..534add7 100644 --- a/Sources/src/main/kotlin/allin/model/User.kt +++ b/Sources/src/main/kotlin/allin/model/User.kt @@ -27,4 +27,10 @@ data class UserRequest( data class CheckUser( val login: String, val password: String +) + +@Serializable +data class UserImage( + val id: String, + val image: ByteArray, ) \ No newline at end of file diff --git a/Sources/src/main/kotlin/allin/routing/basicRouter.kt b/Sources/src/main/kotlin/allin/routing/basicRouter.kt index a9e61ef..92d4e2d 100644 --- a/Sources/src/main/kotlin/allin/routing/basicRouter.kt +++ b/Sources/src/main/kotlin/allin/routing/basicRouter.kt @@ -4,17 +4,11 @@ import allin.model.ApiMessage import io.github.smiley4.ktorswaggerui.dsl.get import io.ktor.http.* import io.ktor.server.application.* -import io.ktor.server.request.* import io.ktor.server.response.* import io.ktor.server.routing.* -import kotlinx.serialization.Serializable -import java.io.File -import java.util.* - -@Serializable -data class ImageResponse(val url: String) fun Application.basicRouter() { + routing { get("/", { description = "Hello World of Allin API" @@ -29,28 +23,5 @@ fun Application.basicRouter() { }) { call.respond(ApiMessage.WELCOME) } - post("/image") { - val base64Image = call.receiveText() - val imageBytes = Base64.getDecoder().decode(base64Image) - val fileName = "${UUID.randomUUID()}.png" - val file = File("uploads/$fileName") - - file.parentFile.mkdirs() - file.writeBytes(imageBytes) - - val imageUrl = "https://codefirst.iut.uca.fr/containers/AllDev-api/images/$fileName" - call.respond(HttpStatusCode.OK, ImageResponse(imageUrl)) - } - - get("/images/{fileName}") { - val fileName = call.parameters["fileName"] - val file = File("uploads/$fileName") - - if (file.exists()) { - call.respondFile(file) - } else { - call.respond(HttpStatusCode.NotFound, "File not found") - } - } } } \ No newline at end of file diff --git a/Sources/src/main/kotlin/allin/routing/userRouter.kt b/Sources/src/main/kotlin/allin/routing/userRouter.kt index ace7d8b..b81a378 100644 --- a/Sources/src/main/kotlin/allin/routing/userRouter.kt +++ b/Sources/src/main/kotlin/allin/routing/userRouter.kt @@ -4,6 +4,9 @@ import allin.dataSource import allin.dto.UserDTO import allin.ext.hasToken import allin.ext.verifyUserFromToken +import allin.hostIP +import allin.hostPort +import allin.isCodeFirstContainer import allin.model.* import allin.utils.AppConfig import io.github.smiley4.ktorswaggerui.dsl.get @@ -15,6 +18,7 @@ import io.ktor.server.auth.jwt.* import io.ktor.server.request.* import io.ktor.server.response.* import io.ktor.server.routing.* +import java.io.File import java.util.* val RegexCheckerUser = AppConfig.regexChecker @@ -107,6 +111,23 @@ fun Application.userRouter() { } } + get("/users/images/{fileName}") { + val fileName = call.parameters["fileName"] + val file = File("images/$fileName.png") + if (file.exists()) { + call.respondFile(file) + } else { + val imageBytes = userDataSource.getImage(fileName.toString()) + if (imageBytes != null) { + file.parentFile.mkdirs() + file.writeBytes(imageBytes) + call.respondFile(file) + } else { + call.respond(HttpStatusCode.NotFound, "File not found") + } + } + } + authenticate { post("/users/delete", { description = "Allow you to delete your account" @@ -198,6 +219,47 @@ fun Application.userRouter() { } } } + + post("/users/image", { + description = "Allow you to add a profil image" + + request { + headerParameter("JWT token of the logged user") + body { + description = "User information" + } + } + response { + HttpStatusCode.Accepted to { + description = "Image added" + } + HttpStatusCode.NotFound to { + description = "User not found" + body(ApiMessage.INCORRECT_LOGIN_PASSWORD) + } + } + + }) { + hasToken { principal -> + verifyUserFromToken(userDataSource, principal) { user , _ -> + + val base64Image = call.receiveText() + val imageBytes = Base64.getDecoder().decode(base64Image) + + val urlfile = "images/${user.id}" + val file = File("${urlfile}.png") + file.parentFile.mkdirs() + file.writeBytes(imageBytes) + userDataSource.removeImage(user.id) + userDataSource.addImage(user.id,imageBytes) + if(isCodeFirstContainer.isEmpty()){ + call.respond(HttpStatusCode.OK, "http://${hostIP}:${hostPort}/users/${urlfile}") + } + else call.respond(HttpStatusCode.OK, "${isCodeFirstContainer}/${urlfile}") + } + } + } + } } } diff --git a/Sources/src/test/kotlin/allin/ApplicationTest.kt b/Sources/src/test/kotlin/allin/ApplicationTest.kt index 055425d..9dd77ad 100644 --- a/Sources/src/test/kotlin/allin/ApplicationTest.kt +++ b/Sources/src/test/kotlin/allin/ApplicationTest.kt @@ -1,4 +1,5 @@ package allin class ApplicationTest { + }