popularBet #13

Merged
lucas.evard merged 16 commits from popularBet into master 11 months ago

@ -58,6 +58,7 @@ private fun Application.extracted() {
}
}
}
install(ContentNegotiation) { json() }
install(SwaggerUI) {
swagger {

@ -17,4 +17,6 @@ interface BetDataSource {
fun getWonNotifications(username: String): List<BetResultDetail>
fun getHistory(username: String): List<BetResultDetail>
fun getCurrent(username: String): List<BetDetail>
fun getMostPopularBet(): Bet?
fun updatePopularityScore(betId: String)
}

@ -1,8 +1,15 @@
package allin.data.mock
import allin.data.BetDataSource
import allin.data.postgres.entities.BetsEntity
import allin.data.postgres.entities.bets
import allin.data.postgres.entities.participations
import allin.model.*
import allin.model.BetStatus.*
import org.ktorm.dsl.and
import org.ktorm.dsl.eq
import org.ktorm.dsl.update
import org.ktorm.entity.*
import java.time.ZonedDateTime
import kotlin.math.roundToInt
@ -199,4 +206,15 @@ class MockBetDataSource(private val mockData: MockDataSource.MockData) : BetData
userParticipation = participation
)
}
override fun getMostPopularBet() =
mockData.bets.filter { !it.isPrivate && it.status == WAITING }.maxBy { it.popularityscore }
override fun updatePopularityScore(betId: String) {
val bet = mockData.bets.firstOrNull { it.id == betId } ?: return
val participations = mockData.participations.filter { it.betId == betId }
val score = participations.size * participations.size + participations.sumOf { it.stake }
bet.popularityscore = score
}
}

@ -143,6 +143,24 @@ 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 updatePopularityScore(betId: String) {
database.bets.filter { it.id eq betId }.firstOrNull() ?: return
val participations = database.participations.filter { it.betId eq betId }
val score = (participations.count() * participations.count()) + participations.map { it.stake }.sum()
database.update(BetsEntity) {
set(it.popularityscore, score)
where { it.id eq betId }
}
}
override fun addBet(bet: Bet) {
database.bets.add(
BetEntity {
@ -205,4 +223,5 @@ class PostgresBetDataSource(private val database: Database) : BetDataSource {
}
}
}
}

@ -48,7 +48,8 @@ class PostgresDataSource : AllInDataSource() {
isprivate boolean,
createdby varchar(250),
status varchar(20),
type varchar(20)
type varchar(20),
popularityscore numeric
)
""".trimIndent()
)

@ -40,15 +40,17 @@ class PostgresUserDataSource(private val database: Database) : UserDataSource {
database.users.removeIf { (it.username eq username) or (it.email eq username) } > 0
override fun addCoins(username: String, amount: Int) {
database.users
.find { it.username eq username }
?.set(UsersEntity.nbCoins.name, UsersEntity.nbCoins + amount)
database.update(UsersEntity) {
set(it.nbCoins, it.nbCoins + amount)
where { it.username eq username }
}
}
override fun removeCoins(username: String, amount: Int) {
database.users
.find { it.username eq username }
?.set(UsersEntity.nbCoins.name, UsersEntity.nbCoins - amount)
database.update(UsersEntity) {
set(it.nbCoins, it.nbCoins - amount)
where { it.username eq username }
}
}
override fun userExists(username: String) =

@ -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<BetEntity> {
var status: BetStatus
var type: BetType
var createdBy: String
var popularityscore: Int
fun toBet(database: Database) =
Bet(
@ -39,7 +41,8 @@ interface BetEntity : Entity<BetEntity> {
} else {
database.responses.filter { it.betId eq id }.map { it.response }
},
createdBy = createdBy
createdBy = createdBy,
popularityscore = popularityscore,
)
fun toBetDetail(database: Database, username: String): BetDetail {
@ -60,6 +63,7 @@ interface BetEntity : Entity<BetEntity> {
)
}
}
object BetsEntity : Table<BetEntity>("bet") {
@ -73,6 +77,7 @@ object BetsEntity : Table<BetEntity>("bet") {
val status = enum<BetStatus>("status").bindTo { it.status }
val type = enum<BetType>("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)

@ -19,7 +19,8 @@ data class Bet(
@Serializable(ZonedDateTimeSerializer::class) var endBet: ZonedDateTime,
var isPrivate: Boolean,
var response: List<String>,
val createdBy: String = ""
val createdBy: String = "",
var popularityscore: Int
)
@Serializable

@ -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)
}
@ -90,6 +90,33 @@ fun Application.betRouter() {
}
}
authenticate {
get("/bets/popular", {
description = "Allows you to recover the most popular public bets"
request {
headerParameter<JWTPrincipal>("JWT token of the logged user")
}
response {
HttpStatusCode.Accepted to {
description = "The most popular public bet is available"
body<Bet> {
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 {

@ -22,6 +22,7 @@ fun Application.participationRouter() {
val userDataSource = this.dataSource.userDataSource
val participationDataSource = this.dataSource.participationDataSource
val betDataSource = this.dataSource.betDataSource
routing {
authenticate {
@ -47,6 +48,11 @@ fun Application.participationRouter() {
hasToken { principal ->
val participation = call.receive<ParticipationRequest>()
verifyUserFromToken(userDataSource, principal) { user, _ ->
if(betDataSource.getBetById(participation.betId)== null){
call.respond(HttpStatusCode.NotFound, ApiMessage.BET_NOT_FOUND)
}
if (user.nbCoins >= participation.stake) {
participationDataSource.addParticipation(
Participation(
@ -59,6 +65,7 @@ fun Application.participationRouter() {
)
userDataSource.removeCoins(username = user.username, amount = participation.stake)
betDataSource.updatePopularityScore(participation.betId)
call.respond(HttpStatusCode.Created)
} else {
call.respond(HttpStatusCode.Forbidden, ApiMessage.NOT_ENOUGH_COINS)

@ -56,24 +56,25 @@ fun Application.userRouter() {
if (RegexCheckerUser.isEmailInvalid(tempUser.email)) {
call.respond(HttpStatusCode.Forbidden, ApiMessage.INVALID_MAIL)
}
if (userDataSource.userExists(tempUser.username)) {
else if (userDataSource.userExists(tempUser.username)) {
call.respond(HttpStatusCode.Conflict, ApiMessage.USER_ALREADY_EXISTS)
}
if(userDataSource.emailExists(tempUser.email)){
else if (userDataSource.emailExists(tempUser.email)) {
call.respond(HttpStatusCode.Conflict, ApiMessage.MAIL_ALREADY_EXISTS)
} else {
val user = User(
id = UUID.randomUUID().toString(),
username = tempUser.username,
email = tempUser.email,
password = tempUser.password,
nbCoins = DEFAULT_COINS,
token = null
)
CryptManagerUser.passwordCrypt(user)
user.token = tokenManagerUser.generateOrReplaceJWTToken(user)
userDataSource.addUser(user)
call.respond(HttpStatusCode.Created, user)
}
val user = User(
id = UUID.randomUUID().toString(),
username = tempUser.username,
email = tempUser.email,
password = tempUser.password,
nbCoins = DEFAULT_COINS,
token = null
)
CryptManagerUser.passwordCrypt(user)
user.token = tokenManagerUser.generateOrReplaceJWTToken(user)
userDataSource.addUser(user)
call.respond(HttpStatusCode.Created, user)
}
post("/users/login", {

Loading…
Cancel
Save