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