diff --git a/src/main/java/net/szymonsawicki/reactivetimesheetapp/application/service/TimeEntryService.java b/src/main/java/net/szymonsawicki/reactivetimesheetapp/application/service/TimeEntryService.java index d7483a4..97e2764 100644 --- a/src/main/java/net/szymonsawicki/reactivetimesheetapp/application/service/TimeEntryService.java +++ b/src/main/java/net/szymonsawicki/reactivetimesheetapp/application/service/TimeEntryService.java @@ -3,8 +3,8 @@ package net.szymonsawicki.reactivetimesheetapp.application.service; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import net.szymonsawicki.reactivetimesheetapp.application.service.exception.TimeEntryServiceException; +import net.szymonsawicki.reactivetimesheetapp.application.service.exception.UserServiceException; import net.szymonsawicki.reactivetimesheetapp.domain.time_entry.TimeEntry; -import net.szymonsawicki.reactivetimesheetapp.domain.time_entry.TimeEntryUtils; import net.szymonsawicki.reactivetimesheetapp.domain.time_entry.dto.CreateTimeEntryDto; import net.szymonsawicki.reactivetimesheetapp.domain.time_entry.dto.GetTimeEntryDto; import net.szymonsawicki.reactivetimesheetapp.domain.time_entry.repository.TimeEntryRepository; @@ -22,28 +22,34 @@ public class TimeEntryService { public Mono addTimeEntry(Mono createTimeEntryDtoMono) { return createTimeEntryDtoMono + .then(checkEntry(createTimeEntryDtoMono)) .flatMap(createTimeEntryDto -> { - - // check if user from time entry exists in db - - userRepository - .findById(createTimeEntryDto.user().id()) - .switchIfEmpty(Mono.error(new TimeEntryServiceException("cannot find user"))); - - // call of the private method, which checks in db if there is a conflict with existing entries - - checkTime(createTimeEntryDto); - return timeEntryRepository.save(createTimeEntryDto.toTimeEntry()) .map(TimeEntry::toGetTimeEntryDto); }); } - private void checkTime(CreateTimeEntryDto timeEntryToCheck) { - timeEntryRepository.findAllByUserAndDate(timeEntryToCheck.user().toUser(), timeEntryToCheck.date()) - .filter(timeEntry -> - TimeEntryUtils.toTimeFrom.apply(timeEntry).isAfter(timeEntryToCheck.timeTo()) || - TimeEntryUtils.toTimeTo.apply(timeEntry).isBefore(timeEntryToCheck.timeFrom())) - .switchIfEmpty(Mono.error(new TimeEntryServiceException("entry time conflict"))); + private Mono checkEntry(Mono timeEntryToCheck) { + return timeEntryToCheck.flatMap(t -> + + // at first check if the user exists + + userRepository + .findById(t.user().id()) + .hasElement() + .flatMap(isUserPresent -> Boolean.TRUE.equals(isUserPresent) + ? + Mono.just(timeEntryToCheck) + : + Mono.error(new UserServiceException("user not exists"))) + + // then collision check of the time entry + + .flatMap(entry -> timeEntryRepository.timeCheck(t.timeFrom(), t.timeTo()) + .flatMap(result -> result + ? + Mono.error(new TimeEntryServiceException("time entry collision")) + : + Mono.just(t)))); } } diff --git a/src/main/java/net/szymonsawicki/reactivetimesheetapp/application/service/UserService.java b/src/main/java/net/szymonsawicki/reactivetimesheetapp/application/service/UserService.java index 367d22d..2ccc36f 100644 --- a/src/main/java/net/szymonsawicki/reactivetimesheetapp/application/service/UserService.java +++ b/src/main/java/net/szymonsawicki/reactivetimesheetapp/application/service/UserService.java @@ -75,5 +75,4 @@ public class UserService { } return Mono.just(member.toGetUserDto()); } - } \ No newline at end of file diff --git a/src/main/java/net/szymonsawicki/reactivetimesheetapp/domain/time_entry/TimeEntry.java b/src/main/java/net/szymonsawicki/reactivetimesheetapp/domain/time_entry/TimeEntry.java index 03182e2..f06abd5 100644 --- a/src/main/java/net/szymonsawicki/reactivetimesheetapp/domain/time_entry/TimeEntry.java +++ b/src/main/java/net/szymonsawicki/reactivetimesheetapp/domain/time_entry/TimeEntry.java @@ -9,8 +9,7 @@ import net.szymonsawicki.reactivetimesheetapp.domain.time_entry.type.Category; import net.szymonsawicki.reactivetimesheetapp.domain.user.User; import net.szymonsawicki.reactivetimesheetapp.infrastructure.persistence.entity.TimeEntryEntity; -import java.time.LocalDate; -import java.time.LocalTime; +import java.time.LocalDateTime; @AllArgsConstructor @NoArgsConstructor @@ -19,9 +18,8 @@ import java.time.LocalTime; public class TimeEntry { String id; - LocalDate date; - LocalTime timeFrom; - LocalTime timeTo; + LocalDateTime timeFrom; + LocalDateTime timeTo; User user; Category category; String description; @@ -29,7 +27,6 @@ public class TimeEntry { public TimeEntryEntity toEntity() { return TimeEntryEntity.builder() .id(id) - .date(date) .timeFrom(timeFrom) .timeTo(timeTo) .user(user.toEntity()) @@ -41,7 +38,6 @@ public class TimeEntry { public GetTimeEntryDto toGetTimeEntryDto() { return new GetTimeEntryDto( id, - date, timeFrom, timeTo, user.toGetUserDto(), diff --git a/src/main/java/net/szymonsawicki/reactivetimesheetapp/domain/time_entry/TimeEntryUtils.java b/src/main/java/net/szymonsawicki/reactivetimesheetapp/domain/time_entry/TimeEntryUtils.java index 9f62f1e..fc6e1fa 100644 --- a/src/main/java/net/szymonsawicki/reactivetimesheetapp/domain/time_entry/TimeEntryUtils.java +++ b/src/main/java/net/szymonsawicki/reactivetimesheetapp/domain/time_entry/TimeEntryUtils.java @@ -1,11 +1,11 @@ package net.szymonsawicki.reactivetimesheetapp.domain.time_entry; -import java.time.LocalTime; +import java.time.LocalDateTime; import java.util.function.Function; public interface TimeEntryUtils { - Function toTimeFrom = timeEntry -> timeEntry.timeFrom; - Function toTimeTo = timeEntry -> timeEntry.timeTo; + Function toTimeFrom = timeEntry -> timeEntry.timeFrom; + Function toTimeTo = timeEntry -> timeEntry.timeTo; } diff --git a/src/main/java/net/szymonsawicki/reactivetimesheetapp/domain/time_entry/dto/CreateTimeEntryDto.java b/src/main/java/net/szymonsawicki/reactivetimesheetapp/domain/time_entry/dto/CreateTimeEntryDto.java index ecdcd91..3f923af 100644 --- a/src/main/java/net/szymonsawicki/reactivetimesheetapp/domain/time_entry/dto/CreateTimeEntryDto.java +++ b/src/main/java/net/szymonsawicki/reactivetimesheetapp/domain/time_entry/dto/CreateTimeEntryDto.java @@ -4,13 +4,11 @@ import net.szymonsawicki.reactivetimesheetapp.domain.time_entry.TimeEntry; import net.szymonsawicki.reactivetimesheetapp.domain.time_entry.type.Category; import net.szymonsawicki.reactivetimesheetapp.domain.user.dto.GetUserDto; -import java.time.LocalDate; -import java.time.LocalTime; +import java.time.LocalDateTime; -public record CreateTimeEntryDto(LocalDate date, LocalTime timeFrom, LocalTime timeTo, GetUserDto user, Category category, String description) { +public record CreateTimeEntryDto(LocalDateTime timeFrom, LocalDateTime timeTo, GetUserDto user, Category category, String description) { public TimeEntry toTimeEntry() { return TimeEntry.builder() - .date(date) .timeFrom(timeFrom) .timeTo(timeTo) .user(user.toUser()) diff --git a/src/main/java/net/szymonsawicki/reactivetimesheetapp/domain/time_entry/dto/GetTimeEntryDto.java b/src/main/java/net/szymonsawicki/reactivetimesheetapp/domain/time_entry/dto/GetTimeEntryDto.java index e7c4d87..9806402 100644 --- a/src/main/java/net/szymonsawicki/reactivetimesheetapp/domain/time_entry/dto/GetTimeEntryDto.java +++ b/src/main/java/net/szymonsawicki/reactivetimesheetapp/domain/time_entry/dto/GetTimeEntryDto.java @@ -2,17 +2,12 @@ package net.szymonsawicki.reactivetimesheetapp.domain.time_entry.dto; import net.szymonsawicki.reactivetimesheetapp.domain.time_entry.TimeEntry; import net.szymonsawicki.reactivetimesheetapp.domain.time_entry.type.Category; -import net.szymonsawicki.reactivetimesheetapp.domain.user.User; import net.szymonsawicki.reactivetimesheetapp.domain.user.dto.GetUserDto; -import java.time.LocalDate; -import java.time.LocalTime; - -public record GetTimeEntryDto(String id, LocalDate date, LocalTime timeFrom, LocalTime timeTo, GetUserDto user, Category category, String description) { +public record GetTimeEntryDto(String id, java.time.LocalDateTime timeFrom, java.time.LocalDateTime timeTo, GetUserDto user, Category category, String description) { TimeEntry toTimeEntry() { return TimeEntry.builder() .id(id) - .date(date) .timeFrom(timeFrom) .timeTo(timeTo) .user(user.toUser()) diff --git a/src/main/java/net/szymonsawicki/reactivetimesheetapp/domain/time_entry/repository/TimeEntryRepository.java b/src/main/java/net/szymonsawicki/reactivetimesheetapp/domain/time_entry/repository/TimeEntryRepository.java index ede5031..24d8a06 100644 --- a/src/main/java/net/szymonsawicki/reactivetimesheetapp/domain/time_entry/repository/TimeEntryRepository.java +++ b/src/main/java/net/szymonsawicki/reactivetimesheetapp/domain/time_entry/repository/TimeEntryRepository.java @@ -4,10 +4,15 @@ import net.szymonsawicki.reactivetimesheetapp.domain.configs.CrudRepository; import net.szymonsawicki.reactivetimesheetapp.domain.time_entry.TimeEntry; import net.szymonsawicki.reactivetimesheetapp.domain.user.User; import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; import java.time.LocalDate; +import java.time.LocalDateTime; public interface TimeEntryRepository extends CrudRepository { Flux findAllByUserAndDate(User user, LocalDate date); + Flux findAllByUser(User user); + + Mono timeCheck(LocalDateTime dateFrom, LocalDateTime dateTo); } diff --git a/src/main/java/net/szymonsawicki/reactivetimesheetapp/infrastructure/persistence/dao/TimeEntryDao.java b/src/main/java/net/szymonsawicki/reactivetimesheetapp/infrastructure/persistence/dao/TimeEntryDao.java index 8a6355f..244c7c6 100644 --- a/src/main/java/net/szymonsawicki/reactivetimesheetapp/infrastructure/persistence/dao/TimeEntryDao.java +++ b/src/main/java/net/szymonsawicki/reactivetimesheetapp/infrastructure/persistence/dao/TimeEntryDao.java @@ -2,12 +2,19 @@ package net.szymonsawicki.reactivetimesheetapp.infrastructure.persistence.dao; import net.szymonsawicki.reactivetimesheetapp.infrastructure.persistence.entity.TimeEntryEntity; import net.szymonsawicki.reactivetimesheetapp.infrastructure.persistence.entity.UserEntity; +import org.springframework.data.mongodb.repository.Query; import org.springframework.data.mongodb.repository.ReactiveMongoRepository; import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; import java.time.LocalDate; +import java.time.LocalDateTime; public interface TimeEntryDao extends ReactiveMongoRepository { Flux findAllByUserAndDate(UserEntity user, LocalDate date); + Flux findAllByUser(UserEntity user); + + @Query(value = "{'timeFrom':{ $gte: ?1},'timeTo':{ $lte: ?0}}") + Mono timeCheck(LocalDateTime timeFrom, LocalDateTime timeTo); } diff --git a/src/main/java/net/szymonsawicki/reactivetimesheetapp/infrastructure/persistence/entity/TimeEntryEntity.java b/src/main/java/net/szymonsawicki/reactivetimesheetapp/infrastructure/persistence/entity/TimeEntryEntity.java index c192fd5..d5de24d 100644 --- a/src/main/java/net/szymonsawicki/reactivetimesheetapp/infrastructure/persistence/entity/TimeEntryEntity.java +++ b/src/main/java/net/szymonsawicki/reactivetimesheetapp/infrastructure/persistence/entity/TimeEntryEntity.java @@ -6,12 +6,10 @@ import lombok.Getter; import lombok.NoArgsConstructor; import net.szymonsawicki.reactivetimesheetapp.domain.time_entry.TimeEntry; import net.szymonsawicki.reactivetimesheetapp.domain.time_entry.type.Category; -import net.szymonsawicki.reactivetimesheetapp.domain.user.User; import org.springframework.data.annotation.Id; import org.springframework.data.mongodb.core.mapping.Document; -import java.time.LocalDate; -import java.time.LocalTime; +import java.time.LocalDateTime; @Document(collection = "time_entries") @Builder @@ -23,9 +21,8 @@ public class TimeEntryEntity { @Id String id; - LocalDate date; - LocalTime timeFrom; - LocalTime timeTo; + LocalDateTime timeFrom; + LocalDateTime timeTo; UserEntity user; Category category; String description; @@ -33,7 +30,6 @@ public class TimeEntryEntity { public TimeEntry toTimeEntry() { return TimeEntry.builder() .id(id) - .date(date) .timeFrom(timeFrom) .timeTo(timeTo) .user(user.toUser()) diff --git a/src/main/java/net/szymonsawicki/reactivetimesheetapp/infrastructure/persistence/repository/TimeEntryRepositoryImpl.java b/src/main/java/net/szymonsawicki/reactivetimesheetapp/infrastructure/persistence/repository/TimeEntryRepositoryImpl.java index bee31d2..1ee4678 100644 --- a/src/main/java/net/szymonsawicki/reactivetimesheetapp/infrastructure/persistence/repository/TimeEntryRepositoryImpl.java +++ b/src/main/java/net/szymonsawicki/reactivetimesheetapp/infrastructure/persistence/repository/TimeEntryRepositoryImpl.java @@ -11,6 +11,7 @@ import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; import java.time.LocalDate; +import java.time.LocalDateTime; import java.util.List; @Repository @@ -56,7 +57,7 @@ public class TimeEntryRepositoryImpl implements TimeEntryRepository { @Override public Flux findAllByUserAndDate(User user, LocalDate date) { - return timeEntryDao.findAllByUserAndDate(user.toEntity(),date) + return timeEntryDao.findAllByUserAndDate(user.toEntity(), date) .flatMap(timeEntryEntity -> Mono.just(timeEntryEntity.toTimeEntry())); } @@ -65,4 +66,9 @@ public class TimeEntryRepositoryImpl implements TimeEntryRepository { return timeEntryDao.findAllByUser(user.toEntity()) .flatMap(timeEntryEntity -> Mono.just(timeEntryEntity.toTimeEntry())); } + + @Override + public Mono timeCheck(LocalDateTime dateFrom, LocalDateTime dateTo) { + return timeEntryDao.timeCheck(dateFrom, dateTo); + } } diff --git a/src/main/java/net/szymonsawicki/reactivetimesheetapp/web/Routing.java b/src/main/java/net/szymonsawicki/reactivetimesheetapp/web/Routing.java index b0f06c6..59a087e 100644 --- a/src/main/java/net/szymonsawicki/reactivetimesheetapp/web/Routing.java +++ b/src/main/java/net/szymonsawicki/reactivetimesheetapp/web/Routing.java @@ -34,7 +34,7 @@ public class Routing { .andRoute(GET("/{username}").and(accept(MediaType.APPLICATION_JSON)), userHandlers::findByUsername) .andRoute(POST("/").and(accept(MediaType.APPLICATION_JSON)), userHandlers::createUser) .andRoute(DELETE("/{id}").and(accept(MediaType.APPLICATION_JSON)), userHandlers::deleteUser)) - .andNest(path("/time_entries"), + .andNest(path("/time-entries"), RouterFunctions.route(POST("/").and(accept(MediaType.APPLICATION_JSON)), timeEntryHandlers::addTimeEntry)); } }