diff --git a/pom.xml b/pom.xml index a3b4a77..091dc51 100644 --- a/pom.xml +++ b/pom.xml @@ -26,6 +26,10 @@ org.springframework.boot spring-boot-starter-web + + org.springframework.boot + spring-boot-starter-data-jpa + org.springframework.boot spring-boot-starter-actuator @@ -63,11 +67,11 @@ spring-boot-starter-validation - - org.mapstruct - mapstruct - ${org.mapstruct.version} - + + org.mapstruct + mapstruct + ${org.mapstruct.version} + org.projectlombok @@ -159,6 +163,18 @@ ${lombok-mapstruct-binding.version} + true + + + -Amapstruct.suppressGeneratorTimestamp=true + + + -Amapstruct.suppressGeneratorVersionInfoComment=true + + + -Amapstruct.verbose=true + + diff --git a/src/main/java/ru/practicum/shareit/PersistenceConfig.java b/src/main/java/ru/practicum/shareit/PersistenceConfig.java new file mode 100644 index 0000000..04d14b2 --- /dev/null +++ b/src/main/java/ru/practicum/shareit/PersistenceConfig.java @@ -0,0 +1,66 @@ +package ru.practicum.shareit; + +import jakarta.persistence.EntityManagerFactory; +import lombok.RequiredArgsConstructor; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.core.env.Environment; +import org.springframework.data.jpa.repository.config.EnableJpaRepositories; +import org.springframework.jdbc.datasource.DriverManagerDataSource; +import org.springframework.orm.jpa.JpaTransactionManager; +import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean; +import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter; +import org.springframework.transaction.annotation.EnableTransactionManagement; + +import javax.sql.DataSource; +import java.util.Properties; + +@Configuration +@RequiredArgsConstructor +@EnableTransactionManagement +@EnableJpaRepositories(basePackages = "ru.practicum") +public class PersistenceConfig { + private final Environment environment; + + @Bean + public DataSource dataSource() { + DriverManagerDataSource dataSource = new DriverManagerDataSource(); + dataSource.setDriverClassName(environment.getRequiredProperty("spring.datasource.driverClassName")); + dataSource.setUrl(environment.getRequiredProperty("spring.datasource.url")); + dataSource.setUsername(environment.getRequiredProperty("spring.datasource.username")); + dataSource.setPassword(environment.getRequiredProperty("spring.datasource.password")); + return dataSource; + } + + private Properties hibernateProperties() { + Properties properties = new Properties(); + properties.put("spring.jpa.properties.hibernate.jdbc.time_zone", + environment.getRequiredProperty("spring.jpa.properties.hibernate.jdbc.time_zone")); + properties.put("spring.jpa.properties.hibernate.format_sql", + environment.getProperty("spring.jpa.properties.hibernate.format_sql", "false")); + return properties; + } + + @Bean + public LocalContainerEntityManagerFactoryBean entityManagerFactory(DataSource dataSource) { + final HibernateJpaVendorAdapter vendorAdapter = + new HibernateJpaVendorAdapter(); + + final LocalContainerEntityManagerFactoryBean emf = + new LocalContainerEntityManagerFactoryBean(); + + emf.setDataSource(dataSource); + emf.setJpaVendorAdapter(vendorAdapter); + emf.setPackagesToScan("ru.practicum"); + emf.setJpaProperties(hibernateProperties()); + + return emf; + } + + @Bean + public JpaTransactionManager transactionManager(EntityManagerFactory entityManagerFactory) { + JpaTransactionManager transactionManager = new JpaTransactionManager(); + transactionManager.setEntityManagerFactory(entityManagerFactory); + return transactionManager; + } +} diff --git a/src/main/java/ru/practicum/shareit/booking/Booking.java b/src/main/java/ru/practicum/shareit/booking/Booking.java deleted file mode 100644 index 8facd50..0000000 --- a/src/main/java/ru/practicum/shareit/booking/Booking.java +++ /dev/null @@ -1,16 +0,0 @@ -package ru.practicum.shareit.booking; - -import java.time.LocalDate; - -/** - * TODO Sprint add-bookings. - */ -public class Booking { - - private Long bookingId; - private LocalDate start; - private LocalDate end; - private Long itemId; - private Long bookerId; - BookingStatus status; -} diff --git a/src/main/java/ru/practicum/shareit/booking/BookingController.java b/src/main/java/ru/practicum/shareit/booking/BookingController.java index b94493d..5d1a56c 100644 --- a/src/main/java/ru/practicum/shareit/booking/BookingController.java +++ b/src/main/java/ru/practicum/shareit/booking/BookingController.java @@ -1,12 +1,49 @@ package ru.practicum.shareit.booking; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; +import jakarta.validation.Valid; +import lombok.RequiredArgsConstructor; +import org.springframework.web.bind.annotation.*; +import ru.practicum.shareit.booking.dto.BookingRequestDto; +import ru.practicum.shareit.booking.dto.BookingResponseDto; +import ru.practicum.shareit.booking.intrfaces.BookingServiceInterface; + +import java.util.Collection; -/** - * TODO Sprint add-bookings. - */ @RestController @RequestMapping(path = "/bookings") +@RequiredArgsConstructor public class BookingController { + private final BookingServiceInterface bookingService; + public static final String USER_ID = "X-Sharer-User-Id"; + + @PostMapping + public BookingResponseDto addBooking(@RequestBody @Valid BookingRequestDto booking, + @RequestHeader(USER_ID) Long bookerId) { + return bookingService.addBooking(booking, bookerId); + } + + @PatchMapping("/{bookingId}") + public BookingResponseDto bookingApprove(@PathVariable Long bookingId, + @RequestHeader (USER_ID) Long ownerId, + @RequestParam Boolean approved) { + return bookingService.bookingApprove(bookingId, ownerId, approved); + } + + @GetMapping("/{bookingId}") + public BookingResponseDto getBooking(@PathVariable Long bookingId, + @RequestHeader(USER_ID) Long userId) { + return bookingService.getBookingByBookingId(bookingId, userId); + } + + @GetMapping + public Collection getBookingsByUser(@RequestHeader (USER_ID) Long userId, + @RequestParam(name = "state", defaultValue = "all") String state) { + return bookingService.getBookingsByUser(userId, state); + } + + @GetMapping("/owner") + public Collection getBookingsByOwner(@RequestHeader (USER_ID) Long userId, + @RequestParam(name = "state", defaultValue = "all") String state) { + return bookingService.getBookingsByOwner(userId, state); + } } diff --git a/src/main/java/ru/practicum/shareit/booking/BookingServiceImpl.java b/src/main/java/ru/practicum/shareit/booking/BookingServiceImpl.java new file mode 100644 index 0000000..4bc3009 --- /dev/null +++ b/src/main/java/ru/practicum/shareit/booking/BookingServiceImpl.java @@ -0,0 +1,198 @@ +package ru.practicum.shareit.booking; + +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import ru.practicum.shareit.booking.dto.BookingRequestDto; +import ru.practicum.shareit.booking.dto.BookingResponseDto; +import ru.practicum.shareit.booking.intrfaces.BookingRepository; +import ru.practicum.shareit.booking.intrfaces.BookingServiceInterface; +import ru.practicum.shareit.booking.mapper.BookingMapper; +import ru.practicum.shareit.booking.model.Booking; +import ru.practicum.shareit.booking.model.BookingStatus; +import ru.practicum.shareit.exception.AnotherUserException; +import ru.practicum.shareit.exception.NotFoundException; +import ru.practicum.shareit.exception.ValidationException; +import ru.practicum.shareit.item.interfaces.ItemRepository; +import ru.practicum.shareit.item.mapper.ItemMapper; +import ru.practicum.shareit.item.model.Item; +import ru.practicum.shareit.user.interfaces.UserRepository; +import ru.practicum.shareit.user.mapper.UserMapper; +import ru.practicum.shareit.user.model.User; + +import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Comparator; + +@Service +@RequiredArgsConstructor +public class BookingServiceImpl implements BookingServiceInterface { + private final BookingRepository storage; + private final UserRepository userStorage; + private final ItemRepository itemStorage; + + private final ItemMapper itemMapper; + private final UserMapper userMapper; + private final BookingRepository bookingRepository; + private final BookingMapper bookingMapper; + + + @Override + public BookingResponseDto addBooking(BookingRequestDto booking, Long bookerId) { + Item item = itemStorage.findById(booking.getItemId()) + .orElseThrow(() -> new NotFoundException("Item not found")); + + User booker = userStorage.getUserByUserId(bookerId) + .orElseThrow(() -> new NotFoundException("User not found")); + + Booking saved = bookingMapper.bookingRequestDtoToBooking(booking); + saved.setBooker(booker); + saved.setItem(item); + + if (item.getIsAvailable().equals(false)) { + saved.setStatus(BookingStatus.REJECTED); + storage.save(saved); + throw new RuntimeException("Booking is rejected, item is not available"); + } else { + saved.setStatus(BookingStatus.WAITING); + storage.save(saved); + } + + return mapBookerAndItemToBooking(saved); + } + + @Override + public BookingResponseDto bookingApprove(Long bookingId, Long ownerId, Boolean isAvailable) { + Booking booking = bookingRepository.getBookingByBookingId(bookingId) + .orElseThrow(() -> new NotFoundException("Booking not found")); + + Item item = itemStorage.getItemByItemId(booking.getItem().getItemId()) + .orElseThrow(() -> new NotFoundException("Item not found")); + + if (!item.getOwner().getUserId().equals(ownerId)) { + throw new AnotherUserException("You are not allowed to approve this booking"); + } + + if (item.getIsAvailable().equals(false)) { + booking.setStatus(BookingStatus.REJECTED); + throw new ValidationException("Booking item is rejected"); + } else { + booking.setStatus(BookingStatus.APPROVED); + bookingRepository.save(booking); + } + + return mapBookerAndItemToBooking(booking); + } + + @Override + public BookingResponseDto getBookingByBookingId(Long bookingId, Long userId) { + Booking booking = bookingRepository.getBookingByBookingId(bookingId) + .orElseThrow(() -> new NotFoundException("Booking not found")); + + if (booking.getBooker().getUserId().equals(userId) || + booking.getItem().getOwner().getUserId().equals(userId)) { + return mapBookerAndItemToBooking(booking); + } else { + throw new AnotherUserException("You are not allowed to view this booking"); + } + } + + @Override + public Collection getBookingsByUser(Long userId, String state) { + User user = userStorage.getUserByUserId(userId) + .orElseThrow(() -> new NotFoundException("User not found")); + + LocalDateTime date = LocalDateTime.now(); + + Collection bookings = new ArrayList<>(); + + if (state.equalsIgnoreCase("ALL")) { + bookings = bookingRepository.getBookingsByBooker_UserId(userId); + + } else if (state.equalsIgnoreCase("CURRENT") || + state.equalsIgnoreCase("PAST") || + state.equalsIgnoreCase("FUTURE")) { + + bookings = getBookingsByTimeState(date, state).stream() + .filter(booking -> booking.getBooker().getUserId().equals(userId)) + .toList(); + + } else if (state.equalsIgnoreCase("WAITING") || + state.equalsIgnoreCase("REJECTED")) { + + if (state.equalsIgnoreCase("WAITING")) { + bookings = bookingRepository.getBookingsByBooker_UserIdAndStatus(userId, BookingStatus.WAITING); + } else { + bookings = bookingRepository.getBookingsByBooker_UserIdAndStatus(userId, BookingStatus.REJECTED); + } + } + + return bookings.stream() + .map(this::mapBookerAndItemToBooking) + .sorted(Comparator.comparing(BookingResponseDto::getStart)) + .toList() + .reversed(); + } + + @Override + public Collection getBookingsByOwner(Long userId, String state) { + User user = userStorage.getUserByUserId(userId) + .orElseThrow(() -> new NotFoundException("User not found")); + + Item item = itemStorage.getItemsByOwner_UserId(userId).stream() + .findFirst() + .orElseThrow(() -> new NotFoundException("User with userId = " + userId + " has no Item")); + + LocalDateTime date = LocalDateTime.now(); + + Collection bookings = new ArrayList<>(); + + if (state.equalsIgnoreCase("ALL")) { + bookings = bookingRepository.getBookingsByOwnerId(userId); + } else if (state.equalsIgnoreCase("CURRENT") || + state.equalsIgnoreCase("PAST") || + state.equalsIgnoreCase("FUTURE")) { + + bookings = getBookingsByTimeState(date, state).stream() + .filter(booking -> booking.getItem().getOwner().getUserId().equals(userId)) + .toList(); + + } else if (state.equalsIgnoreCase("WAITING") || + state.equalsIgnoreCase("REJECTED")) { + + if (state.equalsIgnoreCase("WAITING")) { + bookings = bookingRepository.getBookingsByStatus(BookingStatus.WAITING).stream() + .filter(booking -> booking.getItem().getOwner().getUserId().equals(userId)) + .toList(); + } else { + bookings = bookingRepository.getBookingsByStatus(BookingStatus.REJECTED).stream() + .filter(booking -> booking.getItem().getOwner().getUserId().equals(userId)) + .toList(); + } + } + return bookings.stream() + .map(this::mapBookerAndItemToBooking) + .sorted(Comparator.comparing(BookingResponseDto::getStart)) + .toList() + .reversed(); + } + + + private BookingResponseDto mapBookerAndItemToBooking(Booking booking) { + BookingResponseDto bookingDto = bookingMapper.bookingToBookingResponseDto(booking); + bookingDto.setBooker(userMapper.toUserBookingDto(booking.getBooker())); + bookingDto.setItem(itemMapper.toItemBookerDto(booking.getItem())); + return bookingDto; + } + + private Collection getBookingsByTimeState(LocalDateTime date, String state) { + Collection bookings = new ArrayList<>(); + switch (state.toUpperCase()) { + case "CURRENT" -> bookings = bookingRepository.getBookingsByBooker_UserIdCurrent(date); + case "PAST" -> bookings = bookingRepository.getBookingsByBooker_UserIdPast(date); + case "FUTURE" -> bookings = bookingRepository.getBookingsByBooker_UserIdFuture(date); + } + return bookings; + } +} + diff --git a/src/main/java/ru/practicum/shareit/booking/dto/BookingDto.java b/src/main/java/ru/practicum/shareit/booking/dto/BookingDto.java deleted file mode 100644 index 861de9e..0000000 --- a/src/main/java/ru/practicum/shareit/booking/dto/BookingDto.java +++ /dev/null @@ -1,7 +0,0 @@ -package ru.practicum.shareit.booking.dto; - -/** - * TODO Sprint add-bookings. - */ -public class BookingDto { -} diff --git a/src/main/java/ru/practicum/shareit/booking/dto/BookingRequestDto.java b/src/main/java/ru/practicum/shareit/booking/dto/BookingRequestDto.java new file mode 100644 index 0000000..0e94f98 --- /dev/null +++ b/src/main/java/ru/practicum/shareit/booking/dto/BookingRequestDto.java @@ -0,0 +1,34 @@ +package ru.practicum.shareit.booking.dto; + +import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.constraints.Future; +import jakarta.validation.constraints.NotNull; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import ru.practicum.shareit.booking.model.BookingStatus; + +import java.time.LocalDateTime; + +@Data +@AllArgsConstructor +@NoArgsConstructor +public class BookingRequestDto { + @JsonProperty("id") + private Long bookingId; + + @NotNull + @Future + private LocalDateTime start; + + @NotNull + @Future + private LocalDateTime end; + + @NotNull + private Long itemId; + + private Long bookerId; + + private BookingStatus status; +} diff --git a/src/main/java/ru/practicum/shareit/booking/dto/BookingResponseDto.java b/src/main/java/ru/practicum/shareit/booking/dto/BookingResponseDto.java new file mode 100644 index 0000000..c59d3a4 --- /dev/null +++ b/src/main/java/ru/practicum/shareit/booking/dto/BookingResponseDto.java @@ -0,0 +1,31 @@ +package ru.practicum.shareit.booking.dto; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import ru.practicum.shareit.booking.model.BookingStatus; +import ru.practicum.shareit.item.dto.ItemBookerDto; +import ru.practicum.shareit.user.dto.UserBookingDto; + +import java.time.LocalDateTime; + +@Data +@AllArgsConstructor +@NoArgsConstructor +public class BookingResponseDto { + + @JsonProperty("id") + private Long bookingId; + + private LocalDateTime start; + + private LocalDateTime end; + + private ItemBookerDto item; + + private UserBookingDto booker; + + private BookingStatus status; + +} diff --git a/src/main/java/ru/practicum/shareit/booking/intrfaces/BookingRepository.java b/src/main/java/ru/practicum/shareit/booking/intrfaces/BookingRepository.java new file mode 100644 index 0000000..f5c6a0d --- /dev/null +++ b/src/main/java/ru/practicum/shareit/booking/intrfaces/BookingRepository.java @@ -0,0 +1,37 @@ +package ru.practicum.shareit.booking.intrfaces; + +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; +import ru.practicum.shareit.booking.model.Booking; +import ru.practicum.shareit.booking.model.BookingStatus; + +import java.time.LocalDateTime; +import java.util.Collection; +import java.util.Optional; + +public interface BookingRepository extends JpaRepository { + + Booking save(Booking booking); + + Optional getBookingByBookingId(Long bookingId); + + Collection getBookingsByBooker_UserId(Long bookerId); + + Collection getBookingsByItem_ItemId(Long itemId); + + @Query(value = "SELECT b FROM Booking b WHERE ?1 between b.start and b.end") + Collection getBookingsByBooker_UserIdCurrent(LocalDateTime date); + + @Query(value = "SELECT b FROM Booking b WHERE b.end < ?1") + Collection getBookingsByBooker_UserIdPast(LocalDateTime date); + + @Query(value = "SELECT b FROM Booking b WHERE b.start > ?1") + Collection getBookingsByBooker_UserIdFuture(LocalDateTime date); + + Collection getBookingsByBooker_UserIdAndStatus(Long bookerId, BookingStatus status); + + @Query(value = "SELECT b FROM Booking b JOIN Item i on b.item.itemId = i.itemId WHERE i.owner.userId = ?1") + Collection getBookingsByOwnerId(Long ownerId); + + Collection getBookingsByStatus(BookingStatus status); +} diff --git a/src/main/java/ru/practicum/shareit/booking/intrfaces/BookingServiceInterface.java b/src/main/java/ru/practicum/shareit/booking/intrfaces/BookingServiceInterface.java new file mode 100644 index 0000000..539d1cf --- /dev/null +++ b/src/main/java/ru/practicum/shareit/booking/intrfaces/BookingServiceInterface.java @@ -0,0 +1,18 @@ +package ru.practicum.shareit.booking.intrfaces; + +import ru.practicum.shareit.booking.dto.BookingRequestDto; +import ru.practicum.shareit.booking.dto.BookingResponseDto; + +import java.util.Collection; + +public interface BookingServiceInterface { + BookingResponseDto addBooking(BookingRequestDto booking, Long bookerId); + + BookingResponseDto bookingApprove(Long bookingId, Long ownerId, Boolean isAvailable); + + BookingResponseDto getBookingByBookingId(Long bookingId, Long userId); + + Collection getBookingsByUser(Long userId, String state); + + Collection getBookingsByOwner(Long userId, String state); +} diff --git a/src/main/java/ru/practicum/shareit/booking/mapper/BookingMapper.java b/src/main/java/ru/practicum/shareit/booking/mapper/BookingMapper.java new file mode 100644 index 0000000..9d51d2c --- /dev/null +++ b/src/main/java/ru/practicum/shareit/booking/mapper/BookingMapper.java @@ -0,0 +1,15 @@ +package ru.practicum.shareit.booking.mapper; + +import org.mapstruct.Mapper; +import org.mapstruct.MappingConstants; +import ru.practicum.shareit.booking.dto.BookingRequestDto; +import ru.practicum.shareit.booking.dto.BookingResponseDto; +import ru.practicum.shareit.booking.model.Booking; + +@Mapper(componentModel = MappingConstants.ComponentModel.SPRING) +public interface BookingMapper { + Booking bookingRequestDtoToBooking(BookingRequestDto bookingRequestDto); + + BookingResponseDto bookingToBookingResponseDto(Booking booking); +} + diff --git a/src/main/java/ru/practicum/shareit/booking/model/Booking.java b/src/main/java/ru/practicum/shareit/booking/model/Booking.java new file mode 100644 index 0000000..c4b2ff2 --- /dev/null +++ b/src/main/java/ru/practicum/shareit/booking/model/Booking.java @@ -0,0 +1,42 @@ +package ru.practicum.shareit.booking.model; + +import jakarta.persistence.*; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.ToString; +import ru.practicum.shareit.item.model.Item; +import ru.practicum.shareit.user.model.User; + +import java.time.LocalDateTime; + +@Data +@Entity +@Table(name = "bookings") +@AllArgsConstructor +@NoArgsConstructor +@ToString +public class Booking { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "booking_id") + private Long bookingId; + + @Column(name = "start_date") + private LocalDateTime start; + + @Column(name = "end_date") + private LocalDateTime end; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "item_id") + private Item item; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "booker_id") + private User booker; + + @Enumerated(EnumType.STRING) + private BookingStatus status; +} diff --git a/src/main/java/ru/practicum/shareit/booking/BookingStatus.java b/src/main/java/ru/practicum/shareit/booking/model/BookingStatus.java similarity index 65% rename from src/main/java/ru/practicum/shareit/booking/BookingStatus.java rename to src/main/java/ru/practicum/shareit/booking/model/BookingStatus.java index 51269e0..4eb25ea 100644 --- a/src/main/java/ru/practicum/shareit/booking/BookingStatus.java +++ b/src/main/java/ru/practicum/shareit/booking/model/BookingStatus.java @@ -1,4 +1,4 @@ -package ru.practicum.shareit.booking; +package ru.practicum.shareit.booking.model; public enum BookingStatus { WAITING, diff --git a/src/main/java/ru/practicum/shareit/item/ItemController.java b/src/main/java/ru/practicum/shareit/item/ItemController.java index d033939..418f8b6 100644 --- a/src/main/java/ru/practicum/shareit/item/ItemController.java +++ b/src/main/java/ru/practicum/shareit/item/ItemController.java @@ -6,8 +6,7 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; -import ru.practicum.shareit.item.dto.ItemRequestDto; -import ru.practicum.shareit.item.dto.ItemResponseDto; +import ru.practicum.shareit.item.dto.*; import java.util.Collection; @@ -19,7 +18,7 @@ public class ItemController { public static final String OWNER_ID = "X-Sharer-User-Id"; - private final ItemService itemService; + private final ItemServiceImpl itemService; @PostMapping public ItemResponseDto create(@RequestHeader(OWNER_ID) Long ownerId, @@ -35,8 +34,9 @@ public ItemResponseDto update(@RequestBody ItemRequestDto item, } @GetMapping("/{itemId}") - public ItemResponseDto getItemById(@PathVariable Long itemId) { - return itemService.getItemById(itemId); + public ItemResponseDtoWithComments getItemById(@PathVariable Long itemId, + @RequestHeader(OWNER_ID) Long ownerId) { + return itemService.getItemById(itemId, ownerId); } @GetMapping @@ -50,4 +50,11 @@ public Collection searchItems(@RequestParam String text) { return itemService.searchByText(text); } + @PostMapping("/{itemId}/comment") + public CommentResponseCreatedDto addComment(@RequestBody CommentRequestDto comment, + @PathVariable Long itemId, + @RequestHeader(OWNER_ID) Long commentatorId) { + return itemService.addComment(commentatorId, comment, itemId); + } + } diff --git a/src/main/java/ru/practicum/shareit/item/ItemService.java b/src/main/java/ru/practicum/shareit/item/ItemService.java deleted file mode 100644 index 9dd0d0c..0000000 --- a/src/main/java/ru/practicum/shareit/item/ItemService.java +++ /dev/null @@ -1,77 +0,0 @@ -package ru.practicum.shareit.item; - -import lombok.RequiredArgsConstructor; -import org.springframework.stereotype.Service; -import ru.practicum.shareit.exception.AnotherUserException; -import ru.practicum.shareit.exception.NotFoundException; -import ru.practicum.shareit.exception.ValidationException; -import ru.practicum.shareit.item.dto.ItemRequestDto; -import ru.practicum.shareit.item.dto.ItemResponseDto; -import ru.practicum.shareit.item.interfaces.ItemServiceInterface; -import ru.practicum.shareit.item.mapper.ItemMapper; -import ru.practicum.shareit.item.model.Item; -import ru.practicum.shareit.user.UserStorage; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.stream.Collectors; - -@Service -@RequiredArgsConstructor -public class ItemService implements ItemServiceInterface { - - private final ItemStorage itemStorage; - private final UserStorage userStorage; - private final ItemMapper itemMapper; - - public ItemResponseDto createItem(ItemRequestDto item, Long ownerId) { - if (ownerId == null) { - throw new ValidationException("Owner id cannot be null"); - } - userStorage.getUserById(ownerId) - .orElseThrow(() -> new NotFoundException("User with id " + ownerId + " not found")); - Item itemSaved = itemMapper.toItem(item); - itemSaved.setOwnerId(ownerId); - return itemMapper.toItemResponseDto(itemStorage.createItem(itemSaved)); - } - - public ItemResponseDto getItemById(Long id) { - return itemMapper.toItemResponseDto(itemStorage.getItemById(id) - .orElseThrow(() -> new NotFoundException("Item with id " + id + " not found"))); - } - - public ItemResponseDto updateItem(Long itemId, - ItemRequestDto item, Long ownerId) { - findUserById(ownerId); - Item foundItem = itemStorage.getItemById(itemId) - .orElseThrow(() -> new NotFoundException("Item with id " + itemId + " not found")); - if (foundItem.getOwnerId().equals(ownerId)) { - item.setItemId(itemId); - foundItem = itemMapper.toItem(item); - } else { - throw new AnotherUserException("User with id " + ownerId + " is not owner of this Item"); - } - return itemMapper.toItemResponseDto(itemStorage.updateItem(foundItem)); - } - - public Collection getAllItemsForOwner(Long ownerId) { - return itemStorage.getAllItemsForOwner(ownerId).stream() - .map(itemMapper::toItemResponseDto) - .collect(Collectors.toList()); - } - - public Collection searchByText(String text) { - if (text == null || text.isEmpty()) { - return new ArrayList<>(); - } - return itemStorage.searchByText(text).stream() - .filter(Item::getIsAvailable) - .map(itemMapper::toItemResponseDto) - .collect(Collectors.toList()); - } - - private void findUserById(Long userId) { - userStorage.getUserById(userId) - .orElseThrow(() -> new NotFoundException("User with id = " + userId + " not found")); - } -} diff --git a/src/main/java/ru/practicum/shareit/item/ItemServiceImpl.java b/src/main/java/ru/practicum/shareit/item/ItemServiceImpl.java new file mode 100644 index 0000000..3b77efe --- /dev/null +++ b/src/main/java/ru/practicum/shareit/item/ItemServiceImpl.java @@ -0,0 +1,174 @@ +package ru.practicum.shareit.item; + +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import ru.practicum.shareit.booking.dto.BookingResponseDto; +import ru.practicum.shareit.booking.intrfaces.BookingRepository; +import ru.practicum.shareit.booking.mapper.BookingMapper; +import ru.practicum.shareit.booking.model.Booking; +import ru.practicum.shareit.booking.model.BookingStatus; +import ru.practicum.shareit.exception.AnotherUserException; +import ru.practicum.shareit.exception.NotFoundException; +import ru.practicum.shareit.exception.ValidationException; +import ru.practicum.shareit.item.dto.*; +import ru.practicum.shareit.item.interfaces.CommentRepository; +import ru.practicum.shareit.item.interfaces.ItemRepository; +import ru.practicum.shareit.item.interfaces.ItemServiceInterface; +import ru.practicum.shareit.item.mapper.CommentMapper; +import ru.practicum.shareit.item.mapper.ItemMapper; +import ru.practicum.shareit.item.model.Comment; +import ru.practicum.shareit.item.model.Item; +import ru.practicum.shareit.user.interfaces.UserRepository; +import ru.practicum.shareit.user.mapper.UserMapper; +import ru.practicum.shareit.user.model.User; + +import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Comparator; +import java.util.List; +import java.util.stream.Collectors; + + +@Service +@RequiredArgsConstructor +public class ItemServiceImpl implements ItemServiceInterface { + + private final ItemRepository itemRepository; + private final UserRepository userRepository; + private final CommentRepository commentRepository; + private final BookingRepository bookingRepository; + private final ItemMapper itemMapper; + private final UserMapper userMapper; + private final CommentMapper commentMapper; + private final BookingMapper bookingMapper; + + public ItemResponseDto createItem(ItemRequestDto item, Long ownerId) { + if (ownerId == null) { + throw new ValidationException("Owner id cannot be null"); + } + + User owner = userRepository.getUserByUserId(ownerId) + .orElseThrow(() -> new NotFoundException("User with id " + ownerId + " not found")); + + Item itemSaved = itemMapper.toItem(item); + itemSaved.setOwner(owner); + + itemRepository.save(itemSaved); + + return itemMapper.toItemResponseDto(itemSaved); + } + + public ItemResponseDtoWithComments getItemById(Long itemId, Long ownerId) { + ItemResponseDto item = itemMapper.toItemResponseDto(itemRepository.getItemByItemId(itemId) + .orElseThrow(() -> new NotFoundException("Item with id " + itemId + " not found"))); + + List comments = commentRepository.getCommentsByItem_ItemId(itemId).stream() + .map(commentMapper::toCommentResponseDto) + .collect(Collectors.toList()); + + ItemResponseDtoWithComments itemDto = itemMapper.toItemResponseDtoWithComments( + itemRepository.getItemByItemId(itemId).get()); + itemDto.setComments(comments); + + if (item.getOwnerId().equals(ownerId)) { + List bookingsLast = bookingRepository.getBookingsByItem_ItemId(itemId).stream() + .filter(booking -> booking.getEnd().isBefore(LocalDateTime.now())) + .toList(); + if (!bookingsLast.isEmpty()) { + BookingResponseDto lastBooking = bookingMapper.bookingToBookingResponseDto(bookingsLast.stream() + .sorted(Comparator.comparing(Booking::getEnd)) + .toList() + .getLast()); + itemDto.setLastBooking(lastBooking); + } + + List bookingsNext = bookingRepository.getBookingsByItem_ItemId(itemId).stream() + .filter(booking -> booking.getStart().isAfter(LocalDateTime.now())) + .toList(); + + if (!bookingsNext.isEmpty()) { + BookingResponseDto nextBooking = bookingMapper.bookingToBookingResponseDto(bookingsNext.stream() + .sorted(Comparator.comparing(Booking::getStart)) + .toList() + .getFirst()); + itemDto.setNextBooking(nextBooking); + } + } + return itemDto; + + } + + public ItemResponseDto updateItem(Long itemId, + ItemRequestDto item, Long ownerId) { + + User owner = userRepository.getUserByUserId(ownerId) + .orElseThrow(() -> new NotFoundException("User with id " + ownerId + " not found")); + + Item foundItem = itemRepository.getItemByItemId(itemId) + .orElseThrow(() -> new NotFoundException("Item with id " + itemId + " not found")); + + if (foundItem.getOwner().getUserId().equals(ownerId)) { + + if (item.getIsAvailable() != null) { + foundItem.setIsAvailable(item.getIsAvailable()); + } + + if (item.getItemName() != null) { + foundItem.setItemName(item.getItemName()); + } + + if (item.getItemDescription() != null) { + foundItem.setItemDescription(item.getItemDescription()); + } + + } else { + throw new AnotherUserException("User with id " + ownerId + " is not owner of this Item"); + } + + return itemMapper.toItemResponseDto(foundItem); + } + + public Collection getAllItemsForOwner(Long ownerId) { + User owner = userRepository.getUserByUserId(ownerId) + .orElseThrow(() -> new NotFoundException("User with id " + ownerId + " not found")); + + return itemRepository.getItemsByOwner_UserId(ownerId).stream() + .map(itemMapper::toItemResponseDto) + .peek(item -> item.setOwnerId(ownerId)) + .collect(Collectors.toList()); + } + + public Collection searchByText(String text) { + if (text == null || text.isEmpty()) { + return new ArrayList<>(); + } + return itemRepository.searchByTextContainingIgnoreCase(text).stream() + .filter(Item::getIsAvailable) + .map(itemMapper::toItemResponseDto) + .collect(Collectors.toList()); + } + + public CommentResponseCreatedDto addComment(Long commentatorId, + CommentRequestDto commentDto, Long itemId) { + Collection bookings = bookingRepository.getBookingsByItem_ItemId(itemId); + + Booking booking = bookings.stream() + .filter(booking1 -> booking1.getBooker().getUserId().equals(commentatorId)) + .findFirst() + .orElseThrow(() -> new NotFoundException("Booking with bookerId " + commentatorId + " not found")); + + if (booking.getEnd().isBefore(commentDto.getDate()) && booking.getStatus().equals(BookingStatus.APPROVED)) { + Comment comment = commentMapper.toComment(commentDto); + comment.setItem(itemRepository.getItemByItemId(itemId).get()); + comment.setAuthor(userRepository.getUserByUserId(commentatorId).get()); + + return commentMapper.toCommentResponseCreatedDto(commentRepository.save(comment)); + + } else { + throw new ValidationException("Comment cannot be added to the booking"); + } + } + +} + diff --git a/src/main/java/ru/practicum/shareit/item/ItemStorage.java b/src/main/java/ru/practicum/shareit/item/ItemStorage.java index 6b234d5..e9ba003 100644 --- a/src/main/java/ru/practicum/shareit/item/ItemStorage.java +++ b/src/main/java/ru/practicum/shareit/item/ItemStorage.java @@ -49,7 +49,7 @@ public Item updateItem(Item item) { public Collection getAllItemsForOwner(Long ownerId) { return items.values() .stream() - .filter(item -> Objects.equals(item.getOwnerId(), ownerId)) + .filter(item -> Objects.equals(item.getOwner().getUserId(), ownerId)) .collect(Collectors.toList()); } diff --git a/src/main/java/ru/practicum/shareit/item/dto/CommentRequestDto.java b/src/main/java/ru/practicum/shareit/item/dto/CommentRequestDto.java new file mode 100644 index 0000000..3462221 --- /dev/null +++ b/src/main/java/ru/practicum/shareit/item/dto/CommentRequestDto.java @@ -0,0 +1,19 @@ +package ru.practicum.shareit.item.dto; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Data; + +import java.time.LocalDateTime; + +@Data +public class CommentRequestDto { + + @JsonProperty("id") + private Long authorId; + + @JsonProperty("text") + private String text; + + private LocalDateTime date = LocalDateTime.now(); + +} diff --git a/src/main/java/ru/practicum/shareit/item/dto/CommentResponseCreatedDto.java b/src/main/java/ru/practicum/shareit/item/dto/CommentResponseCreatedDto.java new file mode 100644 index 0000000..f47203c --- /dev/null +++ b/src/main/java/ru/practicum/shareit/item/dto/CommentResponseCreatedDto.java @@ -0,0 +1,17 @@ +package ru.practicum.shareit.item.dto; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Data; + +@Data +public class CommentResponseCreatedDto { + @JsonProperty("id") + private Long commentId; + + @JsonProperty("text") + private String text; + + private String authorName; + + private Boolean created = true; +} diff --git a/src/main/java/ru/practicum/shareit/item/dto/CommentResponseDto.java b/src/main/java/ru/practicum/shareit/item/dto/CommentResponseDto.java new file mode 100644 index 0000000..9dc1ff9 --- /dev/null +++ b/src/main/java/ru/practicum/shareit/item/dto/CommentResponseDto.java @@ -0,0 +1,17 @@ +package ru.practicum.shareit.item.dto; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Data; +import ru.practicum.shareit.user.dto.UserAuthorDto; + +@Data +public class CommentResponseDto { + + @JsonProperty("id") + private Long commentId; + + @JsonProperty("text") + private String text; + + private UserAuthorDto author; +} diff --git a/src/main/java/ru/practicum/shareit/item/dto/ItemBookerDto.java b/src/main/java/ru/practicum/shareit/item/dto/ItemBookerDto.java new file mode 100644 index 0000000..28d23ca --- /dev/null +++ b/src/main/java/ru/practicum/shareit/item/dto/ItemBookerDto.java @@ -0,0 +1,18 @@ +package ru.practicum.shareit.item.dto; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@AllArgsConstructor +@NoArgsConstructor +public class ItemBookerDto { + + @JsonProperty("id") + private Long itemId; + + @JsonProperty("name") + private String itemName; +} diff --git a/src/main/java/ru/practicum/shareit/item/dto/ItemResponseDtoWithComments.java b/src/main/java/ru/practicum/shareit/item/dto/ItemResponseDtoWithComments.java new file mode 100644 index 0000000..63d3bd6 --- /dev/null +++ b/src/main/java/ru/practicum/shareit/item/dto/ItemResponseDtoWithComments.java @@ -0,0 +1,40 @@ +package ru.practicum.shareit.item.dto; + +import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.constraints.NotNull; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import ru.practicum.shareit.booking.dto.BookingResponseDto; + +import java.util.List; + +@Data +@AllArgsConstructor +@NoArgsConstructor +public class ItemResponseDtoWithComments { + + @NotNull + @JsonProperty("id") + private Long itemId; + + @JsonProperty("name") + private String itemName; + + @JsonProperty("description") + private String itemDescription; + + @JsonProperty("available") + private Boolean isAvailable; + + @JsonProperty("userId") + private Long ownerId; + + private Long requestId; + + private BookingResponseDto lastBooking; + + private BookingResponseDto nextBooking; + + private List comments; +} diff --git a/src/main/java/ru/practicum/shareit/item/interfaces/CommentRepository.java b/src/main/java/ru/practicum/shareit/item/interfaces/CommentRepository.java new file mode 100644 index 0000000..01f501c --- /dev/null +++ b/src/main/java/ru/practicum/shareit/item/interfaces/CommentRepository.java @@ -0,0 +1,13 @@ +package ru.practicum.shareit.item.interfaces; + +import org.springframework.data.jpa.repository.JpaRepository; +import ru.practicum.shareit.item.model.Comment; + +import java.util.Collection; + +public interface CommentRepository extends JpaRepository { + + Comment save(Comment comment); + + Collection getCommentsByItem_ItemId(Long itemId); +} diff --git a/src/main/java/ru/practicum/shareit/item/interfaces/ItemRepository.java b/src/main/java/ru/practicum/shareit/item/interfaces/ItemRepository.java new file mode 100644 index 0000000..d27984b --- /dev/null +++ b/src/main/java/ru/practicum/shareit/item/interfaces/ItemRepository.java @@ -0,0 +1,20 @@ +package ru.practicum.shareit.item.interfaces; + +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; +import ru.practicum.shareit.item.model.Item; + +import java.util.Collection; +import java.util.Optional; + +public interface ItemRepository extends JpaRepository { + Item save(Item item); + + Optional getItemByItemId(Long itemId); + + Collection getItemsByOwner_UserId(Long ownerUserId); + + @Query(value = "SELECT i FROM Item i WHERE upper(i.itemName) like upper(concat('%', ?1, '%')) " + + " OR upper(i.itemDescription) LIKE upper(concat('%', ?1, '%'))") + Collection searchByTextContainingIgnoreCase(String text); +} diff --git a/src/main/java/ru/practicum/shareit/item/interfaces/ItemServiceInterface.java b/src/main/java/ru/practicum/shareit/item/interfaces/ItemServiceInterface.java index 053d40c..722ac82 100644 --- a/src/main/java/ru/practicum/shareit/item/interfaces/ItemServiceInterface.java +++ b/src/main/java/ru/practicum/shareit/item/interfaces/ItemServiceInterface.java @@ -2,13 +2,14 @@ import ru.practicum.shareit.item.dto.ItemRequestDto; import ru.practicum.shareit.item.dto.ItemResponseDto; +import ru.practicum.shareit.item.dto.ItemResponseDtoWithComments; import java.util.Collection; public interface ItemServiceInterface { ItemResponseDto createItem(ItemRequestDto item, Long ownerId); - ItemResponseDto getItemById(Long id); + ItemResponseDtoWithComments getItemById(Long id, Long ownerId); ItemResponseDto updateItem(Long itemId, ItemRequestDto item, Long ownerId); diff --git a/src/main/java/ru/practicum/shareit/item/mapper/CommentMapper.java b/src/main/java/ru/practicum/shareit/item/mapper/CommentMapper.java new file mode 100644 index 0000000..ff396e8 --- /dev/null +++ b/src/main/java/ru/practicum/shareit/item/mapper/CommentMapper.java @@ -0,0 +1,30 @@ +package ru.practicum.shareit.item.mapper; + +import org.mapstruct.Mapper; +import org.mapstruct.MappingConstants; +import ru.practicum.shareit.item.dto.CommentRequestDto; +import ru.practicum.shareit.item.dto.CommentResponseCreatedDto; +import ru.practicum.shareit.item.dto.CommentResponseDto; +import ru.practicum.shareit.item.model.Comment; + +@Mapper(componentModel = MappingConstants.ComponentModel.SPRING) +public interface CommentMapper { + Comment toComment(CommentRequestDto comment); + + CommentResponseDto toCommentResponseDto(Comment comment); + + + default CommentResponseCreatedDto toCommentResponseCreatedDto(Comment comment) { + if (comment == null) { + return null; + } + + CommentResponseCreatedDto commentResponseCreatedDto = new CommentResponseCreatedDto(); + commentResponseCreatedDto.setCommentId(comment.getCommentId()); + commentResponseCreatedDto.setText(comment.getText()); + commentResponseCreatedDto.setAuthorName(comment.getAuthor().getUserName()); + + return commentResponseCreatedDto; + } + +} diff --git a/src/main/java/ru/practicum/shareit/item/mapper/ItemMapper.java b/src/main/java/ru/practicum/shareit/item/mapper/ItemMapper.java index 6835d2c..38eb932 100644 --- a/src/main/java/ru/practicum/shareit/item/mapper/ItemMapper.java +++ b/src/main/java/ru/practicum/shareit/item/mapper/ItemMapper.java @@ -2,8 +2,10 @@ import org.mapstruct.Mapper; import org.mapstruct.MappingConstants; +import ru.practicum.shareit.item.dto.ItemBookerDto; import ru.practicum.shareit.item.dto.ItemRequestDto; import ru.practicum.shareit.item.dto.ItemResponseDto; +import ru.practicum.shareit.item.dto.ItemResponseDtoWithComments; import ru.practicum.shareit.item.model.Item; @Mapper(componentModel = MappingConstants.ComponentModel.SPRING) @@ -14,6 +16,48 @@ public interface ItemMapper { Item toItem(ItemRequestDto itemRequestDto); - ItemResponseDto toItemResponseDto(Item item); + default ItemResponseDto toItemResponseDto(Item item) { + if (item == null) { + return null; + } + + ItemResponseDto itemResponseDto = new ItemResponseDto(); + itemResponseDto.setItemId(item.getItemId()); + itemResponseDto.setItemName(item.getItemName()); + itemResponseDto.setItemDescription(item.getItemDescription()); + itemResponseDto.setIsAvailable(item.getIsAvailable()); + itemResponseDto.setOwnerId(item.getOwner().getUserId()); + + if (item.getItemRequest() != null) { + itemResponseDto.setRequestId(item.getItemRequest().getRequesterId()); + } + + return itemResponseDto; + + } + + ItemBookerDto toItemBookerDto(Item item); + + default ItemResponseDtoWithComments toItemResponseDtoWithComments(Item item) { + if (item == null) { + return null; + } + + ItemResponseDtoWithComments itemResponseDtoWithComments = new ItemResponseDtoWithComments(); + + itemResponseDtoWithComments.setItemId(item.getItemId()); + itemResponseDtoWithComments.setItemName(item.getItemName()); + itemResponseDtoWithComments.setItemDescription(item.getItemDescription()); + itemResponseDtoWithComments.setIsAvailable(item.getIsAvailable()); + itemResponseDtoWithComments.setItemId(item.getItemId()); + itemResponseDtoWithComments.setOwnerId(item.getOwner().getUserId()); + + if (item.getItemRequest() != null) { + itemResponseDtoWithComments.setRequestId(item.getItemRequest().getItemRequestId()); + } + + return itemResponseDtoWithComments; + + } } diff --git a/src/main/java/ru/practicum/shareit/item/model/Comment.java b/src/main/java/ru/practicum/shareit/item/model/Comment.java new file mode 100644 index 0000000..f979f3e --- /dev/null +++ b/src/main/java/ru/practicum/shareit/item/model/Comment.java @@ -0,0 +1,34 @@ +package ru.practicum.shareit.item.model; + +import jakarta.persistence.*; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.ToString; +import ru.practicum.shareit.user.model.User; + +@NoArgsConstructor +@AllArgsConstructor +@Data +@Entity +@ToString +@Table(name = "comments") +public class Comment { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "comment_id") + private Long commentId; + + @Column(name = "text") + private String text; + + @ManyToOne(targetEntity = User.class, cascade = CascadeType.ALL) + @JoinColumn(name = "author_id") + private User author; + + @ManyToOne(targetEntity = Item.class,cascade = CascadeType.ALL, fetch = FetchType.LAZY) + @JoinColumn(name = "item_id") + private Item item; + +} \ No newline at end of file diff --git a/src/main/java/ru/practicum/shareit/item/model/Item.java b/src/main/java/ru/practicum/shareit/item/model/Item.java index 6fcf2d1..c1d6d11 100644 --- a/src/main/java/ru/practicum/shareit/item/model/Item.java +++ b/src/main/java/ru/practicum/shareit/item/model/Item.java @@ -1,20 +1,42 @@ package ru.practicum.shareit.item.model; +import jakarta.persistence.*; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; - +import lombok.ToString; +import ru.practicum.shareit.request.ItemRequest; +import ru.practicum.shareit.user.model.User; @Data @NoArgsConstructor @AllArgsConstructor +@Entity +@ToString +@Table(name = "items") public class Item { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "item_id") private Long itemId; + + @Column(name = "item_name") private String itemName; + + @Column(name = "item_description") private String itemDescription; + + @Column(name = "is_available") private Boolean isAvailable; - private Long ownerId; - private Long requestId; + + @ManyToOne + @JoinColumn(name = "owner_id") + private User owner; + + @ManyToOne + @JoinColumn(name = "request_id") + private ItemRequest itemRequest; + } diff --git a/src/main/java/ru/practicum/shareit/request/ItemRequest.java b/src/main/java/ru/practicum/shareit/request/ItemRequest.java index c12fab1..0da7fda 100644 --- a/src/main/java/ru/practicum/shareit/request/ItemRequest.java +++ b/src/main/java/ru/practicum/shareit/request/ItemRequest.java @@ -1,13 +1,35 @@ package ru.practicum.shareit.request; +import jakarta.persistence.*; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.ToString; + import java.time.LocalDate; /** * TODO Sprint add-item-requests. */ +@Data +@Entity +@Table(name = "requests") +@AllArgsConstructor +@NoArgsConstructor +@ToString public class ItemRequest { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "request_id") private Long itemRequestId; + + @Column(name = "description") private String requestDescription; + + @Column(name = "requestor_id") private Long requesterId; + + @Transient private LocalDate requestDate; } diff --git a/src/main/java/ru/practicum/shareit/request/interfaces/RequestRepository.java b/src/main/java/ru/practicum/shareit/request/interfaces/RequestRepository.java new file mode 100644 index 0000000..cea05b1 --- /dev/null +++ b/src/main/java/ru/practicum/shareit/request/interfaces/RequestRepository.java @@ -0,0 +1,8 @@ +package ru.practicum.shareit.request.interfaces; + +import org.springframework.data.jpa.repository.JpaRepository; +import ru.practicum.shareit.request.ItemRequest; + +public interface RequestRepository extends JpaRepository { + ItemRequest save(ItemRequest item); +} diff --git a/src/main/java/ru/practicum/shareit/user/UserController.java b/src/main/java/ru/practicum/shareit/user/UserController.java index 4c334a4..0289b90 100644 --- a/src/main/java/ru/practicum/shareit/user/UserController.java +++ b/src/main/java/ru/practicum/shareit/user/UserController.java @@ -12,7 +12,7 @@ @RequestMapping(path = "/users") @RequiredArgsConstructor public class UserController { - private final UserService userService; + private final UserServiceImpl userService; @PostMapping public UserResponseDto createUser(@Valid @RequestBody UserRequestDto user) { diff --git a/src/main/java/ru/practicum/shareit/user/UserService.java b/src/main/java/ru/practicum/shareit/user/UserServiceImpl.java similarity index 65% rename from src/main/java/ru/practicum/shareit/user/UserService.java rename to src/main/java/ru/practicum/shareit/user/UserServiceImpl.java index e4c8802..c988d8a 100644 --- a/src/main/java/ru/practicum/shareit/user/UserService.java +++ b/src/main/java/ru/practicum/shareit/user/UserServiceImpl.java @@ -6,6 +6,7 @@ import ru.practicum.shareit.exception.NotFoundException; import ru.practicum.shareit.user.dto.UserRequestDto; import ru.practicum.shareit.user.dto.UserResponseDto; +import ru.practicum.shareit.user.interfaces.UserRepository; import ru.practicum.shareit.user.interfaces.UserServiceInterface; import ru.practicum.shareit.user.mapper.UserMapper; import ru.practicum.shareit.user.model.User; @@ -15,42 +16,54 @@ @Service @AllArgsConstructor -public class UserService implements UserServiceInterface { +public class UserServiceImpl implements UserServiceInterface { - private final UserStorage userStorage; + private final UserRepository userStorage; private final UserMapper userMapper; public UserResponseDto createUser(UserRequestDto user) { validateEmail(user.getUserEmail()); User newUser = userMapper.toUser(user); - return userMapper.toUserResponseDto(userStorage.createUser(newUser)); + return userMapper.toUserResponseDto(userStorage.save(newUser)); } public UserResponseDto getUserById(Long userId) throws NotFoundException { - return userMapper.toUserResponseDto(userStorage.getUserById(userId) + return userMapper.toUserResponseDto(userStorage.getUserByUserId(userId) .orElseThrow(() -> new NotFoundException("User not found, id = " + userId))); } public UserResponseDto updateUser(Long userId, UserRequestDto user) throws NotFoundException { + User updated = userStorage.getUserByUserId(userId) + .orElseThrow(() -> new NotFoundException("User not found, id = " + userId)); + validateEmail(user.getUserEmail()); - return userMapper.toUserResponseDto(userStorage.updateUser(userId, userMapper.toUser(user))); + + if (user.getUserEmail() != null) { + updated.setUserEmail(user.getUserEmail()); + } + + if (user.getUserName() != null) { + updated.setUserName(user.getUserName()); + } + + return userMapper.toUserResponseDto(userStorage.save(updated)); } public void deleteUser(Long userId) throws NotFoundException { - getUserById(userId); - userStorage.deleteUser(userId); + User user = userMapper.toUser(getUserById(userId)); + userStorage.delete(user); } public void deleteAllUsers() { - userStorage.deleteAllUsers(); + userStorage.deleteAll(); } private void validateEmail(String email) { - Collection users = userStorage.getAllUsers(); + Collection users = userStorage.findAll(); if (!users.isEmpty()) { Optional first = - userStorage.getAllUsers().stream() + userStorage.findAll().stream() .map(User::getUserEmail) .filter(userEmail -> userEmail.equals(email)) .findFirst(); diff --git a/src/main/java/ru/practicum/shareit/user/dto/UserAuthorDto.java b/src/main/java/ru/practicum/shareit/user/dto/UserAuthorDto.java new file mode 100644 index 0000000..dbc923a --- /dev/null +++ b/src/main/java/ru/practicum/shareit/user/dto/UserAuthorDto.java @@ -0,0 +1,19 @@ +package ru.practicum.shareit.user.dto; + +import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.constraints.NotNull; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@AllArgsConstructor +@NoArgsConstructor +public class UserAuthorDto { + @NotNull + @JsonProperty("id") + private Long userId; + + @JsonProperty("authorName") + private String userName; +} diff --git a/src/main/java/ru/practicum/shareit/user/dto/UserBookingDto.java b/src/main/java/ru/practicum/shareit/user/dto/UserBookingDto.java new file mode 100644 index 0000000..ef634fa --- /dev/null +++ b/src/main/java/ru/practicum/shareit/user/dto/UserBookingDto.java @@ -0,0 +1,20 @@ +package ru.practicum.shareit.user.dto; + +import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.constraints.NotNull; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@AllArgsConstructor +@NoArgsConstructor +public class UserBookingDto { + @NotNull + @JsonProperty("id") + private Long userId; + + @JsonProperty("name") + private String userName; + +} diff --git a/src/main/java/ru/practicum/shareit/user/interfaces/UserRepository.java b/src/main/java/ru/practicum/shareit/user/interfaces/UserRepository.java new file mode 100644 index 0000000..2024294 --- /dev/null +++ b/src/main/java/ru/practicum/shareit/user/interfaces/UserRepository.java @@ -0,0 +1,19 @@ +package ru.practicum.shareit.user.interfaces; + +import org.springframework.data.jpa.repository.JpaRepository; +import ru.practicum.shareit.user.model.User; + +import java.util.List; +import java.util.Optional; + +public interface UserRepository extends JpaRepository { + User save(User user); + + Optional getUserByUserId(Long userId); + + List findAll(); + + void deleteUserByUserId(Long id); + + void deleteAll(); +} diff --git a/src/main/java/ru/practicum/shareit/user/mapper/UserMapper.java b/src/main/java/ru/practicum/shareit/user/mapper/UserMapper.java index 086a773..feeeb99 100644 --- a/src/main/java/ru/practicum/shareit/user/mapper/UserMapper.java +++ b/src/main/java/ru/practicum/shareit/user/mapper/UserMapper.java @@ -1,13 +1,13 @@ package ru.practicum.shareit.user.mapper; -import org.mapstruct.InjectionStrategy; import org.mapstruct.Mapper; +import ru.practicum.shareit.user.dto.UserAuthorDto; +import ru.practicum.shareit.user.dto.UserBookingDto; import ru.practicum.shareit.user.dto.UserRequestDto; import ru.practicum.shareit.user.dto.UserResponseDto; import ru.practicum.shareit.user.model.User; -@Mapper(componentModel = "spring", uses = UserMapper - .class, injectionStrategy = InjectionStrategy.CONSTRUCTOR) +@Mapper(componentModel = "spring") public interface UserMapper { UserRequestDto toUserRequestDto(User user); @@ -17,4 +17,9 @@ public interface UserMapper { UserResponseDto toUserResponseDto(User user); User toUser(UserResponseDto userDto); + + UserAuthorDto toUserAuthorDto(User user); + + UserBookingDto toUserBookingDto(User booker); + } diff --git a/src/main/java/ru/practicum/shareit/user/model/User.java b/src/main/java/ru/practicum/shareit/user/model/User.java index c7c00cc..5d289c4 100644 --- a/src/main/java/ru/practicum/shareit/user/model/User.java +++ b/src/main/java/ru/practicum/shareit/user/model/User.java @@ -1,14 +1,27 @@ package ru.practicum.shareit.user.model; +import jakarta.persistence.*; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; +import lombok.ToString; @Data @NoArgsConstructor @AllArgsConstructor +@Entity +@ToString +@Table(name = "users") public class User { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "user_id") private Long userId; + + @Column(name = "user_name") private String userName; + + @Column(name = "user_email") private String userEmail; } diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index b9e5d4b..e1fc5d9 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -1,14 +1,13 @@ spring.jpa.hibernate.ddl-auto=none spring.jpa.properties.hibernate.format_sql=true +spring.jpa.properties.hibernate.jdbc.time_zone=UTC spring.sql.init.mode=always +spring.datasource.url=jdbc:postgresql://localhost:5432/postgres +spring.datasource.driverClassName=org.postgresql.Driver +spring.datasource.username=user +spring.datasource.password=12345 logging.level.org.springframework.orm.jpa=INFO logging.level.org.springframework.transaction=INFO logging.level.org.springframework.transaction.interceptor=TRACE -logging.level.org.springframework.orm.jpa.JpaTransactionManager=DEBUG - -# TODO Append connection to DB -#spring.datasource.driverClassName -#spring.datasource.url -#spring.datasource.username -#spring.datasource.password +logging.level.org.springframework.orm.jpa.JpaTransactionManager=DEBUG \ No newline at end of file diff --git a/src/main/resources/schema.sql b/src/main/resources/schema.sql new file mode 100644 index 0000000..c07802f --- /dev/null +++ b/src/main/resources/schema.sql @@ -0,0 +1,42 @@ +CREATE TABLE IF NOT EXISTS users ( + user_id BIGSERIAL PRIMARY KEY, + user_name CHARACTER VARYING(255) NOT NULL, + user_email CHARACTER VARYING(500) NOT NULL UNIQUE +); + +CREATE TABLE IF NOT EXISTS items ( + item_id BIGSERIAL PRIMARY KEY, + item_name CHARACTER VARYING(255) NOT NULL, + item_description CHARACTER VARYING(150) NOT NULL, + is_available BOOLEAN NOT NULL, + owner_id BIGINT NOT NULL, + request_id BIGINT, + CONSTRAINT fk_items_to_users FOREIGN KEY(owner_id) REFERENCES users(user_id) ON DELETE CASCADE +); + +CREATE TABLE IF NOT EXISTS comments ( + comment_id BIGSERIAL PRIMARY KEY, + text CHARACTER VARYING(2000) NOT NULL, + item_id BIGINT NOT NULL, + author_id BIGINT NOT NULL, + CONSTRAINT fk_comments_to_users FOREIGN KEY (author_id) REFERENCES users (user_id) ON DELETE CASCADE, + CONSTRAINT fk_comments_to_items FOREIGN KEY (item_id) REFERENCES items(item_id) ON DELETE CASCADE +); + +CREATE TABLE IF NOT EXISTS bookings ( + booking_id BIGSERIAL PRIMARY KEY, + start_date TIMESTAMP WITHOUT TIME ZONE NOT NULL, + end_date TIMESTAMP WITHOUT TIME ZONE NOT NULL, + item_id BIGINT NOT NULL, + booker_id BIGINT NOT NULL, + status CHARACTER VARYING (50), + FOREIGN KEY (item_id) REFERENCES items (item_id) ON DELETE CASCADE, + FOREIGN KEY (booker_id) REFERENCES users (user_id) ON DELETE CASCADE +); + +CREATE TABLE IF NOT EXISTS requests ( + request_id BIGSERIAL PRIMARY KEY, + requestor_id BIGINT NOT NULL, + description CHARACTER VARYING (200), + FOREIGN KEY (requestor_id) REFERENCES users (user_id) ON DELETE CASCADE +); \ No newline at end of file diff --git a/src/test/java/ru/practicum/shareit/mapperTest/BookingMapperTest.java b/src/test/java/ru/practicum/shareit/mapperTest/BookingMapperTest.java new file mode 100644 index 0000000..5744f96 --- /dev/null +++ b/src/test/java/ru/practicum/shareit/mapperTest/BookingMapperTest.java @@ -0,0 +1,80 @@ +package ru.practicum.shareit.mapperTest; + +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import ru.practicum.shareit.booking.dto.BookingRequestDto; +import ru.practicum.shareit.booking.dto.BookingResponseDto; +import ru.practicum.shareit.booking.mapper.BookingMapper; +import ru.practicum.shareit.booking.model.Booking; +import ru.practicum.shareit.booking.model.BookingStatus; +import ru.practicum.shareit.item.dto.ItemBookerDto; +import ru.practicum.shareit.item.mapper.ItemMapper; +import ru.practicum.shareit.item.model.Item; +import ru.practicum.shareit.request.ItemRequest; +import ru.practicum.shareit.user.dto.UserBookingDto; +import ru.practicum.shareit.user.mapper.UserMapper; +import ru.practicum.shareit.user.model.User; + +import java.time.LocalDate; +import java.time.LocalDateTime; + +import static org.junit.jupiter.api.Assertions.assertAll; +import static org.junit.jupiter.api.Assertions.assertEquals; + +@SpringBootTest +public class BookingMapperTest { + @Autowired + private BookingMapper bookingMapper; + + @Autowired + private UserMapper userMapper; + + @Autowired + private ItemMapper itemMapper; + + User user = new User(1L, "testName1", "test1@test.com"); + + ItemRequest itemRequest = new ItemRequest(1L, "testDescription1", + 1L, LocalDate.of(2025, 6, 25)); + + Item item = new Item(1L, "TestName1", "Test description1", true, user, itemRequest); + LocalDateTime startTime = LocalDateTime.of(2025, 6, 25, 12, 30); + LocalDateTime endTime = LocalDateTime.of(2025, 6, 27, 13, 30); + + @Test + public void bookingRequestDtoToBookingTest() { + BookingRequestDto bookingRequestDto = new BookingRequestDto(); + + bookingRequestDto.setBookingId(1L); + bookingRequestDto.setStart(startTime); + bookingRequestDto.setEnd(endTime); + bookingRequestDto.setStatus(BookingStatus.WAITING); + + Booking booking = bookingMapper.bookingRequestDtoToBooking(bookingRequestDto); + assertAll(() -> { + assertEquals(booking.getBookingId(), bookingRequestDto.getBookingId()); + assertEquals(booking.getStart(), bookingRequestDto.getStart()); + assertEquals(booking.getEnd(), bookingRequestDto.getEnd()); + assertEquals(booking.getStatus(), bookingRequestDto.getStatus()); + }); + } + + @Test + public void bookingToBookingResponseDtoTest() { + Booking booking = new Booking(3L, startTime, endTime, item, user, BookingStatus.APPROVED); + + BookingResponseDto bookingResponseDto = bookingMapper.bookingToBookingResponseDto(booking); + + ItemBookerDto itemBookerDto = itemMapper.toItemBookerDto(item); + UserBookingDto userBookingDto = userMapper.toUserBookingDto(user); + assertAll(() -> { + assertEquals(booking.getBookingId(), bookingResponseDto.getBookingId()); + assertEquals(booking.getStart(), bookingResponseDto.getStart()); + assertEquals(booking.getEnd(), bookingResponseDto.getEnd()); + assertEquals(booking.getStatus(), bookingResponseDto.getStatus()); + assertEquals(userBookingDto, bookingResponseDto.getBooker()); + assertEquals(itemBookerDto, bookingResponseDto.getItem()); + }); + } +} diff --git a/src/test/java/ru/practicum/shareit/mapperTest/CommentMapperTest.java b/src/test/java/ru/practicum/shareit/mapperTest/CommentMapperTest.java new file mode 100644 index 0000000..6b7179f --- /dev/null +++ b/src/test/java/ru/practicum/shareit/mapperTest/CommentMapperTest.java @@ -0,0 +1,73 @@ +package ru.practicum.shareit.mapperTest; + +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import ru.practicum.shareit.item.dto.CommentRequestDto; +import ru.practicum.shareit.item.dto.CommentResponseCreatedDto; +import ru.practicum.shareit.item.dto.CommentResponseDto; +import ru.practicum.shareit.item.mapper.CommentMapper; +import ru.practicum.shareit.item.model.Comment; +import ru.practicum.shareit.item.model.Item; +import ru.practicum.shareit.request.ItemRequest; +import ru.practicum.shareit.user.dto.UserAuthorDto; +import ru.practicum.shareit.user.mapper.UserMapper; +import ru.practicum.shareit.user.model.User; + +import java.time.LocalDate; + +import static org.junit.jupiter.api.Assertions.assertAll; +import static org.junit.jupiter.api.Assertions.assertEquals; + +@SpringBootTest +public class CommentMapperTest { + @Autowired + private CommentMapper commentMapper; + + @Autowired + private UserMapper userMapper; + + User user = new User(1L, "testName1", "test1@test.com"); + + ItemRequest itemRequest = new ItemRequest(1L, "testDescription1", + 1L, LocalDate.of(2025, 6, 25)); + + Item item = new Item(1L, "TestName1", "Test description1", true, user, itemRequest); + + @Test + public void commentToCommentDtoTest() { + Comment comment = new Comment(1L, "testComment1", user, item); + UserAuthorDto authorDto = userMapper.toUserAuthorDto(user); + CommentResponseDto commentResponseDto = commentMapper.toCommentResponseDto(comment); + + assertAll(() -> { + assertEquals("testComment1", commentResponseDto.getText()); + assertEquals(1L, commentResponseDto.getCommentId()); + assertEquals(authorDto, commentResponseDto.getAuthor()); + }); + } + + @Test + public void commentToCommentResponseCreatedDtoTest() { + Comment comment = new Comment(1L, "testComment1", user, item); + + CommentResponseCreatedDto createdDto = commentMapper.toCommentResponseCreatedDto(comment); + assertAll(() -> { + assertEquals("testComment1", createdDto.getText()); + assertEquals(1L, createdDto.getCommentId()); + assertEquals(user.getUserName(), createdDto.getAuthorName()); + assertEquals(true, createdDto.getCreated()); + }); + } + + @Test + public void commentRequestDtoToCommentTest() { + CommentRequestDto commentRequestDto = new CommentRequestDto(); + commentRequestDto.setAuthorId(user.getUserId()); + commentRequestDto.setText("testComment1"); + + Comment comment = commentMapper.toComment(commentRequestDto); + + assertAll(() -> assertEquals("testComment1", comment.getText())); + } +} diff --git a/src/test/java/ru/practicum/shareit/ItemMapperTest.java b/src/test/java/ru/practicum/shareit/mapperTest/ItemMapperTest.java similarity index 57% rename from src/test/java/ru/practicum/shareit/ItemMapperTest.java rename to src/test/java/ru/practicum/shareit/mapperTest/ItemMapperTest.java index 05ba9ca..5143e32 100644 --- a/src/test/java/ru/practicum/shareit/ItemMapperTest.java +++ b/src/test/java/ru/practicum/shareit/mapperTest/ItemMapperTest.java @@ -1,12 +1,15 @@ -package ru.practicum.shareit; +package ru.practicum.shareit.mapperTest; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; -import ru.practicum.shareit.item.dto.ItemRequestDto; -import ru.practicum.shareit.item.dto.ItemResponseDto; +import ru.practicum.shareit.item.dto.*; import ru.practicum.shareit.item.mapper.ItemMapper; import ru.practicum.shareit.item.model.Item; +import ru.practicum.shareit.request.ItemRequest; +import ru.practicum.shareit.user.model.User; + +import java.time.LocalDate; import static org.junit.jupiter.api.Assertions.*; @@ -16,6 +19,11 @@ public class ItemMapperTest { @Autowired private ItemMapper itemMapper; + User user = new User(1L, "testName1", "test1@test.com"); + + ItemRequest itemRequest = new ItemRequest(1L, "testDescription1", + 1L, LocalDate.of(2025, 6, 25)); + @Test public void itemRequestDtoToItemTest() { ItemRequestDto itemRequestDto = new ItemRequestDto( @@ -28,14 +36,13 @@ public void itemRequestDtoToItemTest() { assertEquals("TestName", item.getItemName()); assertEquals("Test description", item.getItemDescription()); assertEquals(true, item.getIsAvailable()); - assertNull(item.getOwnerId()); - assertEquals(1L, item.getRequestId()); + assertNull(item.getOwner()); }); } @Test public void itemToItemResponseDtoTest() { - Item item = new Item(2L, "TestName2", "Test description2", true, 2L, 2L); + Item item = new Item(2L, "TestName2", "Test description2", true, user, itemRequest); ItemResponseDto itemResponseDto = itemMapper.toItemResponseDto(item); assertAll(() -> { @@ -43,8 +50,8 @@ public void itemToItemResponseDtoTest() { assertEquals("TestName2", itemResponseDto.getItemName()); assertEquals("Test description2", itemResponseDto.getItemDescription()); assertEquals(true, itemResponseDto.getIsAvailable()); - assertEquals(2L, itemResponseDto.getOwnerId()); - assertEquals(2L, itemResponseDto.getRequestId()); + assertEquals(user.getUserId(), itemResponseDto.getOwnerId()); + assertEquals(itemRequest.getItemRequestId(), itemResponseDto.getRequestId()); }); } @@ -67,7 +74,8 @@ public void itemRequestDtoToItemResponseDtoTest() { @Test public void itemResponseDtoToItemRequestDtoTest() { ItemResponseDto itemResponseDto = new ItemResponseDto( - 4L, "TestName4", "Test description4", false, 4L, 4L); + 4L, "TestName4", "Test description4", + false, 4L, 4L); ItemRequestDto itemRequestDto = itemMapper.toItemRequestDto(itemResponseDto); assertAll(() -> { assertEquals(4L, itemRequestDto.getItemId()); @@ -78,4 +86,37 @@ public void itemResponseDtoToItemRequestDtoTest() { }); } + @Test + public void itemToItemResponseDtoWithCommentsTest() { + + Item item = new Item(2L, "testName2", "testDescription2", + true, user, itemRequest); + + ItemResponseDtoWithComments itemResponse = itemMapper.toItemResponseDtoWithComments(item); + + assertAll(() -> { + assertEquals(2L, itemResponse.getItemId()); + assertEquals("testName2", itemResponse.getItemName()); + assertEquals("testDescription2", itemResponse.getItemDescription()); + assertEquals(true, itemResponse.getIsAvailable()); + assertEquals(user.getUserId(), itemResponse.getOwnerId()); + assertEquals(itemRequest.getItemRequestId(), itemResponse.getRequestId()); + assertNull(itemResponse.getComments()); + assertNull(itemResponse.getLastBooking()); + assertNull(itemResponse.getNextBooking()); + }); + } + + @Test + public void itemToItemBookerDto() { + Item item = new Item(2L, "testName2", "testDescription2", + true, user, itemRequest); + + ItemBookerDto itemBookerDto = itemMapper.toItemBookerDto(item); + + assertAll(() -> { + assertEquals(2L, itemBookerDto.getItemId()); + assertEquals("testName2", itemBookerDto.getItemName()); + }); + } } diff --git a/src/test/java/ru/practicum/shareit/UserMapperTest.java b/src/test/java/ru/practicum/shareit/mapperTest/UserMapperTest.java similarity index 72% rename from src/test/java/ru/practicum/shareit/UserMapperTest.java rename to src/test/java/ru/practicum/shareit/mapperTest/UserMapperTest.java index 0bd6da2..b79e842 100644 --- a/src/test/java/ru/practicum/shareit/UserMapperTest.java +++ b/src/test/java/ru/practicum/shareit/mapperTest/UserMapperTest.java @@ -1,8 +1,10 @@ -package ru.practicum.shareit; +package ru.practicum.shareit.mapperTest; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; +import ru.practicum.shareit.user.dto.UserAuthorDto; +import ru.practicum.shareit.user.dto.UserBookingDto; import ru.practicum.shareit.user.dto.UserRequestDto; import ru.practicum.shareit.user.dto.UserResponseDto; import ru.practicum.shareit.user.mapper.UserMapper; @@ -62,4 +64,28 @@ public void userToUserResponseDtoTest() { assertEquals("test4@test.com", userResponseDto.getUserEmail()); }); } + + @Test + public void userToUserAuthorDtoTest() { + User user = new User(5L, "TestName5", "test5@test.com"); + + UserAuthorDto userAuthorDto = userMapper.toUserAuthorDto(user); + + assertAll(() -> { + assertEquals(5L, userAuthorDto.getUserId()); + assertEquals("TestName5", userAuthorDto.getUserName()); + }); + } + + @Test + public void userToUserBookingDtoTest() { + User user = new User(6L, "TestName6", "test6@test.com"); + + UserBookingDto userBookingDto = userMapper.toUserBookingDto(user); + + assertAll(() -> { + assertEquals(6L, userBookingDto.getUserId()); + assertEquals("TestName6", userBookingDto.getUserName()); + }); + } } diff --git a/src/test/resources/application.properties b/src/test/resources/application.properties new file mode 100644 index 0000000..0024b61 --- /dev/null +++ b/src/test/resources/application.properties @@ -0,0 +1,10 @@ +spring.sql.init.mode=always +spring.datasource.url=jdbc:h2:mem:testdb;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE +spring.datasource.driverClassName=org.h2.Driver +spring.datasource.username=user +spring.datasource.password=12345 + +spring.jpa.properties.hibernate.format_sql=true +spring.jpa.properties.hibernate.jdbc.time_zone=UTC +spring.jpa.hibernate.ddl-auto=create-drop +spring.jpa.database-platform=org.hibernate.dialect.H2Dialect \ No newline at end of file