Merge pull request 'Link_Database' (#3) from Link_Database into master
continuous-integration/drone/push Build is passing
Details
continuous-integration/drone/push Build is passing
Details
Reviewed-on: #3pull/4/head
commit
63599de591
@ -1,15 +1,4 @@
|
||||
package allin.dto
|
||||
|
||||
import allin.model.User
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
data class UserDTO(val username: String,val email: String, val nbCoins: Int)
|
||||
@Serializable
|
||||
data class UserDTOWithToken(val username: String,val email: String, val nbCoins: Int, val token:String?)
|
||||
fun convertUserToUserDTO(user: User): UserDTO {
|
||||
return UserDTO(user.username, user.email, user.nbCoins)
|
||||
}
|
||||
fun convertUserToUserDTOToken(user: User): UserDTOWithToken {
|
||||
return UserDTOWithToken(user.username, user.email, user.nbCoins,user.token)
|
||||
}
|
||||
data class UserDTO(val username: String, val email: String, val nbCoins: Double, var token:String?)
|
||||
|
@ -1,11 +1,79 @@
|
||||
package allin.entities
|
||||
|
||||
import allin.database
|
||||
import allin.dto.UserDTO
|
||||
import allin.model.User
|
||||
import allin.utils.Execute
|
||||
import org.ktorm.dsl.*
|
||||
import org.ktorm.entity.*
|
||||
import org.ktorm.expression.SqlExpression
|
||||
import org.ktorm.schema.Table
|
||||
import org.ktorm.schema.double
|
||||
import org.ktorm.schema.int
|
||||
import org.ktorm.schema.varchar
|
||||
|
||||
object UserEntity : Table<Nothing>("user") {
|
||||
interface UserEntity : Entity<UserEntity> {
|
||||
val username: String
|
||||
var email: String
|
||||
var password: String
|
||||
var nbCoins: Double
|
||||
}
|
||||
object UsersEntity : Table<UserEntity>("utilisateur") {
|
||||
val id = int("id").primaryKey()
|
||||
val username = varchar("username")
|
||||
val password = varchar("password")
|
||||
}
|
||||
val nbCoins = double("coins")
|
||||
val email = varchar("email")
|
||||
|
||||
fun getUserToUserDTO(): MutableList<UserDTO> {
|
||||
return database.from(UsersEntity).select().map {
|
||||
row -> UserDTO(
|
||||
row[username].toString(),
|
||||
row[email].toString(),
|
||||
row[nbCoins]?:0.0,
|
||||
null
|
||||
)
|
||||
}.toMutableList()
|
||||
}
|
||||
|
||||
fun createUserTable(){
|
||||
val request="CREATE TABLE IF not exists utilisateur ( id SERIAL PRIMARY KEY, username VARCHAR(255), password VARCHAR(255),coins double precision,email VARCHAR(255))"
|
||||
database.Execute(request)
|
||||
}
|
||||
|
||||
|
||||
fun getUserByUsernameAndPassword(login: String): Pair<UserDTO?, String?> {
|
||||
return database.from(UsersEntity)
|
||||
.select()
|
||||
.where { (username eq login) /*and (password eq passwordParam)*/ }
|
||||
.map { row ->
|
||||
Pair(
|
||||
UserDTO(
|
||||
row[username].toString(),
|
||||
row[email].toString(),
|
||||
row[nbCoins] ?: 0.0,
|
||||
null
|
||||
),
|
||||
row[password].toString()
|
||||
)
|
||||
}
|
||||
.firstOrNull() ?: Pair(null, null)
|
||||
}
|
||||
|
||||
fun addUserEntity(user : User){
|
||||
database.insert(UsersEntity){
|
||||
set(it.nbCoins,user.nbCoins)
|
||||
set(it.username,user.username)
|
||||
set(it.password,user.password)
|
||||
set(it.email,user.email)
|
||||
}
|
||||
}
|
||||
fun deleteUserByUsername(username: String): Boolean {
|
||||
val deletedCount = database.delete(UsersEntity) {
|
||||
it.username eq username
|
||||
}
|
||||
return deletedCount > 0
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -0,0 +1,24 @@
|
||||
package allin.ext
|
||||
|
||||
import allin.dto.UserDTO
|
||||
import allin.entities.UsersEntity
|
||||
import allin.model.ApiMessage
|
||||
import io.ktor.http.*
|
||||
import io.ktor.server.application.*
|
||||
import io.ktor.server.auth.*
|
||||
import io.ktor.server.auth.jwt.*
|
||||
import io.ktor.server.response.*
|
||||
import io.ktor.util.pipeline.*
|
||||
|
||||
suspend fun PipelineContext<*, ApplicationCall>.hasToken(content: suspend (principal: JWTPrincipal) -> Unit) =
|
||||
call.principal<JWTPrincipal>()?.let { content(it) } ?: call.respond(HttpStatusCode.Unauthorized)
|
||||
|
||||
suspend fun PipelineContext<*, ApplicationCall>.verifyUserFromToken(
|
||||
principal: JWTPrincipal,
|
||||
content: suspend (user: UserDTO, password: String) -> Unit
|
||||
) {
|
||||
val username = principal.payload.getClaim("username").asString()
|
||||
val userPassword = UsersEntity.getUserByUsernameAndPassword(username)
|
||||
userPassword.first?.let { content(it, userPassword.second ?: "") }
|
||||
?: call.respond(HttpStatusCode.NotFound, ApiMessage.TokenUserNotFound)
|
||||
}
|
@ -0,0 +1,14 @@
|
||||
package allin.model
|
||||
|
||||
object ApiMessage {
|
||||
const val Welcome = "Welcome on AllIn's API !"
|
||||
const val TokenUserNotFound = "User not found with the valid token !"
|
||||
const val UserNotFound = "User not found."
|
||||
const val BetNotFound = "Bet not found."
|
||||
const val BetAlreadyExist = "Bet already exists."
|
||||
const val IncorrectLoginPassword = "Login and/or password incorrect."
|
||||
const val UserAlreadyExist = "Mail and/or username already exists."
|
||||
const val InvalidMail = "Invalid mail."
|
||||
const val ParticipationNotFound = "Participation not found."
|
||||
const val NotEnoughCoins = "Not enough coins."
|
||||
}
|
@ -1,19 +1,36 @@
|
||||
package allin.model
|
||||
|
||||
import allin.dto.UserDTOWithToken
|
||||
import allin.serializer.DateSerializer
|
||||
import allin.serializer.ZonedDateTimeSerializer
|
||||
import kotlinx.serialization.Serializable
|
||||
import java.util.*
|
||||
import java.time.ZonedDateTime
|
||||
|
||||
@Serializable
|
||||
data class Bet(val id: Int, val theme: String, val sentenceBet: String, @Serializable(DateSerializer::class) val endRegistration: Date, @Serializable(DateSerializer::class) var endBet : Date, var isPrivate : Boolean, var response : MutableList<String>, val createdBy : String)
|
||||
data class Bet(
|
||||
val id: String,
|
||||
val theme: String,
|
||||
val sentenceBet: String,
|
||||
@Serializable(ZonedDateTimeSerializer::class) val endRegistration: ZonedDateTime,
|
||||
@Serializable(ZonedDateTimeSerializer::class) var endBet: ZonedDateTime,
|
||||
var isPrivate: Boolean,
|
||||
var response: MutableList<String>,
|
||||
val createdBy: String
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class UpdatedBetData(val id: Int,@Serializable(DateSerializer::class) val endBet: Date, val isPrivate: Boolean, val response: MutableList<String>)
|
||||
data class UpdatedBetData(
|
||||
val id: String,
|
||||
@Serializable(ZonedDateTimeSerializer::class) val endBet: ZonedDateTime,
|
||||
val isPrivate: Boolean,
|
||||
val response: MutableList<String>
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class BetWithoutId(val theme: String, val sentenceBet: String, @Serializable(DateSerializer::class) val endRegistration: Date, @Serializable(DateSerializer::class) var endBet : Date, var isPrivate : Boolean, var response : MutableList<String>, val createdBy : String)
|
||||
|
||||
fun convertBetWithoutIdToBet(betWithoutId: BetWithoutId,id : Int, username : String): Bet {
|
||||
return Bet(id,betWithoutId.theme,betWithoutId.sentenceBet,betWithoutId.endRegistration, betWithoutId.endBet, betWithoutId.isPrivate, betWithoutId.response, username)
|
||||
}
|
||||
data class BetWithoutId(
|
||||
val theme: String,
|
||||
val sentenceBet: String,
|
||||
@Serializable(ZonedDateTimeSerializer::class) val endRegistration: ZonedDateTime,
|
||||
@Serializable(ZonedDateTimeSerializer::class) var endBet: ZonedDateTime,
|
||||
var isPrivate: Boolean,
|
||||
var response: MutableList<String>,
|
||||
val createdBy: String
|
||||
)
|
@ -1,5 +1,5 @@
|
||||
package allin.model
|
||||
|
||||
import allin.dto.UserDTOWithToken
|
||||
import allin.dto.UserDTO
|
||||
data class BetAction(val id:Int, val coins: Int, val user: String, val bet: Int)
|
||||
data class BetActionCompleted(val id:Int, val coins: Int, val user: UserDTOWithToken, val bet: Bet)
|
||||
data class BetActionCompleted(val id:Int, val coins: Int, val user: UserDTO, val bet: Bet)
|
||||
|
@ -0,0 +1,19 @@
|
||||
package allin.model
|
||||
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
data class Participation(
|
||||
val id: String,
|
||||
val betId: String,
|
||||
val username: String,
|
||||
val answer: String,
|
||||
val stake: Int
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class ParticipationRequest(
|
||||
val betId: String,
|
||||
val answer: String,
|
||||
val stake: Int
|
||||
)
|
@ -1,10 +1,27 @@
|
||||
package allin.model
|
||||
|
||||
import allin.dto.UserDTO
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
|
||||
@Serializable
|
||||
data class User(
|
||||
val id: String,
|
||||
val username: String,
|
||||
val email: String,
|
||||
var password: String,
|
||||
var nbCoins: Int = 500,
|
||||
var token: String? = null
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class User(val username: String, val email: String, var password: String, var nbCoins: Int = 1000, var token: String? = null)
|
||||
data class UserRequest(
|
||||
val username: String,
|
||||
val email: String,
|
||||
var password: String
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class CheckUser(val login: String,val password: String)
|
||||
data class CheckUser(
|
||||
val login: String,
|
||||
val password: String
|
||||
)
|
@ -0,0 +1,56 @@
|
||||
package allin.routing
|
||||
|
||||
import allin.ext.hasToken
|
||||
import allin.ext.verifyUserFromToken
|
||||
import allin.model.ApiMessage
|
||||
import allin.model.Participation
|
||||
import allin.model.ParticipationRequest
|
||||
import io.ktor.http.*
|
||||
import io.ktor.server.application.*
|
||||
import io.ktor.server.auth.*
|
||||
import io.ktor.server.request.*
|
||||
import io.ktor.server.response.*
|
||||
import io.ktor.server.routing.*
|
||||
import java.util.*
|
||||
|
||||
val participations = mutableListOf<Participation>()
|
||||
|
||||
fun Application.ParticipationRouter() {
|
||||
routing {
|
||||
authenticate {
|
||||
post("/participations/add") {
|
||||
hasToken { principal ->
|
||||
val participation = call.receive<ParticipationRequest>()
|
||||
verifyUserFromToken(principal) { user, _ ->
|
||||
if (user.nbCoins >= participation.stake) {
|
||||
participations.add(
|
||||
Participation(
|
||||
id = UUID.randomUUID().toString(),
|
||||
betId = participation.betId,
|
||||
username = user.username,
|
||||
answer = participation.answer,
|
||||
stake = participation.stake
|
||||
)
|
||||
)
|
||||
call.respond(HttpStatusCode.Created)
|
||||
} else {
|
||||
call.respond(HttpStatusCode.Forbidden, ApiMessage.NotEnoughCoins)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
delete("/participations/delete") {
|
||||
hasToken { principal ->
|
||||
val participationId = call.receive<String>()
|
||||
participations.find { it.id == participationId }?.let { participation ->
|
||||
verifyUserFromToken(principal) { user, _ ->
|
||||
// user.nbCoins += participation.stake
|
||||
participations.remove(participation)
|
||||
call.respond(HttpStatusCode.NoContent)
|
||||
}
|
||||
} ?: call.respond(HttpStatusCode.NotFound, ApiMessage.ParticipationNotFound)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,81 +1,99 @@
|
||||
package allin.routing
|
||||
|
||||
import allin.dto.*
|
||||
import allin.entities.UsersEntity.addUserEntity
|
||||
import allin.entities.UsersEntity.deleteUserByUsername
|
||||
import allin.entities.UsersEntity.getUserByUsernameAndPassword
|
||||
import allin.entities.UsersEntity.getUserToUserDTO
|
||||
import allin.ext.hasToken
|
||||
import allin.ext.verifyUserFromToken
|
||||
import allin.model.ApiMessage
|
||||
import allin.model.CheckUser
|
||||
import allin.model.User
|
||||
import allin.model.UserRequest
|
||||
import allin.utils.AppConfig
|
||||
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.*
|
||||
import org.ktorm.database.Database
|
||||
import java.util.*
|
||||
|
||||
val users = mutableListOf<User>()
|
||||
val RegexCheckerUser= AppConfig.regexChecker
|
||||
val CryptManagerUser= AppConfig.cryptManager
|
||||
val tokenManagerUser=AppConfig.tokenManager
|
||||
|
||||
|
||||
val RegexCheckerUser = AppConfig.regexChecker
|
||||
val CryptManagerUser = AppConfig.cryptManager
|
||||
val tokenManagerUser = AppConfig.tokenManager
|
||||
const val DEFAULT_COINS = 500
|
||||
fun Application.UserRouter() {
|
||||
|
||||
routing {
|
||||
route("/users/register"){
|
||||
route("/users/register") {
|
||||
post {
|
||||
val TempUser = call.receive<User>()
|
||||
if (RegexCheckerUser.isEmailInvalid(TempUser.email)){
|
||||
call.respond(HttpStatusCode.Forbidden,"Input a valid mail !")
|
||||
val tempUser = call.receive<UserRequest>()
|
||||
if (RegexCheckerUser.isEmailInvalid(tempUser.email)) {
|
||||
call.respond(HttpStatusCode.Forbidden, ApiMessage.InvalidMail)
|
||||
}
|
||||
val user = users.find { it.username == TempUser.username || it.email == TempUser.email }
|
||||
if(user == null) {
|
||||
CryptManagerUser.passwordCrypt(TempUser)
|
||||
TempUser.token=tokenManagerUser.generateOrReplaceJWTToken(TempUser)
|
||||
users.add(TempUser)
|
||||
call.respond(HttpStatusCode.Created, TempUser)
|
||||
val users = getUserToUserDTO()
|
||||
users.find { it.username == tempUser.username || it.email == tempUser.email }?.let { user ->
|
||||
call.respond(HttpStatusCode.Conflict, ApiMessage.UserAlreadyExist)
|
||||
} ?: run {
|
||||
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)
|
||||
addUserEntity(user)
|
||||
call.respond(HttpStatusCode.Created, user)
|
||||
}
|
||||
call.respond(HttpStatusCode.Conflict,"Mail or/and username already exist")
|
||||
}
|
||||
}
|
||||
|
||||
route("/users/login") {
|
||||
post {
|
||||
val checkUser = call.receive<CheckUser>()
|
||||
val user = users.find { it.username == checkUser.login || it.email == checkUser.login }
|
||||
if (user != null && CryptManagerUser.passwordDecrypt(user,checkUser.password)) {
|
||||
user.token=tokenManagerUser.generateOrReplaceJWTToken(user)
|
||||
call.respond(HttpStatusCode.OK, convertUserToUserDTOToken(user))
|
||||
val user = getUserByUsernameAndPassword(checkUser.login)
|
||||
if (CryptManagerUser.passwordDecrypt(user.second ?: "", checkUser.password)) {
|
||||
user.first?.let { userDtoWithToken ->
|
||||
userDtoWithToken.token = tokenManagerUser.generateOrReplaceJWTToken(userDtoWithToken)
|
||||
call.respond(HttpStatusCode.OK, userDtoWithToken)
|
||||
} ?: call.respond(HttpStatusCode.NotFound, ApiMessage.UserNotFound)
|
||||
} else {
|
||||
call.respond(HttpStatusCode.NotFound,"Login and/or password incorrect.")
|
||||
call.respond(HttpStatusCode.NotFound, ApiMessage.IncorrectLoginPassword)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
route("/users/delete") {
|
||||
post {
|
||||
val checkUser = call.receive<CheckUser>()
|
||||
val user = users.find { it.username == checkUser.login || it.email == checkUser.login }
|
||||
if (user != null && user.password == checkUser.password) {
|
||||
users.remove(user)
|
||||
call.respond(HttpStatusCode.Accepted,convertUserToUserDTO(user))
|
||||
} else {
|
||||
call.respond(HttpStatusCode.NotFound,"Login and/or password incorrect.")
|
||||
authenticate {
|
||||
post("/users/delete") {
|
||||
hasToken { principal ->
|
||||
verifyUserFromToken(principal) { _, password ->
|
||||
val checkUser = call.receive<CheckUser>()
|
||||
|
||||
if (CryptManagerUser.passwordDecrypt(password, checkUser.password)) {
|
||||
if (!deleteUserByUsername(checkUser.login)) {
|
||||
call.respond(HttpStatusCode.InternalServerError, "This user can't be delete now !")
|
||||
}
|
||||
call.respond(HttpStatusCode.Accepted, password)
|
||||
} else {
|
||||
call.respond(HttpStatusCode.NotFound, "Login and/or password incorrect.")
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
authenticate {
|
||||
get("/users/token") {
|
||||
val principal = call.principal<JWTPrincipal>()
|
||||
val username = principal!!.payload.getClaim("username").asString()
|
||||
val user = users.find { it.username == username }
|
||||
if (user != null) {
|
||||
call.respond(HttpStatusCode.OK,convertUserToUserDTO(user))
|
||||
} else {
|
||||
call.respond(HttpStatusCode.NotFound, "User not found with the valid token !")
|
||||
hasToken { principal ->
|
||||
verifyUserFromToken(principal) { userDto, _ ->
|
||||
call.respond(HttpStatusCode.OK, userDto)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,13 @@
|
||||
package allin.utils
|
||||
|
||||
import allin.database
|
||||
import org.ktorm.database.Database
|
||||
|
||||
fun Database.Execute(request: String){
|
||||
if(!request.isNullOrEmpty())
|
||||
database.useTransaction {
|
||||
val connection = it.connection
|
||||
connection.prepareStatement(request).execute()
|
||||
connection.commit()
|
||||
}
|
||||
}
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -1,4 +0,0 @@
|
||||
secret="secret"
|
||||
issuer="http://0.0.0.0:8080/"
|
||||
audience="http://0.0.0.0:8080/"
|
||||
realm="Access to main page"
|
@ -1,12 +0,0 @@
|
||||
<configuration>
|
||||
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
|
||||
<encoder>
|
||||
<pattern>%d{YYYY-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
|
||||
</encoder>
|
||||
</appender>
|
||||
<root level="trace">
|
||||
<appender-ref ref="STDOUT"/>
|
||||
</root>
|
||||
<logger name="org.eclipse.jetty" level="INFO"/>
|
||||
<logger name="io.netty" level="INFO"/>
|
||||
</configuration>
|
Binary file not shown.
Binary file not shown.
Loading…
Reference in new issue