From 0bb80d1162b72b2fd6260f869f882904e6336a50 Mon Sep 17 00:00:00 2001 From: Billy Brawner Date: Sat, 1 Jun 2019 14:46:04 -0700 Subject: [PATCH] Add account balance endpoint --- .../wbrawner/budgetserver/account/Account.kt | 4 +++- .../budgetserver/account/AccountController.kt | 17 ++++++++++++++++- .../budgetserver/config/SecurityConfig.kt | 5 ----- .../transaction/TransactionRepository.kt | 6 ++++++ src/main/resources/application.properties | 4 ++-- 5 files changed, 27 insertions(+), 9 deletions(-) diff --git a/src/main/kotlin/com/wbrawner/budgetserver/account/Account.kt b/src/main/kotlin/com/wbrawner/budgetserver/account/Account.kt index fc765f3..68437ba 100644 --- a/src/main/kotlin/com/wbrawner/budgetserver/account/Account.kt +++ b/src/main/kotlin/com/wbrawner/budgetserver/account/Account.kt @@ -3,7 +3,6 @@ package com.wbrawner.budgetserver.account import com.wbrawner.budgetserver.category.Category import com.wbrawner.budgetserver.transaction.Transaction import com.wbrawner.budgetserver.user.User -import com.wbrawner.budgetserver.user.UserResponse import java.util.* import javax.persistence.* @@ -12,6 +11,7 @@ data class Account( @Id @GeneratedValue(strategy = GenerationType.AUTO) val id: Long? = null, val name: String = "", val description: String? = null, + val currencyCode: String? = null, @OneToMany(mappedBy = "account") val transactions: Set = TreeSet(), @OneToMany(mappedBy = "account") val categories: Set = TreeSet(), @ManyToMany val users: Set = mutableSetOf(), @@ -25,3 +25,5 @@ data class UpdateAccountRequest(val name: String?, val description: String?, val data class AccountResponse(val id: Long, val name: String, val description: String?, val users: List) { constructor(account: Account) : this(account.id!!, account.name, account.description, account.users.map { it.id!! }) } + +data class AccountBalanceResponse(val id: Long, val balance: Long) diff --git a/src/main/kotlin/com/wbrawner/budgetserver/account/AccountController.kt b/src/main/kotlin/com/wbrawner/budgetserver/account/AccountController.kt index d480c45..98ce58d 100644 --- a/src/main/kotlin/com/wbrawner/budgetserver/account/AccountController.kt +++ b/src/main/kotlin/com/wbrawner/budgetserver/account/AccountController.kt @@ -1,6 +1,7 @@ package com.wbrawner.budgetserver.account import com.wbrawner.budgetserver.getCurrentUser +import com.wbrawner.budgetserver.transaction.TransactionRepository import com.wbrawner.budgetserver.user.UserRepository import io.swagger.annotations.Api import io.swagger.annotations.ApiOperation @@ -15,7 +16,11 @@ import javax.transaction.Transactional @RestController @RequestMapping("/accounts") @Api(value = "Accounts", tags = ["Accounts"], authorizations = [Authorization("basic")]) -class AccountController @Autowired constructor(private val accountRepository: AccountRepository, private val userRepository: UserRepository) { +class AccountController @Autowired constructor( + private val accountRepository: AccountRepository, + private val transactionRepository: TransactionRepository, + private val userRepository: UserRepository +) { @Transactional @GetMapping("", produces = [MediaType.APPLICATION_JSON_VALUE]) @ApiOperation(value = "getAccounts", nickname = "getAccounts", tags = ["Accounts"]) @@ -36,6 +41,16 @@ class AccountController @Autowired constructor(private val accountRepository: Ac ResponseEntity.ok(AccountResponse(it)) } ?: ResponseEntity.notFound().build() + @Transactional + @GetMapping("/{id}/balance", produces = [MediaType.APPLICATION_JSON_VALUE]) + @ApiOperation(value = "getAccountBalance", nickname = "getAccountBalance", tags = ["Accounts"]) + fun getAccountBalance(@PathVariable id: Long): ResponseEntity = + accountRepository.findByUsersContainsAndId(getCurrentUser()!!, id) + .orElse(null) + ?.let { + ResponseEntity.ok(AccountBalanceResponse(it.id!!, transactionRepository.sumBalanceByAccount(it))) + } ?: ResponseEntity.notFound().build() + @PostMapping("/new", consumes = [MediaType.APPLICATION_JSON_VALUE], produces = [MediaType.APPLICATION_JSON_VALUE]) @ApiOperation(value = "newAccount", nickname = "newAccount", tags = ["Accounts"]) fun newAccount(@RequestBody request: NewAccountRequest): ResponseEntity { diff --git a/src/main/kotlin/com/wbrawner/budgetserver/config/SecurityConfig.kt b/src/main/kotlin/com/wbrawner/budgetserver/config/SecurityConfig.kt index f31e5de..b7974fe 100644 --- a/src/main/kotlin/com/wbrawner/budgetserver/config/SecurityConfig.kt +++ b/src/main/kotlin/com/wbrawner/budgetserver/config/SecurityConfig.kt @@ -11,7 +11,6 @@ import org.springframework.security.config.annotation.authentication.builders.Au import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity import org.springframework.security.config.annotation.method.configuration.GlobalMethodSecurityConfiguration import org.springframework.security.config.annotation.web.builders.HttpSecurity -import org.springframework.security.config.annotation.web.builders.WebSecurity import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder @@ -52,10 +51,6 @@ constructor( auth!!.authenticationProvider(authenticationProvider) } - override fun configure(web: WebSecurity?) { - web?.ignoring()?.antMatchers("/v2/api-docs") - } - @Throws(Exception::class) public override fun configure(http: HttpSecurity) { http.authorizeRequests() diff --git a/src/main/kotlin/com/wbrawner/budgetserver/transaction/TransactionRepository.kt b/src/main/kotlin/com/wbrawner/budgetserver/transaction/TransactionRepository.kt index 79e8511..0746ec2 100644 --- a/src/main/kotlin/com/wbrawner/budgetserver/transaction/TransactionRepository.kt +++ b/src/main/kotlin/com/wbrawner/budgetserver/transaction/TransactionRepository.kt @@ -3,6 +3,7 @@ package com.wbrawner.budgetserver.transaction import com.wbrawner.budgetserver.account.Account import com.wbrawner.budgetserver.category.Category import org.springframework.data.domain.Pageable +import org.springframework.data.jpa.repository.Query import org.springframework.data.repository.PagingAndSortingRepository import java.util.* @@ -10,4 +11,9 @@ interface TransactionRepository: PagingAndSortingRepository { fun findAllByAccount(account: Account, pageable: Pageable): List fun findByAccountAndId(account: Account, id: Long): Optional fun findAllByAccountAndCategory(account: Account, category: Category): List + @Query( + nativeQuery = true, + value = "SELECT (COALESCE((SELECT SUM(amount) from transaction WHERE is_expense = 0), 0)) - (COALESCE((SELECT SUM(amount) from transaction WHERE is_expense = 1), 0));" + ) + fun sumBalanceByAccount(account: Account): Long } \ No newline at end of file diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index 0951dc6..fb4bb76 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -1,6 +1,6 @@ -spring.jpa.hibernate.ddl-auto=create-drop +spring.jpa.hibernate.ddl-auto=update spring.datasource.url=jdbc:mysql://localhost:3306/budget spring.datasource.username=budget spring.datasource.password=budget spring.datasource.driver-class-name=com.mysql.jdbc.Driver -spring.profiles.active=dev +spring.profiles.active=prod