This commit is contained in:
Vladimir Voronin
2025-01-07 13:15:08 +03:00
parent 2506e6081f
commit 8b440ad9e8
45 changed files with 51 additions and 1048 deletions

View File

@@ -1,20 +0,0 @@
package space.luminic.budgerapp.configs
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor
import java.util.concurrent.Executor
//
//@Configuration
//class AsyncConfig {
// @Bean(name = ["taskExecutor"])
// fun taskExecutor(): Executor {
// val executor = ThreadPoolTaskExecutor()
// executor.corePoolSize = 5
// executor.maxPoolSize = 10
// executor.setQueueCapacity(25)
// executor.setThreadNamePrefix("Async-")
// executor.initialize()
// return executor
// }
//}

View File

@@ -1,18 +0,0 @@
package space.luminic.budgerapp.configs
import org.springframework.context.annotation.Configuration
import org.springframework.web.reactive.config.CorsRegistry
import org.springframework.web.reactive.config.WebFluxConfigurer
@Configuration
class CorsConfig : WebFluxConfigurer {
override fun addCorsMappings(registry: CorsRegistry) {
registry.addMapping("/**") // Разрешить все пути
.allowedOrigins("http://localhost:5173") // Разрешить домен localhost:5173
.allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS", "PATCH") // Разрешить методы
.allowedHeaders("*") // Разрешить все заголовки
.allowCredentials(true) // Разрешить передачу cookies
}
}

View File

@@ -1,44 +0,0 @@
//package space.luminic.budgerapp.configs
//import org.springframework.http.HttpHeaders
//import org.springframework.http.HttpStatus
//import org.springframework.security.authentication.UsernamePasswordAuthenticationToken
//import org.springframework.security.core.context.SecurityContextHolder
//import org.springframework.stereotype.Component
//import org.springframework.web.server.ServerWebExchange
//import org.springframework.web.server.WebFilter
//import org.springframework.web.server.WebFilterChain
//import reactor.core.publisher.Mono
//import space.luminic.budgerapp.services.AuthService
//import space.luminic.budgerapp.services.TokenService
//import space.luminic.budgerapp.utils.JWTUtil
//
//@Component
//class JWTAuthFilter(
// private val jwtUtil: JWTUtil,
// private val authService: AuthService
//) : WebFilter {
//
// override fun filter(exchange: ServerWebExchange, chain: WebFilterChain): Mono<Void> {
// val authHeader = exchange.request.headers.getFirst(HttpHeaders.AUTHORIZATION)
//
// if (authHeader != null && authHeader.startsWith("Bearer ")) {
// val token = authHeader.substring(7)
// return Mono.just(token)
// .filter { authService.isTokenValid(it) }
// .flatMap { validToken ->
// val username = jwtUtil.validateToken(validToken)
// if (username != null) {
// val auth = UsernamePasswordAuthenticationToken(username, null, emptyList())
// SecurityContextHolder.getContext().authentication = auth
// }
// chain.filter(exchange)
// }
// .onErrorResume {
// exchange.response.statusCode = HttpStatus.UNAUTHORIZED
// exchange.response.setComplete()
// }
// }
//
// return chain.filter(exchange)
// }
//}

View File

@@ -1,33 +0,0 @@
//package space.luminic.budgerapp.configs
//
//import org.springframework.security.authentication.UsernamePasswordAuthenticationToken
//import org.springframework.security.authentication.ReactiveAuthenticationManager
//import org.springframework.security.core.Authentication
//import org.springframework.security.core.userdetails.ReactiveUserDetailsService
//import org.springframework.security.crypto.password.PasswordEncoder
//import org.springframework.stereotype.Component
//import reactor.core.publisher.Mono
//import space.luminic.budgerapp.services.CustomReactiveUserDetailsService
//import space.luminic.budgerapp.services.TokenService
//import space.luminic.budgerapp.utils.JWTUtil
//
//@Component
//class JWTReactiveAuthenticationManager(
// private val passwordEncoder: PasswordEncoder,
// private val userDetailsService: CustomReactiveUserDetailsService
//) : ReactiveAuthenticationManager {
//
//
// override fun authenticate(authentication: Authentication): Mono<Authentication> {
// val username = authentication.principal as String
// val password = authentication.credentials as String
//
// return userDetailsService.findByUsername(username)
// .filter { userDetails -> password == passwordEncoder.encode(userDetails.password) } // Пример проверки пароля
// .map { userDetails ->
// UsernamePasswordAuthenticationToken(userDetails, null, userDetails.authorities)
// }
// }
//
//
//}

View File

@@ -1,5 +1,6 @@
package space.luminic.budgerapp.configs package space.luminic.budgerapp.configs
import org.springframework.context.annotation.Bean import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration import org.springframework.context.annotation.Configuration
import org.springframework.http.HttpMethod import org.springframework.http.HttpMethod
@@ -8,20 +9,15 @@ import org.springframework.security.config.web.server.ServerHttpSecurity
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder
import org.springframework.security.crypto.password.PasswordEncoder import org.springframework.security.crypto.password.PasswordEncoder
import org.springframework.security.web.server.SecurityWebFilterChain import org.springframework.security.web.server.SecurityWebFilterChain
import space.luminic.budgerapp.controllers.CustomAuthenticationEntryPoint
import space.luminic.budgerapp.services.AuthService
@Configuration @Configuration
class SecurityConfig( class SecurityConfig(
private val authService: AuthService
) { ) {
@Bean @Bean
fun securityWebFilterChain( fun securityWebFilterChain(
http: ServerHttpSecurity, http: ServerHttpSecurity,
bearerTokenFilter: BearerTokenFilter, bearerTokenFilter: BearerTokenFilter
customAuthenticationEntryPoint: CustomAuthenticationEntryPoint
): SecurityWebFilterChain { ): SecurityWebFilterChain {
return http return http
.csrf { it.disable() } .csrf { it.disable() }

View File

@@ -1,22 +1,17 @@
package space.luminic.budgerapp.controllers package space.luminic.budgerapp.controllers
import org.springframework.http.ResponseEntity
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken
import org.springframework.security.core.Authentication
import org.springframework.web.bind.annotation.* import org.springframework.web.bind.annotation.*
import reactor.core.publisher.Mono import reactor.core.publisher.Mono
//import space.luminic.budgerapp.configs.JWTReactiveAuthenticationManager
import space.luminic.budgerapp.models.User import space.luminic.budgerapp.models.User
import space.luminic.budgerapp.services.AuthService import space.luminic.budgerapp.services.AuthService
import space.luminic.budgerapp.services.UserService import space.luminic.budgerapp.services.UserService
import space.luminic.budgerapp.utils.JWTUtil
@RestController @RestController
@RequestMapping("/auth") @RequestMapping("/auth")
class AuthController( class AuthController(
// private val authenticationManager: JWTReactiveAuthenticationManager,
private val jwtUtil: JWTUtil,
private val userService: UserService, private val userService: UserService,
private val authService: AuthService private val authService: AuthService
) { ) {
@@ -34,11 +29,6 @@ class AuthController(
.flatMap { username -> .flatMap { username ->
userService.getByUserNameWoPass(username.username) userService.getByUserNameWoPass(username.username)
} }
// return mapOf(
// "username" to authentication.name,
// "details" to authentication.details,
// "roles" to authentication.authorities.map { it.authority }
// )
} }
} }

View File

@@ -1,14 +1,12 @@
package space.luminic.budgerapp.controllers package space.luminic.budgerapp.controllers
import org.slf4j.LoggerFactory import org.slf4j.LoggerFactory
import org.springframework.http.HttpStatus
import org.springframework.http.ResponseEntity import org.springframework.http.ResponseEntity
import org.springframework.web.bind.annotation.DeleteMapping import org.springframework.web.bind.annotation.DeleteMapping
import org.springframework.web.bind.annotation.GetMapping import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.PathVariable import org.springframework.web.bind.annotation.PathVariable
import org.springframework.web.bind.annotation.PostMapping import org.springframework.web.bind.annotation.PostMapping
import org.springframework.web.bind.annotation.RequestBody import org.springframework.web.bind.annotation.RequestBody
import org.springframework.web.bind.annotation.RequestMapping import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.RequestParam import org.springframework.web.bind.annotation.RequestParam
import org.springframework.web.bind.annotation.RestController import org.springframework.web.bind.annotation.RestController
@@ -18,11 +16,7 @@ import space.luminic.budgerapp.models.Budget
import space.luminic.budgerapp.models.BudgetDTO import space.luminic.budgerapp.models.BudgetDTO
import space.luminic.budgerapp.models.Transaction import space.luminic.budgerapp.models.Transaction
import space.luminic.budgerapp.models.Warn import space.luminic.budgerapp.models.Warn
import space.luminic.budgerapp.services.BudgetService import space.luminic.budgerapp.services.BudgetService
import space.luminic.budgerapp.services.CacheInspector
import java.math.BigDecimal
import java.sql.Date
import java.time.LocalDate import java.time.LocalDate
@@ -41,7 +35,7 @@ class BudgetController(
@GetMapping("/{id}") @GetMapping("/{id}")
fun getBudget(@PathVariable id: String): Mono<BudgetDTO> { fun getBudget(@PathVariable id: String): Mono<BudgetDTO> {
// logger.info(cacheInspector.getCacheContent("budgets").toString())
return budgetService.getBudget(id) return budgetService.getBudget(id)
} }
@@ -88,11 +82,7 @@ class BudgetController(
} }
} }
@GetMapping("/recalc-categories")
fun recalcCategories(): Mono<Void> {
return budgetService.recalcBudgetCategory()
}
@GetMapping("/{id}/warns") @GetMapping("/{id}/warns")
fun budgetWarns(@PathVariable id: String, @RequestParam hidden: Boolean? = null): Mono<List<Warn>> { fun budgetWarns(@PathVariable id: String, @RequestParam hidden: Boolean? = null): Mono<List<Warn>> {
@@ -101,7 +91,7 @@ class BudgetController(
@PostMapping("/{id}/warns/{warnId}/hide") @PostMapping("/{id}/warns/{warnId}/hide")
fun setWarnHide(@PathVariable id: String, @PathVariable warnId: String): Mono<Warn> { fun setWarnHide(@PathVariable id: String, @PathVariable warnId: String): Mono<Warn> {
return budgetService.hideWarn(id, warnId) return budgetService.hideWarn( warnId)
} }

View File

@@ -27,12 +27,8 @@ class CategoriesController(
private val logger = LoggerFactory.getLogger(javaClass) private val logger = LoggerFactory.getLogger(javaClass)
@GetMapping() @GetMapping()
fun getCategories(): ResponseEntity<Any> { fun getCategories(): Mono<List<Category>> {
return try { return categoryService.getCategories()
ResponseEntity.ok(categoryService.getCategories())
} catch (e: Exception) {
ResponseEntity(HttpClientErrorException(HttpStatus.INTERNAL_SERVER_ERROR), HttpStatus.INTERNAL_SERVER_ERROR)
}
} }
@@ -40,7 +36,7 @@ class CategoriesController(
fun getCategoriesTypes(): ResponseEntity<Any> { fun getCategoriesTypes(): ResponseEntity<Any> {
return try { return try {
ResponseEntity.ok(categoryService.getCategoryTypes()) ResponseEntity.ok(categoryService.getCategoryTypes())
}catch (e: Exception) { } catch (e: Exception) {
ResponseEntity(HttpClientErrorException(HttpStatus.INTERNAL_SERVER_ERROR), HttpStatus.INTERNAL_SERVER_ERROR) ResponseEntity(HttpClientErrorException(HttpStatus.INTERNAL_SERVER_ERROR), HttpStatus.INTERNAL_SERVER_ERROR)
} }

View File

@@ -1,34 +0,0 @@
package space.luminic.budgerapp.controllers
import com.fasterxml.jackson.databind.ObjectMapper
import org.springframework.http.HttpStatus
import org.springframework.http.MediaType
import org.springframework.security.core.AuthenticationException
import org.springframework.security.web.server.ServerAuthenticationEntryPoint
import org.springframework.stereotype.Component
import org.springframework.web.server.ServerWebExchange
import reactor.core.publisher.Mono
import java.util.*
@Component
class CustomAuthenticationEntryPoint : ServerAuthenticationEntryPoint {
override fun commence(
exchange: ServerWebExchange,
ex: AuthenticationException
): Mono<Void> {
val response = exchange.response
response.statusCode = HttpStatus.UNAUTHORIZED
response.headers.contentType = MediaType.APPLICATION_JSON
val body = mapOf(
"timestamp" to Date(),
"status" to HttpStatus.UNAUTHORIZED.value(),
"error" to "Unauthorized",
"message" to ex.message,
"path" to exchange.request.path.value()
)
val buffer = response.bufferFactory().wrap(ObjectMapper().writeValueAsBytes(body))
return response.writeWith(Mono.just(buffer))
}
}

View File

@@ -3,11 +3,8 @@ package space.luminic.budgerapp.controllers
import org.springframework.http.HttpStatus import org.springframework.http.HttpStatus
import org.springframework.http.ResponseEntity import org.springframework.http.ResponseEntity
import org.springframework.http.server.reactive.ServerHttpRequest import org.springframework.http.server.reactive.ServerHttpRequest
import org.springframework.security.core.AuthenticationException
import org.springframework.web.bind.annotation.ExceptionHandler import org.springframework.web.bind.annotation.ExceptionHandler
import org.springframework.web.bind.annotation.RestControllerAdvice import org.springframework.web.bind.annotation.RestControllerAdvice
import org.springframework.web.reactive.function.server.ServerRequest
import org.springframework.web.server.ServerWebExchange import org.springframework.web.server.ServerWebExchange
import reactor.core.publisher.Mono import reactor.core.publisher.Mono
import space.luminic.budgerapp.configs.AuthException import space.luminic.budgerapp.configs.AuthException
@@ -77,7 +74,7 @@ class GlobalExceptionHandler {
exchange: ServerWebExchange exchange: ServerWebExchange
): Mono<ResponseEntity<Map<String, Any?>>?> { ): Mono<ResponseEntity<Map<String, Any?>>?> {
e.printStackTrace() e.printStackTrace()
val errorBody = mapOf("error" to e.message.orEmpty())
return Mono.just( return Mono.just(
ResponseEntity( ResponseEntity(
constructErrorBody( constructErrorBody(
@@ -96,14 +93,8 @@ class GlobalExceptionHandler {
exchange: ServerWebExchange exchange: ServerWebExchange
): Mono<out ResponseEntity<out Map<String, Any?>>?> { ): Mono<out ResponseEntity<out Map<String, Any?>>?> {
e.printStackTrace() e.printStackTrace()
// val errorBody = mapOf("error" to "An unexpected error occurred")
val errorResponse = mapOf(
"timestamp" to System.currentTimeMillis(),
"status" to HttpStatus.INTERNAL_SERVER_ERROR.value(),
"error" to "Internal Server Error",
"message" to e.message,
"path" to exchange.request.path.value()
)
return Mono.just( return Mono.just(
ResponseEntity( ResponseEntity(
constructErrorBody( constructErrorBody(

View File

@@ -5,11 +5,10 @@ import org.springframework.boot.web.reactive.error.ErrorAttributes
import org.springframework.context.ApplicationContext import org.springframework.context.ApplicationContext
import org.springframework.core.annotation.Order import org.springframework.core.annotation.Order
import org.springframework.http.MediaType import org.springframework.http.MediaType
import org.springframework.http.codec.ServerCodecConfigurer
import org.springframework.stereotype.Component import org.springframework.stereotype.Component
import org.springframework.web.reactive.function.BodyInserters import org.springframework.web.reactive.function.BodyInserters
import org.springframework.web.reactive.function.server.* import org.springframework.web.reactive.function.server.*
import org.springframework.web.reactive.result.view.ViewResolver
import org.springframework.http.codec.ServerCodecConfigurer
import reactor.core.publisher.Mono import reactor.core.publisher.Mono
@Component @Component
@@ -45,7 +44,5 @@ class GlobalErrorWebExceptionHandler(
.body(BodyInserters.fromValue(errorAttributesMap)) .body(BodyInserters.fromValue(errorAttributesMap))
} }
private fun getHttpStatus(errorAttributes: Map<String, Any>): Int {
return errorAttributes["status"] as Int
}
} }

View File

@@ -1,6 +1,5 @@
package space.luminic.budgerapp.controllers package space.luminic.budgerapp.controllers
import org.springframework.http.ResponseEntity
import org.springframework.web.bind.annotation.DeleteMapping import org.springframework.web.bind.annotation.DeleteMapping
import org.springframework.web.bind.annotation.GetMapping import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.PathVariable import org.springframework.web.bind.annotation.PathVariable
@@ -47,8 +46,5 @@ class RecurrentController (
} }
@GetMapping("/transfer")
fun transferRecurrents() : ResponseEntity<Any> {
return ResponseEntity.ok(recurrentService.transferRecurrents())
}
} }

View File

@@ -1,19 +0,0 @@
package space.luminic.budgerapp.controllers
import org.springframework.http.ResponseEntity
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.RestController
@RestController
@RequestMapping("/push")
class SubsController {
@GetMapping("/vapid")
fun getVapid(): ResponseEntity<String> {
return ResponseEntity.ok("BKmMyBUhpkcmzYWcYsjH_spqcy0zf_8eVtZo60f7949TgLztCmv3YD0E_vtV2dTfECQ4sdLdPK3ICDcyOkCqr84")
}
}

View File

@@ -2,6 +2,7 @@ package space.luminic.budgerapp.controllers
import org.springframework.http.ResponseEntity import org.springframework.http.ResponseEntity
import org.springframework.security.core.Authentication import org.springframework.security.core.Authentication
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.PostMapping import org.springframework.web.bind.annotation.PostMapping
import org.springframework.web.bind.annotation.RequestBody import org.springframework.web.bind.annotation.RequestBody
import org.springframework.web.bind.annotation.RequestMapping import org.springframework.web.bind.annotation.RequestMapping
@@ -21,6 +22,11 @@ class SubscriptionController(
) { ) {
@GetMapping("/vapid")
fun getVapid(): ResponseEntity<String> {
return ResponseEntity.ok("BKmMyBUhpkcmzYWcYsjH_spqcy0zf_8eVtZo60f7949TgLztCmv3YD0E_vtV2dTfECQ4sdLdPK3ICDcyOkCqr84")
}
@PostMapping("/subscribe") @PostMapping("/subscribe")
fun subscribe( fun subscribe(
@RequestBody subscription: SubscriptionDTO, @RequestBody subscription: SubscriptionDTO,

View File

@@ -1,12 +1,9 @@
package space.luminic.budgerapp.controllers package space.luminic.budgerapp.controllers
import org.springframework.data.mongodb.core.aggregation.AggregationResults
import org.springframework.http.HttpStatus import org.springframework.http.HttpStatus
import org.springframework.http.ResponseEntity import org.springframework.http.ResponseEntity
import org.springframework.security.core.Authentication
import org.springframework.web.bind.annotation.DeleteMapping import org.springframework.web.bind.annotation.DeleteMapping
import org.springframework.web.bind.annotation.GetMapping import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.PatchMapping
import org.springframework.web.bind.annotation.PathVariable import org.springframework.web.bind.annotation.PathVariable
import org.springframework.web.bind.annotation.PostMapping import org.springframework.web.bind.annotation.PostMapping
import org.springframework.web.bind.annotation.PutMapping import org.springframework.web.bind.annotation.PutMapping
@@ -23,7 +20,7 @@ import space.luminic.budgerapp.services.TransactionService
@RestController @RestController
@RequestMapping("/transactions") @RequestMapping("/transactions")
class TransactionController(private val transactionService: TransactionService, val budgetService: BudgetService) { class TransactionController(private val transactionService: TransactionService) {
@GetMapping @GetMapping
@@ -91,17 +88,6 @@ class TransactionController(private val transactionService: TransactionService,
} }
// @PatchMapping("/{id}/set-done")
// fun setTransactionDoneStatus(@PathVariable id: String, @RequestBody transaction: Transaction): ResponseEntity<Any> {
// try {
// transactionService.setTransactionDone(transaction)
// return ResponseEntity.ok(true)
// } catch (e: Exception) {
// e.printStackTrace()
// return ResponseEntity(e.message, HttpStatus.INTERNAL_SERVER_ERROR)
// }
// }
@GetMapping("/{id}/child") @GetMapping("/{id}/child")
fun getChildTransactions(@PathVariable id: String): ResponseEntity<Any> { fun getChildTransactions(@PathVariable id: String): ResponseEntity<Any> {
return ResponseEntity.ok(transactionService.getChildTransaction(id)) return ResponseEntity.ok(transactionService.getChildTransaction(id))
@@ -112,10 +98,7 @@ class TransactionController(private val transactionService: TransactionService,
return ResponseEntity.ok(transactionService.getAverageSpendingByCategory()) return ResponseEntity.ok(transactionService.getAverageSpendingByCategory())
} }
// @GetMapping("/_transfer")
// fun transfer(): ResponseEntity<Any> {
// return ResponseEntity.ok(transactionService.transferTransactions())
// }
@GetMapping("/types") @GetMapping("/types")
fun getTypes(): ResponseEntity<Any> { fun getTypes(): ResponseEntity<Any> {
@@ -126,10 +109,6 @@ class TransactionController(private val transactionService: TransactionService,
} }
} }
// @GetMapping("/test")
// fun getSome(): List<Map<*, *>?> {
// return transactionService.getPlannedForBudget(budgetService.getBudget("675ae567f232c35272f8a692")!!)
// }
} }

View File

@@ -1,37 +0,0 @@
package space.luminic.budgerapp.controllers
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.RestController
import reactor.core.publisher.Mono
import space.luminic.budgerapp.models.Budget
import space.luminic.budgerapp.models.Category
import space.luminic.budgerapp.models.Recurrent
import space.luminic.budgerapp.models.Transaction
import space.luminic.budgerapp.services.TransferService
@RestController
@RequestMapping("/transfer")
class TransferController(private val transferService: TransferService) {
@GetMapping("/transactions")
fun transferTransactions(): Mono<List<Transaction>> {
return transferService.getTransactions()
}
@GetMapping("/categories")
fun transferCategories(): Mono<List<Category>> {
return transferService.getCategories()
}
@GetMapping("/recurrents")
fun recurrentTransactions(): Mono<List<Recurrent>> {
return transferService.recurrents()
}
@GetMapping("/budgets")
fun budgets(): Mono<List<Budget>> {
return transferService.transferBudgets()
}
}

View File

@@ -1,7 +1,6 @@
package space.luminic.budgerapp.controllers package space.luminic.budgerapp.controllers
import org.slf4j.LoggerFactory import org.slf4j.LoggerFactory
import org.springframework.http.ResponseEntity
import org.springframework.web.bind.annotation.GetMapping import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.PathVariable import org.springframework.web.bind.annotation.PathVariable
import org.springframework.web.bind.annotation.RequestMapping import org.springframework.web.bind.annotation.RequestMapping
@@ -24,12 +23,8 @@ class UsersController(val userService: UserService) {
@GetMapping("/") @GetMapping("/")
fun getUsers(): Mono<List<User>> { fun getUsers(): Mono<List<User>> {
// return ResponseEntity.ok("teset")
return userService.getUsers() return userService.getUsers()
} }
//
// @GetMapping("/regen")
// fun regenUsers(): ResponseEntity<Any> {
// return ResponseEntity.ok(userService.regenPass())
// }
} }

View File

@@ -2,18 +2,12 @@ package space.luminic.budgerapp.repos
import org.springframework.data.domain.Sort import org.springframework.data.domain.Sort
import org.springframework.data.mongodb.core.aggregation.SortOperation
import org.springframework.data.mongodb.repository.MongoRepository
import org.springframework.data.mongodb.repository.Query
import org.springframework.data.mongodb.repository.ReactiveMongoRepository import org.springframework.data.mongodb.repository.ReactiveMongoRepository
import org.springframework.data.repository.PagingAndSortingRepository
import org.springframework.stereotype.Repository import org.springframework.stereotype.Repository
import reactor.core.publisher.Flux import reactor.core.publisher.Flux
import reactor.core.publisher.Mono import reactor.core.publisher.Mono
import space.luminic.budgerapp.models.Budget import space.luminic.budgerapp.models.Budget
import java.time.LocalDate import java.time.LocalDate
import java.util.Date
import java.util.Optional
@Repository @Repository
interface BudgetRepo: ReactiveMongoRepository<Budget, String> { interface BudgetRepo: ReactiveMongoRepository<Budget, String> {

View File

@@ -1,11 +1,9 @@
package space.luminic.budgerapp.repos package space.luminic.budgerapp.repos
import org.springframework.data.mongodb.repository.MongoRepository
import org.springframework.data.mongodb.repository.ReactiveMongoRepository import org.springframework.data.mongodb.repository.ReactiveMongoRepository
import org.springframework.stereotype.Repository import org.springframework.stereotype.Repository
import reactor.core.publisher.Mono import reactor.core.publisher.Mono
import space.luminic.budgerapp.models.Category import space.luminic.budgerapp.models.Category
import java.util.Optional
@Repository @Repository
interface CategoryRepo : ReactiveMongoRepository<Category, String> { interface CategoryRepo : ReactiveMongoRepository<Category, String> {

View File

@@ -1,11 +0,0 @@
package space.luminic.budgerapp.repos
import org.springframework.data.mongodb.repository.MongoRepository
import org.springframework.stereotype.Repository
import space.luminic.budgerapp.models.Category
@Repository
interface CategoryRepoOld: MongoRepository<Category, String> {
fun findByName(name: String): Category?
}

View File

@@ -1,7 +1,5 @@
package space.luminic.budgerapp.repos package space.luminic.budgerapp.repos
import org.bson.types.ObjectId
import org.springframework.data.mongodb.repository.MongoRepository
import org.springframework.data.mongodb.repository.ReactiveMongoRepository import org.springframework.data.mongodb.repository.ReactiveMongoRepository
import org.springframework.stereotype.Repository import org.springframework.stereotype.Repository
import space.luminic.budgerapp.models.Recurrent import space.luminic.budgerapp.models.Recurrent

View File

@@ -1,6 +0,0 @@
package space.luminic.budgerapp.repos
import org.springframework.data.mongodb.repository.MongoRepository
import space.luminic.budgerapp.models.Recurrent
interface RecurrentRepoOld : MongoRepository<Recurrent, String>

View File

@@ -1,7 +1,6 @@
package space.luminic.budgerapp.repos package space.luminic.budgerapp.repos
import org.springframework.data.mongodb.repository.MongoRepository
import org.springframework.data.mongodb.repository.ReactiveMongoRepository import org.springframework.data.mongodb.repository.ReactiveMongoRepository
import org.springframework.stereotype.Repository import org.springframework.stereotype.Repository
import space.luminic.budgerapp.models.Subscription import space.luminic.budgerapp.models.Subscription

View File

@@ -1,17 +1,15 @@
package space.luminic.budgerapp.repos package space.luminic.budgerapp.repos
import org.springframework.data.mongodb.repository.MongoRepository
import org.springframework.data.mongodb.repository.ReactiveMongoRepository import org.springframework.data.mongodb.repository.ReactiveMongoRepository
import org.springframework.stereotype.Repository import org.springframework.stereotype.Repository
import reactor.core.publisher.Mono import reactor.core.publisher.Mono
import space.luminic.budgerapp.models.Token import space.luminic.budgerapp.models.Token
import space.luminic.budgerapp.models.TokenStatus
import java.time.LocalDateTime import java.time.LocalDateTime
@Repository @Repository
interface TokenRepo: ReactiveMongoRepository<Token, String> { interface TokenRepo: ReactiveMongoRepository<Token, String> {
fun findByToken(token: String): Mono<Token> fun findByToken(token: String): Mono<Token>
fun findByUsernameAndStatus(username: String, status: TokenStatus): Mono<List<Token>>
fun deleteByExpiresAtBefore(dateTime: LocalDateTime) fun deleteByExpiresAtBefore(dateTime: LocalDateTime)
} }

View File

@@ -1,20 +0,0 @@
package space.luminic.budgerapp.repos
import org.bson.types.ObjectId
import org.springframework.data.mongodb.repository.MongoRepository
import org.springframework.data.mongodb.repository.ReactiveMongoRepository
import org.springframework.stereotype.Repository
import space.luminic.budgerapp.models.Transaction
import java.util.Optional
@Repository
interface TransactionReactiveRepo: ReactiveMongoRepository<Transaction, String> {
// fun findByOldId(transactionId: Int): Optional<Transaction>
fun findByParentId(parentId: String): Optional<Transaction>
}

View File

@@ -1,12 +1,9 @@
package space.luminic.budgerapp.repos package space.luminic.budgerapp.repos
import org.bson.types.ObjectId
import org.springframework.data.mongodb.repository.MongoRepository
import org.springframework.data.mongodb.repository.ReactiveMongoRepository import org.springframework.data.mongodb.repository.ReactiveMongoRepository
import org.springframework.stereotype.Repository import org.springframework.stereotype.Repository
import reactor.core.publisher.Mono import reactor.core.publisher.Mono
import space.luminic.budgerapp.models.Transaction import space.luminic.budgerapp.models.Transaction
import java.util.Optional
@Repository @Repository

View File

@@ -1,12 +1,10 @@
package space.luminic.budgerapp.repos package space.luminic.budgerapp.repos
import org.springframework.data.mongodb.repository.MongoRepository
import org.springframework.data.mongodb.repository.Query import org.springframework.data.mongodb.repository.Query
import org.springframework.data.mongodb.repository.ReactiveMongoRepository import org.springframework.data.mongodb.repository.ReactiveMongoRepository
import org.springframework.stereotype.Repository import org.springframework.stereotype.Repository
import reactor.core.publisher.Mono import reactor.core.publisher.Mono
import space.luminic.budgerapp.models.User import space.luminic.budgerapp.models.User
import java.util.Optional
@Repository @Repository
interface UserRepo : ReactiveMongoRepository<User, String> { interface UserRepo : ReactiveMongoRepository<User, String> {

View File

@@ -1,9 +0,0 @@
package space.luminic.budgerapp.repos
import org.springframework.data.mongodb.repository.MongoRepository
import space.luminic.budgerapp.models.User
interface UserRepoOld: MongoRepository<User, String> {
fun findByUsername(username: String): User?
}

View File

@@ -1,6 +1,5 @@
package space.luminic.budgerapp.repos package space.luminic.budgerapp.repos
import org.springframework.data.mongodb.repository.MongoRepository
import org.springframework.data.mongodb.repository.ReactiveMongoRepository import org.springframework.data.mongodb.repository.ReactiveMongoRepository
import org.springframework.stereotype.Repository import org.springframework.stereotype.Repository
import reactor.core.publisher.Flux import reactor.core.publisher.Flux
@@ -11,7 +10,6 @@ import space.luminic.budgerapp.models.Warn
interface WarnRepo : ReactiveMongoRepository<Warn, String> { interface WarnRepo : ReactiveMongoRepository<Warn, String> {
fun findAllByBudgetIdAndIsHide(budgetId: String, isHide: Boolean): Flux<Warn> fun findAllByBudgetIdAndIsHide(budgetId: String, isHide: Boolean): Flux<Warn>
fun deleteAllByBudgetId(budgetId: String)
fun findWarnByContext(context: String): Mono<Warn> fun findWarnByContext(context: String): Mono<Warn>

View File

@@ -1,137 +0,0 @@
package space.luminic.budgerapp.repos.sqlrepo
import org.slf4j.LoggerFactory
import org.springframework.jdbc.core.JdbcTemplate
import org.springframework.jdbc.core.RowMapper
import org.springframework.stereotype.Repository
import space.luminic.budgerapp.controllers.dtos.BudgetCreationDTO
import space.luminic.budgerapp.models.Budget
import space.luminic.budgerapp.models.BudgetCategory
import space.luminic.budgerapp.models.Category
import space.luminic.budgerapp.models.CategoryType
import space.luminic.budgerapp.models.Transaction
import space.luminic.budgerapp.models.TransactionType
import space.luminic.budgerapp.services.CategoryService
import space.luminic.budgerapp.services.UserService
import java.time.LocalDate
import java.time.LocalDateTime
import java.time.LocalTime
import java.time.ZoneId
import java.time.ZoneOffset
@Repository
class BudgetRepoSQL(
val jdbcTemplate: JdbcTemplate,
val userService: UserService,
val categoryService: CategoryService,
val transactionsRepoSQl: TransactionsRepoSQl
) {
private val logger = LoggerFactory.getLogger(BudgetRepoSQL::class.java)
fun getBudgetsIds(): List<Int> {
return jdbcTemplate.queryForList("SELECT id FROM budger.budgets", Int::class.java)
}
fun getBudgets(): List<BudgetCreationDTO> {
val sql = "SELECT * FROM budger.budgets"
return jdbcTemplate.query(sql, RowMapper { rs, _ ->
BudgetCreationDTO(
Budget(
// id = rs.getString("id"),
name = rs.getString("name"),
dateFrom = rs.getDate("date_from").toLocalDate(),
dateTo = rs.getDate("date_to").toLocalDate(),
createdAt = LocalDateTime.of(rs.getDate("created_at").toLocalDate(), LocalTime.NOON),
), false
)
})
}
// fun getBudgetCategory(id: Int): List<BudgetCategory> {
// val sql = "SELECT c.*, \n" +
// " COALESCE(SUM(CASE WHEN t.transaction_type_code = 'INSTANT' THEN t.amount END), 0) AS total_instant_expenses,\n" +
// " COALESCE(SUM(CASE WHEN t.transaction_type_code = 'PLANNED' THEN t.amount END), 0) AS total_planned_expenses,\n" +
// " COALESCE(bcs.category_setting_value, 0) AS current_limit,\n" +
// " COALESCE((SELECT AVG(amount) FROM budger.transactions where category_id=c.id AND transaction_type_code='INSTANT'),0) as average\n" +
// "FROM\n" +
// " budger.budget_category_settings bcs\n" +
// "JOIN\n" +
// " budger.budgets b ON bcs.budget_id = b.id\n" +
// "LEFT JOIN\n" +
// " budger.transactions t ON bcs.category_id = t.category_id\n" +
// " AND t.date BETWEEN b.date_from AND b.date_to\n" +
// "JOIN\n" +
// " budger.categories c ON bcs.category_id = c.id\n" +
// "WHERE\n" +
// " b.id = ? -- Укажите ID бюджета, для которого нужно вывести данные\n" +
// "GROUP BY\n" +
// " c.id, bcs.category_setting_value\n" +
// "ORDER BY\n" +
// " c.id;"
// return jdbcTemplate.query(sql, RowMapper { rs, _ ->
// BudgetCategory(
// currentSpent = rs.getBigDecimal("total_instant_expenses"),
// currentLimit = rs.getBigDecimal("current_limit"),
// category = categoryService.getCategoryByName(rs.getString("name"))
// )
// }, id)
// }
fun getBudgetTransactions(id: Int, transactionType: String?, categoryType: String?): List<Transaction> {
val whereConditions = mutableListOf<String>()
val parameters = mutableListOf<Any>()
// Базовое условие
whereConditions.add("b.id = ?")
parameters.add(id)
// Условие для transactionType, если указано
if (transactionType != null) {
whereConditions.add("t.transaction_type_code = ?")
parameters.add(transactionType)
}
// Условие для categoryType, если указано
if (categoryType != null) {
whereConditions.add("c.type_code = ?")
parameters.add(categoryType)
}
// Генерация WHERE
val whereClause = if (whereConditions.isNotEmpty()) "WHERE ${whereConditions.joinToString(" AND ")}" else ""
// SQL запрос
val sql = """
SELECT
tt.code as tt_code,
tt.name as tt_name,
t.comment,
t.date,
t.amount,
t.is_done,
t.created_at,
u.username,
c.name as c_name,
t.id
FROM budger.transactions t
JOIN budger.transaction_types tt ON tt.code = t.transaction_type_code
JOIN budger.categories c ON c.id = t.category_id
JOIN budger.category_types ct ON ct.code = c.type_code
JOIN budger.budgets b ON t.date BETWEEN b.date_from AND b.date_to
LEFT JOIN budger.users u ON t.user_id = u.id
$whereClause
ORDER BY t.date DESC, c.name, t.id
""".trimIndent()
logger.info(parameters.toTypedArray().toString())
// Выполнение запроса
return jdbcTemplate.query(
sql, parameters.toTypedArray(),
transactionsRepoSQl.transactionRowMapper()
)
}
}

View File

@@ -1,40 +0,0 @@
package space.luminic.budgerapp.repos.sqlrepo
import org.springframework.jdbc.core.JdbcTemplate
import org.springframework.jdbc.core.RowMapper
import org.springframework.stereotype.Repository
import space.luminic.budgerapp.models.Category
import space.luminic.budgerapp.models.CategoryType
import space.luminic.budgerapp.models.Transaction
import space.luminic.budgerapp.models.TransactionType
import java.time.LocalDate
import java.time.ZoneId
@Repository
class CategoriesRepoSQL(private val jdbcTemplate: JdbcTemplate) {
fun getCategories(): List<Category> {
val sql = "SELECT * FROM budger.categories"
return jdbcTemplate.query(sql, categoriesRowMapper())
}
fun categoriesRowMapper() = RowMapper { rs, _ ->
val category = Category(
type = if (rs.getString("type_code") == "EXPENSE") CategoryType("EXPENSE", "Траты") else CategoryType(
"INCOME",
"Поступления"
),
name = rs.getString("name"),
description = rs.getString("description"),
icon = rs.getString("icon")
)
return@RowMapper category
}
}

View File

@@ -1,39 +0,0 @@
package space.luminic.budgerapp.repos.sqlrepo
import org.slf4j.LoggerFactory
import org.springframework.jdbc.core.JdbcTemplate
import org.springframework.jdbc.core.RowMapper
import org.springframework.stereotype.Repository
import space.luminic.budgerapp.models.Recurrent
import space.luminic.budgerapp.models.Transaction
import space.luminic.budgerapp.models.TransactionType
import space.luminic.budgerapp.repos.CategoryRepoOld
@Repository
class RecurrentRepoSQL(
private val jdbcTemplate: JdbcTemplate,
private val categoryRepoOld: CategoryRepoOld
) {
private val logger = LoggerFactory.getLogger(RecurrentRepoSQL::class.java)
fun getRecurrents(): List<Recurrent> {
return jdbcTemplate.query("SELECT r.*, c.name as c_name FROM budger.recurrent_payments r join budger.categories c on r.category_id = c.id ", recurrentRowMapper())
}
fun recurrentRowMapper() = RowMapper { rs, _ ->
val recurrent = Recurrent(
atDay = rs.getInt("at_day"),
category = categoryRepoOld.findByName(rs.getString("c_name"))!!,
name = rs.getString("name"),
description = rs.getString("description"),
amount = rs.getInt("amount")
)
logger.info(recurrent.toString())
return@RowMapper recurrent
}
}

View File

@@ -1,65 +0,0 @@
package space.luminic.budgerapp.repos.sqlrepo
import org.slf4j.LoggerFactory
import org.springframework.jdbc.core.JdbcTemplate
import org.springframework.jdbc.core.RowMapper
import org.springframework.stereotype.Repository
import space.luminic.budgerapp.models.Category
import space.luminic.budgerapp.models.Transaction
import space.luminic.budgerapp.models.TransactionType
import space.luminic.budgerapp.models.User
import space.luminic.budgerapp.repos.CategoryRepoOld
import space.luminic.budgerapp.repos.UserRepoOld
import space.luminic.budgerapp.services.CategoryService
import space.luminic.budgerapp.services.UserService
import java.sql.SQLException
import java.time.LocalDate
import java.time.ZoneId
@Repository
class TransactionsRepoSQl(
private val jdbcTemplate: JdbcTemplate,
private val userRepoOld: UserRepoOld,
private val categoryRepoOld: CategoryRepoOld
) {
private val logger = LoggerFactory.getLogger(TransactionsRepoSQl::class.java)
fun getTransactions(): List<Transaction> {
return jdbcTemplate.query(
"SELECT tt.code as tt_code, tt.name as tt_name, u.username, c.name as c_name, t.comment, t.date, t.amount, t.is_done, t.created_at, t.id" +
" FROM budger.transactions t" +
" JOIN budger.transaction_types tt on t.transaction_type_code = tt.code " +
" JOIN budger.categories c on t.category_id = c.id" +
" LEFT JOIN budger.users u on t.user_id = u.id", transactionRowMapper()
)
}
fun transactionRowMapper() = RowMapper { rs, _ ->
val transaction = Transaction(
type = TransactionType(rs.getString("tt_code"), rs.getString("tt_name")),
user = rs.getString("username")
?.let { userRepoOld.findByUsername(it) }
?: userRepoOld.findByUsername("voroninv"),
category = categoryRepoOld.findByName(rs.getString("c_name"))!!,
comment = rs.getString("comment"),
date = rs.getDate("date").toLocalDate(),
amount = rs.getDouble("amount"),
isDone = rs.getBoolean("is_done"),
createdAt = rs.getTimestamp("created_at").toInstant()
.atZone(ZoneId.systemDefault())
.toLocalDateTime()
)
logger.info(transaction.toString())
return@RowMapper transaction
}
}

View File

@@ -1,9 +1,7 @@
package space.luminic.budgerapp.services package space.luminic.budgerapp.services
import org.springframework.cache.annotation.Cacheable import org.springframework.cache.annotation.Cacheable
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder
import org.springframework.security.crypto.password.PasswordEncoder
import org.springframework.stereotype.Service import org.springframework.stereotype.Service
import reactor.core.publisher.Mono import reactor.core.publisher.Mono
import space.luminic.budgerapp.configs.AuthException import space.luminic.budgerapp.configs.AuthException
@@ -16,7 +14,6 @@ import space.luminic.budgerapp.utils.JWTUtil
import java.time.LocalDateTime import java.time.LocalDateTime
import java.time.ZoneId import java.time.ZoneId
import java.util.Date import java.util.Date
import java.util.UUID
@Service @Service

View File

@@ -1,42 +1,37 @@
package space.luminic.budgerapp.services package space.luminic.budgerapp.services
import org.slf4j.LoggerFactory import org.slf4j.LoggerFactory
import org.springframework.cache.annotation.CacheEvict import org.springframework.cache.annotation.CacheEvict
import org.springframework.cache.annotation.Cacheable import org.springframework.cache.annotation.Cacheable
import org.springframework.context.event.EventListener import org.springframework.context.event.EventListener
import org.springframework.data.domain.Sort import org.springframework.data.domain.Sort
import org.springframework.data.domain.Sort.Direction
import org.springframework.stereotype.Service
import space.luminic.budgerapp.models.Budget
import space.luminic.budgerapp.models.BudgetCategory
import space.luminic.budgerapp.models.Transaction
import org.springframework.data.mongodb.core.aggregation.Aggregation.newAggregation
import org.springframework.data.mongodb.core.MongoTemplate
import org.springframework.data.mongodb.core.ReactiveMongoTemplate import org.springframework.data.mongodb.core.ReactiveMongoTemplate
import org.springframework.data.mongodb.core.aggregation.Aggregation.group import org.springframework.data.mongodb.core.aggregation.Aggregation.group
import org.springframework.data.mongodb.core.aggregation.Aggregation.lookup import org.springframework.data.mongodb.core.aggregation.Aggregation.lookup
import org.springframework.data.mongodb.core.aggregation.Aggregation.match import org.springframework.data.mongodb.core.aggregation.Aggregation.match
import org.springframework.data.mongodb.core.aggregation.Aggregation.newAggregation
import org.springframework.data.mongodb.core.aggregation.Aggregation.project import org.springframework.data.mongodb.core.aggregation.Aggregation.project
import org.springframework.data.mongodb.core.aggregation.Aggregation.sort import org.springframework.data.mongodb.core.aggregation.Aggregation.sort
import org.springframework.data.mongodb.core.aggregation.Aggregation.unwind import org.springframework.data.mongodb.core.aggregation.Aggregation.unwind
import org.springframework.data.mongodb.core.query.Criteria import org.springframework.data.mongodb.core.query.Criteria
import org.springframework.stereotype.Service
import reactor.core.publisher.Flux import reactor.core.publisher.Flux
import reactor.core.publisher.Mono import reactor.core.publisher.Mono
import space.luminic.budgerapp.models.Budget
import space.luminic.budgerapp.models.BudgetCategory
import space.luminic.budgerapp.models.BudgetDTO import space.luminic.budgerapp.models.BudgetDTO
import space.luminic.budgerapp.models.BudgetNotFoundException import space.luminic.budgerapp.models.BudgetNotFoundException
import space.luminic.budgerapp.models.PushMessage import space.luminic.budgerapp.models.PushMessage
import space.luminic.budgerapp.models.SortSetting import space.luminic.budgerapp.models.SortSetting
import space.luminic.budgerapp.models.Transaction
import space.luminic.budgerapp.models.TransactionEvent import space.luminic.budgerapp.models.TransactionEvent
import space.luminic.budgerapp.models.TransactionEventType import space.luminic.budgerapp.models.TransactionEventType
import space.luminic.budgerapp.models.Warn import space.luminic.budgerapp.models.Warn
import space.luminic.budgerapp.models.WarnSerenity import space.luminic.budgerapp.models.WarnSerenity
import space.luminic.budgerapp.repos.BudgetRepo import space.luminic.budgerapp.repos.BudgetRepo
import space.luminic.budgerapp.repos.WarnRepo import space.luminic.budgerapp.repos.WarnRepo
import java.time.LocalDate import java.time.LocalDate
import java.util.Optional import java.util.Optional
import kotlin.collections.get import kotlin.collections.get
@@ -57,7 +52,7 @@ class BudgetService(
@CacheEvict(cacheNames = ["budgets"], allEntries = true) @CacheEvict(cacheNames = ["budgets"], allEntries = true)
fun handleTransactionEvent(event: TransactionEvent) { fun handleTransactionEvent(event: TransactionEvent) {
logger.info("Got ${event.eventType} event on transaction ${event.newTransaction.id}") logger.info("Got ${event.eventType} event on transaction ${event.newTransaction.id}")
if (event.newTransaction.category.type?.code == "EXPENSE") { if (event.newTransaction.category.type.code == "EXPENSE") {
when (event.eventType) { when (event.eventType) {
TransactionEventType.EDIT -> updateBudgetOnEdit(event) TransactionEventType.EDIT -> updateBudgetOnEdit(event)
TransactionEventType.CREATE -> updateBudgetOnCreate(event) TransactionEventType.CREATE -> updateBudgetOnCreate(event)
@@ -196,23 +191,6 @@ class BudgetService(
} }
fun updateBudgetTransactions(budget: Budget): Budget {
// budget.plannedExpenses = getBudgetTransactions(
// budget = budget,
// transactionType = "PLANNED",
// categoryType = "EXPENSE",
// sortBy = SortSetting("date", Direction.ASC)
// )
// budget.plannedIncomes = getBudgetTransactions(
// budget = budget,
// transactionType = "PLANNED",
// categoryType = "INCOME",
// sortBy = SortSetting("date", Direction.ASC)
// )
return budget
}
@Cacheable("budgetsList") @Cacheable("budgetsList")
fun getBudgets(sortSetting: SortSetting? = null): Mono<MutableList<Budget>> { fun getBudgets(sortSetting: SortSetting? = null): Mono<MutableList<Budget>> {
val sort = if (sortSetting != null) { val sort = if (sortSetting != null) {
@@ -277,22 +255,6 @@ class BudgetService(
} }
// fun transferBudgets() {
// val budgets = getBudgets()
// budgetRepo.saveAll<Budget>(budgets)
//
// }
//
// fun getBudgets(): List<Budget> {
// val budgetIds = budgetRepoSql.getBudgetsIds()
// var budgets = mutableListOf<Budget>()
// budgetIds.forEach { budgetId ->
// budgets.add(getBudgetSQL(budgetId)!!)
// }
// return budgets
// }
@CacheEvict(cacheNames = ["budgets", "budgetsList"], allEntries = true) @CacheEvict(cacheNames = ["budgets", "budgetsList"], allEntries = true)
fun createBudget(budget: Budget, createRecurrent: Boolean): Mono<Budget> { fun createBudget(budget: Budget, createRecurrent: Boolean): Mono<Budget> {
return Mono.zip( return Mono.zip(
@@ -323,6 +285,7 @@ class BudgetService(
budget.categories = categories budget.categories = categories
budgetRepo.save(budget) budgetRepo.save(budget)
} }
.publishOn(reactor.core.scheduler.Schedulers.boundedElastic())
.doOnNext { savedBudget -> .doOnNext { savedBudget ->
// Выполнение updateBudgetWarns в фоне // Выполнение updateBudgetWarns в фоне
updateBudgetWarns(budget = savedBudget) updateBudgetWarns(budget = savedBudget)
@@ -374,27 +337,6 @@ class BudgetService(
} }
} }
fun getBudgetTransactions(
budget: Budget,
transactionType: String? = null,
isDone: Boolean? = null,
categoryType: String? = null,
sortBy: SortSetting? = null
): Mono<MutableList<Transaction>> {
val defaultSort = SortSetting("date", Sort.Direction.ASC) // Сортировка по умолчанию
return transactionService.getTransactions(
dateFrom = budget.dateFrom,
dateTo = budget.dateTo,
transactionType = transactionType,
isDone = isDone,
categoryType = categoryType,
sortSetting = sortBy ?: defaultSort
).onErrorResume { e ->
Mono.error(RuntimeException("Error fetching transactions: ${e.message}", e))
}
}
@CacheEvict(cacheNames = ["budgets", "budgetsList"], allEntries = true) @CacheEvict(cacheNames = ["budgets", "budgetsList"], allEntries = true)
fun deleteBudget(budgetId: String): Mono<Void> { fun deleteBudget(budgetId: String): Mono<Void> {
@@ -436,38 +378,14 @@ class BudgetService(
} }
fun recalcBudgetCategory(): Mono<Void> {
return budgetRepo.findAll(Sort.by(Direction.DESC, "dateFrom")) // Получаем все бюджеты
// .flatMapIterable { budgets -> budgets } // Преобразуем Flux<Budget> в Flux<Budget> (итерация по бюджетам)
// .flatMap { budget ->
// logger.warn("HERE $budget")
// Flux.fromIterable(budget.categories) // Преобразуем категории в поток
// .flatMap { category ->
// logger.warn("HERE $category")
// Mono.zip(
// transactionService.calcTransactionsSum(budget, category.category.id!!, "PLANNED"),
// transactionService.calcTransactionsSum(budget, category.category.id!!, "INSTANT", isDone = true),
// transactionService.calcTransactionsSum(budget, category.category.id!!, "PLANNED")
// ).map { (plannedSum, spentSum, limitSum) ->
// category.currentPlanned = plannedSum
// category.currentSpent = spentSum
// category.currentLimit = limitSum
// }
// }
// .then() // Завершаем поток категорий
// .flatMap { updateBudgetWarns(budgetId = budget.id!!) } // Обновляем предупреждения
// }
// .collectList() // Собираем все бюджеты
// .flatMap { budgets -> budgetRepo.saveAll(budgets).collectList() } // Сохраняем все бюджеты
.then() // Завершаем метод
}
fun getWarns(budgetId: String, isHide: Boolean? = null): Mono<List<Warn>> { fun getWarns(budgetId: String, isHide: Boolean? = null): Mono<List<Warn>> {
return warnRepo.findAllByBudgetIdAndIsHide(budgetId, isHide == true).collectList() return warnRepo.findAllByBudgetIdAndIsHide(budgetId, isHide == true).collectList()
} }
fun hideWarn(budgetId: String, warnId: String): Mono<Warn> { fun hideWarn(warnId: String): Mono<Warn> {
return warnRepo.findById(warnId) // Ищем предупреждение return warnRepo.findById(warnId) // Ищем предупреждение
.flatMap { warn -> .flatMap { warn ->
warn.isHide = true // Обновляем поле warn.isHide = true // Обновляем поле

View File

@@ -5,9 +5,7 @@ import org.bson.Document
import org.slf4j.LoggerFactory import org.slf4j.LoggerFactory
import org.springframework.cache.annotation.CacheEvict import org.springframework.cache.annotation.CacheEvict
import org.springframework.cache.annotation.Cacheable import org.springframework.cache.annotation.Cacheable
import org.springframework.data.mongodb.core.ReactiveMongoTemplate import org.springframework.data.mongodb.core.ReactiveMongoTemplate
import org.springframework.stereotype.Service import org.springframework.stereotype.Service
import reactor.core.publisher.Flux import reactor.core.publisher.Flux
import reactor.core.publisher.Mono import reactor.core.publisher.Mono
@@ -22,8 +20,6 @@ import java.time.ZoneId
import java.time.ZoneOffset import java.time.ZoneOffset
import java.util.Date import java.util.Date
import kotlin.jvm.optionals.getOrNull
@Service @Service
class CategoryService( class CategoryService(
private val categoryRepo: CategoryRepo, private val categoryRepo: CategoryRepo,
@@ -33,10 +29,6 @@ class CategoryService(
private val logger = LoggerFactory.getLogger(javaClass) private val logger = LoggerFactory.getLogger(javaClass)
fun getCategoryByName(name: String): Mono<Category> {
return categoryRepo.findByName(name)
}
@Cacheable("getAllCategories") @Cacheable("getAllCategories")
fun getCategories(): Mono<List<Category>> { fun getCategories(): Mono<List<Category>> {

View File

@@ -1,16 +0,0 @@
package space.luminic.budgerapp.services
import org.springframework.security.core.userdetails.ReactiveUserDetailsService
import org.springframework.security.core.userdetails.UserDetails
import org.springframework.security.core.userdetails.UserDetailsService
import org.springframework.stereotype.Service
import reactor.core.publisher.Mono
@Service
class CustomReactiveUserDetailsService(
private val userDetailsService: UserDetailsService // Ваш синхронный сервис
) : ReactiveUserDetailsService {
override fun findByUsername(username: String): Mono<UserDetails> {
return Mono.fromCallable { userDetailsService.loadUserByUsername(username) }
}
}

View File

@@ -6,7 +6,6 @@ import org.springframework.cache.annotation.CacheEvict
import org.springframework.cache.annotation.Cacheable import org.springframework.cache.annotation.Cacheable
import org.springframework.security.core.context.ReactiveSecurityContextHolder import org.springframework.security.core.context.ReactiveSecurityContextHolder
import org.springframework.stereotype.Service import org.springframework.stereotype.Service
import reactor.core.publisher.Flux
import reactor.core.publisher.Mono import reactor.core.publisher.Mono
import space.luminic.budgerapp.models.Budget import space.luminic.budgerapp.models.Budget
import space.luminic.budgerapp.models.NotFoundException import space.luminic.budgerapp.models.NotFoundException
@@ -15,19 +14,12 @@ import space.luminic.budgerapp.models.Transaction
import space.luminic.budgerapp.models.TransactionType import space.luminic.budgerapp.models.TransactionType
import space.luminic.budgerapp.repos.RecurrentRepo import space.luminic.budgerapp.repos.RecurrentRepo
import space.luminic.budgerapp.repos.TransactionRepo import space.luminic.budgerapp.repos.TransactionRepo
import space.luminic.budgerapp.repos.sqlrepo.RecurrentRepoSQL
import java.math.BigDecimal
import java.time.LocalDate
import java.time.LocalDateTime
import java.time.LocalTime
import java.time.YearMonth import java.time.YearMonth
import kotlin.jvm.optionals.getOrNull
@Service @Service
class RecurrentService( class RecurrentService(
private val recurrentRepo: RecurrentRepo, private val recurrentRepo: RecurrentRepo,
private val recurrentRepoSQL: RecurrentRepoSQL,
private val transactionRepo: TransactionRepo, private val transactionRepo: TransactionRepo,
private val userService: UserService, private val userService: UserService,
) { ) {
@@ -120,9 +112,6 @@ class RecurrentService(
} }
fun transferRecurrents() {
recurrentRepo.saveAll(recurrentRepoSQL.getRecurrents()).then().subscribe()
}
} }

View File

@@ -1,16 +1,14 @@
package space.luminic.budgerapp.services package space.luminic.budgerapp.services
import com.interaso.webpush.VapidKeys import com.interaso.webpush.VapidKeys
import com.interaso.webpush.WebPushService import com.interaso.webpush.WebPushService
import kotlinx.serialization.json.Json
import kotlinx.serialization.encodeToString import kotlinx.serialization.encodeToString
import kotlinx.serialization.json.Json
import org.slf4j.LoggerFactory import org.slf4j.LoggerFactory
import org.springframework.dao.DuplicateKeyException import org.springframework.dao.DuplicateKeyException
import org.springframework.stereotype.Service import org.springframework.stereotype.Service
import reactor.core.publisher.Mono import reactor.core.publisher.Mono
import space.luminic.budgerapp.models.PushMessage import space.luminic.budgerapp.models.PushMessage
import space.luminic.budgerapp.models.Subscription import space.luminic.budgerapp.models.Subscription
import space.luminic.budgerapp.models.SubscriptionDTO import space.luminic.budgerapp.models.SubscriptionDTO
@@ -19,7 +17,6 @@ import space.luminic.budgerapp.repos.SubscriptionRepo
import space.luminic.budgerapp.services.VapidConstants.VAPID_PRIVATE_KEY import space.luminic.budgerapp.services.VapidConstants.VAPID_PRIVATE_KEY
import space.luminic.budgerapp.services.VapidConstants.VAPID_PUBLIC_KEY import space.luminic.budgerapp.services.VapidConstants.VAPID_PUBLIC_KEY
import space.luminic.budgerapp.services.VapidConstants.VAPID_SUBJECT import space.luminic.budgerapp.services.VapidConstants.VAPID_SUBJECT
import java.security.GeneralSecurityException
object VapidConstants { object VapidConstants {
const val VAPID_PUBLIC_KEY = const val VAPID_PUBLIC_KEY =

View File

@@ -1,6 +1,5 @@
package space.luminic.budgerapp.services package space.luminic.budgerapp.services
import org.springframework.cache.annotation.CacheEvict import org.springframework.cache.annotation.CacheEvict
import org.springframework.cache.annotation.Cacheable
import org.springframework.stereotype.Service import org.springframework.stereotype.Service
import reactor.core.publisher.Mono import reactor.core.publisher.Mono
import space.luminic.budgerapp.models.Token import space.luminic.budgerapp.models.Token
@@ -12,29 +11,28 @@ import java.time.LocalDateTime
class TokenService(private val tokenRepository: TokenRepo) { class TokenService(private val tokenRepository: TokenRepo) {
@CacheEvict("tokens", allEntries = true) @CacheEvict("tokens", allEntries = true)
fun saveToken(token: String, username: String, expiresAt: LocalDateTime) { fun saveToken(token: String, username: String, expiresAt: LocalDateTime): Mono<Token> {
val newToken = Token( val newToken = Token(
token = token, token = token,
username = username, username = username,
issuedAt = LocalDateTime.now(), issuedAt = LocalDateTime.now(),
expiresAt = expiresAt expiresAt = expiresAt
) )
tokenRepository.save(newToken) return tokenRepository.save(newToken)
} }
@CacheEvict("tokens", allEntries = true) @CacheEvict("tokens", allEntries = true)
fun revokeToken(token: String): Mono<Void> { fun revokeToken(token: String): Mono<Void> {
return tokenRepository.findByToken(token) return tokenRepository.findByToken(token)
.switchIfEmpty(Mono.error(Exception("Token not found")))
.flatMap { existingToken -> .flatMap { existingToken ->
val updatedToken = existingToken.copy(status = TokenStatus.REVOKED) val updatedToken = existingToken.copy(status = TokenStatus.REVOKED)
tokenRepository.save(updatedToken).then() tokenRepository.save(updatedToken).then()
} }
.switchIfEmpty(Mono.error(Exception("Token not found")))
} }
@CacheEvict("tokens", allEntries = true) @CacheEvict("tokens", allEntries = true)
fun deleteExpiredTokens() { fun deleteExpiredTokens() {
tokenRepository.deleteByExpiresAtBefore(LocalDateTime.now()) tokenRepository.deleteByExpiresAtBefore(LocalDateTime.now())

View File

@@ -1,9 +1,6 @@
package space.luminic.budgerapp.services package space.luminic.budgerapp.services
import com.mongodb.client.model.Aggregates.addFields
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.async
import kotlinx.coroutines.runBlocking
import org.bson.Document import org.bson.Document
import org.bson.types.ObjectId import org.bson.types.ObjectId
import org.slf4j.LoggerFactory import org.slf4j.LoggerFactory
@@ -12,74 +9,44 @@ import org.springframework.cache.annotation.Cacheable
import org.springframework.context.ApplicationEventPublisher import org.springframework.context.ApplicationEventPublisher
import org.springframework.data.domain.Sort import org.springframework.data.domain.Sort
import org.springframework.data.domain.Sort.Direction import org.springframework.data.domain.Sort.Direction
import org.springframework.data.mongodb.MongoExpression
import org.springframework.data.mongodb.core.aggregation.Aggregation.newAggregation
import org.springframework.data.mongodb.core.MongoTemplate
import org.springframework.data.mongodb.core.ReactiveMongoTemplate import org.springframework.data.mongodb.core.ReactiveMongoTemplate
import org.springframework.data.mongodb.core.aggregation.AddFieldsOperation
import org.springframework.data.mongodb.core.aggregation.Aggregation
import org.springframework.data.mongodb.core.aggregation.Aggregation.ROOT
import org.springframework.data.mongodb.core.aggregation.Aggregation.group import org.springframework.data.mongodb.core.aggregation.Aggregation.group
import org.springframework.data.mongodb.core.aggregation.Aggregation.limit
import org.springframework.data.mongodb.core.aggregation.Aggregation.lookup import org.springframework.data.mongodb.core.aggregation.Aggregation.lookup
import org.springframework.data.mongodb.core.aggregation.Aggregation.match import org.springframework.data.mongodb.core.aggregation.Aggregation.match
import org.springframework.data.mongodb.core.aggregation.Aggregation.newAggregation
import org.springframework.data.mongodb.core.aggregation.Aggregation.project import org.springframework.data.mongodb.core.aggregation.Aggregation.project
import org.springframework.data.mongodb.core.aggregation.Aggregation.skip
import org.springframework.data.mongodb.core.aggregation.Aggregation.sort import org.springframework.data.mongodb.core.aggregation.Aggregation.sort
import org.springframework.data.mongodb.core.aggregation.Aggregation.unwind import org.springframework.data.mongodb.core.aggregation.Aggregation.unwind
import org.springframework.data.mongodb.core.aggregation.Aggregation.addFields
import org.springframework.data.mongodb.core.aggregation.Aggregation.limit
import org.springframework.data.mongodb.core.aggregation.Aggregation.skip
import org.springframework.data.mongodb.core.aggregation.AggregationExpression
import org.springframework.data.mongodb.core.aggregation.AggregationResults
import org.springframework.data.mongodb.core.aggregation.ArrayOperators
import org.springframework.data.mongodb.core.aggregation.ArrayOperators.Filter.filter
import org.springframework.data.mongodb.core.aggregation.ConditionalOperators
import org.springframework.data.mongodb.core.aggregation.ConditionalOperators.IfNull.ifNull
import org.springframework.data.mongodb.core.aggregation.DateOperators
import org.springframework.data.mongodb.core.aggregation.DateOperators.DateToString import org.springframework.data.mongodb.core.aggregation.DateOperators.DateToString
import org.springframework.data.mongodb.core.aggregation.LookupOperation
import org.springframework.data.mongodb.core.aggregation.MatchOperation
import org.springframework.data.mongodb.core.query.Criteria import org.springframework.data.mongodb.core.query.Criteria
import org.springframework.data.mongodb.core.query.Query import org.springframework.data.mongodb.core.query.Query
import org.springframework.data.mongodb.core.query.update
import org.springframework.security.core.context.ReactiveSecurityContextHolder import org.springframework.security.core.context.ReactiveSecurityContextHolder
import org.springframework.stereotype.Service import org.springframework.stereotype.Service
import reactor.core.publisher.Flux import reactor.core.publisher.Flux
import reactor.core.publisher.Mono import reactor.core.publisher.Mono
import space.luminic.budgerapp.models.Budget import space.luminic.budgerapp.models.Budget
import space.luminic.budgerapp.models.Category import space.luminic.budgerapp.models.Category
import space.luminic.budgerapp.models.CategoryType import space.luminic.budgerapp.models.CategoryType
import space.luminic.budgerapp.models.SortSetting import space.luminic.budgerapp.models.SortSetting
import space.luminic.budgerapp.models.SortTypes
import space.luminic.budgerapp.models.Transaction import space.luminic.budgerapp.models.Transaction
import space.luminic.budgerapp.models.TransactionEvent import space.luminic.budgerapp.models.TransactionEvent
import space.luminic.budgerapp.models.TransactionEventType import space.luminic.budgerapp.models.TransactionEventType
import space.luminic.budgerapp.models.TransactionType import space.luminic.budgerapp.models.TransactionType
import space.luminic.budgerapp.models.User import space.luminic.budgerapp.models.User
import space.luminic.budgerapp.repos.TransactionRepo import space.luminic.budgerapp.repos.TransactionRepo
import java.math.BigDecimal
import java.time.LocalDate import java.time.LocalDate
import java.time.LocalDateTime import java.time.LocalDateTime
import java.time.LocalTime import java.time.LocalTime
import java.time.ZoneId import java.time.ZoneId
import java.time.ZoneOffset import java.time.ZoneOffset
import java.time.ZonedDateTime
import java.time.format.DateTimeFormatter
import java.time.temporal.TemporalAdjusters import java.time.temporal.TemporalAdjusters
import java.util.ArrayList import java.util.ArrayList
import java.util.Arrays
import java.util.Date import java.util.Date
import kotlin.jvm.optionals.getOrNull
@Service @Service
class TransactionService( class TransactionService(
private val mongoTemplate: MongoTemplate,
private val reactiveMongoTemplate: ReactiveMongoTemplate, private val reactiveMongoTemplate: ReactiveMongoTemplate,
val transactionsRepo: TransactionRepo, val transactionsRepo: TransactionRepo,
val userService: UserService, val userService: UserService,
@@ -608,13 +575,6 @@ class TransactionService(
} }
fun getCategoriesExplainReactive(pipeline: List<Document>): Mono<Document> {
val command = Document("aggregate", "transactions")
.append("pipeline", pipeline)
.append("explain", true)
return reactiveMongoTemplate.executeCommand(command)
}
private fun extractTransactions(aggregationResult: Document, key: String): Mono<List<Transaction>> { private fun extractTransactions(aggregationResult: Document, key: String): Mono<List<Transaction>> {
val resultTransactions = aggregationResult[key] as? List<Document> ?: emptyList() val resultTransactions = aggregationResult[key] as? List<Document> ?: emptyList()
@@ -658,7 +618,7 @@ class TransactionService(
transactionType["code"] as String, transactionType["code"] as String,
transactionType["name"] as String transactionType["name"] as String
), ),
user = user!!, user = user,
category = category, category = category,
comment = document["comment"] as String, comment = document["comment"] as String,
date = (document["date"] as Date).toInstant().atZone(ZoneId.systemDefault()).toLocalDate(), date = (document["date"] as Date).toInstant().atZone(ZoneId.systemDefault()).toLocalDate(),
@@ -669,116 +629,4 @@ class TransactionService(
) )
} }
// fun getPlannedForBudget(budget: Budget, transactionType: String? = null): List<Map<String, Any>> {
// // 1) $lookup: "categories"
// val lookupCategories = Aggregation.lookup(
// "categories",
// "category.\$id",
// "_id",
// "categoryDetailed"
// )
//
// // 2) $lookup: "budgets" (pipeline + let)
// val matchBudgetsDoc = Document(
// "\$expr", Document(
// "\$and", listOf(
// Document("\$gte", listOf("\$\$transactionDate", "\$dateFrom")),
// Document("\$lt", listOf("\$\$transactionDate", "\$dateTo"))
// )
// )
// )
// val matchBudgetsOp = MatchOperation(matchBudgetsDoc)
//
// val lookupBudgets = LookupOperation.newLookup()
// .from("budgets")
// .letValueOf("transactionDate").bindTo("date")
// .pipeline(matchBudgetsOp)
// .`as`("budgetDetails")
//
// // 3) $unwind
// val unwindCategory = Aggregation.unwind("categoryDetailed")
// val unwindBudget = Aggregation.unwind("budgetDetails")
//
// // 4) $match: диапазон дат
// val matchDates = Aggregation.match(
// Criteria("date")
// .gte(budget.dateFrom)
// .lt(budget.dateTo)
// )
//
// // 5) $facet (разные ветки: plannedExpenses, plannedExpensesSum, ...)
// // plannedExpenses
// val plannedExpensesMatch = Aggregation.match(
// Criteria().andOperator(
// Criteria("type.code").`is`("PLANNED"),
// Criteria("categoryDetailed.type.code").`is`("EXPENSE")
// )
// )
// val plannedExpensesPipeline = listOf(plannedExpensesMatch)
//
// // plannedExpensesSum
// val plannedExpensesSumPipeline = listOf(
// plannedExpensesMatch,
// group(null).`as`("_id").sum("amount").`as`("sum"),
// project("sum").andExclude("_id")
// )
//
// // plannedIncome
// val plannedIncomeMatch = Aggregation.match(
// Criteria().andOperator(
// Criteria("type.code").`is`("PLANNED"),
// Criteria("categoryDetailed.type.code").`is`("INCOME")
// )
// )
// val plannedIncomePipeline = listOf(plannedIncomeMatch)
//
// // plannedIncomeSum
// val plannedIncomeSumPipeline = listOf(
// plannedIncomeMatch,
// group().`as`("_id").sum("amount").`as`("sum"),
// project("sum").andExclude("_id")
// )
//
// // instantTransactions
// val instantTransactionsMatch = Aggregation.match(
// Criteria("type.code").`is`("INSTANT")
// )
// val instantTransactionsProject = Aggregation.project(
// "_id", "type", "comment", "user", "amount", "date",
// "category", "isDone", "createdAt", "parentId"
// )
// val instantTransactionsPipeline = listOf(instantTransactionsMatch, instantTransactionsProject)
//
// val facetStage = Aggregation.facet(*plannedExpensesPipeline.toTypedArray()).`as`("plannedExpenses")
// .and(*plannedExpensesSumPipeline.toTypedArray()).`as`("plannedExpensesSum")
// .and(*plannedIncomePipeline.toTypedArray()).`as`("plannedIncome")
// .and(*plannedIncomeSumPipeline.toTypedArray()).`as`("plannedIncomeSum")
// .and(*instantTransactionsPipeline.toTypedArray()).`as`("instantTransactions")
//
// // 6) $set: вытаскиваем суммы из массивов
// val setStage = AddFieldsOperation.builder()
// .addField("plannedExpensesSum").withValue(
// ArrayOperators.ArrayElemAt.arrayOf("\$plannedExpensesSum.sum").elementAt(0)
// )
// .addField("plannedIncomeSum").withValue(
// ArrayOperators.ArrayElemAt.arrayOf("\$plannedIncomeSum.sum").elementAt(0)
// )
// .build()
//
// // Собираем все стадии
// val aggregation = Aggregation.newAggregation(
// lookupCategories,
// lookupBudgets,
// unwindCategory,
// unwindBudget,
// matchDates,
// facetStage,
// setStage
// )
//
// val results = mongoTemplate.aggregate(aggregation, "transactions", Map::class.java)
// return results.mappedResults
// }
} }

View File

@@ -1,62 +0,0 @@
package space.luminic.budgerapp.services
import org.springframework.stereotype.Service
import reactor.core.publisher.Flux
import reactor.core.publisher.Mono
import space.luminic.budgerapp.models.Budget
import space.luminic.budgerapp.models.Category
import space.luminic.budgerapp.models.Recurrent
import space.luminic.budgerapp.models.Transaction
import space.luminic.budgerapp.repos.BudgetRepo
import space.luminic.budgerapp.repos.CategoryRepo
import space.luminic.budgerapp.repos.RecurrentRepo
import space.luminic.budgerapp.repos.TransactionRepo
import space.luminic.budgerapp.repos.sqlrepo.BudgetRepoSQL
import space.luminic.budgerapp.repos.sqlrepo.CategoriesRepoSQL
import space.luminic.budgerapp.repos.sqlrepo.RecurrentRepoSQL
import space.luminic.budgerapp.repos.sqlrepo.TransactionsRepoSQl
@Service
class TransferService(
private val transactionsRepoSQl: TransactionsRepoSQl,
private val categoriesRepoSQL: CategoriesRepoSQL,
private val recurrentRepoSQL: RecurrentRepoSQL,
private val budgetRepoSQL: BudgetRepoSQL,
private val categoryRepo: CategoryRepo,
private val transactionRepo: TransactionRepo,
private val recurrentRepo: RecurrentRepo,
private val budgetService: BudgetService
) {
fun getTransactions(): Mono<List<Transaction>> {
val transactions = transactionsRepoSQl.getTransactions()
return transactionRepo.saveAll(transactions).collectList()
}
fun getCategories(): Mono<List<Category>> {
val categories = categoriesRepoSQL.getCategories()
return Flux.fromIterable(categories)
.flatMap { category -> categoryRepo.save(category) }
.collectList() // Преобразуем Flux<Category> в Mono<List<Category>>
}
fun recurrents(): Mono<List<Recurrent>> {
val recurrents = recurrentRepoSQL.getRecurrents()
return Flux.fromIterable(recurrents).flatMap { recurrent ->
recurrentRepo.save(recurrent)
}.collectList()
}
fun transferBudgets(): Mono<List<Budget>> {
val budgets = budgetRepoSQL.getBudgets()
return Flux.fromIterable(budgets)
.flatMap { budget ->
budgetService.createBudget(budget.budget, budget.createRecurrent)
}.collectList()
}
}

View File

@@ -3,27 +3,17 @@ package space.luminic.budgerapp.services
import org.slf4j.LoggerFactory import org.slf4j.LoggerFactory
import org.springframework.cache.annotation.Cacheable import org.springframework.cache.annotation.Cacheable
import org.springframework.security.crypto.password.PasswordEncoder
import org.springframework.stereotype.Service import org.springframework.stereotype.Service
import reactor.core.publisher.Mono import reactor.core.publisher.Mono
import space.luminic.budgerapp.models.NotFoundException import space.luminic.budgerapp.models.NotFoundException
import space.luminic.budgerapp.models.User import space.luminic.budgerapp.models.User
import space.luminic.budgerapp.repos.UserRepo import space.luminic.budgerapp.repos.UserRepo
import kotlin.jvm.optionals.getOrNull
@Service @Service
class UserService(val userRepo: UserRepo, val passwordEncoder: PasswordEncoder) { class UserService(val userRepo: UserRepo) {
val logger = LoggerFactory.getLogger(javaClass) val logger = LoggerFactory.getLogger(javaClass)
// fun regenPass(): List<User>? {
// var users = getUsers()!!.toMutableList()
// for (user in users) {
// user.password = passwordEncoder.encode(user.password)
// }
// userRepo.saveAll<User>(users)
// return users
// }
@Cacheable("users", key = "#username") @Cacheable("users", key = "#username")
fun getByUsername(username: String): Mono<User> { fun getByUsername(username: String): Mono<User> {
@@ -47,6 +37,7 @@ class UserService(val userRepo: UserRepo, val passwordEncoder: PasswordEncoder)
return userRepo.findByUsernameWOPassword(username) return userRepo.findByUsernameWOPassword(username)
} }
@Cacheable("usersList")
fun getUsers(): Mono<List<User>> { fun getUsers(): Mono<List<User>> {
return userRepo.findAll() return userRepo.findAll()
.map { user -> user.apply { password = null } } // Убираем пароль .map { user -> user.apply { password = null } } // Убираем пароль

View File

@@ -1,19 +0,0 @@
package space.luminic.budgerapp.utils
import com.fasterxml.jackson.core.JsonParser
import com.fasterxml.jackson.databind.DeserializationContext
import com.fasterxml.jackson.databind.JsonDeserializer
import java.time.LocalDateTime
import java.time.format.DateTimeFormatter
import java.util.Date
//class DateSerializer : JsonDeserializer<LocalDateTime>() {
//
// private val formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd") // Пример формата
//
// override fun deserialize(p: JsonParser, ctxt: DeserializationContext): LocalDateTime {
// val dateAsString = p.text
// var date = formatter.parse(dateAsString)
// return LocalDateTime.from(date, LocalDateTime.MIN ) // Преобразуем строку в LocalDateTime
// }
//}

View File

@@ -36,19 +36,5 @@ class JWTUtil(private val tokenService: TokenService) {
} }
fun validateToken(token: String): String? {
return try {
val claims = Jwts.parserBuilder().setSigningKey(key).build().parseClaimsJws(token)
claims.body.subject
} catch (e: io.jsonwebtoken.ExpiredJwtException) {
println("Token expired: ${e.message}")
null
} catch (e: io.jsonwebtoken.SignatureException) {
println("Invalid token signature: ${e.message}")
null
} catch (e: Exception) {
println("Token validation error: ${e.message}")
null
}
}
} }