From 9ff2e8d8962917869b64f926a1b0662fe00582b5 Mon Sep 17 00:00:00 2001 From: luevard <99143550+saucepommefrite@users.noreply.github.com> Date: Tue, 21 May 2024 14:25:55 +0200 Subject: [PATCH] :sparkles: Add route and column for get the most popular bet --- .../main/kotlin/allin/data/BetDataSource.kt | 1 + .../allin/data/mock/MockBetDataSource.kt | 4 +++ .../data/postgres/PostgresBetDataSource.kt | 9 ++++++ .../allin/data/postgres/PostgresDataSource.kt | 32 ++++++++++++++++++- .../allin/data/postgres/entities/BetEntity.kt | 4 +++ .../main/kotlin/allin/routing/betRouter.kt | 29 ++++++++++++++++- 6 files changed, 77 insertions(+), 2 deletions(-) diff --git a/Sources/src/main/kotlin/allin/data/BetDataSource.kt b/Sources/src/main/kotlin/allin/data/BetDataSource.kt index 7aa2762..ad94ffb 100644 --- a/Sources/src/main/kotlin/allin/data/BetDataSource.kt +++ b/Sources/src/main/kotlin/allin/data/BetDataSource.kt @@ -20,4 +20,5 @@ interface BetDataSource { fun getWonNotifications(username: String): List fun getHistory(username: String): List fun getCurrent(username: String): List + fun getMostPopularBet(): Bet? } \ No newline at end of file diff --git a/Sources/src/main/kotlin/allin/data/mock/MockBetDataSource.kt b/Sources/src/main/kotlin/allin/data/mock/MockBetDataSource.kt index 20a20ec..53278d5 100644 --- a/Sources/src/main/kotlin/allin/data/mock/MockBetDataSource.kt +++ b/Sources/src/main/kotlin/allin/data/mock/MockBetDataSource.kt @@ -164,4 +164,8 @@ class MockBetDataSource(private val mockData: MockDataSource.MockData) : BetData userParticipation = participation ) } + + override fun getMostPopularBet(): Bet? { + TODO("Not yet implemented") + } } diff --git a/Sources/src/main/kotlin/allin/data/postgres/PostgresBetDataSource.kt b/Sources/src/main/kotlin/allin/data/postgres/PostgresBetDataSource.kt index f650a69..75a5f43 100644 --- a/Sources/src/main/kotlin/allin/data/postgres/PostgresBetDataSource.kt +++ b/Sources/src/main/kotlin/allin/data/postgres/PostgresBetDataSource.kt @@ -110,6 +110,14 @@ class PostgresBetDataSource(private val database: Database) : BetDataSource { } } + override fun getMostPopularBet(): Bet? { + val max=database.bets.filter { (it.isPrivate eq false) and (it.status eq BetStatus.WAITING) }.maxBy { it.popularityscore } + if(max!=null){ + return database.bets.filter { (it.popularityscore eq max) and (it.isPrivate eq false) and (it.status eq BetStatus.WAITING) }.map { it.toBet(database) }.first() + } + return null + } + override fun addBet(bet: Bet) { database.bets.add( BetEntity { @@ -172,4 +180,5 @@ class PostgresBetDataSource(private val database: Database) : BetDataSource { } } } + } \ 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 3e08eff..921d658 100644 --- a/Sources/src/main/kotlin/allin/data/postgres/PostgresDataSource.kt +++ b/Sources/src/main/kotlin/allin/data/postgres/PostgresDataSource.kt @@ -48,7 +48,8 @@ class PostgresDataSource : AllInDataSource() { isprivate boolean, createdby varchar(250), status varchar(20), - type varchar(20) + type varchar(20), + popularityscore numeric ) """.trimIndent() ) @@ -124,6 +125,35 @@ class PostgresDataSource : AllInDataSource() { ) """.trimIndent() ) + + database.execute(""" + CREATE OR REPLACE FUNCTION update_popularity_score() + RETURNS TRIGGER AS ${'$'}${'$'} + DECLARE + participant_count INT; + total_stakes INT; + BEGIN + -- Calculate participant count and total stakes for the bet + SELECT COUNT(*), COALESCE(SUM(stake), 0) INTO participant_count, total_stakes + FROM participation + WHERE bet = NEW.bet; + + -- Update the popularityscore in the bet table + UPDATE bet + SET popularityscore = (participant_count * participant_count + total_stakes) + WHERE id = NEW.bet; + + RETURN NEW; + END; + ${'$'}${'$'} LANGUAGE plpgsql; + + DROP TRIGGER IF EXISTS update_popularity_score ON participation; + + CREATE TRIGGER update_popularity_score + AFTER INSERT OR UPDATE ON participation + FOR EACH ROW + EXECUTE FUNCTION update_popularity_score(); + """.trimIndent()) } override val userDataSource: UserDataSource by lazy { PostgresUserDataSource(database) } diff --git a/Sources/src/main/kotlin/allin/data/postgres/entities/BetEntity.kt b/Sources/src/main/kotlin/allin/data/postgres/entities/BetEntity.kt index ad68238..8c0e964 100644 --- a/Sources/src/main/kotlin/allin/data/postgres/entities/BetEntity.kt +++ b/Sources/src/main/kotlin/allin/data/postgres/entities/BetEntity.kt @@ -5,6 +5,7 @@ import org.ktorm.database.Database import org.ktorm.dsl.eq import org.ktorm.entity.* import org.ktorm.schema.* +import org.postgresql.util.ByteConverter.numeric import java.time.Instant import java.time.ZoneId import java.time.ZonedDateTime @@ -23,6 +24,7 @@ interface BetEntity : Entity { var status: BetStatus var type: BetType var createdBy: String + var popularityscore: Int fun toBet(database: Database) = Bet( @@ -60,6 +62,7 @@ interface BetEntity : Entity { ) } + } object BetsEntity : Table("bet") { @@ -73,6 +76,7 @@ object BetsEntity : Table("bet") { val status = enum("status").bindTo { it.status } val type = enum("type").bindTo { it.type } val createdBy = varchar("createdby").bindTo { it.createdBy } + val popularityscore = int("popularityscore").bindTo { it.popularityscore } } val Database.bets get() = this.sequenceOf(BetsEntity) \ No newline at end of file diff --git a/Sources/src/main/kotlin/allin/routing/betRouter.kt b/Sources/src/main/kotlin/allin/routing/betRouter.kt index 2cc737f..f97727e 100644 --- a/Sources/src/main/kotlin/allin/routing/betRouter.kt +++ b/Sources/src/main/kotlin/allin/routing/betRouter.kt @@ -53,7 +53,7 @@ fun Application.betRouter() { betDataSource.getBetById(id)?.let { call.respond(HttpStatusCode.Conflict, ApiMessage.BET_ALREADY_EXIST) } ?: run { - val betWithId = bet.copy(id = id, createdBy = user.first?.username.toString()) + val betWithId = bet.copy(id = id, createdBy = user.first?.id.toString()) betDataSource.addBet(betWithId) call.respond(HttpStatusCode.Created, betWithId) } @@ -83,6 +83,33 @@ fun Application.betRouter() { } } + authenticate { + get("/bets/popular", { + description = "Allows you to recover the most popular public bets" + request { + headerParameter("JWT token of the logged user") + } + response { + HttpStatusCode.Accepted to { + description = "The most popular public bet is available" + body { + description = "The most popular public bet" + } + } + } + }) { + hasToken { principal -> + verifyUserFromToken(userDataSource, principal) { _, _ -> + val bet = betDataSource.getMostPopularBet() + if (bet != null) { + call.respond(HttpStatusCode.Accepted, bet) + } + call.respond(HttpStatusCode.NotFound,"Aucun bet n'a pu être récupérer") + } + } + } + } + get("/bets/get/{id}", { description = "Retrieves a specific bet" request {