From b9825bb5caab5697439247bc0774d67467aa66ea Mon Sep 17 00:00:00 2001 From: luevard <99143550+saucepommefrite@users.noreply.github.com> Date: Tue, 14 May 2024 16:15:38 +0200 Subject: [PATCH 1/4] :sparkles: [no_ci] Add friend interface --- .../kotlin/allin/data/FriendDataSource.kt | 9 +++++++ .../data/postgres/PostgresFriendDataSource.kt | 27 +++++++++++++++++++ 2 files changed, 36 insertions(+) create mode 100644 Sources/src/main/kotlin/allin/data/FriendDataSource.kt create mode 100644 Sources/src/main/kotlin/allin/data/postgres/PostgresFriendDataSource.kt diff --git a/Sources/src/main/kotlin/allin/data/FriendDataSource.kt b/Sources/src/main/kotlin/allin/data/FriendDataSource.kt new file mode 100644 index 0000000..5a57e22 --- /dev/null +++ b/Sources/src/main/kotlin/allin/data/FriendDataSource.kt @@ -0,0 +1,9 @@ +package allin.data + +interface FriendDataSource { + fun addFriend(sender: String, receiver: String) + fun getFriendFromUserId(id: String) + fun getFriendFromUsername(username: String) + fun deleteFriend(senderId: String, receiverId: String) + fun isFriend(firstUser: String, secondUser: String) +} \ No newline at end of file diff --git a/Sources/src/main/kotlin/allin/data/postgres/PostgresFriendDataSource.kt b/Sources/src/main/kotlin/allin/data/postgres/PostgresFriendDataSource.kt new file mode 100644 index 0000000..050a3a9 --- /dev/null +++ b/Sources/src/main/kotlin/allin/data/postgres/PostgresFriendDataSource.kt @@ -0,0 +1,27 @@ +package allin.data.postgres + +import allin.data.FriendDataSource +import org.ktorm.database.Database + +class PostgresFriendDataSource(private val database: Database) : FriendDataSource { + override fun addFriend(sender: String, receiver: String) { +// TODO("Not yet implemented") + } + + override fun getFriendFromUserId(id: String) { + TODO("Not yet implemented") + } + + override fun getFriendFromUsername(username: String) { + TODO("Not yet implemented") + } + + override fun deleteFriend(senderId: String, receiverId: String) { + TODO("Not yet implemented") + } + + override fun isFriend(firstUser: String, secondUser: String) { + TODO("Not yet implemented") + } + +} \ No newline at end of file From 7c49c34167d86c512994dee63e90f3472cae1715 Mon Sep 17 00:00:00 2001 From: luevard Date: Tue, 14 May 2024 17:07:51 +0200 Subject: [PATCH 2/4] :sparkles: [no_ci] Add Friend methods and entity --- .../main/kotlin/allin/data/AllInDataSource.kt | 1 + .../kotlin/allin/data/FriendDataSource.kt | 4 ++- .../kotlin/allin/data/mock/MockDataSource.kt | 6 ++--- .../allin/data/mock/MockFriendDataSource.kt | 26 +++++++++++++++++++ .../allin/data/postgres/PostgresDataSource.kt | 16 +++++++++--- .../data/postgres/PostgresFriendDataSource.kt | 12 ++++++--- .../data/postgres/entities/FriendEntity.kt | 15 +++++++++++ 7 files changed, 68 insertions(+), 12 deletions(-) create mode 100644 Sources/src/main/kotlin/allin/data/mock/MockFriendDataSource.kt create mode 100644 Sources/src/main/kotlin/allin/data/postgres/entities/FriendEntity.kt diff --git a/Sources/src/main/kotlin/allin/data/AllInDataSource.kt b/Sources/src/main/kotlin/allin/data/AllInDataSource.kt index a0861bb..4cf498b 100644 --- a/Sources/src/main/kotlin/allin/data/AllInDataSource.kt +++ b/Sources/src/main/kotlin/allin/data/AllInDataSource.kt @@ -4,4 +4,5 @@ abstract class AllInDataSource { abstract val userDataSource: UserDataSource abstract val betDataSource: BetDataSource abstract val participationDataSource: ParticipationDataSource + abstract val friendDataSource: FriendDataSource } \ No newline at end of file diff --git a/Sources/src/main/kotlin/allin/data/FriendDataSource.kt b/Sources/src/main/kotlin/allin/data/FriendDataSource.kt index 5a57e22..05b0658 100644 --- a/Sources/src/main/kotlin/allin/data/FriendDataSource.kt +++ b/Sources/src/main/kotlin/allin/data/FriendDataSource.kt @@ -1,8 +1,10 @@ package allin.data +import allin.model.User + interface FriendDataSource { fun addFriend(sender: String, receiver: String) - fun getFriendFromUserId(id: String) + fun getFriendFromUserId(id: String): List fun getFriendFromUsername(username: String) fun deleteFriend(senderId: String, receiverId: String) fun isFriend(firstUser: String, secondUser: String) diff --git a/Sources/src/main/kotlin/allin/data/mock/MockDataSource.kt b/Sources/src/main/kotlin/allin/data/mock/MockDataSource.kt index 6df3197..36517cc 100644 --- a/Sources/src/main/kotlin/allin/data/mock/MockDataSource.kt +++ b/Sources/src/main/kotlin/allin/data/mock/MockDataSource.kt @@ -1,9 +1,6 @@ package allin.data.mock -import allin.data.AllInDataSource -import allin.data.BetDataSource -import allin.data.ParticipationDataSource -import allin.data.UserDataSource +import allin.data.* import allin.model.Bet import allin.model.BetResult import allin.model.Participation @@ -30,4 +27,5 @@ class MockDataSource : AllInDataSource() { override val userDataSource: UserDataSource by lazy { MockUserDataSource(mockData) } override val betDataSource: BetDataSource by lazy { MockBetDataSource(mockData) } override val participationDataSource: ParticipationDataSource by lazy { MockParticipationDataSource(mockData) } + override val friendDataSource: FriendDataSource by lazy { MockFriendDataSource(mockData) } } diff --git a/Sources/src/main/kotlin/allin/data/mock/MockFriendDataSource.kt b/Sources/src/main/kotlin/allin/data/mock/MockFriendDataSource.kt new file mode 100644 index 0000000..ce77707 --- /dev/null +++ b/Sources/src/main/kotlin/allin/data/mock/MockFriendDataSource.kt @@ -0,0 +1,26 @@ +package allin.data.mock + +import allin.data.FriendDataSource +import allin.model.User + +class MockFriendDataSource(mockData: MockDataSource.MockData) : FriendDataSource { + override fun addFriend(sender: String, receiver: String) { + TODO("Not yet implemented") + } + + override fun getFriendFromUserId(id: String): List { + TODO("Not yet implemented") + } + + override fun getFriendFromUsername(username: String) { + TODO("Not yet implemented") + } + + override fun deleteFriend(senderId: String, receiverId: String) { + TODO("Not yet implemented") + } + + override fun isFriend(firstUser: String, secondUser: String) { + TODO("Not yet implemented") + } +} \ No newline at end of file diff --git a/Sources/src/main/kotlin/allin/data/postgres/PostgresDataSource.kt b/Sources/src/main/kotlin/allin/data/postgres/PostgresDataSource.kt index 335d111..26e15c8 100644 --- a/Sources/src/main/kotlin/allin/data/postgres/PostgresDataSource.kt +++ b/Sources/src/main/kotlin/allin/data/postgres/PostgresDataSource.kt @@ -1,9 +1,6 @@ package allin.data.postgres -import allin.data.AllInDataSource -import allin.data.BetDataSource -import allin.data.ParticipationDataSource -import allin.data.UserDataSource +import allin.data.* import allin.ext.execute import org.ktorm.database.Database @@ -95,9 +92,20 @@ class PostgresDataSource : AllInDataSource() { ) """.trimIndent() ) + + database.execute( + """ + CREATE TABLE IF NOT EXISTS friend( + sender VARCHAR(255), + receiver VARCHAR(255), + CONSTRAINT pk_friend PRIMARY KEY (sender,receiver) + ) + """.trimIndent() + ) } override val userDataSource: UserDataSource by lazy { PostgresUserDataSource(database) } override val betDataSource: BetDataSource by lazy { PostgresBetDataSource(database) } override val participationDataSource: ParticipationDataSource by lazy { PostgresParticipationDataSource(database) } + override val friendDataSource: FriendDataSource by lazy { PostgresFriendDataSource(database) } } \ No newline at end of file diff --git a/Sources/src/main/kotlin/allin/data/postgres/PostgresFriendDataSource.kt b/Sources/src/main/kotlin/allin/data/postgres/PostgresFriendDataSource.kt index 050a3a9..9354419 100644 --- a/Sources/src/main/kotlin/allin/data/postgres/PostgresFriendDataSource.kt +++ b/Sources/src/main/kotlin/allin/data/postgres/PostgresFriendDataSource.kt @@ -1,15 +1,21 @@ package allin.data.postgres import allin.data.FriendDataSource +import allin.data.postgres.entities.FriendsEntity +import allin.model.User import org.ktorm.database.Database +import org.ktorm.dsl.insert class PostgresFriendDataSource(private val database: Database) : FriendDataSource { override fun addFriend(sender: String, receiver: String) { -// TODO("Not yet implemented") + database.insert(FriendsEntity) { + set(it.sender, sender) + set(it.receiver, receiver) + } } - override fun getFriendFromUserId(id: String) { - TODO("Not yet implemented") + override fun getFriendFromUserId(id: String): List { + TODO() } override fun getFriendFromUsername(username: String) { diff --git a/Sources/src/main/kotlin/allin/data/postgres/entities/FriendEntity.kt b/Sources/src/main/kotlin/allin/data/postgres/entities/FriendEntity.kt new file mode 100644 index 0000000..a436c71 --- /dev/null +++ b/Sources/src/main/kotlin/allin/data/postgres/entities/FriendEntity.kt @@ -0,0 +1,15 @@ +package allin.data.postgres.entities + +import org.ktorm.entity.Entity +import org.ktorm.schema.Table +import org.ktorm.schema.varchar + +interface FriendEntity : Entity { + val sender: String + val receiver: String +} + +object FriendsEntity : Table("friend") { + val sender = varchar("id").primaryKey().bindTo { it.sender } + val receiver = varchar("bet").primaryKey().bindTo { it.receiver } +} \ No newline at end of file From d4da0fd3f671dc955bfacf78f854e242b48f88ec Mon Sep 17 00:00:00 2001 From: luevard <99143550+saucepommefrite@users.noreply.github.com> Date: Wed, 15 May 2024 12:42:38 +0200 Subject: [PATCH 3/4] :sparkles: [no_ci] Add friend routes --- Sources/src/main/kotlin/allin/Application.kt | 3 +- .../kotlin/allin/data/FriendDataSource.kt | 9 +- .../allin/data/mock/MockFriendDataSource.kt | 10 +- .../data/postgres/PostgresFriendDataSource.kt | 47 +++++--- .../data/postgres/entities/FriendEntity.kt | 24 +++- .../src/main/kotlin/allin/model/ApiMessage.kt | 3 + Sources/src/main/kotlin/allin/model/Friend.kt | 7 ++ .../main/kotlin/allin/routing/friendRouter.kt | 114 ++++++++++++++++++ 8 files changed, 179 insertions(+), 38 deletions(-) create mode 100644 Sources/src/main/kotlin/allin/model/Friend.kt create mode 100644 Sources/src/main/kotlin/allin/routing/friendRouter.kt diff --git a/Sources/src/main/kotlin/allin/Application.kt b/Sources/src/main/kotlin/allin/Application.kt index 209ec90..0bc84fa 100644 --- a/Sources/src/main/kotlin/allin/Application.kt +++ b/Sources/src/main/kotlin/allin/Application.kt @@ -38,7 +38,7 @@ val Application.dataSource: AllInDataSource get() = allInDataSource fun main() { - embeddedServer(Netty, port = 8080, host = "0.0.0.0") { + embeddedServer(Netty, port = 10001, host = "0.0.0.0") { extracted() }.start(wait = true) } @@ -85,6 +85,7 @@ private fun Application.extracted() { betRouter() participationRouter() betDetailRouter() + friendRouter() kronJob(BET_VERIFY_DELAY) { dataSource.betDataSource.updateBetStatuses(ZonedDateTime.now()) diff --git a/Sources/src/main/kotlin/allin/data/FriendDataSource.kt b/Sources/src/main/kotlin/allin/data/FriendDataSource.kt index 05b0658..bb72df0 100644 --- a/Sources/src/main/kotlin/allin/data/FriendDataSource.kt +++ b/Sources/src/main/kotlin/allin/data/FriendDataSource.kt @@ -1,11 +1,8 @@ package allin.data -import allin.model.User - interface FriendDataSource { fun addFriend(sender: String, receiver: String) - fun getFriendFromUserId(id: String): List - fun getFriendFromUsername(username: String) - fun deleteFriend(senderId: String, receiverId: String) - fun isFriend(firstUser: String, secondUser: String) + fun getFriendFromUserId(id: String): List + fun deleteFriend(senderId: String, receiverId: String): Boolean + fun isFriend(firstUser: String, secondUser: String): Boolean } \ No newline at end of file diff --git a/Sources/src/main/kotlin/allin/data/mock/MockFriendDataSource.kt b/Sources/src/main/kotlin/allin/data/mock/MockFriendDataSource.kt index ce77707..585d394 100644 --- a/Sources/src/main/kotlin/allin/data/mock/MockFriendDataSource.kt +++ b/Sources/src/main/kotlin/allin/data/mock/MockFriendDataSource.kt @@ -1,26 +1,22 @@ package allin.data.mock import allin.data.FriendDataSource -import allin.model.User class MockFriendDataSource(mockData: MockDataSource.MockData) : FriendDataSource { override fun addFriend(sender: String, receiver: String) { TODO("Not yet implemented") } - override fun getFriendFromUserId(id: String): List { + override fun getFriendFromUserId(id: String): List { TODO("Not yet implemented") } - override fun getFriendFromUsername(username: String) { + override fun deleteFriend(senderId: String, receiverId: String): Boolean { TODO("Not yet implemented") } - override fun deleteFriend(senderId: String, receiverId: String) { + override fun isFriend(firstUser: String, secondUser: String): Boolean { TODO("Not yet implemented") } - override fun isFriend(firstUser: String, secondUser: String) { - TODO("Not yet implemented") - } } \ No newline at end of file diff --git a/Sources/src/main/kotlin/allin/data/postgres/PostgresFriendDataSource.kt b/Sources/src/main/kotlin/allin/data/postgres/PostgresFriendDataSource.kt index 9354419..cbfd179 100644 --- a/Sources/src/main/kotlin/allin/data/postgres/PostgresFriendDataSource.kt +++ b/Sources/src/main/kotlin/allin/data/postgres/PostgresFriendDataSource.kt @@ -1,33 +1,42 @@ package allin.data.postgres import allin.data.FriendDataSource -import allin.data.postgres.entities.FriendsEntity -import allin.model.User +import allin.data.postgres.entities.FriendEntity +import allin.data.postgres.entities.friends import org.ktorm.database.Database -import org.ktorm.dsl.insert +import org.ktorm.dsl.and +import org.ktorm.dsl.eq +import org.ktorm.entity.add +import org.ktorm.entity.filter +import org.ktorm.entity.map +import org.ktorm.entity.removeIf class PostgresFriendDataSource(private val database: Database) : FriendDataSource { override fun addFriend(sender: String, receiver: String) { - database.insert(FriendsEntity) { - set(it.sender, sender) - set(it.receiver, receiver) - } + database.friends.add( + FriendEntity { + this.sender = sender + this.receiver = receiver + } + ) } - override fun getFriendFromUserId(id: String): List { - TODO() + override fun getFriendFromUserId(id: String): List { + val friendList = database.friends.map { it.toFriend() } + val friendPairs = friendList.map { it.sender to it.receiver }.toSet() + return friendList + .filter { it.sender == id } + .map { it.receiver } } - override fun getFriendFromUsername(username: String) { - TODO("Not yet implemented") - } - - override fun deleteFriend(senderId: String, receiverId: String) { - TODO("Not yet implemented") - } - - override fun isFriend(firstUser: String, secondUser: String) { - TODO("Not yet implemented") + override fun deleteFriend(senderId: String, receiverId: String): Boolean { + database.friends.removeIf { it.sender eq senderId } + return database.friends.removeIf { it.sender eq senderId } > 0 } + override fun isFriend(firstUser: String, secondUser: String) = + database.friends + .filter { (it.sender eq firstUser) and (it.receiver eq secondUser) } + .map { it.toFriend() } + .isNotEmpty() } \ No newline at end of file diff --git a/Sources/src/main/kotlin/allin/data/postgres/entities/FriendEntity.kt b/Sources/src/main/kotlin/allin/data/postgres/entities/FriendEntity.kt index a436c71..5ef4920 100644 --- a/Sources/src/main/kotlin/allin/data/postgres/entities/FriendEntity.kt +++ b/Sources/src/main/kotlin/allin/data/postgres/entities/FriendEntity.kt @@ -1,15 +1,29 @@ package allin.data.postgres.entities +import allin.model.Friend +import org.ktorm.database.Database import org.ktorm.entity.Entity +import org.ktorm.entity.sequenceOf import org.ktorm.schema.Table import org.ktorm.schema.varchar interface FriendEntity : Entity { - val sender: String - val receiver: String + companion object : Entity.Factory() + + var sender: String + var receiver: String + + fun toFriend() = + Friend( + sender = sender, + receiver = receiver, + ) + } object FriendsEntity : Table("friend") { - val sender = varchar("id").primaryKey().bindTo { it.sender } - val receiver = varchar("bet").primaryKey().bindTo { it.receiver } -} \ No newline at end of file + val sender = varchar("sender").primaryKey().bindTo { it.sender } + val receiver = varchar("receiver").primaryKey().bindTo { it.receiver } +} + +val Database.friends get() = this.sequenceOf(FriendsEntity) diff --git a/Sources/src/main/kotlin/allin/model/ApiMessage.kt b/Sources/src/main/kotlin/allin/model/ApiMessage.kt index a09c1e1..2d1a045 100644 --- a/Sources/src/main/kotlin/allin/model/ApiMessage.kt +++ b/Sources/src/main/kotlin/allin/model/ApiMessage.kt @@ -13,4 +13,7 @@ object ApiMessage { const val NOT_ENOUGH_COINS = "Not enough coins." const val NO_GIFT = "Can't get daily gift." const val USER_CANT_BE_DELETE = "This user can't be delete now !" + const val FRIENDS_ALREADY_EXISTS = "User already exists in your Friends List." + const val FRIENDS_DOESNT_EXISTS = "User already exists in your Friends List." + } \ No newline at end of file diff --git a/Sources/src/main/kotlin/allin/model/Friend.kt b/Sources/src/main/kotlin/allin/model/Friend.kt new file mode 100644 index 0000000..a9efe26 --- /dev/null +++ b/Sources/src/main/kotlin/allin/model/Friend.kt @@ -0,0 +1,7 @@ +package allin.model + + +data class Friend( + val sender: String, + val receiver: String +) \ No newline at end of file diff --git a/Sources/src/main/kotlin/allin/routing/friendRouter.kt b/Sources/src/main/kotlin/allin/routing/friendRouter.kt new file mode 100644 index 0000000..c1ad79b --- /dev/null +++ b/Sources/src/main/kotlin/allin/routing/friendRouter.kt @@ -0,0 +1,114 @@ +package allin.routing + +import allin.dataSource +import allin.ext.hasToken +import allin.model.ApiMessage +import io.github.smiley4.ktorswaggerui.dsl.post +import io.ktor.http.* + +import io.ktor.server.application.* +import io.ktor.server.auth.* +import io.ktor.server.auth.jwt.* +import io.ktor.server.request.* +import io.ktor.server.response.* +import io.ktor.server.routing.* + +fun Application.friendRouter() { + + val userDataSource = this.dataSource.userDataSource + val friendDataSource = this.dataSource.friendDataSource + + + routing { + authenticate { + + post("/friend/add", { + description = "Allows a user to add a friend" + request { + headerParameter("JWT token of the logged user") + body { + description = "User to add in the friends list" + } + } + response { + HttpStatusCode.Created to { + description = "the friend has been added" + body() { + description = "Friend with assigned id" + } + } + HttpStatusCode.Conflict to { + description = "Friend already exist in the friends list" + body(ApiMessage.FRIENDS_ALREADY_EXISTS) + } + } + }) { + hasToken { principal -> + val requestMap = call.receive>() + val usernameFriend = requestMap["username"] ?: return@hasToken call.respond(HttpStatusCode.BadRequest, "Username is missing") + val username = tokenManagerBet.getUsernameFromToken(principal) + + val user = userDataSource.getUserByUsername(username).first + val userFriend = userDataSource.getUserByUsername(usernameFriend).first + + if (user == null || userFriend == null) { + call.respond(HttpStatusCode.Conflict, ApiMessage.USER_NOT_FOUND) + } else { + val friendlist = friendDataSource.getFriendFromUserId(user.id) + if (friendlist.contains(userFriend.id)) { + call.respond(HttpStatusCode.Conflict,ApiMessage.FRIENDS_ALREADY_EXISTS) + } else { + friendDataSource.addFriend(user.id, userFriend.id) + call.respond(HttpStatusCode.Created, usernameFriend) + } + } + } + + } + post("/friend/delete", { + description = "Allows a user to delete a friend" + request { + headerParameter("JWT token of the logged user") + body { + description = "User to delete in the friends list" + } + } + response { + HttpStatusCode.Created to { + description = "the friend has been delete" + body() { + description = "Friend with assigned id" + } + } + HttpStatusCode.Conflict to { + description = "Friend doesn't exist in the friends list" + body(ApiMessage.FRIENDS_DOESNT_EXISTS) + } + } + }) { + hasToken { principal -> + val requestMap = call.receive>() + val usernameFriend = requestMap["username"] ?: return@hasToken call.respond(HttpStatusCode.BadRequest, "Username is missing") + val username = tokenManagerBet.getUsernameFromToken(principal) + + val user = userDataSource.getUserByUsername(username).first + val userFriend = userDataSource.getUserByUsername(usernameFriend).first + + if (user == null || userFriend == null) { + call.respond(HttpStatusCode.Conflict, ApiMessage.USER_NOT_FOUND) + } else { + val friendlist = friendDataSource.getFriendFromUserId(user.id) + if (!friendlist.contains(userFriend.id)) { + call.respond(HttpStatusCode.Conflict,ApiMessage.FRIENDS_DOESNT_EXISTS) + } else { + friendDataSource.deleteFriend(user.id, userFriend.id) + call.respond(HttpStatusCode.Created, usernameFriend) + } + } + } + + } + + } + } +} \ No newline at end of file From cad34d0f2a9fc3abbfdf002c447755c1ad0ce81f Mon Sep 17 00:00:00 2001 From: luevard <99143550+saucepommefrite@users.noreply.github.com> Date: Thu, 16 May 2024 08:34:45 +0200 Subject: [PATCH 4/4] :sparkles: Patch mock DataSource --- Sources/src/main/kotlin/allin/data/mock/MockDataSource.kt | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/Sources/src/main/kotlin/allin/data/mock/MockDataSource.kt b/Sources/src/main/kotlin/allin/data/mock/MockDataSource.kt index 5b93834..8dbf3f1 100644 --- a/Sources/src/main/kotlin/allin/data/mock/MockDataSource.kt +++ b/Sources/src/main/kotlin/allin/data/mock/MockDataSource.kt @@ -1,9 +1,6 @@ package allin.data.mock -import allin.data.AllInDataSource -import allin.data.BetDataSource -import allin.data.ParticipationDataSource -import allin.data.UserDataSource +import allin.data.* import allin.model.* import java.time.ZonedDateTime @@ -29,4 +26,5 @@ class MockDataSource : AllInDataSource() { override val userDataSource: UserDataSource by lazy { MockUserDataSource(mockData) } override val betDataSource: BetDataSource by lazy { MockBetDataSource(mockData) } override val participationDataSource: ParticipationDataSource by lazy { MockParticipationDataSource(mockData) } + override val friendDataSource: FriendDataSource by lazy { MockFriendDataSource(mockData) } }