Files
luminic-back/src/main/kotlin/space/luminic/budgerapp/services/SpaceService.kt
2025-02-17 17:58:07 +03:00

233 lines
12 KiB
Kotlin
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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()
// }
}