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