Add Swagger's comments

pull/12/head
Lucas EVARD 1 year ago
parent 01a016b34f
commit 734c6c6fb1

@ -149,6 +149,12 @@
<artifactId>swagger-codegen-generators</artifactId>
<version>1.0.38</version>
</dependency>
<dependency>
<groupId>org.hamcrest</groupId>
<artifactId>hamcrest-core</artifactId>
<version>1.3</version>
</dependency>
</dependencies>
<build>
<sourceDirectory>${project.basedir}/src/main/kotlin</sourceDirectory>
@ -164,7 +170,7 @@
<groupId>org.jetbrains.kotlin</groupId>
<version>${kotlin.version}</version>
<configuration>
<jvmTarget>1.8</jvmTarget>
<jvmTarget>11</jvmTarget>
</configuration>
<executions>
<execution>

@ -12,4 +12,5 @@ object ApiMessage {
const val PARTICIPATION_NOT_FOUND = "Participation not found."
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 !"
}

@ -1,6 +1,8 @@
package allin.routing
import allin.model.ApiMessage
import io.github.smiley4.ktorswaggerui.dsl.get
import io.ktor.http.*
import io.ktor.server.application.*
import io.ktor.server.response.*
import io.ktor.server.routing.*
@ -8,7 +10,17 @@ import io.ktor.server.routing.*
fun Application.BasicRouting() {
routing {
get("/") {
get("/", {
description = "Hello World of Allin API"
response {
HttpStatusCode.OK to {
description = "Successful Request"
}
HttpStatusCode.InternalServerError to {
description = "Something unexpected happened"
}
}
}) {
call.respond(ApiMessage.WELCOME)
}
}

@ -6,11 +6,14 @@ import allin.ext.verifyUserFromToken
import allin.model.ApiMessage
import allin.model.BetDetail
import allin.model.getBetAnswerDetail
import io.github.smiley4.ktorswaggerui.dsl.get
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.server.routing.*
import java.util.*
fun Application.BetDetailRouter() {
@ -20,7 +23,23 @@ fun Application.BetDetailRouter() {
routing {
authenticate {
get("/betdetail/get/{id}") {
get("/betdetail/get/{id}", {
description = "Retrieves the details of a specific bet"
request {
headerParameter<JWTPrincipal>("JWT token of the logged user")
pathParameter<UUID>("Id of the desired detail bet")
}
response {
HttpStatusCode.Accepted to {
description = "The bet can be returned"
body<BetDetail>()
}
HttpStatusCode.NotFound to {
description = "Bet not found in the selected source"
body(ApiMessage.BET_NOT_FOUND)
}
}
}) {
hasToken { principal ->
verifyUserFromToken(userDataSource, principal) { user, _ ->
val id = call.parameters["id"].toString()

@ -5,12 +5,17 @@ import allin.ext.hasToken
import allin.ext.verifyUserFromToken
import allin.model.*
import allin.utils.AppConfig
import io.github.smiley4.ktorswaggerui.dsl.get
import io.github.smiley4.ktorswaggerui.dsl.post
import io.github.smiley4.ktorswaggerui.dsl.route
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 io.swagger.annotations.Api
import java.util.*
val tokenManagerBet = AppConfig.tokenManager
@ -22,69 +27,154 @@ fun Application.BetRouter() {
val participationDataSource = this.dataSource.participationDataSource
routing {
route("/bets/add") {
authenticate {
post {
hasToken { principal ->
val bet = call.receive<Bet>()
val id = UUID.randomUUID().toString()
val username = tokenManagerBet.getUsernameFromToken(principal)
betDataSource.getBetById(id)?.let {
call.respond(HttpStatusCode.Conflict, ApiMessage.BET_ALREADY_EXIST)
} ?: run {
val betWithId = bet.copy(id = id, createdBy = username)
betDataSource.addBet(betWithId)
call.respond(HttpStatusCode.Created, betWithId)
authenticate {
post("/bets/add", {
description = "Allows a user to create a new bet"
request {
headerParameter<JWTPrincipal>("JWT token of the logged user")
body<Bet> {
description = "Bet to add in the selected source"
}
}
response {
HttpStatusCode.Created to {
description = "the bet has been added"
body<Bet>() {
description = "Bet with assigned id"
}
}
HttpStatusCode.Conflict to {
description = "Id already exist"
body(ApiMessage.BET_ALREADY_EXIST)
}
}
}) {
hasToken { principal ->
val bet = call.receive<Bet>()
val id = UUID.randomUUID().toString()
val username = tokenManagerBet.getUsernameFromToken(principal)
betDataSource.getBetById(id)?.let {
call.respond(HttpStatusCode.Conflict, ApiMessage.BET_ALREADY_EXIST)
} ?: run {
val betWithId = bet.copy(id = id, createdBy = username)
betDataSource.addBet(betWithId)
call.respond(HttpStatusCode.Created, betWithId)
}
}
}
}
authenticate {
get("/bets/gets") {
get("/bets/gets", {
description = "Allows you to recover all bets"
request {
headerParameter<JWTPrincipal>("JWT token of the logged user")
}
response {
HttpStatusCode.Accepted to {
description = "The list of bets is available"
body<List<Bet>>() {
description = "List of all bet in the selected source"
}
}
}
}) {
hasToken { principal ->
verifyUserFromToken(userDataSource, principal) { user, _ ->
verifyUserFromToken(userDataSource, principal) { _, _ ->
call.respond(HttpStatusCode.Accepted, betDataSource.getAllBets())
}
}
}
}
route("/bets/get/{id}") {
get {
val id = call.parameters["id"] ?: ""
betDataSource.getBetById(id)?.let { bet ->
call.respond(HttpStatusCode.Accepted, bet)
} ?: call.respond(HttpStatusCode.NotFound, ApiMessage.BET_NOT_FOUND)
get("/bets/get/{id}", {
description = "Retrieves a specific bet"
request {
pathParameter<UUID>("Id of the desired bet")
}
response {
HttpStatusCode.Accepted to {
description = "The bet is available"
body<Bet> {
description = "Desired bet"
}
}
HttpStatusCode.NotFound to {
description = "Bet not found in the selected source"
body(ApiMessage.BET_NOT_FOUND)
}
}
}) {
val id = call.parameters["id"] ?: ""
betDataSource.getBetById(id)?.let { bet ->
call.respond(HttpStatusCode.Accepted, bet)
} ?: call.respond(HttpStatusCode.NotFound, ApiMessage.BET_NOT_FOUND)
}
route("/bets/delete") {
post {
val id = call.receive<Map<String, String>>()["id"] ?: ""
if (betDataSource.removeBet(id)) {
call.respond(HttpStatusCode.Accepted)
} else {
call.respond(HttpStatusCode.NotFound, ApiMessage.BET_NOT_FOUND)
post("/bets/delete", {
description = "Delete a specific bet"
request {
body<Map<String, String>> {
description = "Id of the desired bet"
}
}
response {
HttpStatusCode.Accepted to {
description = "The bet has been deleted"
}
HttpStatusCode.NotFound to {
description = "Bet not found in the selected source"
body(ApiMessage.BET_NOT_FOUND)
}
}
}) {
val id = call.receive<Map<String, String>>()["id"] ?: ""
if (betDataSource.removeBet(id)) {
call.respond(HttpStatusCode.Accepted)
} else {
call.respond(HttpStatusCode.NotFound, ApiMessage.BET_NOT_FOUND)
}
}
route("bets/update") {
post {
val updatedBetData = call.receive<UpdatedBetData>()
if (betDataSource.updateBet(updatedBetData)) {
call.respond(HttpStatusCode.Accepted)
} else {
call.respond(HttpStatusCode.NotFound, ApiMessage.BET_NOT_FOUND)
post("bets/update", {
description = "Update a specific bet"
request {
body<UpdatedBetData> {
description = "Information of the updated bet"
}
}
response {
HttpStatusCode.Accepted to {
description = "The bet has been updated"
}
HttpStatusCode.NotFound to {
description = "Bet not found in the selected source"
body(ApiMessage.BET_NOT_FOUND)
}
}
}) {
val updatedBetData = call.receive<UpdatedBetData>()
if (betDataSource.updateBet(updatedBetData)) {
call.respond(HttpStatusCode.Accepted)
} else {
call.respond(HttpStatusCode.NotFound, ApiMessage.BET_NOT_FOUND)
}
}
authenticate {
get("/bets/toConfirm") {
get("/bets/toConfirm", {
description = "Allows a user to know which bets can be validated"
request {
headerParameter<JWTPrincipal>("JWT token of the logged user")
}
response {
HttpStatusCode.Accepted to {
description = "The list of bets that can be validated is available"
body<List<BetDetail>>() {
description = "list of bets that can be validated"
}
}
}
}) {
hasToken { principal ->
verifyUserFromToken(userDataSource, principal) { user, _ ->
val response = betDataSource.getToConfirm(user.username).map {
@ -103,7 +193,20 @@ fun Application.BetRouter() {
}
authenticate {
get("/bets/getWon") {
get("/bets/getWon", {
description = "Allows a user to know their won bets"
request {
headerParameter<JWTPrincipal>("JWT token of the logged user")
}
response {
HttpStatusCode.Accepted to {
description = "The list of won bets is available"
body<List<BetResultDetail>>() {
description = "List of won bets"
}
}
}
}) {
hasToken { principal ->
verifyUserFromToken(userDataSource, principal) { user, _ ->
call.respond(HttpStatusCode.Accepted, betDataSource.getWonNotifications(user.username))
@ -113,7 +216,20 @@ fun Application.BetRouter() {
}
authenticate {
get("/bets/history") {
get("/bets/history", {
description = "Allows a user to know own history of bets"
request {
headerParameter<JWTPrincipal>("JWT token of the logged user")
}
response {
HttpStatusCode.Accepted to {
description = "Bet history is available"
body<List<BetResultDetail>>() {
description = "Betting history list"
}
}
}
}) {
hasToken { principal ->
verifyUserFromToken(userDataSource, principal) { user, _ ->
call.respond(HttpStatusCode.Accepted, betDataSource.getHistory(user.username))
@ -123,7 +239,20 @@ fun Application.BetRouter() {
}
authenticate {
get("/bets/current") {
get("/bets/current", {
description = "Allows a user to know current bets"
request {
headerParameter<JWTPrincipal>("JWT token of the logged user")
}
response {
HttpStatusCode.Accepted to {
description = "List of current bets is available"
body<List<BetDetail>> {
description = "List of current bets"
}
}
}
}) {
hasToken { principal ->
verifyUserFromToken(userDataSource, principal) { user, _ ->
call.respond(HttpStatusCode.Accepted, betDataSource.getCurrent(user.username))
@ -133,7 +262,24 @@ fun Application.BetRouter() {
}
authenticate {
post("/bets/confirm/{id}") {
post("/bets/confirm/{id}", {
description = "allows the creator of a bet to confrm the final answer"
request {
headerParameter<JWTPrincipal>("JWT token of the logged user")
pathParameter<UUID>("Id of the desired bet")
body<String> {
description = "Final answer of the bet"
}
}
response {
HttpStatusCode.OK to {
description = "The final answer has been set"
}
HttpStatusCode.Unauthorized to {
description = "The user is not the creator of the bet"
}
}
}) {
hasToken { principal ->
verifyUserFromToken(userDataSource, principal) { user, _ ->
val betId = call.parameters["id"] ?: ""

@ -6,9 +6,12 @@ import allin.ext.verifyUserFromToken
import allin.model.ApiMessage
import allin.model.Participation
import allin.model.ParticipationRequest
import io.github.smiley4.ktorswaggerui.dsl.delete
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.*
@ -22,7 +25,25 @@ fun Application.ParticipationRouter() {
routing {
authenticate {
post("/participations/add") {
post("/participations/add", {
description = "Allows a user to add a stake to a bet"
request {
headerParameter<JWTPrincipal>("JWT token of the logged user")
body<ParticipationRequest> {
description = "Participation in a bet"
}
}
response {
HttpStatusCode.Created to {
description = "The stake has been bet"
}
HttpStatusCode.Forbidden to {
description = "User does not have enough coins"
body(ApiMessage.NOT_ENOUGH_COINS)
}
}
}) {
hasToken { principal ->
val participation = call.receive<ParticipationRequest>()
verifyUserFromToken(userDataSource, principal) { user, _ ->
@ -46,7 +67,24 @@ fun Application.ParticipationRouter() {
}
}
}
delete("/participations/delete") {
delete("/participations/delete", {
description = "Allows to delete a participation to a bet"
request {
headerParameter<JWTPrincipal>("JWT token of the logged user")
body<String> {
description = "Id of the participation"
}
}
response {
HttpStatusCode.NotFound to {
description = "Participation was not found"
body(ApiMessage.PARTICIPATION_NOT_FOUND)
}
HttpStatusCode.NoContent to {
description = "The operation was successful"
}
}
}) {
hasToken {
val participationId = call.receive<String>()
if (participationDataSource.deleteParticipation(participationId)) {

@ -1,16 +1,21 @@
package allin.routing
import allin.dataSource
import allin.dto.UserDTO
import allin.ext.hasToken
import allin.ext.verifyUserFromToken
import allin.model.*
import allin.utils.AppConfig
import io.github.smiley4.ktorswaggerui.dsl.get
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.*
import io.swagger.annotations.Api
import java.util.*
val RegexCheckerUser = AppConfig.regexChecker
@ -24,54 +29,113 @@ fun Application.UserRouter() {
val userDataSource = this.dataSource.userDataSource
routing {
route("/users/register") {
post {
val tempUser = call.receive<UserRequest>()
if (RegexCheckerUser.isEmailInvalid(tempUser.email)) {
call.respond(HttpStatusCode.Forbidden, ApiMessage.INVALID_MAIL)
post("/users/register", {
description = "Allows a user to register"
request {
body<UserRequest> {
description = "User information"
}
if (userDataSource.userExists(tempUser.username, tempUser.email)) {
call.respond(HttpStatusCode.Conflict, ApiMessage.USER_ALREADY_EXISTS)
}
response {
HttpStatusCode.Created to {
description = "User created"
body<User>()
}
HttpStatusCode.Conflict to {
description = "Email or username already taken"
body(ApiMessage.USER_ALREADY_EXISTS)
}
HttpStatusCode.Forbidden to {
description = "Email invalid"
body(ApiMessage.INVALID_MAIL)
}
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 tempUser = call.receive<UserRequest>()
if (RegexCheckerUser.isEmailInvalid(tempUser.email)) {
call.respond(HttpStatusCode.Forbidden, ApiMessage.INVALID_MAIL)
}
if (userDataSource.userExists(tempUser.username, tempUser.email)) {
call.respond(HttpStatusCode.Conflict, ApiMessage.USER_ALREADY_EXISTS)
}
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)
}
route("/users/login") {
post {
val checkUser = call.receive<CheckUser>()
val user = userDataSource.getUserByUsername(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.USER_NOT_FOUND)
} else {
call.respond(HttpStatusCode.NotFound, ApiMessage.INCORRECT_LOGIN_PASSWORD)
post("/users/login", {
description = "Allows a user to login"
request {
body<UserRequest> {
description = "User information"
}
}
response {
HttpStatusCode.OK to {
description = "User logged in"
body<UserDTO>()
}
HttpStatusCode.NotFound to {
description = "Invalid credentials"
body(ApiMessage.USER_NOT_FOUND)
}
}
}) {
val checkUser = call.receive<CheckUser>()
val user = userDataSource.getUserByUsername(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.USER_NOT_FOUND)
} else {
call.respond(HttpStatusCode.NotFound, ApiMessage.INCORRECT_LOGIN_PASSWORD)
}
}
authenticate {
post("/users/delete") {
post("/users/delete", {
description = "Allow you to delete your account"
request {
headerParameter<JWTPrincipal>("JWT token of the logged user")
body<CheckUser> {
description = "User information"
}
}
response {
HttpStatusCode.InternalServerError to {
description = "User can't be delete"
body(ApiMessage.USER_CANT_BE_DELETE)
}
HttpStatusCode.Accepted to {
body<String> {
description = "Password of the user"
}
}
HttpStatusCode.NotFound to {
description = "User not found"
body(ApiMessage.INCORRECT_LOGIN_PASSWORD)
}
}
}) {
hasToken { principal ->
verifyUserFromToken(userDataSource, principal) { _, password ->
val checkUser = call.receive<CheckUser>()
if (CryptManagerUser.passwordDecrypt(password, checkUser.password)) {
if (!userDataSource.deleteUser(checkUser.login)) {
call.respond(HttpStatusCode.InternalServerError, "This user can't be delete now !")
call.respond(HttpStatusCode.InternalServerError, ApiMessage.USER_CANT_BE_DELETE)
}
call.respond(HttpStatusCode.Accepted, password)
} else {
@ -82,14 +146,44 @@ fun Application.UserRouter() {
}
}
get("/users/token") {
get("/users/token", {
description = "Allows you to retrieve the user linked to a JWT token"
request {
headerParameter<JWTPrincipal>("JWT token of the user")
}
response {
HttpStatusCode.OK to {
body<UserDTO> {
description = "Limited user information"
}
}
}
}) {
hasToken { principal ->
verifyUserFromToken(userDataSource, principal) { userDto, _ ->
call.respond(HttpStatusCode.OK, userDto)
}
}
}
get("/users/gift") {
get("/users/gift", {
description = "Allows you to collect your daily gift"
request {
headerParameter<JWTPrincipal>("JWT token of the logged user")
}
response {
HttpStatusCode.OK to {
description = "Daily gift allowed !"
body<Int>() {
description = "Number of coins offered"
}
}
HttpStatusCode.MethodNotAllowed to {
description = "You can't have you daily gift now"
body(ApiMessage.NO_GIFT)
}
}
}) {
hasToken { principal ->
verifyUserFromToken(userDataSource, principal) { userDto, _ ->
if (userDataSource.canHaveDailyGift(userDto.username)) {

Loading…
Cancel
Save