add spaces
This commit is contained in:
@@ -26,7 +26,7 @@ class BearerTokenFilter(private val authService: AuthService) : SecurityContextS
|
||||
override fun filter(exchange: ServerWebExchange, chain: WebFilterChain): Mono<Void> {
|
||||
val token = exchange.request.headers.getFirst(HttpHeaders.AUTHORIZATION)?.removePrefix("Bearer ")
|
||||
|
||||
if (exchange.request.path.value() == "/api/auth/login" || exchange.request.path.value()
|
||||
if (exchange.request.path.value() in listOf("/api/auth/login","/api/auth/register") || exchange.request.path.value()
|
||||
.startsWith("/api/actuator")
|
||||
) {
|
||||
return chain.filter(exchange)
|
||||
|
||||
@@ -25,7 +25,7 @@ class SecurityConfig(
|
||||
|
||||
.logout { it.disable() }
|
||||
.authorizeExchange {
|
||||
it.pathMatchers(HttpMethod.POST, "/auth/login").permitAll()
|
||||
it.pathMatchers(HttpMethod.POST, "/auth/login", "/auth/register").permitAll()
|
||||
it.pathMatchers("/actuator/**").permitAll()
|
||||
it.anyExchange().authenticated()
|
||||
}
|
||||
|
||||
@@ -22,6 +22,11 @@ class AuthController(
|
||||
.map { token -> mapOf("token" to token) }
|
||||
}
|
||||
|
||||
@PostMapping("/register")
|
||||
fun register(@RequestBody request: RegisterRequest): Mono<User> {
|
||||
return authService.register(request.username, request.password, request.firstName)
|
||||
}
|
||||
|
||||
|
||||
@GetMapping("/me")
|
||||
fun getMe(@RequestHeader("Authorization") token: String): Mono<User> {
|
||||
@@ -33,3 +38,4 @@ class AuthController(
|
||||
}
|
||||
|
||||
data class AuthRequest(val username: String, val password: String)
|
||||
data class RegisterRequest(val username: String, val password: String, val firstName: String)
|
||||
@@ -30,8 +30,8 @@ class BudgetController(
|
||||
private val logger = LoggerFactory.getLogger(BudgetController::class.java)
|
||||
|
||||
@GetMapping
|
||||
fun getBudgets(): Mono<MutableList<Budget>> {
|
||||
return financialService.getBudgets()
|
||||
fun getBudgets(): Mono<List<Budget>> {
|
||||
return financialService.getBudgets("123")
|
||||
}
|
||||
|
||||
@GetMapping("/{id}")
|
||||
@@ -40,10 +40,10 @@ class BudgetController(
|
||||
}
|
||||
|
||||
|
||||
@GetMapping("/by-dates")
|
||||
fun getBudgetByDate(@RequestParam date: LocalDate): ResponseEntity<Any> {
|
||||
return ResponseEntity.ok(financialService.getBudgetByDate(date))
|
||||
}
|
||||
// @GetMapping("/by-dates")
|
||||
// fun getBudgetByDate(@RequestParam date: LocalDate): ResponseEntity<Any> {
|
||||
// return ResponseEntity.ok(financialService.getBudgetByDate(date))
|
||||
// }
|
||||
|
||||
|
||||
@GetMapping("/{id}/categories")
|
||||
@@ -52,17 +52,17 @@ class BudgetController(
|
||||
}
|
||||
|
||||
@GetMapping("/{id}/transactions")
|
||||
fun getBudgetTransactions(@PathVariable id: String):Mono<Map<String,List<Transaction>>> {
|
||||
fun getBudgetTransactions(@PathVariable id: String): Mono<Map<String, List<Transaction>>> {
|
||||
return financialService.getBudgetTransactionsByType(id)
|
||||
}
|
||||
|
||||
@PostMapping("/")
|
||||
fun createBudget(@RequestBody budgetCreationDTO: BudgetCreationDTO): Mono<Budget> {
|
||||
return financialService.createBudget(
|
||||
budgetCreationDTO.budget,
|
||||
budgetCreationDTO.createRecurrent
|
||||
)
|
||||
}
|
||||
// @PostMapping("/")
|
||||
// fun createBudget(@RequestBody budgetCreationDTO: BudgetCreationDTO): Mono<Budget> {
|
||||
// return financialService.createBudget(
|
||||
// budgetCreationDTO.budget,
|
||||
// budgetCreationDTO.createRecurrent
|
||||
// )
|
||||
// }
|
||||
|
||||
@DeleteMapping("/{id}")
|
||||
fun deleteBudget(@PathVariable id: String): Mono<Void> {
|
||||
@@ -83,7 +83,6 @@ class BudgetController(
|
||||
}
|
||||
|
||||
|
||||
|
||||
@GetMapping("/{id}/warns")
|
||||
fun budgetWarns(@PathVariable id: String, @RequestParam hidden: Boolean? = null): Mono<List<Warn>> {
|
||||
return financialService.getWarns(id, hidden)
|
||||
@@ -91,13 +90,18 @@ class BudgetController(
|
||||
|
||||
@PostMapping("/{id}/warns/{warnId}/hide")
|
||||
fun setWarnHide(@PathVariable id: String, @PathVariable warnId: String): Mono<Warn> {
|
||||
return financialService.hideWarn( warnId)
|
||||
}
|
||||
|
||||
@GetMapping("/regencats")
|
||||
fun regenCats(): Mono<Void>{
|
||||
return financialService.regenCats()
|
||||
return financialService.hideWarn(warnId)
|
||||
}
|
||||
//
|
||||
// @GetMapping("/regencats")
|
||||
// fun regenCats(): Mono<Void> {
|
||||
// return financialService.regenCats()
|
||||
// }
|
||||
//
|
||||
// @GetMapping("/regenSpaces")
|
||||
// fun regenSpaces(): Mono<Void> {
|
||||
// return financialService.regenBudgets()
|
||||
// }
|
||||
|
||||
data class LimitValue(
|
||||
var limit: Double
|
||||
|
||||
@@ -31,61 +31,61 @@ class CategoriesController(
|
||||
|
||||
|
||||
private val logger = LoggerFactory.getLogger(javaClass)
|
||||
|
||||
@GetMapping()
|
||||
fun getCategories(
|
||||
@RequestParam("type") type: String? = null,
|
||||
@RequestParam("sort") sortBy: String = "name",
|
||||
@RequestParam("direction") direction: String = "ASC"
|
||||
): Mono<List<Category>> {
|
||||
return categoryService.getCategories(type, sortBy, direction)
|
||||
|
||||
}
|
||||
|
||||
@GetMapping("/types")
|
||||
fun getCategoriesTypes(): ResponseEntity<Any> {
|
||||
return try {
|
||||
ResponseEntity.ok(categoryService.getCategoryTypes())
|
||||
} catch (e: Exception) {
|
||||
ResponseEntity(HttpClientErrorException(HttpStatus.INTERNAL_SERVER_ERROR), HttpStatus.INTERNAL_SERVER_ERROR)
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@PostMapping()
|
||||
fun createCategory(@RequestBody category: Category): Mono<Category> {
|
||||
return categoryService.createCategory(category)
|
||||
}
|
||||
|
||||
@PutMapping("/{categoryId}")
|
||||
fun editCategory(@PathVariable categoryId: String, @RequestBody category: Category): Mono<Category> {
|
||||
return categoryService.editCategory(category)
|
||||
}
|
||||
|
||||
@DeleteMapping("/{categoryId}")
|
||||
fun deleteCategory(@PathVariable categoryId: String): Mono<String> {
|
||||
return categoryService.deleteCategory(categoryId)
|
||||
}
|
||||
|
||||
@GetMapping("/test")
|
||||
fun test(): Mono<MutableList<BudgetCategory>> {
|
||||
var dateFrom = LocalDate.parse("2025-01-10")
|
||||
var dateTo = LocalDate.parse("2025-02-09")
|
||||
|
||||
return financialService.getCategoryTransactionPipeline(dateFrom, dateTo)
|
||||
|
||||
}
|
||||
|
||||
|
||||
@GetMapping("/by-month")
|
||||
fun getCategoriesSumsByMonths(): Mono<List<Document>> {
|
||||
return financialService.getCategorySumsPipeline(LocalDate.of(2024, 8, 1), LocalDate.of(2025, 1, 12))
|
||||
}
|
||||
|
||||
@GetMapping("/by-month2")
|
||||
fun getCategoriesSumsByMonthsV2(): Mono<List<Document>> {
|
||||
return financialService.getCategorySummaries(LocalDate.now().minusMonths(6))
|
||||
}
|
||||
//
|
||||
// @GetMapping()
|
||||
// fun getCategories(
|
||||
// @RequestParam("type") type: String? = null,
|
||||
// @RequestParam("sort") sortBy: String = "name",
|
||||
// @RequestParam("direction") direction: String = "ASC"
|
||||
// ): Mono<List<Category>> {
|
||||
// return categoryService.getCategories(type, sortBy, direction)
|
||||
//
|
||||
// }
|
||||
//
|
||||
// @GetMapping("/types")
|
||||
// fun getCategoriesTypes(): ResponseEntity<Any> {
|
||||
// return try {
|
||||
// ResponseEntity.ok(categoryService.getCategoryTypes())
|
||||
// } catch (e: Exception) {
|
||||
// ResponseEntity(HttpClientErrorException(HttpStatus.INTERNAL_SERVER_ERROR), HttpStatus.INTERNAL_SERVER_ERROR)
|
||||
//
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// @PostMapping()
|
||||
// fun createCategory(@RequestBody category: Category): Mono<Category> {
|
||||
// return categoryService.createCategory(category)
|
||||
// }
|
||||
//
|
||||
// @PutMapping("/{categoryId}")
|
||||
// fun editCategory(@PathVariable categoryId: String, @RequestBody category: Category): Mono<Category> {
|
||||
// return categoryService.editCategory(category)
|
||||
// }
|
||||
//
|
||||
//// @DeleteMapping("/{categoryId}")
|
||||
//// fun deleteCategory(@PathVariable categoryId: String): Mono<String> {
|
||||
//// return categoryService.deleteCategory(categoryId)
|
||||
//// }
|
||||
//
|
||||
// @GetMapping("/test")
|
||||
// fun test(): Mono<MutableList<BudgetCategory>> {
|
||||
// var dateFrom = LocalDate.parse("2025-01-10")
|
||||
// var dateTo = LocalDate.parse("2025-02-09")
|
||||
//
|
||||
// return financialService.getCategoryTransactionPipeline(dateFrom, dateTo)
|
||||
//
|
||||
// }
|
||||
//
|
||||
//
|
||||
// @GetMapping("/by-month")
|
||||
// fun getCategoriesSumsByMonths(): Mono<List<Document>> {
|
||||
// return financialService.getCategorySumsPipeline(LocalDate.of(2024, 8, 1), LocalDate.of(2025, 1, 12))
|
||||
// }
|
||||
//
|
||||
// @GetMapping("/by-month2")
|
||||
// fun getCategoriesSumsByMonthsV2(@RequestParam spaceId: String): Mono<List<Document>> {
|
||||
// return financialService.getCategorySummaries(spaceId, LocalDate.now().minusMonths(6))
|
||||
// }
|
||||
|
||||
|
||||
}
|
||||
@@ -17,33 +17,38 @@ import space.luminic.budgerapp.services.RecurrentService
|
||||
class RecurrentController (
|
||||
private val recurrentService: RecurrentService
|
||||
){
|
||||
|
||||
@GetMapping("/")
|
||||
fun getRecurrents(): Mono<List<Recurrent>> {
|
||||
return recurrentService.getRecurrents()
|
||||
}
|
||||
|
||||
|
||||
@GetMapping("/{id}")
|
||||
fun getRecurrent(@PathVariable id: String): Mono<Recurrent> {
|
||||
return recurrentService.getRecurrentById(id)
|
||||
}
|
||||
|
||||
@PostMapping("/")
|
||||
fun createRecurrent(@RequestBody recurrent: Recurrent): Mono<Recurrent> {
|
||||
return recurrentService.createRecurrent(recurrent)
|
||||
}
|
||||
|
||||
@PutMapping("/{id}")
|
||||
fun editRecurrent(@PathVariable id: String, @RequestBody recurrent: Recurrent): Mono<Recurrent> {
|
||||
return recurrentService.editRecurrent(recurrent)
|
||||
}
|
||||
|
||||
|
||||
@DeleteMapping("/{id}")
|
||||
fun deleteRecurrent(@PathVariable id: String): Mono<Void> {
|
||||
return recurrentService.deleteRecurrent(id)
|
||||
}
|
||||
//
|
||||
// @GetMapping("/")
|
||||
// fun getRecurrents(): Mono<List<Recurrent>> {
|
||||
// return recurrentService.getRecurrents()
|
||||
// }
|
||||
//
|
||||
//
|
||||
// @GetMapping("/{id}")
|
||||
// fun getRecurrent(@PathVariable id: String): Mono<Recurrent> {
|
||||
// return recurrentService.getRecurrentById(id)
|
||||
// }
|
||||
//
|
||||
// @PostMapping("/")
|
||||
// fun createRecurrent(@RequestBody recurrent: Recurrent): Mono<Recurrent> {
|
||||
// return recurrentService.createRecurrent(recurrent)
|
||||
// }
|
||||
//
|
||||
// @PutMapping("/{id}")
|
||||
// fun editRecurrent(@PathVariable id: String, @RequestBody recurrent: Recurrent): Mono<Recurrent> {
|
||||
// return recurrentService.editRecurrent(recurrent)
|
||||
// }
|
||||
//
|
||||
//
|
||||
// @DeleteMapping("/{id}")
|
||||
// fun deleteRecurrent(@PathVariable id: String): Mono<Void> {
|
||||
// return recurrentService.deleteRecurrent(id)
|
||||
// }
|
||||
//
|
||||
// @GetMapping("/regen")
|
||||
// fun regenRecurrents(): Mono<List<Recurrent>> {
|
||||
// return recurrentService.regenRecurrents()
|
||||
// }
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,265 @@
|
||||
package space.luminic.budgerapp.controllers
|
||||
|
||||
import org.bson.Document
|
||||
import org.springframework.http.HttpStatus
|
||||
import org.springframework.http.ResponseEntity
|
||||
import org.springframework.web.bind.annotation.*
|
||||
import org.springframework.web.client.HttpClientErrorException
|
||||
import reactor.core.publisher.Flux
|
||||
import reactor.core.publisher.Mono
|
||||
import space.luminic.budgerapp.controllers.dtos.BudgetCreationDTO
|
||||
import space.luminic.budgerapp.models.*
|
||||
import space.luminic.budgerapp.services.CategoryService
|
||||
import space.luminic.budgerapp.services.FinancialService
|
||||
import space.luminic.budgerapp.services.RecurrentService
|
||||
import space.luminic.budgerapp.services.SpaceService
|
||||
import java.time.LocalDate
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/spaces")
|
||||
class SpaceController(
|
||||
private val spaceService: SpaceService,
|
||||
private val financialService: FinancialService,
|
||||
private val categoryService: CategoryService,
|
||||
private val recurrentService: RecurrentService
|
||||
) {
|
||||
|
||||
|
||||
@GetMapping
|
||||
fun getSpaces(): Mono<List<Space>> {
|
||||
return spaceService.getSpaces()
|
||||
}
|
||||
|
||||
|
||||
@PostMapping
|
||||
fun createSpace(@RequestBody space: Space): Mono<Space> {
|
||||
return spaceService.createSpace(space)
|
||||
}
|
||||
|
||||
|
||||
@GetMapping("{spaceId}")
|
||||
fun getSpace(@PathVariable spaceId: String): Mono<Space> {
|
||||
return spaceService.getSpace(spaceId)
|
||||
}
|
||||
|
||||
|
||||
@DeleteMapping("/{spaceId}")
|
||||
fun deleteSpace(@PathVariable spaceId: String): Mono<Void> {
|
||||
return spaceService.deleteSpace(spaceId)
|
||||
}
|
||||
|
||||
@PostMapping("/{spaceId}/invite")
|
||||
fun inviteSpace(@PathVariable spaceId: String): Mono<SpaceInvite> {
|
||||
return spaceService.createInviteSpace(spaceId)
|
||||
}
|
||||
|
||||
@PostMapping("/invite/{code}")
|
||||
fun acceptInvite(@PathVariable code: String): Mono<Space> {
|
||||
return spaceService.acceptInvite(code)
|
||||
}
|
||||
|
||||
@DeleteMapping("/{spaceId}/leave")
|
||||
fun leaveSpace(@PathVariable spaceId: String): Mono<Void> {
|
||||
return spaceService.leaveSpace(spaceId)
|
||||
}
|
||||
|
||||
@DeleteMapping("/{spaceId}/members/kick/{username}")
|
||||
fun kickMembers(@PathVariable spaceId: String, @PathVariable username: String): Mono<Void> {
|
||||
return spaceService.kickMember(spaceId, username)
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
//Budgets API
|
||||
//
|
||||
@GetMapping("{spaceId}/budgets")
|
||||
fun getBudgets(@PathVariable spaceId: String): Mono<List<Budget>> {
|
||||
return financialService.getBudgets(spaceId)
|
||||
}
|
||||
|
||||
@PostMapping("/{spaceId}/budgets")
|
||||
fun createBudget(
|
||||
@PathVariable spaceId: String,
|
||||
@RequestBody budgetCreationDTO: BudgetCreationDTO,
|
||||
): Mono<Budget> {
|
||||
return financialService.createBudget(spaceId, budgetCreationDTO.budget, budgetCreationDTO.createRecurrent)
|
||||
}
|
||||
|
||||
|
||||
// Transactions API
|
||||
@GetMapping("/{spaceId}/transactions")
|
||||
fun getTransactions(
|
||||
@PathVariable spaceId: String,
|
||||
@RequestParam(value = "transaction_type") transactionType: String? = null,
|
||||
@RequestParam(value = "category_type") categoryType: String? = null,
|
||||
@RequestParam(value = "user_id") userId: String? = null,
|
||||
@RequestParam(value = "is_child") isChild: Boolean? = null,
|
||||
@RequestParam(value = "limit") limit: Int = 10,
|
||||
@RequestParam(value = "offset") offset: Int = 0
|
||||
): ResponseEntity<Any> {
|
||||
try {
|
||||
return ResponseEntity.ok(
|
||||
financialService.getTransactions(
|
||||
spaceId = spaceId,
|
||||
transactionType = transactionType,
|
||||
categoryType = categoryType,
|
||||
userId = userId,
|
||||
isChild = isChild,
|
||||
limit = limit,
|
||||
offset = offset
|
||||
)
|
||||
)
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
return ResponseEntity(HttpStatus.INTERNAL_SERVER_ERROR)
|
||||
}
|
||||
}
|
||||
|
||||
@GetMapping("/{spaceId}/transactions/{id}")
|
||||
fun getTransaction(
|
||||
@PathVariable spaceId: String,
|
||||
@PathVariable id: String
|
||||
): ResponseEntity<Any> {
|
||||
try {
|
||||
return ResponseEntity.ok(financialService.getTransactionById(id))
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
return ResponseEntity(e.message, HttpStatus.INTERNAL_SERVER_ERROR)
|
||||
}
|
||||
}
|
||||
|
||||
@PostMapping("/{spaceId}/transactions")
|
||||
fun createTransaction(@PathVariable spaceId: String, @RequestBody transaction: Transaction): ResponseEntity<Any> {
|
||||
try {
|
||||
return ResponseEntity.ok(financialService.createTransaction(spaceId, transaction))
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
return ResponseEntity(e.message, HttpStatus.INTERNAL_SERVER_ERROR)
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@PutMapping("/{spaceId}/transactions/{id}")
|
||||
fun editTransaction(
|
||||
@PathVariable spaceId: String, @PathVariable id: String, @RequestBody transaction: Transaction
|
||||
): ResponseEntity<Any> {
|
||||
try {
|
||||
return ResponseEntity.ok(financialService.editTransaction(transaction))
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
return ResponseEntity(e.message, HttpStatus.INTERNAL_SERVER_ERROR)
|
||||
}
|
||||
}
|
||||
|
||||
@DeleteMapping("/{spaceId}/transactions/{id}")
|
||||
fun deleteTransaction(@PathVariable spaceId: String, @PathVariable id: String): Mono<Void> {
|
||||
return financialService.deleteTransaction(id)
|
||||
}
|
||||
|
||||
//
|
||||
// Categories API
|
||||
//
|
||||
|
||||
|
||||
@GetMapping("/{spaceId}/categories")
|
||||
fun getCategories(
|
||||
@PathVariable spaceId: String,
|
||||
@RequestParam("type") type: String? = null,
|
||||
@RequestParam("sort") sortBy: String = "name",
|
||||
@RequestParam("direction") direction: String = "ASC"
|
||||
): Mono<List<Category>> {
|
||||
return spaceService.isValidRequest(spaceId).flatMap {
|
||||
categoryService.getCategories(spaceId, type, sortBy, direction)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@GetMapping("/{spaceId}/categories/types")
|
||||
fun getCategoriesTypes(): ResponseEntity<Any> {
|
||||
return try {
|
||||
ResponseEntity.ok(categoryService.getCategoryTypes())
|
||||
} catch (e: Exception) {
|
||||
ResponseEntity(HttpClientErrorException(HttpStatus.INTERNAL_SERVER_ERROR), HttpStatus.INTERNAL_SERVER_ERROR)
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@PostMapping("/{spaceId}/categories")
|
||||
fun createCategory(
|
||||
@PathVariable spaceId: String, @RequestBody category: Category
|
||||
): Mono<Category> {
|
||||
return spaceService.isValidRequest(spaceId).flatMap {
|
||||
categoryService.createCategory(it,category)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@PutMapping("/{spaceId}/{categoryId}")
|
||||
fun editCategory(@PathVariable categoryId: String, @RequestBody category: Category): Mono<Category> {
|
||||
return categoryService.editCategory(category)
|
||||
}
|
||||
|
||||
|
||||
@GetMapping("/by-month")
|
||||
fun getCategoriesSumsByMonths(): Mono<List<Document>> {
|
||||
return financialService.getCategorySumsPipeline(LocalDate.of(2024, 8, 1), LocalDate.of(2025, 1, 12))
|
||||
}
|
||||
|
||||
@GetMapping("/{spaceId}/analytics/by-month")
|
||||
fun getCategoriesSumsByMonthsV2(@PathVariable spaceId: String): Mono<List<Document>> {
|
||||
return financialService.getCategorySummaries(spaceId, LocalDate.now().minusMonths(6))
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Recurrents API
|
||||
//
|
||||
|
||||
@GetMapping("/{spaceId}/recurrents")
|
||||
fun getRecurrents(@PathVariable spaceId: String): Mono<List<Recurrent>> {
|
||||
return spaceService.isValidRequest(spaceId).flatMap {
|
||||
recurrentService.getRecurrents(it)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@GetMapping("/{spaceId}/recurrents/{id}")
|
||||
fun getRecurrent(@PathVariable spaceId: String, @PathVariable id: String): Mono<Recurrent> {
|
||||
return spaceService.isValidRequest(spaceId).flatMap {
|
||||
recurrentService.getRecurrentById(it, id)
|
||||
}
|
||||
}
|
||||
|
||||
@PostMapping("/{spaceId}/recurrent")
|
||||
fun createRecurrent(@PathVariable spaceId: String, @RequestBody recurrent: Recurrent): Mono<Recurrent> {
|
||||
return spaceService.isValidRequest(spaceId).flatMap {
|
||||
recurrentService.createRecurrent(it, recurrent)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@PutMapping("/{spaceId}/recurrent/{id}")
|
||||
fun editRecurrent(
|
||||
@PathVariable spaceId: String,
|
||||
@PathVariable id: String,
|
||||
@RequestBody recurrent: Recurrent
|
||||
): Mono<Recurrent> {
|
||||
return spaceService.isValidRequest(spaceId).flatMap {
|
||||
recurrentService.editRecurrent(recurrent)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@DeleteMapping("/{spaceId}/recurrent/{id}")
|
||||
fun deleteRecurrent(@PathVariable spaceId: String, @PathVariable id: String): Mono<Void> {
|
||||
return spaceService.isValidRequest(spaceId).flatMap {
|
||||
recurrentService.deleteRecurrent(id)
|
||||
}
|
||||
}
|
||||
|
||||
// @GetMapping("/regen")
|
||||
// fun regenSpaces(): Mono<List<Space>> {
|
||||
// return spaceService.regenSpaces()
|
||||
// }
|
||||
}
|
||||
@@ -26,6 +26,7 @@ class TransactionController(private val financialService: FinancialService) {
|
||||
|
||||
@GetMapping
|
||||
fun getTransactions(
|
||||
@RequestParam spaceId: String,
|
||||
@RequestParam(value = "transaction_type") transactionType: String? = null,
|
||||
@RequestParam(value = "category_type") categoryType: String? = null,
|
||||
@RequestParam(value = "user_id") userId: String? = null,
|
||||
@@ -36,6 +37,7 @@ class TransactionController(private val financialService: FinancialService) {
|
||||
try {
|
||||
return ResponseEntity.ok(
|
||||
financialService.getTransactions(
|
||||
spaceId = spaceId,
|
||||
transactionType = transactionType,
|
||||
categoryType = categoryType,
|
||||
userId = userId,
|
||||
@@ -61,9 +63,9 @@ class TransactionController(private val financialService: FinancialService) {
|
||||
}
|
||||
|
||||
@PostMapping
|
||||
fun createTransaction(@RequestBody transaction: Transaction): ResponseEntity<Any> {
|
||||
fun createTransaction(@RequestParam spaceId: String, @RequestBody transaction: Transaction): ResponseEntity<Any> {
|
||||
try {
|
||||
return ResponseEntity.ok(financialService.createTransaction(transaction))
|
||||
return ResponseEntity.ok(financialService.createTransaction(spaceId,transaction))
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
return ResponseEntity(e.message, HttpStatus.INTERNAL_SERVER_ERROR)
|
||||
@@ -109,5 +111,10 @@ class TransactionController(private val financialService: FinancialService) {
|
||||
}
|
||||
}
|
||||
|
||||
// @GetMapping("/regenTransactions")
|
||||
// fun regenTransactions(): Mono<Void> {
|
||||
// return financialService.regenTransactions()
|
||||
// }
|
||||
|
||||
|
||||
}
|
||||
@@ -10,6 +10,7 @@ import kotlin.collections.mutableListOf
|
||||
|
||||
data class BudgetDTO(
|
||||
var id: String? = null,
|
||||
var space: Space? = null,
|
||||
var name: String,
|
||||
var dateFrom: LocalDate,
|
||||
var dateTo: LocalDate,
|
||||
@@ -26,6 +27,7 @@ data class BudgetDTO(
|
||||
@Document("budgets")
|
||||
data class Budget(
|
||||
@Id var id: String? = null,
|
||||
@DBRef var space: Space? = null,
|
||||
var name: String,
|
||||
var dateFrom: LocalDate,
|
||||
var dateTo: LocalDate,
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package space.luminic.budgerapp.models
|
||||
|
||||
import org.springframework.data.annotation.Id
|
||||
import org.springframework.data.mongodb.core.mapping.DBRef
|
||||
import org.springframework.data.mongodb.core.mapping.Document
|
||||
|
||||
|
||||
@@ -8,6 +9,7 @@ import org.springframework.data.mongodb.core.mapping.Document
|
||||
data class Category(
|
||||
@Id
|
||||
val id: String? = null,
|
||||
@DBRef var space: Space? = null,
|
||||
var type: CategoryType,
|
||||
val name: String,
|
||||
val description: String? = null,
|
||||
|
||||
@@ -8,6 +8,7 @@ import java.util.Date
|
||||
@Document(collection = "recurrents")
|
||||
data class Recurrent(
|
||||
@Id val id: String? = null,
|
||||
@DBRef var space: Space? = null,
|
||||
var atDay: Int,
|
||||
@DBRef var category: Category,
|
||||
var name: String,
|
||||
|
||||
25
src/main/kotlin/space/luminic/budgerapp/models/Space.kt
Normal file
25
src/main/kotlin/space/luminic/budgerapp/models/Space.kt
Normal file
@@ -0,0 +1,25 @@
|
||||
package space.luminic.budgerapp.models
|
||||
|
||||
import org.springframework.data.annotation.Id
|
||||
import org.springframework.data.mongodb.core.mapping.DBRef
|
||||
import org.springframework.data.mongodb.core.mapping.Document
|
||||
import java.time.LocalDate
|
||||
import java.time.LocalDateTime
|
||||
|
||||
|
||||
@Document("spaces")
|
||||
data class Space (
|
||||
@Id var id: String? = null,
|
||||
var name: String? = null,
|
||||
var description: String? = null,
|
||||
@DBRef var owner: User? = null,
|
||||
@DBRef val users: MutableList<User> = mutableListOf(),
|
||||
var invites: MutableList<SpaceInvite> = mutableListOf(),
|
||||
val createdAt: LocalDate = LocalDate.now(),
|
||||
)
|
||||
|
||||
data class SpaceInvite(
|
||||
val code: String,
|
||||
@DBRef val fromUser: User,
|
||||
val activeTill: LocalDateTime,
|
||||
)
|
||||
@@ -12,6 +12,7 @@ import java.util.Date
|
||||
@Document(collection = "transactions")
|
||||
data class Transaction(
|
||||
@Id var id: String? = null,
|
||||
@DBRef var space: Space? = null,
|
||||
var type: TransactionType,
|
||||
@DBRef var user: User?=null,
|
||||
@DBRef var category: Category,
|
||||
|
||||
@@ -4,6 +4,8 @@ import com.fasterxml.jackson.annotation.JsonIgnore
|
||||
import jakarta.validation.constraints.NotBlank
|
||||
import org.springframework.data.annotation.Id
|
||||
import org.springframework.data.mongodb.core.mapping.Document
|
||||
import java.time.LocalDate
|
||||
import java.time.LocalDateTime
|
||||
import java.util.Date
|
||||
|
||||
@Document("users")
|
||||
@@ -17,8 +19,8 @@ data class User (
|
||||
@JsonIgnore // Скрывает пароль при сериализации
|
||||
var password: String? = null,
|
||||
var isActive: Boolean = true,
|
||||
var regDate: Date? = null,
|
||||
val createdAt: Date? = null,
|
||||
var regDate: LocalDate = LocalDate.now(),
|
||||
val createdAt: LocalDateTime = LocalDateTime.now(),
|
||||
var roles: MutableList<String> = mutableListOf(),
|
||||
)
|
||||
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
package space.luminic.budgerapp.repos
|
||||
|
||||
|
||||
|
||||
import org.bson.types.ObjectId
|
||||
import org.springframework.data.domain.Sort
|
||||
import org.springframework.data.mongodb.repository.Query
|
||||
import org.springframework.data.mongodb.repository.ReactiveMongoRepository
|
||||
import org.springframework.stereotype.Repository
|
||||
import reactor.core.publisher.Flux
|
||||
@@ -16,4 +19,10 @@ interface BudgetRepo: ReactiveMongoRepository<Budget, String> {
|
||||
|
||||
fun findByDateFromLessThanEqualAndDateToGreaterThanEqual(dateOne: LocalDate, dateTwo: LocalDate): Mono<Budget>
|
||||
|
||||
@Query("{'dateFrom': {'\$lte': ?0}, 'dateTo': {'\$gte': ?1}, 'space': ?2}")
|
||||
fun findByDateFromLessThanEqualAndDateToGreaterThanEqualAndSpace(dateOne: LocalDate, dateTwo: LocalDate, spaceId: ObjectId): Mono<Budget>
|
||||
|
||||
|
||||
@Query("{ 'space': { '\$ref': 'spaces','\$id': ?0 } }")
|
||||
fun findBySpaceId(spaceId: ObjectId, sort: Sort): Flux<Budget>
|
||||
}
|
||||
@@ -1,9 +1,17 @@
|
||||
package space.luminic.budgerapp.repos
|
||||
|
||||
import org.bson.types.ObjectId
|
||||
import org.springframework.data.mongodb.repository.Query
|
||||
import org.springframework.data.mongodb.repository.ReactiveMongoRepository
|
||||
import org.springframework.stereotype.Repository
|
||||
import reactor.core.publisher.Flux
|
||||
import reactor.core.publisher.Mono
|
||||
import space.luminic.budgerapp.models.Recurrent
|
||||
import space.luminic.budgerapp.models.Space
|
||||
|
||||
@Repository
|
||||
interface RecurrentRepo: ReactiveMongoRepository<Recurrent, String> {
|
||||
|
||||
@Query("{ 'space': { '\$ref': 'spaces', '\$id': ?0 } }")
|
||||
fun findRecurrentsBySpaceId(spaceID: ObjectId): Flux<Recurrent>
|
||||
}
|
||||
21
src/main/kotlin/space/luminic/budgerapp/repos/SpaceRepo.kt
Normal file
21
src/main/kotlin/space/luminic/budgerapp/repos/SpaceRepo.kt
Normal file
@@ -0,0 +1,21 @@
|
||||
package space.luminic.budgerapp.repos
|
||||
|
||||
import org.bson.types.ObjectId
|
||||
import org.springframework.data.mongodb.repository.Query
|
||||
import org.springframework.data.mongodb.repository.ReactiveMongoRepository
|
||||
import org.springframework.stereotype.Repository
|
||||
import reactor.core.publisher.Flux
|
||||
import reactor.core.publisher.Mono
|
||||
import space.luminic.budgerapp.models.Space
|
||||
import space.luminic.budgerapp.models.User
|
||||
|
||||
|
||||
@Repository
|
||||
interface SpaceRepo: ReactiveMongoRepository<Space, String> {
|
||||
|
||||
@Query("{ 'users': { '\$ref': 'users', '\$id': ?0 } }")
|
||||
fun findByArrayElement(userId: ObjectId): Flux<Space>
|
||||
|
||||
@Query("{ 'invites.code': ?0 }") // Исправленный путь, чтобы находить вложенные документы
|
||||
fun findSpaceByInvites(code: String): Mono<Space>
|
||||
}
|
||||
@@ -43,6 +43,26 @@ class AuthService(
|
||||
}
|
||||
}
|
||||
|
||||
fun register(username: String, password: String, firstName: String): Mono<User> {
|
||||
return userRepository.findByUsername(username)
|
||||
.flatMap<User> { Mono.error(IllegalArgumentException("User with username '$username' already exists")) } // Ошибка, если пользователь уже существует
|
||||
.switchIfEmpty(
|
||||
Mono.defer {
|
||||
val newUser = User(
|
||||
username = username,
|
||||
password = passwordEncoder.encode(password), // Шифрование пароля
|
||||
firstName = firstName,
|
||||
roles = mutableListOf("USER")
|
||||
)
|
||||
userRepository.save(newUser).map { user ->
|
||||
user.password = null
|
||||
user
|
||||
} // Сохранение нового пользователя
|
||||
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
@Cacheable("tokens")
|
||||
fun isTokenValid(token: String): Mono<User> {
|
||||
return tokenService.getToken(token)
|
||||
|
||||
@@ -21,11 +21,7 @@ import org.springframework.data.mongodb.core.query.isEqualTo
|
||||
import org.springframework.stereotype.Service
|
||||
import reactor.core.publisher.Flux
|
||||
import reactor.core.publisher.Mono
|
||||
import space.luminic.budgerapp.models.BudgetCategory
|
||||
import space.luminic.budgerapp.models.Category
|
||||
import space.luminic.budgerapp.models.CategoryType
|
||||
import space.luminic.budgerapp.models.SortSetting
|
||||
import space.luminic.budgerapp.models.Transaction
|
||||
import space.luminic.budgerapp.models.*
|
||||
import space.luminic.budgerapp.repos.CategoryRepo
|
||||
import java.time.LocalDate
|
||||
import java.time.LocalDateTime
|
||||
@@ -50,11 +46,12 @@ class CategoryService(
|
||||
return categoryRepo.findById(id)
|
||||
}
|
||||
|
||||
// @Cacheable("categories")
|
||||
fun getCategories(type: String? = null, sortBy: String, direction: String): Mono<List<Category>> {
|
||||
// @Cacheable("categories")
|
||||
fun getCategories(spaceId: String, type: String? = null, sortBy: String, direction: String): Mono<List<Category>> {
|
||||
val matchCriteria = mutableListOf<Criteria>()
|
||||
|
||||
// Добавляем фильтры
|
||||
matchCriteria.add(Criteria.where("spaceDetails._id").`is`(ObjectId(spaceId)))
|
||||
type?.let { matchCriteria.add(Criteria.where("type.code").isEqualTo(it)) }
|
||||
|
||||
val match = match(Criteria().andOperator(*matchCriteria.toTypedArray()))
|
||||
@@ -62,16 +59,17 @@ class CategoryService(
|
||||
|
||||
val sort = sort(Sort.by(direction, sortBy))
|
||||
|
||||
val lookupSpaces = lookup("spaces", "space.\$id", "_id", "spaceDetails")
|
||||
|
||||
val aggregationBuilder = mutableListOf(
|
||||
|
||||
|
||||
lookupSpaces,
|
||||
match.takeIf { matchCriteria.isNotEmpty() },
|
||||
sort,
|
||||
).filterNotNull()
|
||||
|
||||
val aggregation = newAggregation(aggregationBuilder)
|
||||
|
||||
logger.error("STARTED")
|
||||
return mongoTemplate.aggregate(
|
||||
aggregation, "categories", Category::class.java
|
||||
)
|
||||
@@ -97,7 +95,8 @@ class CategoryService(
|
||||
}
|
||||
|
||||
@CacheEvict(cacheNames = ["getAllCategories"], allEntries = true)
|
||||
fun createCategory(category: Category): Mono<Category> {
|
||||
fun createCategory(space: Space, category: Category): Mono<Category> {
|
||||
category.space = space
|
||||
return categoryRepo.save(category)
|
||||
}
|
||||
|
||||
@@ -113,32 +112,32 @@ class CategoryService(
|
||||
}
|
||||
|
||||
@CacheEvict(cacheNames = ["getAllCategories"], allEntries = true)
|
||||
fun deleteCategory(categoryId: String): Mono<String> {
|
||||
return categoryRepo.findById(categoryId).switchIfEmpty(
|
||||
Mono.error(IllegalArgumentException("Category with id: $categoryId not found"))
|
||||
).flatMap {
|
||||
financialService.getTransactions(categoryId = categoryId)
|
||||
.flatMapMany { transactions ->
|
||||
categoryRepo.findByName("Другое").switchIfEmpty(
|
||||
categoryRepo.save(
|
||||
Category(
|
||||
type = CategoryType("EXPENSE", "Траты"),
|
||||
name = "Другое",
|
||||
description = "Категория для других трат",
|
||||
icon = "🚮"
|
||||
)
|
||||
)
|
||||
).flatMapMany { category ->
|
||||
Flux.fromIterable(transactions).flatMap { transaction ->
|
||||
transaction.category = category // Присваиваем конкретный объект категории
|
||||
financialService.editTransaction(transaction) // Сохраняем изменения
|
||||
}
|
||||
}
|
||||
}
|
||||
.then(categoryRepo.deleteById(categoryId)) // Удаляем старую категорию
|
||||
.thenReturn(categoryId) // Возвращаем удалённую категорию
|
||||
}
|
||||
}
|
||||
// fun deleteCategory(categoryId: String): Mono<String> {
|
||||
// return categoryRepo.findById(categoryId).switchIfEmpty(
|
||||
// Mono.error(IllegalArgumentException("Category with id: $categoryId not found"))
|
||||
// ).flatMap {
|
||||
// financialService.getTransactions(categoryId = categoryId)
|
||||
// .flatMapMany { transactions ->
|
||||
// categoryRepo.findByName("Другое").switchIfEmpty(
|
||||
// categoryRepo.save(
|
||||
// Category(
|
||||
// type = CategoryType("EXPENSE", "Траты"),
|
||||
// name = "Другое",
|
||||
// description = "Категория для других трат",
|
||||
// icon = "🚮"
|
||||
// )
|
||||
// )
|
||||
// ).flatMapMany { category ->
|
||||
// Flux.fromIterable(transactions).flatMap { transaction ->
|
||||
// transaction.category = category // Присваиваем конкретный объект категории
|
||||
// financialService.editTransaction(transaction) // Сохраняем изменения
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// .then(categoryRepo.deleteById(categoryId)) // Удаляем старую категорию
|
||||
// .thenReturn(categoryId) // Возвращаем удалённую категорию
|
||||
// }
|
||||
// }
|
||||
|
||||
|
||||
fun getBudgetCategories(dateFrom: LocalDate, dateTo: LocalDate): Mono<Map<String, Map<String, Double>>> {
|
||||
|
||||
@@ -8,6 +8,7 @@ import org.springframework.cache.annotation.CacheEvict
|
||||
import org.springframework.cache.annotation.Cacheable
|
||||
import org.springframework.data.domain.Sort
|
||||
import org.springframework.data.domain.Sort.Direction
|
||||
import org.springframework.data.mongodb.core.MongoTemplate
|
||||
import org.springframework.data.mongodb.core.ReactiveMongoTemplate
|
||||
import org.springframework.data.mongodb.core.aggregation.Aggregation.*
|
||||
import org.springframework.data.mongodb.core.aggregation.DateOperators.DateToString
|
||||
@@ -19,6 +20,7 @@ import reactor.core.publisher.Flux
|
||||
import reactor.core.publisher.Mono
|
||||
import space.luminic.budgerapp.models.*
|
||||
import space.luminic.budgerapp.repos.BudgetRepo
|
||||
import space.luminic.budgerapp.repos.CategoryRepo
|
||||
import space.luminic.budgerapp.repos.TransactionRepo
|
||||
import space.luminic.budgerapp.repos.WarnRepo
|
||||
import java.time.*
|
||||
@@ -32,7 +34,9 @@ class FinancialService(
|
||||
val transactionsRepo: TransactionRepo,
|
||||
val recurrentService: RecurrentService,
|
||||
val userService: UserService,
|
||||
val reactiveMongoTemplate: ReactiveMongoTemplate
|
||||
val reactiveMongoTemplate: ReactiveMongoTemplate,
|
||||
private val spaceService: SpaceService,
|
||||
private val categoryRepo: CategoryRepo
|
||||
) {
|
||||
private val logger = LoggerFactory.getLogger(FinancialService::class.java)
|
||||
|
||||
@@ -191,24 +195,58 @@ class FinancialService(
|
||||
}.then() // Возвращаем корректный Mono<Void>
|
||||
}
|
||||
|
||||
@Cacheable("budgetsList")
|
||||
fun getBudgets(sortSetting: SortSetting? = null): Mono<MutableList<Budget>> {
|
||||
val sort = if (sortSetting != null) {
|
||||
Sort.by(sortSetting.order, sortSetting.by)
|
||||
fun getBudgets(spaceId: String, sortSetting: SortSetting? = null): Mono<List<Budget>> {
|
||||
val sort = sortSetting?.let {
|
||||
Sort.by(it.order, it.by)
|
||||
} ?: Sort.by(Sort.Direction.DESC, "dateFrom")
|
||||
|
||||
return ReactiveSecurityContextHolder.getContext()
|
||||
.map { it.authentication }
|
||||
.flatMap { authentication ->
|
||||
val username = authentication.name
|
||||
spaceService.getSpace(spaceId)
|
||||
.switchIfEmpty(Mono.error(IllegalArgumentException("Space not found for $spaceId")))
|
||||
.flatMap { space ->
|
||||
userService.getByUsername(username)
|
||||
.switchIfEmpty(Mono.error(IllegalArgumentException("User not found for username: $username")))
|
||||
.flatMap { user ->
|
||||
val userIds = space.users.mapNotNull { it.id?.toString() }
|
||||
if (user.id !in userIds) {
|
||||
Mono.error(IllegalArgumentException("User cannot access this Space"))
|
||||
} else {
|
||||
Sort.by(Sort.Direction.DESC, "dateFrom")
|
||||
val spaceObjectId = try {
|
||||
ObjectId(space.id!!) // Преобразуем строку в ObjectId
|
||||
} catch (e: IllegalArgumentException) {
|
||||
return@flatMap Mono.error(IllegalArgumentException("Invalid Space ID format: ${space.id}"))
|
||||
}
|
||||
|
||||
return budgetRepo.findAll(sort)
|
||||
.collectList() // Сбор Flux<Budget> в Mono<List<Budget>>
|
||||
println("Space ID type: ${spaceObjectId::class.java}, value: $spaceObjectId")
|
||||
// Применяем сортировку к запросу
|
||||
budgetRepo.findBySpaceId(spaceObjectId, sort).collectList()
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// @Cacheable("budgets", key = "#id")
|
||||
fun getBudget(id: String): Mono<BudgetDTO> {
|
||||
return budgetRepo.findById(id)
|
||||
return ReactiveSecurityContextHolder.getContext()
|
||||
.flatMap { securityContext ->
|
||||
val username = securityContext.authentication.name
|
||||
budgetRepo.findById(id)
|
||||
.flatMap { budget ->
|
||||
// Проверяем, что пользователь есть в space бюджета
|
||||
if (!budget.space!!.users.any { it.username == username }) {
|
||||
return@flatMap Mono.error(IllegalArgumentException("User does not have access to this space"))
|
||||
}
|
||||
|
||||
// Если доступ есть, продолжаем процесс
|
||||
val budgetDTO = BudgetDTO(
|
||||
budget.id,
|
||||
budget.space,
|
||||
budget.name,
|
||||
budget.dateFrom,
|
||||
budget.dateTo,
|
||||
@@ -219,16 +257,13 @@ class FinancialService(
|
||||
|
||||
logger.info("Fetching categories and transactions")
|
||||
val categoriesMono = getBudgetCategories(budgetDTO.dateFrom, budgetDTO.dateTo)
|
||||
val transactionsMono =
|
||||
getTransactionsByTypes(budgetDTO.dateFrom, budgetDTO.dateTo)
|
||||
|
||||
val transactionsMono = getTransactionsByTypes(budgetDTO.dateFrom, budgetDTO.dateTo)
|
||||
|
||||
Mono.zip(categoriesMono, transactionsMono)
|
||||
.flatMap { tuple ->
|
||||
val categories = tuple.t1
|
||||
val transactions = tuple.t2
|
||||
|
||||
|
||||
Flux.fromIterable(budgetDTO.categories)
|
||||
.map { category ->
|
||||
categories[category.category.id]?.let { data ->
|
||||
@@ -253,13 +288,15 @@ class FinancialService(
|
||||
}
|
||||
.switchIfEmpty(Mono.error(BudgetNotFoundException("Budget not found with id: $id")))
|
||||
}
|
||||
}
|
||||
|
||||
fun regenCats(): Mono<Void> {
|
||||
|
||||
fun regenBudgets(): Mono<Void> {
|
||||
return budgetRepo.findAll()
|
||||
.flatMap { budget ->
|
||||
getCategoryTransactionPipeline(budget.dateFrom, budget.dateTo, "INCOME")
|
||||
.map { categories ->
|
||||
budget.incomeCategories = categories
|
||||
spaceService.getSpace("67af3c0f652da946a7dd9931")
|
||||
.map { space ->
|
||||
budget.space = space
|
||||
budget
|
||||
}
|
||||
.flatMap { updatedBudget -> budgetRepo.save(updatedBudget) }
|
||||
@@ -267,12 +304,38 @@ class FinancialService(
|
||||
.then()
|
||||
}
|
||||
|
||||
fun regenTransactions(): Mono<Void> {
|
||||
return transactionsRepo.findAll().flatMap { transaction ->
|
||||
spaceService.getSpace("67af3c0f652da946a7dd9931")
|
||||
.map { space ->
|
||||
transaction.space = space
|
||||
transaction
|
||||
}
|
||||
.flatMap { updatedTransaction -> transactionsRepo.save(updatedTransaction) }
|
||||
}
|
||||
.then()
|
||||
}
|
||||
|
||||
|
||||
fun regenCats(): Mono<Void> {
|
||||
return categoryRepo.findAll()// Получаем список категорий
|
||||
.flatMap { cat ->
|
||||
spaceService.getSpace("67af3c0f652da946a7dd9931") // Получаем space
|
||||
.map { space ->
|
||||
cat.space = space // Привязываем пространство к категории
|
||||
cat
|
||||
}
|
||||
}
|
||||
.flatMap { updatedCategory -> categoryRepo.save(updatedCategory) } // Сохраняем в БД
|
||||
.then() // Завершаем Mono<Void>
|
||||
}
|
||||
|
||||
@CacheEvict(cacheNames = ["budgets", "budgetsList"], allEntries = true)
|
||||
fun createBudget(budget: Budget, createRecurrent: Boolean): Mono<Budget> {
|
||||
fun createBudget(spaceId: String, budget: Budget, createRecurrent: Boolean): Mono<Budget> {
|
||||
return Mono.zip(
|
||||
getBudgetByDate(budget.dateFrom).map { Optional.ofNullable(it) }
|
||||
getBudgetByDate(budget.dateFrom, spaceId).map { Optional.ofNullable(it) }
|
||||
.switchIfEmpty(Mono.just(Optional.empty())),
|
||||
getBudgetByDate(budget.dateTo).map { Optional.ofNullable(it) }
|
||||
getBudgetByDate(budget.dateTo, spaceId).map { Optional.ofNullable(it) }
|
||||
.switchIfEmpty(Mono.just(Optional.empty()))
|
||||
).flatMap { tuple ->
|
||||
val startBudget = tuple.t1.orElse(null)
|
||||
@@ -283,9 +346,27 @@ class FinancialService(
|
||||
return@flatMap Mono.error<Budget>(IllegalArgumentException("Бюджет с теми же датами найден"))
|
||||
}
|
||||
|
||||
// Получаем Space по spaceId
|
||||
return@flatMap spaceService.getSpace(spaceId)
|
||||
.switchIfEmpty(Mono.error(IllegalArgumentException("Space not found for $spaceId")))
|
||||
|
||||
.flatMap { space ->
|
||||
// Проверяем, входит ли пользователь в этот Space
|
||||
ReactiveSecurityContextHolder.getContext().flatMap { securityContext ->
|
||||
val username = securityContext.authentication.name
|
||||
userService.getByUsername(username)
|
||||
.switchIfEmpty(Mono.error(IllegalArgumentException("User not found for username: $username")))
|
||||
.flatMap { user ->
|
||||
if (space.users.none { it.id == user.id }) {
|
||||
return@flatMap Mono.error<Budget>(IllegalArgumentException("User does not have access to this space"))
|
||||
}
|
||||
|
||||
// Присваиваем Space бюджету
|
||||
budget.space = space
|
||||
|
||||
// Если createRecurrent=true, создаем рекуррентные транзакции
|
||||
val recurrentsCreation = if (createRecurrent) {
|
||||
recurrentService.createRecurrentsForBudget(budget)
|
||||
recurrentService.createRecurrentsForBudget(space, budget)
|
||||
} else {
|
||||
Mono.empty()
|
||||
}
|
||||
@@ -311,8 +392,13 @@ class FinancialService(
|
||||
}
|
||||
}
|
||||
|
||||
fun getBudgetByDate(date: LocalDate): Mono<Budget> {
|
||||
return budgetRepo.findByDateFromLessThanEqualAndDateToGreaterThanEqual(date, date).switchIfEmpty(Mono.empty())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun getBudgetByDate(date: LocalDate, spaceId: String): Mono<Budget> {
|
||||
return budgetRepo.findByDateFromLessThanEqualAndDateToGreaterThanEqualAndSpace(date, date, ObjectId(spaceId))
|
||||
.switchIfEmpty(Mono.empty())
|
||||
}
|
||||
|
||||
|
||||
@@ -530,6 +616,7 @@ class FinancialService(
|
||||
|
||||
@Cacheable("transactions")
|
||||
fun getTransactions(
|
||||
spaceId: String,
|
||||
dateFrom: LocalDate? = null,
|
||||
dateTo: LocalDate? = null,
|
||||
transactionType: String? = null,
|
||||
@@ -543,25 +630,46 @@ class FinancialService(
|
||||
limit: Int? = null,
|
||||
offset: Int? = null,
|
||||
): Mono<MutableList<Transaction>> {
|
||||
return ReactiveSecurityContextHolder.getContext()
|
||||
.map { it.authentication }
|
||||
.flatMap { authentication ->
|
||||
val username = authentication.name
|
||||
spaceService.getSpace(spaceId)
|
||||
.switchIfEmpty(Mono.error(IllegalArgumentException("Space not found for $spaceId")))
|
||||
.flatMap { space ->
|
||||
userService.getByUsername(username)
|
||||
.switchIfEmpty(Mono.error(IllegalArgumentException("User not found for username: $username")))
|
||||
.flatMap { user ->
|
||||
if (space.users.none { it.id.toString() == user.id }) {
|
||||
return@flatMap Mono.error<MutableList<Transaction>>(IllegalArgumentException("User does not have access to this Space"))
|
||||
}
|
||||
|
||||
val matchCriteria = mutableListOf<Criteria>()
|
||||
|
||||
// Добавляем фильтры
|
||||
matchCriteria.add(Criteria.where("spaceDetails._id").`is`(ObjectId(spaceId)))
|
||||
dateFrom?.let { matchCriteria.add(Criteria.where("date").gte(it)) }
|
||||
dateTo?.let { matchCriteria.add(Criteria.where("date").lt(it)) }
|
||||
transactionType?.let { matchCriteria.add(Criteria.where("type.code").`is`(it)) }
|
||||
isDone?.let { matchCriteria.add(Criteria.where("isDone").`is`(it)) }
|
||||
categoryId?.let { matchCriteria.add(Criteria.where("categoryDetails._id").`is`(it)) }
|
||||
categoryType?.let { matchCriteria.add(Criteria.where("categoryDetails.type.code").`is`(it)) }
|
||||
categoryType?.let {
|
||||
matchCriteria.add(
|
||||
Criteria.where("categoryDetails.type.code").`is`(it)
|
||||
)
|
||||
}
|
||||
userId?.let { matchCriteria.add(Criteria.where("userDetails._id").`is`(ObjectId(it))) }
|
||||
parentId?.let { matchCriteria.add(Criteria.where("parentId").`is`(it)) }
|
||||
isChild?.let { matchCriteria.add(Criteria.where("parentId").exists(it)) }
|
||||
|
||||
// Сборка агрегации
|
||||
val lookup = lookup("categories", "category.\$id", "_id", "categoryDetails")
|
||||
val lookupSpaces = lookup("spaces", "space.\$id", "_id", "spaceDetails")
|
||||
val lookupUsers = lookup("users", "user.\$id", "_id", "userDetails")
|
||||
val match = match(Criteria().andOperator(*matchCriteria.toTypedArray()))
|
||||
|
||||
var sort = sort(Sort.by(Direction.DESC, "date").and(Sort.by(Direction.DESC, "createdAt")))
|
||||
var sort =
|
||||
sort(Sort.by(Direction.DESC, "date").and(Sort.by(Direction.DESC, "createdAt")))
|
||||
|
||||
sortSetting?.let {
|
||||
sort = sort(Sort.by(it.order, it.by).and(Sort.by(Direction.ASC, "createdAt")))
|
||||
@@ -569,6 +677,7 @@ class FinancialService(
|
||||
|
||||
val aggregationBuilder = mutableListOf(
|
||||
lookup,
|
||||
lookupSpaces,
|
||||
lookupUsers,
|
||||
match.takeIf { matchCriteria.isNotEmpty() },
|
||||
sort,
|
||||
@@ -578,12 +687,15 @@ class FinancialService(
|
||||
|
||||
val aggregation = newAggregation(aggregationBuilder)
|
||||
|
||||
return reactiveMongoTemplate.aggregate(
|
||||
return@flatMap reactiveMongoTemplate.aggregate(
|
||||
aggregation, "transactions", Transaction::class.java
|
||||
)
|
||||
.collectList() // Преобразуем Flux<Transaction> в Mono<List<Transaction>>
|
||||
.collectList()
|
||||
.map { it.toMutableList() }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun getTransactionsToDelete(dateFrom: LocalDate, dateTo: LocalDate): Mono<List<Transaction>> {
|
||||
val criteria = Criteria().andOperator(
|
||||
@@ -618,15 +730,24 @@ class FinancialService(
|
||||
|
||||
|
||||
@CacheEvict(cacheNames = ["transactions"], allEntries = true)
|
||||
fun createTransaction(transaction: Transaction): Mono<Transaction> {
|
||||
fun createTransaction(spaceId: String, transaction: Transaction): Mono<Transaction> {
|
||||
return ReactiveSecurityContextHolder.getContext()
|
||||
.map { it.authentication }
|
||||
.flatMap { authentication ->
|
||||
val username = authentication.name
|
||||
spaceService.getSpace(spaceId)
|
||||
.switchIfEmpty(Mono.error(IllegalArgumentException("Space not found for $spaceId")))
|
||||
.flatMap { space ->
|
||||
userService.getByUsername(username)
|
||||
.switchIfEmpty(Mono.error(IllegalArgumentException("User not found for username: $username")))
|
||||
.flatMap { user ->
|
||||
if (space.users.none { it.id.toString() == user.id }) {
|
||||
return@flatMap Mono.error<Transaction>(IllegalArgumentException("User does not have access to this Space"))
|
||||
}
|
||||
// Привязываем space и user к транзакции
|
||||
transaction.user = user
|
||||
transaction.space = space
|
||||
|
||||
transactionsRepo.save(transaction)
|
||||
.flatMap { savedTransaction ->
|
||||
updateBudgetOnCreate(savedTransaction)
|
||||
@@ -635,6 +756,7 @@ class FinancialService(
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@CacheEvict(cacheNames = ["transactions", "budgets"], allEntries = true)
|
||||
@@ -1034,8 +1156,8 @@ class FinancialService(
|
||||
tgUserName = userDocument["tgUserName"]?.let { it as String },
|
||||
password = null,
|
||||
isActive = userDocument["isActive"] as Boolean,
|
||||
regDate = userDocument["regDate"] as Date,
|
||||
createdAt = userDocument["createdAt"] as Date,
|
||||
regDate = userDocument["regDate"] as LocalDate,
|
||||
createdAt = userDocument["createdAt"] as LocalDateTime,
|
||||
roles = userDocument["roles"] as ArrayList<String>,
|
||||
)
|
||||
|
||||
@@ -1051,6 +1173,7 @@ class FinancialService(
|
||||
)
|
||||
return Transaction(
|
||||
(document["_id"] as ObjectId).toString(),
|
||||
null,
|
||||
TransactionType(
|
||||
transactionType["code"] as String,
|
||||
transactionType["name"] as String
|
||||
@@ -1582,7 +1705,7 @@ class FinancialService(
|
||||
.collectList()
|
||||
}
|
||||
|
||||
fun getCategorySummaries(dateFrom: LocalDate): Mono<List<Document>> {
|
||||
fun getCategorySummaries(spaceId: String, dateFrom: LocalDate): Mono<List<Document>> {
|
||||
val sixMonthsAgo = Date.from(
|
||||
LocalDateTime.of(dateFrom, LocalTime.MIN)
|
||||
.atZone(ZoneId.systemDefault())
|
||||
@@ -1591,6 +1714,16 @@ class FinancialService(
|
||||
|
||||
val aggregation = listOf(
|
||||
// 1. Фильтр за последние 6 месяцев
|
||||
Document(
|
||||
"\$lookup", Document("from", "spaces")
|
||||
.append("localField", "space.\$id")
|
||||
.append("foreignField", "_id")
|
||||
.append("as", "spaceInfo")
|
||||
),
|
||||
|
||||
// 4. Распаковываем массив категорий
|
||||
Document("\$unwind", "\$spaceInfo"),
|
||||
Document("\$match", Document("spaceInfo._id", ObjectId(spaceId))),
|
||||
Document(
|
||||
"\$match",
|
||||
Document("date", Document("\$gte", sixMonthsAgo).append("\$lt", Date())).append("type.code", "INSTANT")
|
||||
@@ -1720,6 +1853,7 @@ class FinancialService(
|
||||
Document("\$sort", Document("categoryName", 1))
|
||||
)
|
||||
|
||||
|
||||
// Выполняем агрегацию
|
||||
return reactiveMongoTemplate.getCollection("transactions")
|
||||
.flatMapMany { it.aggregate(aggregation) }
|
||||
|
||||
@@ -1,17 +1,14 @@
|
||||
package space.luminic.budgerapp.services
|
||||
|
||||
|
||||
import org.bson.types.ObjectId
|
||||
import org.slf4j.LoggerFactory
|
||||
import org.springframework.cache.annotation.CacheEvict
|
||||
import org.springframework.cache.annotation.Cacheable
|
||||
import org.springframework.security.core.context.ReactiveSecurityContextHolder
|
||||
import org.springframework.stereotype.Service
|
||||
import reactor.core.publisher.Mono
|
||||
import space.luminic.budgerapp.models.Budget
|
||||
import space.luminic.budgerapp.models.NotFoundException
|
||||
import space.luminic.budgerapp.models.Recurrent
|
||||
import space.luminic.budgerapp.models.Transaction
|
||||
import space.luminic.budgerapp.models.TransactionType
|
||||
import space.luminic.budgerapp.models.*
|
||||
import space.luminic.budgerapp.repos.RecurrentRepo
|
||||
import space.luminic.budgerapp.repos.TransactionRepo
|
||||
import java.time.YearMonth
|
||||
@@ -22,31 +19,40 @@ class RecurrentService(
|
||||
private val recurrentRepo: RecurrentRepo,
|
||||
private val transactionRepo: TransactionRepo,
|
||||
private val userService: UserService,
|
||||
private val spaceService: SpaceService,
|
||||
) {
|
||||
|
||||
private val logger = LoggerFactory.getLogger(javaClass)
|
||||
|
||||
@Cacheable("recurrentsList")
|
||||
fun getRecurrents(): Mono<List<Recurrent>> {
|
||||
return recurrentRepo.findAll().collectList()
|
||||
fun getRecurrents(space: Space): Mono<List<Recurrent>> {
|
||||
|
||||
// Запрос рекуррентных платежей
|
||||
return recurrentRepo.findRecurrentsBySpaceId(ObjectId(space.id))
|
||||
.collectList() // Преобразуем Flux<Recurrent> в Mono<List<Recurrent>>
|
||||
}
|
||||
|
||||
|
||||
@Cacheable("recurrents", key = "#id")
|
||||
fun getRecurrentById(id: String): Mono<Recurrent> {
|
||||
fun getRecurrentById(space: Space, id: String): Mono<Recurrent> {
|
||||
// Запрос рекуррентных платежей
|
||||
return recurrentRepo.findById(id)
|
||||
.switchIfEmpty(Mono.error(NotFoundException("Recurrent with id: $id not found")))
|
||||
}
|
||||
|
||||
|
||||
@CacheEvict(cacheNames = ["recurrentsList", "recurrents"])
|
||||
fun createRecurrent(recurrent: Recurrent): Mono<Recurrent> {
|
||||
return if (recurrent.id == null && recurrent.atDay <= 31) recurrentRepo.save(recurrent) else Mono.error(
|
||||
fun createRecurrent(space: Space, recurrent: Recurrent): Mono<Recurrent> {
|
||||
return if (recurrent.id == null && recurrent.atDay <= 31) {
|
||||
recurrent.space = space
|
||||
recurrentRepo.save(recurrent)
|
||||
} else Mono.error(
|
||||
RuntimeException("Cannot create recurrent with id or date cannot be higher than 31")
|
||||
)
|
||||
}
|
||||
|
||||
@CacheEvict(cacheNames = ["recurrentsList", "recurrents"])
|
||||
fun createRecurrentsForBudget(budget: Budget): Mono<Void> {
|
||||
fun createRecurrentsForBudget(space: Space, budget: Budget): Mono<Void> {
|
||||
val currentYearMonth = YearMonth.of(budget.dateFrom.year, budget.dateFrom.monthValue)
|
||||
val daysInCurrentMonth = currentYearMonth.lengthOfMonth()
|
||||
val context = ReactiveSecurityContextHolder.getContext()
|
||||
@@ -63,7 +69,7 @@ class RecurrentService(
|
||||
.switchIfEmpty(Mono.error(IllegalArgumentException("User not found for username: $username")))
|
||||
}
|
||||
.flatMapMany { user ->
|
||||
recurrentRepo.findAll()
|
||||
recurrentRepo.findRecurrentsBySpaceId(ObjectId(space.id))
|
||||
.map { recurrent ->
|
||||
// Определяем дату транзакции
|
||||
val transactionDate = when {
|
||||
@@ -111,7 +117,17 @@ class RecurrentService(
|
||||
return recurrentRepo.deleteById(id)
|
||||
}
|
||||
|
||||
|
||||
fun regenRecurrents(): Mono<List<Recurrent>> {
|
||||
return recurrentRepo.findAll()
|
||||
.flatMap { recurrent ->
|
||||
spaceService.getSpace("67af3c0f652da946a7dd9931")
|
||||
.flatMap { space ->
|
||||
recurrent.space = space
|
||||
recurrentRepo.save(recurrent) // Сохраняем и возвращаем сохраненный объект
|
||||
}
|
||||
}
|
||||
.collectList() // Собираем результаты в список
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
233
src/main/kotlin/space/luminic/budgerapp/services/SpaceService.kt
Normal file
233
src/main/kotlin/space/luminic/budgerapp/services/SpaceService.kt
Normal file
@@ -0,0 +1,233 @@
|
||||
package space.luminic.budgerapp.services
|
||||
|
||||
import org.bson.types.ObjectId
|
||||
import org.springframework.data.domain.Sort
|
||||
import org.springframework.data.domain.Sort.Direction
|
||||
import org.springframework.security.core.context.ReactiveSecurityContextHolder
|
||||
import org.springframework.stereotype.Service
|
||||
import reactor.core.publisher.Mono
|
||||
import space.luminic.budgerapp.models.Space
|
||||
import space.luminic.budgerapp.models.SpaceInvite
|
||||
import space.luminic.budgerapp.models.Transaction
|
||||
import space.luminic.budgerapp.repos.BudgetRepo
|
||||
import space.luminic.budgerapp.repos.SpaceRepo
|
||||
import space.luminic.budgerapp.repos.UserRepo
|
||||
import java.time.LocalDateTime
|
||||
import java.util.UUID
|
||||
|
||||
@Service
|
||||
class SpaceService(
|
||||
private val spaceRepo: SpaceRepo,
|
||||
private val userService: UserService,
|
||||
private val budgetRepo: BudgetRepo,
|
||||
private val userRepo: UserRepo
|
||||
) {
|
||||
|
||||
fun isValidRequest(spaceId: String): Mono<Space> {
|
||||
return ReactiveSecurityContextHolder.getContext()
|
||||
.map { it.authentication }
|
||||
.flatMap { authentication ->
|
||||
val username = authentication.name
|
||||
// Получаем пользователя по имени
|
||||
userService.getByUsername(username)
|
||||
.switchIfEmpty(Mono.error(IllegalArgumentException("User not found for username: $username")))
|
||||
.flatMap { user ->
|
||||
// Получаем пространство по ID
|
||||
spaceRepo.findById(spaceId)
|
||||
.switchIfEmpty(Mono.error(IllegalArgumentException("Space not found for id: $spaceId")))
|
||||
.flatMap { space ->
|
||||
// Проверяем доступ пользователя к пространству
|
||||
if (space.users.none { it.id.toString() == user.id }) {
|
||||
return@flatMap Mono.error<Space>(IllegalArgumentException("User does not have access to this Space"))
|
||||
}
|
||||
// Если проверка прошла успешно, возвращаем пространство
|
||||
Mono.just(space)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun getSpaces(): Mono<List<Space>> {
|
||||
return ReactiveSecurityContextHolder.getContext()
|
||||
.map { it.authentication }
|
||||
.flatMap { authentication ->
|
||||
val username = authentication.name
|
||||
userService.getByUsername(username)
|
||||
.switchIfEmpty(Mono.error(IllegalArgumentException("User not found for username: $username")))
|
||||
.flatMapMany { user ->
|
||||
spaceRepo.findByArrayElement(ObjectId(user.id!!))
|
||||
}
|
||||
.collectList() // Возвращаем Mono<List<Space>>
|
||||
}
|
||||
}
|
||||
|
||||
fun getSpace(spaceId: String): Mono<Space> {
|
||||
return spaceRepo.findById(spaceId)
|
||||
.switchIfEmpty(Mono.error(IllegalArgumentException("SpaceId not found for spaceId: $spaceId")))
|
||||
}
|
||||
|
||||
fun createSpace(space: Space): Mono<Space> {
|
||||
return ReactiveSecurityContextHolder.getContext()
|
||||
.map { it.authentication }
|
||||
.flatMap { authentication ->
|
||||
val username = authentication.name
|
||||
userService.getByUsername(username)
|
||||
.switchIfEmpty(Mono.error(IllegalArgumentException("User not found for username: $username")))
|
||||
.flatMap { user ->
|
||||
space.owner = user
|
||||
space.users.add(user)
|
||||
spaceRepo.save(space)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun deleteSpace(spaceId: String): Mono<Void> {
|
||||
return budgetRepo.findBySpaceId(ObjectId(spaceId), Sort.by(Direction.DESC, "dateFrom"))
|
||||
.flatMap { budget ->
|
||||
budgetRepo.delete(budget) // Удаляем все бюджеты, связанные с этим Space
|
||||
}
|
||||
.then(spaceRepo.deleteById(spaceId)) // Затем удаляем сам Space
|
||||
}
|
||||
|
||||
|
||||
fun createInviteSpace(spaceId: String): Mono<SpaceInvite> {
|
||||
return ReactiveSecurityContextHolder.getContext()
|
||||
.map { it.authentication }
|
||||
.flatMap { authentication ->
|
||||
val username = authentication.name
|
||||
userService.getByUsername(username)
|
||||
.switchIfEmpty(Mono.error(IllegalArgumentException("User not found for username: $username")))
|
||||
.flatMap { user ->
|
||||
spaceRepo.findById(spaceId)
|
||||
.switchIfEmpty(Mono.error(IllegalArgumentException("Space not found for id: $spaceId")))
|
||||
.flatMap { space ->
|
||||
if (space.users.none { it.id.toString() == user.id }) {
|
||||
return@flatMap Mono.error<SpaceInvite>(IllegalArgumentException("User does not have access to this Space"))
|
||||
}
|
||||
|
||||
val invite = SpaceInvite(
|
||||
UUID.randomUUID().toString().split("-")[0],
|
||||
user,
|
||||
LocalDateTime.now().plusHours(1),
|
||||
|
||||
)
|
||||
space.invites.add(invite)
|
||||
|
||||
// Сохраняем изменения и возвращаем созданное приглашение
|
||||
spaceRepo.save(space).thenReturn(invite)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fun acceptInvite(code: String): Mono<Space> {
|
||||
return ReactiveSecurityContextHolder.getContext()
|
||||
.map { it.authentication }
|
||||
.flatMap { authentication ->
|
||||
val username = authentication.name
|
||||
userService.getByUsername(username)
|
||||
.switchIfEmpty(Mono.error(IllegalArgumentException("User not found for username: $username")))
|
||||
.flatMap { user ->
|
||||
spaceRepo.findSpaceByInvites(code)
|
||||
.switchIfEmpty(Mono.error(IllegalArgumentException("Space with invite code: $code not found")))
|
||||
.flatMap { space ->
|
||||
val invite = space.invites.find { it.code == code }
|
||||
|
||||
// Проверяем, есть ли инвайт и не истек ли он
|
||||
if (invite == null || invite.activeTill.isBefore(LocalDateTime.now())) {
|
||||
return@flatMap Mono.error<Space>(IllegalArgumentException("Invite is invalid or expired"))
|
||||
}
|
||||
|
||||
// Проверяем, не является ли пользователь уже участником
|
||||
if (space.users.any { it.id == user.id }) {
|
||||
return@flatMap Mono.error<Space>(IllegalArgumentException("User is already a member of this Space"))
|
||||
}
|
||||
|
||||
// Добавляем пользователя и удаляем использованный инвайт
|
||||
space.users.add(user)
|
||||
space.invites.remove(invite)
|
||||
|
||||
spaceRepo.save(space)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun leaveSpace(spaceId: String): Mono<Void> {
|
||||
return ReactiveSecurityContextHolder.getContext()
|
||||
.map { it.authentication }
|
||||
.flatMap { authentication ->
|
||||
val username = authentication.name
|
||||
userService.getByUsername(username)
|
||||
.switchIfEmpty(Mono.error(IllegalArgumentException("User not found for username: $username")))
|
||||
.flatMap { user ->
|
||||
spaceRepo.findById(spaceId)
|
||||
.switchIfEmpty(Mono.error(IllegalArgumentException("Space not found for id: $spaceId")))
|
||||
.flatMap { space ->
|
||||
if (space.users.none { it.id.toString() == user.id }) {
|
||||
return@flatMap Mono.error<Void>(IllegalArgumentException("User does not have access to this Space"))
|
||||
}
|
||||
// Удаляем пользователя из массива
|
||||
space.users.removeIf { it.id == user.id }
|
||||
// Сохраняем изменения
|
||||
spaceRepo.save(space).then() // .then() для Mono<Void>
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun kickMember(spaceId: String, kickedUsername: String): Mono<Void> {
|
||||
return ReactiveSecurityContextHolder.getContext()
|
||||
.map { it.authentication }
|
||||
.flatMap { authentication ->
|
||||
val username = authentication.name
|
||||
// Получаем текущего пользователя
|
||||
userService.getByUsername(username)
|
||||
.switchIfEmpty(Mono.error(IllegalArgumentException("User not found for username: $username")))
|
||||
.flatMap { user ->
|
||||
// Получаем пользователя, которого нужно исключить
|
||||
userService.getByUsername(kickedUsername)
|
||||
.switchIfEmpty(Mono.error(IllegalArgumentException("User not found for username: $kickedUsername")))
|
||||
.flatMap { kickedUser ->
|
||||
// Получаем пространство
|
||||
spaceRepo.findById(spaceId)
|
||||
.switchIfEmpty(Mono.error(IllegalArgumentException("Space not found for id: $spaceId")))
|
||||
.flatMap { space ->
|
||||
// Проверяем, является ли текущий пользователь владельцем
|
||||
if (space.owner?.id != user.id) {
|
||||
return@flatMap Mono.error<Void>(IllegalArgumentException("Only owners allowed for this action"))
|
||||
}
|
||||
|
||||
// Проверяем, что пользователь, которого нужно исключить, присутствует в списке пользователей
|
||||
val userToKick = space.users.find { it.username == kickedUsername }
|
||||
if (userToKick != null) {
|
||||
// Удаляем пользователя из пространства
|
||||
space.users.removeIf { it.username == kickedUsername }
|
||||
// Сохраняем изменения
|
||||
return@flatMap spaceRepo.save(space).then()
|
||||
} else {
|
||||
return@flatMap Mono.error<Void>(IllegalArgumentException("User not found in this space"))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// fun regenSpaces(): Mono<List<Space>> {
|
||||
// return spaceRepo.findAll()
|
||||
// .flatMap { space ->
|
||||
// userService.getUsers()
|
||||
// .flatMap { users ->
|
||||
// if (users.isEmpty()) {
|
||||
// return@flatMap Mono.error<Space>(IllegalStateException("No users found"))
|
||||
// }
|
||||
// val updatedSpace = space.copy(owner = users.first()) // Создаем копию (если `Space` data class)
|
||||
// spaceRepo.save(updatedSpace)
|
||||
// }
|
||||
// }
|
||||
// .collectList()
|
||||
// }
|
||||
|
||||
}
|
||||
52
src/main/resources/persprof.json
Normal file
52
src/main/resources/persprof.json
Normal file
@@ -0,0 +1,52 @@
|
||||
[
|
||||
{
|
||||
"$lookup": {
|
||||
"from": "categories",
|
||||
"localField": "category.$id",
|
||||
"foreignField": "_id",
|
||||
"as": "categoryDetails"
|
||||
}
|
||||
},
|
||||
{
|
||||
"$lookup": {
|
||||
"from": "spaces",
|
||||
"localField": "space.$id",
|
||||
"foreignField": "_id",
|
||||
"as": "spaceDetails"
|
||||
}
|
||||
},
|
||||
{
|
||||
"$lookup": {
|
||||
"from": "users",
|
||||
"localField": "user.$id",
|
||||
"foreignField": "_id",
|
||||
"as": "userDetails"
|
||||
}
|
||||
},
|
||||
{
|
||||
"$match": {
|
||||
"$and": [
|
||||
{
|
||||
"spaceDetails._id": {
|
||||
"$oid": "67af52e8b0aa7b0f7f74b491"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type.code": "INSTANT"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"$sort": {
|
||||
"date": -1,
|
||||
"createdAt": -1
|
||||
}
|
||||
},
|
||||
{
|
||||
"$skip": 0
|
||||
},
|
||||
{
|
||||
"$limit": 10
|
||||
}
|
||||
]
|
||||
Reference in New Issue
Block a user