diff --git a/Api/api-app/pom.xml b/Api/api-app/pom.xml
index 8e31198ad..691aa417f 100644
--- a/Api/api-app/pom.xml
+++ b/Api/api-app/pom.xml
@@ -23,10 +23,6 @@
-
- org.springframework.boot
- spring-boot-starter
-
org.jetbrains.kotlin
kotlin-reflect
@@ -68,6 +64,11 @@
api-persister-postgres
${api.version}
+
+ io.springfox
+ springfox-boot-starter
+ 3.0.0
+
org.springframework.boot
diff --git a/Api/api-app/src/main/kotlin/co/nilin/opex/app/ApiApp.kt b/Api/api-app/src/main/kotlin/co/nilin/opex/app/ApiApp.kt
index 9c797d8e3..616a58bf7 100644
--- a/Api/api-app/src/main/kotlin/co/nilin/opex/app/ApiApp.kt
+++ b/Api/api-app/src/main/kotlin/co/nilin/opex/app/ApiApp.kt
@@ -2,12 +2,102 @@ package co.nilin.opex.app
import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.boot.runApplication
+import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.ComponentScan
+import org.springframework.security.core.annotation.AuthenticationPrincipal
+import springfox.documentation.builders.*
+import springfox.documentation.builders.PathSelectors.regex
+import springfox.documentation.service.*
+import springfox.documentation.spi.DocumentationType
+import springfox.documentation.spi.service.contexts.SecurityContext
+import springfox.documentation.spring.web.plugins.Docket
+import springfox.documentation.swagger.web.SecurityConfiguration
+import springfox.documentation.swagger.web.SecurityConfigurationBuilder
+import springfox.documentation.swagger2.annotations.EnableSwagger2
+import java.security.Principal
+import java.util.Collections.singletonList
+
@SpringBootApplication
@ComponentScan("co.nilin.opex")
-class AccountantApp
+@EnableSwagger2
+class ApiApp {
+ @Bean
+ fun opexApi(): Docket? {
+ return Docket(DocumentationType.SWAGGER_2)
+ .groupName("opex-api")
+ .apiInfo(apiInfo())
+ .select()
+ .paths(regex("^/api/v3.*"))
+ .build()
+ .globalRequestParameters(
+ singletonList(
+ RequestParameterBuilder()
+ .name("content-type")
+ .description("content-type")
+ .`in`(ParameterType.HEADER)
+ .required(true)
+ .build()
+ )
+ )
+ .ignoredParameterTypes(AuthenticationPrincipal::class.java, Principal::class.java)
+ .useDefaultResponseMessages(false)
+ .securitySchemes(singletonList(oauth()))
+ .securityContexts(singletonList(securityContext()))
+ }
+
+ private fun apiInfo(): ApiInfo? {
+ return ApiInfoBuilder()
+ .title("OPEX API")
+ .description("Backend for opex exchange.")
+ .license("MIT License")
+ .licenseUrl("https://github.com/opexdev/Back-end/blob/feature/1-MVP/LICENSE")
+ .version("0.1")
+ .build()
+ }
+
+ @Bean
+ fun oauth(): SecurityScheme? {
+ return OAuthBuilder()
+ .name("opex")
+ .grantTypes(grantTypes())
+ .scopes(scopes())
+ .build()
+ }
+
+ fun scopes(): List? {
+ return emptyList()
+ }
+
+ fun grantTypes(): List? {
+ val tokenUrl = "http://localhost:8083/auth/realms/mixchange/protocol/openid-connect/token"
+ val grantType = ResourceOwnerPasswordCredentialsGrant(tokenUrl)
+ return singletonList(grantType)
+ }
+
+ @Bean
+ fun securityContext(): SecurityContext? {
+ val securityReference = SecurityReference.builder()
+ .reference("opex")
+ .scopes(emptyArray())
+ .build()
+ return SecurityContext.builder()
+ .securityReferences(singletonList(securityReference))
+ .operationSelector { true }
+ .build()
+ }
+
+ @Bean
+ fun securityInfo(): SecurityConfiguration? {
+ return SecurityConfigurationBuilder.builder()
+ .clientId("admin-cli")
+ .realm("mixchange")
+ .appName("opex")
+ .scopeSeparator(",")
+ .build()
+ }
+}
fun main(args: Array) {
- runApplication(*args)
-}
\ No newline at end of file
+ runApplication(*args)
+}
diff --git a/Api/api-ports/api-binance-rest/pom.xml b/Api/api-ports/api-binance-rest/pom.xml
index b446d9769..049c12a74 100644
--- a/Api/api-ports/api-binance-rest/pom.xml
+++ b/Api/api-ports/api-binance-rest/pom.xml
@@ -102,6 +102,11 @@
reactor-test
test
+
+ io.swagger
+ swagger-annotations
+ 1.5.20
+
diff --git a/Api/api-ports/api-binance-rest/src/main/kotlin/co/nilin/opex/port/api/binance/config/SecurityConfig.kt b/Api/api-ports/api-binance-rest/src/main/kotlin/co/nilin/opex/port/api/binance/config/SecurityConfig.kt
index 16a25ce47..72a22d040 100644
--- a/Api/api-ports/api-binance-rest/src/main/kotlin/co/nilin/opex/port/api/binance/config/SecurityConfig.kt
+++ b/Api/api-ports/api-binance-rest/src/main/kotlin/co/nilin/opex/port/api/binance/config/SecurityConfig.kt
@@ -23,6 +23,9 @@ class SecurityConfig {
.authorizeExchange()
.pathMatchers("/hello").permitAll()
.pathMatchers("/actuator/**").permitAll()
+ .pathMatchers("/swagger-ui/**").permitAll()
+ .pathMatchers("/swagger-resources/**").permitAll()
+ .pathMatchers("/v2/api-docs").permitAll()
.pathMatchers("/**").hasAuthority("SCOPE_trust")
.anyExchange().authenticated()
.and()
diff --git a/Api/api-ports/api-binance-rest/src/main/kotlin/co/nilin/opex/port/api/binance/controller/AccountController.kt b/Api/api-ports/api-binance-rest/src/main/kotlin/co/nilin/opex/port/api/binance/controller/AccountController.kt
index 04265ba89..09119c0de 100644
--- a/Api/api-ports/api-binance-rest/src/main/kotlin/co/nilin/opex/port/api/binance/controller/AccountController.kt
+++ b/Api/api-ports/api-binance-rest/src/main/kotlin/co/nilin/opex/port/api/binance/controller/AccountController.kt
@@ -12,15 +12,13 @@ import co.nilin.opex.port.api.binance.util.asMatchingOrderType
import co.nilin.opex.port.api.binance.util.asOrderDirection
import co.nilin.opex.api.core.inout.*
import com.fasterxml.jackson.annotation.JsonInclude
+import io.swagger.annotations.*
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.map
import org.slf4j.LoggerFactory
import org.springframework.http.MediaType
import org.springframework.security.core.annotation.AuthenticationPrincipal
-import org.springframework.web.bind.annotation.GetMapping
-import org.springframework.web.bind.annotation.PostMapping
-import org.springframework.web.bind.annotation.RequestParam
-import org.springframework.web.bind.annotation.RestController
+import org.springframework.web.bind.annotation.*
import java.math.BigDecimal
import java.security.Principal
import java.util.*
@@ -108,6 +106,16 @@ class AccountController(
consumes = [MediaType.APPLICATION_FORM_URLENCODED_VALUE],
produces = [MediaType.APPLICATION_JSON_VALUE]
)
+ @ApiResponse(
+ message = "OK",
+ code = 200,
+ examples = Example(
+ ExampleProperty(
+ value = "{ \"symbol\": \"btc_usdt\", \"orderId\": -1, \"orderListId\": -1, \"transactTime\": \"2021-08-03T11:09:23.190+00:00\" }",
+ mediaType = "application/json"
+ )
+ )
+ )
suspend fun createNewOrder(
@RequestParam(name = "symbol")
symbol: String,
@@ -123,16 +131,24 @@ class AccountController(
quoteOrderQty: BigDecimal?,
@RequestParam(name = "price", required = false)
price: BigDecimal?,
+ @ApiParam(
+ value = "A unique id among open orders. Automatically generated if not sent.\n" +
+ "Orders with the same newClientOrderID can be accepted only when the previous one is filled, otherwise the order will be rejected."
+ )
@RequestParam(name = "newClientOrderId", required = false)
newClientOrderId: String?, /* A unique id among open orders. Automatically generated if not sent.
Orders with the same newClientOrderID can be accepted only when the previous one is filled, otherwise the order will be rejected.
*/
+ @ApiParam(value = "Used with STOP_LOSS, STOP_LOSS_LIMIT, TAKE_PROFIT, and TAKE_PROFIT_LIMIT orders.")
@RequestParam(name = "stopPrice", required = false)
stopPrice: BigDecimal?, //Used with STOP_LOSS, STOP_LOSS_LIMIT, TAKE_PROFIT, and TAKE_PROFIT_LIMIT orders.
@RequestParam(name = "icebergQty", required = false)
+ @ApiParam(value = "Used with LIMIT, STOP_LOSS_LIMIT, and TAKE_PROFIT_LIMIT to create an iceberg order.")
icebergQty: BigDecimal?, //Used with LIMIT, STOP_LOSS_LIMIT, and TAKE_PROFIT_LIMIT to create an iceberg order.
@RequestParam(name = "newOrderRespType", required = false)
+ @ApiParam(value = "Set the response JSON. ACK, RESULT, or FULL; MARKET and LIMIT order types default to FULL, all other orders default to ACK.")
newOrderRespType: OrderResponseType?, //Set the response JSON. ACK, RESULT, or FULL; MARKET and LIMIT order types default to FULL, all other orders default to ACK.
+ @ApiParam(value = "The value cannot be greater than 60000")
@RequestParam(name = "recvWindow", required = false)
recvWindow: Long?, //The value cannot be greater than 60000
@RequestParam(name = "timestamp")
@@ -179,6 +195,16 @@ class AccountController(
consumes = [MediaType.APPLICATION_FORM_URLENCODED_VALUE],
produces = [MediaType.APPLICATION_JSON_VALUE]
)
+ @ApiResponse(
+ message = "OK",
+ code = 200,
+ examples = Example(
+ ExampleProperty(
+ value = "{ \"symbol\": \"btc_usdt\", \"orderId\": 12, \"orderListId\": -1, \"clientOrderId\": \"\", \"price\": 1, \"origQty\": 10, \"executedQty\": 0, \"cummulativeQuoteQty\": 0, \"status\": \"NEW\", \"timeInForce\": \"GTC\", \"type\": \"LIMIT\", \"side\": \"SELL\", \"time\": \"2021-08-04T12:10:13.488+00:00\", \"updateTime\": \"2021-08-04T12:10:13.488+00:00\", \"isWorking\": true, \"origQuoteOrderQty\": 10 }",
+ mediaType = "application/json"
+ )
+ )
+ )
suspend fun queryOrder(
principal: Principal,
@RequestParam(name = "symbol")
@@ -187,6 +213,7 @@ class AccountController(
orderId: Long?,
@RequestParam(name = "origClientOrderId", required = false)
origClientOrderId: String?,
+ @ApiParam(value = "The value cannot be greater than 60000")
@RequestParam(name = "recvWindow", required = false)
recvWindow: Long?, //The value cannot be greater than 60000
@RequestParam(name = "timestamp")
@@ -230,10 +257,21 @@ class AccountController(
consumes = [MediaType.APPLICATION_FORM_URLENCODED_VALUE],
produces = [MediaType.APPLICATION_JSON_VALUE]
)
+ @ApiResponse(
+ message = "OK",
+ code = 200,
+ examples = Example(
+ ExampleProperty(
+ value = "[ { \"symbol\": \"btc_usdt\", \"orderId\": 12, \"orderListId\": -1, \"clientOrderId\": \"\", \"price\": 1, \"origQty\": 10, \"executedQty\": 0, \"cummulativeQuoteQty\": 0, \"status\": \"NEW\", \"timeInForce\": \"GTC\", \"type\": \"LIMIT\", \"side\": \"SELL\", \"time\": \"2021-08-04T12:10:13.488+00:00\", \"updateTime\": \"2021-08-04T12:10:13.488+00:00\", \"isWorking\": true, \"origQuoteOrderQty\": 10 } ]",
+ mediaType = "application/json"
+ )
+ )
+ )
suspend fun fetchOpenOrders(
principal: Principal,
@RequestParam(name = "symbol", required = false)
symbol: String?,
+ @ApiParam(value = "The value cannot be greater than 60000")
@RequestParam(name = "recvWindow", required = false)
recvWindow: Long?, //The value cannot be greater than 60000
@RequestParam(name = "timestamp")
@@ -274,6 +312,16 @@ class AccountController(
consumes = [MediaType.APPLICATION_FORM_URLENCODED_VALUE],
produces = [MediaType.APPLICATION_JSON_VALUE]
)
+ @ApiResponse(
+ message = "OK",
+ code = 200,
+ examples = Example(
+ ExampleProperty(
+ value = "{ }",
+ mediaType = "application/json"
+ )
+ )
+ )
suspend fun fetchAllOrders(
principal: Principal,
@RequestParam(name = "symbol", required = false)
@@ -282,8 +330,10 @@ class AccountController(
startTime: Date?,
@RequestParam(name = "endTime", required = false)
endTime: Date?,
+ @ApiParam(value = "Default 500; max 1000.")
@RequestParam(name = "limit", required = false)
limit: Int? = 500, //Default 500; max 1000.
+ @ApiParam(value = "The value cannot be greater than 60000")
@RequestParam(name = "recvWindow", required = false)
recvWindow: Long?, //The value cannot be greater than 60000
@RequestParam(name = "timestamp")
@@ -325,6 +375,16 @@ class AccountController(
consumes = [MediaType.APPLICATION_FORM_URLENCODED_VALUE],
produces = [MediaType.APPLICATION_JSON_VALUE]
)
+ @ApiResponse(
+ message = "OK",
+ code = 200,
+ examples = Example(
+ ExampleProperty(
+ value = "{ }",
+ mediaType = "application/json"
+ )
+ )
+ )
suspend fun fetchAllTrades(
principal: Principal,
@RequestParam(name = "symbol")
@@ -333,10 +393,13 @@ class AccountController(
startTime: Date?,
@RequestParam(name = "endTime", required = false)
endTime: Date?,
+ @ApiParam(value = "TradeId to fetch from. Default gets most recent trades.")
@RequestParam(name = "fromId", required = false)
fromId: Long?,//TradeId to fetch from. Default gets most recent trades.
+ @ApiParam(value = "Default 500; max 1000.")
@RequestParam(name = "limit", required = false)
limit: Int? = 500, //Default 500; max 1000.
+ @ApiParam(value = "The value cannot be greater than 60000")
@RequestParam(name = "recvWindow", required = false)
recvWindow: Long?, //The value cannot be greater than 60000
@RequestParam(name = "timestamp")
@@ -358,9 +421,20 @@ class AccountController(
consumes = [MediaType.APPLICATION_FORM_URLENCODED_VALUE],
produces = [MediaType.APPLICATION_JSON_VALUE]
)
+ @ApiResponse(
+ message = "OK",
+ code = 200,
+ examples = Example(
+ ExampleProperty(
+ value = "{ \"makerCommission\": 0, \"takerCommission\": 0, \"buyerCommission\": 0, \"sellerCommission\": 0, \"canTrade\": true, \"canWithdraw\": true, \"canDeposit\": true, \"updateTime\": 1628420513843, \"accountType\": \"SPOT\", \"balances\": [ { \"asset\": \"usdt\", \"free\": 1000, \"locked\": 0 } ], \"permissions\": [ \"SPOT\" ] }",
+ mediaType = "application/json"
+ )
+ )
+ )
suspend fun accountInfo(
@AuthenticationPrincipal
auth: CustomAuthToken,
+ @ApiParam(value = "The value cannot be greater than 60000")
@RequestParam(name = "recvWindow", required = false)
recvWindow: Long?, //The value cannot be greater than 60000
@RequestParam(name = "timestamp")
diff --git a/MatchingGateway/gateway-app/pom.xml b/MatchingGateway/gateway-app/pom.xml
index 06de82d8d..d4efe0ee5 100644
--- a/MatchingGateway/gateway-app/pom.xml
+++ b/MatchingGateway/gateway-app/pom.xml
@@ -84,6 +84,11 @@
bcprov-jdk15on
1.60
+
+ io.springfox
+ springfox-boot-starter
+ 3.0.0
+
diff --git a/MatchingGateway/gateway-app/src/main/kotlin/co/nilin/opex/app/MatchingGatewayApp.kt b/MatchingGateway/gateway-app/src/main/kotlin/co/nilin/opex/app/MatchingGatewayApp.kt
index c97f380a6..e1e67cbba 100644
--- a/MatchingGateway/gateway-app/src/main/kotlin/co/nilin/opex/app/MatchingGatewayApp.kt
+++ b/MatchingGateway/gateway-app/src/main/kotlin/co/nilin/opex/app/MatchingGatewayApp.kt
@@ -2,11 +2,101 @@ package co.nilin.opex.app
import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.boot.runApplication
+import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.ComponentScan
+import org.springframework.security.core.annotation.AuthenticationPrincipal
+import springfox.documentation.builders.ApiInfoBuilder
+import springfox.documentation.builders.OAuthBuilder
+import springfox.documentation.builders.PathSelectors.regex
+import springfox.documentation.builders.RequestParameterBuilder
+import springfox.documentation.service.*
+import springfox.documentation.spi.DocumentationType
+import springfox.documentation.spi.service.contexts.SecurityContext
+import springfox.documentation.spring.web.plugins.Docket
+import springfox.documentation.swagger.web.SecurityConfiguration
+import springfox.documentation.swagger.web.SecurityConfigurationBuilder
+import java.security.Principal
+import java.util.Collections.singletonList
@SpringBootApplication
@ComponentScan("co.nilin.opex")
-class MatchingGatewayApp
+class MatchingGatewayApp {
+ @Bean
+ fun opexMatchingGateway(): Docket? {
+ return Docket(DocumentationType.SWAGGER_2)
+ .groupName("opex-matching-gateway")
+ .apiInfo(apiInfo())
+ .select()
+ .paths(regex("^/actuator.*").negate())
+ .build()
+ .globalRequestParameters(
+ singletonList(
+ RequestParameterBuilder()
+ .name("content-type")
+ .description("content-type")
+ .`in`(ParameterType.HEADER)
+ .required(true)
+ .build()
+ )
+ )
+ .ignoredParameterTypes(AuthenticationPrincipal::class.java, Principal::class.java)
+ .useDefaultResponseMessages(false)
+ .securitySchemes(singletonList(oauth()))
+ .securityContexts(singletonList(securityContext()))
+ }
+
+ private fun apiInfo(): ApiInfo? {
+ return ApiInfoBuilder()
+ .title("OPEX API")
+ .description("Backend for opex exchange.")
+ .license("MIT License")
+ .licenseUrl("https://github.com/opexdev/Back-end/blob/feature/1-MVP/LICENSE")
+ .version("0.1")
+ .build()
+ }
+
+ @Bean
+ fun oauth(): SecurityScheme? {
+ return OAuthBuilder()
+ .name("opex")
+ .grantTypes(grantTypes())
+ .scopes(scopes())
+ .build()
+ }
+
+ fun scopes(): List? {
+ return emptyList()
+ }
+
+ fun grantTypes(): List? {
+ val tokenUrl = "http://localhost:8083/auth/realms/mixchange/protocol/openid-connect/token"
+ val grantType = ResourceOwnerPasswordCredentialsGrant(tokenUrl)
+ return singletonList(grantType)
+ }
+
+ @Bean
+ fun securityContext(): SecurityContext? {
+ val securityReference = SecurityReference.builder()
+ .reference("opex")
+ .scopes(emptyArray())
+ .build()
+ return SecurityContext.builder()
+ .securityReferences(singletonList(securityReference))
+ .operationSelector { true }
+ .build()
+ }
+
+ @Bean
+ fun securityInfo(): SecurityConfiguration? {
+ return SecurityConfigurationBuilder.builder()
+ .clientId("admin-cli")
+ .realm("mixchange")
+ .appName("opex")
+ .scopeSeparator(",")
+ .build()
+ }
+}
+
fun main(args: Array) {
- runApplication(*args)
+ runApplication(*args)
}
\ No newline at end of file
diff --git a/MatchingGateway/gateway-app/src/main/kotlin/co/nilin/opex/app/config/SecurityConfig.kt b/MatchingGateway/gateway-app/src/main/kotlin/co/nilin/opex/app/config/SecurityConfig.kt
index 69ef4adc7..0398b3bf4 100644
--- a/MatchingGateway/gateway-app/src/main/kotlin/co/nilin/opex/app/config/SecurityConfig.kt
+++ b/MatchingGateway/gateway-app/src/main/kotlin/co/nilin/opex/app/config/SecurityConfig.kt
@@ -22,6 +22,9 @@ class SecurityConfig {
.authorizeExchange()
.pathMatchers("/hello").permitAll()
.pathMatchers("/actuator/**").permitAll()
+ .pathMatchers("/swagger-ui/**").permitAll()
+ .pathMatchers("/swagger-resources/**").permitAll()
+ .pathMatchers("/v2/api-docs").permitAll()
.pathMatchers("/**").hasAuthority("SCOPE_trust")
.anyExchange().authenticated()
.and()
diff --git a/MatchingGateway/gateway-app/src/main/kotlin/co/nilin/opex/app/controller/OrderController.kt b/MatchingGateway/gateway-app/src/main/kotlin/co/nilin/opex/app/controller/OrderController.kt
index 7cec99df2..4cfa7b290 100644
--- a/MatchingGateway/gateway-app/src/main/kotlin/co/nilin/opex/app/controller/OrderController.kt
+++ b/MatchingGateway/gateway-app/src/main/kotlin/co/nilin/opex/app/controller/OrderController.kt
@@ -2,27 +2,34 @@ package co.nilin.opex.app.controller
import co.nilin.opex.app.inout.CreateOrderRequest
import co.nilin.opex.app.service.OrderService
-import co.nilin.opex.matching.core.model.MatchConstraint
-import co.nilin.opex.matching.core.model.OrderDirection
-import co.nilin.opex.matching.core.model.OrderType
-import co.nilin.opex.matching.core.model.Pair
-import co.nilin.opex.port.order.kafka.inout.OrderSubmitRequest
import co.nilin.opex.port.order.kafka.inout.OrderSubmitResult
-import co.nilin.opex.port.order.kafka.service.OrderSubmitter
-import org.springframework.web.bind.annotation.GetMapping
+import io.swagger.annotations.ApiResponse
+import io.swagger.annotations.Example
+import io.swagger.annotations.ExampleProperty
import org.springframework.web.bind.annotation.PostMapping
import org.springframework.web.bind.annotation.RequestBody
import org.springframework.web.bind.annotation.RestController
import java.security.Principal
-import java.util.*
@RestController
class OrderController(val orderService: OrderService) {
@PostMapping("/order")
- suspend fun submitNewOrder(principal: Principal, @RequestBody createOrderRequest: CreateOrderRequest): OrderSubmitResult {
+ @ApiResponse(
+ message = "OK",
+ code = 200,
+ examples = Example(
+ ExampleProperty(
+ value = "{ }",
+ mediaType = "application/json"
+ )
+ )
+ )
+ suspend fun submitNewOrder(
+ principal: Principal,
+ @RequestBody createOrderRequest: CreateOrderRequest
+ ): OrderSubmitResult {
createOrderRequest.uuid = principal.name
return orderService.submitNewOrder(createOrderRequest)
}
-
}
\ No newline at end of file
diff --git a/Wallet/wallet-app/pom.xml b/Wallet/wallet-app/pom.xml
index e8f736272..b1f90db12 100644
--- a/Wallet/wallet-app/pom.xml
+++ b/Wallet/wallet-app/pom.xml
@@ -107,6 +107,11 @@
bcprov-jdk15on
1.60
+
+ io.springfox
+ springfox-boot-starter
+ 3.0.0
+
diff --git a/Wallet/wallet-app/src/main/kotlin/co/nilin/opex/wallet/app/WalletApp.kt b/Wallet/wallet-app/src/main/kotlin/co/nilin/opex/wallet/app/WalletApp.kt
index 2c3b013d2..bb281db17 100644
--- a/Wallet/wallet-app/src/main/kotlin/co/nilin/opex/wallet/app/WalletApp.kt
+++ b/Wallet/wallet-app/src/main/kotlin/co/nilin/opex/wallet/app/WalletApp.kt
@@ -2,12 +2,103 @@ package co.nilin.opex.wallet.app
import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.boot.runApplication
+import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.ComponentScan
+import org.springframework.security.core.annotation.AuthenticationPrincipal
+import springfox.documentation.builders.ApiInfoBuilder
+import springfox.documentation.builders.OAuthBuilder
+import springfox.documentation.builders.PathSelectors.regex
+import springfox.documentation.builders.RequestParameterBuilder
+import springfox.documentation.service.*
+import springfox.documentation.spi.DocumentationType
+import springfox.documentation.spi.service.contexts.SecurityContext
+import springfox.documentation.spring.web.plugins.Docket
+import springfox.documentation.swagger.web.SecurityConfiguration
+import springfox.documentation.swagger.web.SecurityConfigurationBuilder
+import java.security.Principal
+import java.util.Collections.singletonList
@SpringBootApplication
@ComponentScan("co.nilin.opex")
-class WalletApp
+class WalletApp {
+ @Bean
+ fun opexWallet(): Docket? {
+ return Docket(DocumentationType.SWAGGER_2)
+ .groupName("opex-wallet")
+ .apiInfo(apiInfo())
+ .select()
+ .paths(regex("^/actuator.*").negate())
+ .build()
+ .globalRequestParameters(
+ singletonList(
+ RequestParameterBuilder()
+ .name("content-type")
+ .description("content-type")
+ .`in`(ParameterType.HEADER)
+ .required(true)
+ .build()
+ )
+ )
+ .ignoredParameterTypes(AuthenticationPrincipal::class.java, Principal::class.java)
+ .useDefaultResponseMessages(false)
+ .securitySchemes(singletonList(oauth()))
+ .securityContexts(singletonList(securityContext()))
+ }
+
+ private fun apiInfo(): ApiInfo? {
+ return ApiInfoBuilder()
+ .title("OPEX API")
+ .description("Backend for opex exchange.")
+ .license("MIT License")
+ .licenseUrl("https://github.com/opexdev/Back-end/blob/feature/1-MVP/LICENSE")
+ .version("0.1")
+ .build()
+ }
+
+ @Bean
+ fun oauth(): SecurityScheme? {
+ return OAuthBuilder()
+ .name("opex")
+ .grantTypes(grantTypes())
+ .scopes(scopes())
+ .build()
+ }
+
+ fun scopes(): List? {
+ return emptyList()
+ }
+
+ fun grantTypes(): List? {
+ val tokenUrl = "http://localhost:8083/auth/realms/mixchange/protocol/openid-connect/token"
+ val grantType = ResourceOwnerPasswordCredentialsGrant(tokenUrl)
+ return singletonList(grantType)
+ }
+
+ @Bean
+ fun securityContext(): SecurityContext? {
+ val securityReference = SecurityReference.builder()
+ .reference("opex")
+ .scopes(emptyArray())
+ .build()
+ return SecurityContext.builder()
+ .securityReferences(singletonList(securityReference))
+ .operationSelector {
+ it.requestMappingPattern().matches(Regex("^/(balanceOf|owner)/.*"))
+ }
+ .build()
+ }
+
+ @Bean
+ fun securityInfo(): SecurityConfiguration? {
+ return SecurityConfigurationBuilder.builder()
+ .clientId("admin-cli")
+ .realm("mixchange")
+ .appName("opex")
+ .scopeSeparator(",")
+ .build()
+ }
+}
fun main(args: Array) {
- runApplication(*args)
+ runApplication(*args)
}
diff --git a/Wallet/wallet-app/src/main/kotlin/co/nilin/opex/wallet/app/controller/BalanceController.kt b/Wallet/wallet-app/src/main/kotlin/co/nilin/opex/wallet/app/controller/BalanceController.kt
index 14ef1720a..714a9d207 100644
--- a/Wallet/wallet-app/src/main/kotlin/co/nilin/opex/wallet/app/controller/BalanceController.kt
+++ b/Wallet/wallet-app/src/main/kotlin/co/nilin/opex/wallet/app/controller/BalanceController.kt
@@ -2,6 +2,9 @@ package co.nilin.opex.wallet.app.controller
import co.nilin.opex.wallet.core.spi.WalletManager
import co.nilin.opex.wallet.core.spi.WalletOwnerManager
+import io.swagger.annotations.ApiResponse
+import io.swagger.annotations.Example
+import io.swagger.annotations.ExampleProperty
import org.slf4j.LoggerFactory
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.PathVariable
@@ -18,6 +21,16 @@ class BalanceController(
data class BalanceResponse(val balance: BigDecimal)
@GetMapping("/balanceOf/wallet_type/{wallet_type}/currency/{currency}")
+ @ApiResponse(
+ message = "OK",
+ code = 200,
+ examples = Example(
+ ExampleProperty(
+ value = "{ \"balance\": 990 }",
+ mediaType = "application/json"
+ )
+ )
+ )
suspend fun getBalance(
principal: Principal,
@PathVariable("currency") currency: String,
diff --git a/Wallet/wallet-app/src/main/kotlin/co/nilin/opex/wallet/app/controller/InquiryController.kt b/Wallet/wallet-app/src/main/kotlin/co/nilin/opex/wallet/app/controller/InquiryController.kt
index d52a520c8..1aff512a9 100644
--- a/Wallet/wallet-app/src/main/kotlin/co/nilin/opex/wallet/app/controller/InquiryController.kt
+++ b/Wallet/wallet-app/src/main/kotlin/co/nilin/opex/wallet/app/controller/InquiryController.kt
@@ -3,6 +3,9 @@ package co.nilin.opex.wallet.app.controller
import co.nilin.opex.wallet.core.model.Amount
import co.nilin.opex.wallet.core.spi.WalletManager
import co.nilin.opex.wallet.core.spi.WalletOwnerManager
+import io.swagger.annotations.ApiResponse
+import io.swagger.annotations.Example
+import io.swagger.annotations.ExampleProperty
import org.slf4j.LoggerFactory
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.PathVariable
@@ -17,6 +20,16 @@ class InquiryController(
data class BooleanResponse(val result: Boolean)
@GetMapping("{uuid}/wallet_type/{wallet_type}/can_withdraw/{amount}_{currency}")
+ @ApiResponse(
+ message = "OK",
+ code = 200,
+ examples = Example(
+ ExampleProperty(
+ value = "{ }",
+ mediaType = "application/json"
+ )
+ )
+ )
suspend fun canFulfill(
@PathVariable("uuid") uuid: String,
@PathVariable("currency") currency: String,
diff --git a/Wallet/wallet-app/src/main/kotlin/co/nilin/opex/wallet/app/controller/TransferController.kt b/Wallet/wallet-app/src/main/kotlin/co/nilin/opex/wallet/app/controller/TransferController.kt
index e8958454d..03f0d2a80 100644
--- a/Wallet/wallet-app/src/main/kotlin/co/nilin/opex/wallet/app/controller/TransferController.kt
+++ b/Wallet/wallet-app/src/main/kotlin/co/nilin/opex/wallet/app/controller/TransferController.kt
@@ -6,6 +6,9 @@ import co.nilin.opex.wallet.core.model.Amount
import co.nilin.opex.wallet.core.service.TransferService
import co.nilin.opex.wallet.core.spi.WalletManager
import co.nilin.opex.wallet.core.spi.WalletOwnerManager
+import io.swagger.annotations.ApiResponse
+import io.swagger.annotations.Example
+import io.swagger.annotations.ExampleProperty
import org.springframework.web.bind.annotation.PathVariable
import org.springframework.web.bind.annotation.PostMapping
import org.springframework.web.bind.annotation.RestController
@@ -17,6 +20,16 @@ class TransferController(
val transferService: TransferService, val walletManager: WalletManager, val walletOwnerManager: WalletOwnerManager
) {
@PostMapping("/transfer/{amount}_{symbol}/from/{senderUuid}_{senderWalletType}/to/{receiverUuid}_{receiverWalletType}")
+ @ApiResponse(
+ message = "OK",
+ code = 200,
+ examples = Example(
+ ExampleProperty(
+ value = "{ }",
+ mediaType = "application/json"
+ )
+ )
+ )
suspend fun transfer(
@PathVariable("symbol") symbol: String,
@PathVariable("senderWalletType") senderWalletType: String,
@@ -31,10 +44,19 @@ class TransferController(
val sourceWallet =
walletManager.findWalletByOwnerAndCurrencyAndType(sourceOwner, senderWalletType, Symbol(symbol))
?: throw IllegalArgumentException()
- val receiverOwner = walletOwnerManager.findWalletOwner(receiverUuid) ?: walletOwnerManager.createWalletOwner(senderUuid, "noset", "")
+ val receiverOwner = walletOwnerManager.findWalletOwner(receiverUuid) ?: walletOwnerManager.createWalletOwner(
+ senderUuid,
+ "noset",
+ ""
+ )
val receiverWallet = walletManager.findWalletByOwnerAndCurrencyAndType(
receiverOwner, receiverWalletType, Symbol(symbol)
- ) ?: walletManager.createWallet(receiverOwner, Amount(Symbol(symbol), BigDecimal.ZERO), Symbol(symbol), receiverWalletType)
+ ) ?: walletManager.createWallet(
+ receiverOwner,
+ Amount(Symbol(symbol), BigDecimal.ZERO),
+ Symbol(symbol),
+ receiverWalletType
+ )
return transferService.transfer(
TransferCommand(
sourceWallet,
diff --git a/Wallet/wallet-app/src/main/kotlin/co/nilin/opex/wallet/app/controller/WalletOwnerController.kt b/Wallet/wallet-app/src/main/kotlin/co/nilin/opex/wallet/app/controller/WalletOwnerController.kt
index 1940dd245..239ca052e 100644
--- a/Wallet/wallet-app/src/main/kotlin/co/nilin/opex/wallet/app/controller/WalletOwnerController.kt
+++ b/Wallet/wallet-app/src/main/kotlin/co/nilin/opex/wallet/app/controller/WalletOwnerController.kt
@@ -2,6 +2,9 @@ package co.nilin.opex.wallet.app.controller
import co.nilin.opex.wallet.core.spi.WalletManager
import co.nilin.opex.wallet.core.spi.WalletOwnerManager
+import io.swagger.annotations.ApiResponse
+import io.swagger.annotations.Example
+import io.swagger.annotations.ExampleProperty
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.RestController
import java.math.BigDecimal
@@ -26,6 +29,16 @@ class WalletOwnerController(
)
@GetMapping("/owner/wallet/all")
+ @ApiResponse(
+ message = "OK",
+ code = 200,
+ examples = Example(
+ ExampleProperty(
+ value = "{ }",
+ mediaType = "application/json"
+ )
+ )
+ )
suspend fun getAllWallets(principal: Principal): List {
val owner = walletOwnerManager.findWalletOwner(principal.name)
if (owner != null) {
@@ -38,6 +51,16 @@ class WalletOwnerController(
}
@GetMapping("/owner/limits")
+ @ApiResponse(
+ message = "OK",
+ code = 200,
+ examples = Example(
+ ExampleProperty(
+ value = "{ }",
+ mediaType = "application/json"
+ )
+ )
+ )
suspend fun getWalletOwnerLimits(principal: Principal): OwnerLimitsResponse {
val owner = walletOwnerManager.findWalletOwner(principal.name)
return if (owner != null)
@@ -45,5 +68,4 @@ class WalletOwnerController(
else
OwnerLimitsResponse(canTrade = false, canWithdraw = false, canDeposit = false)
}
-
}
\ No newline at end of file