From 8861148fc4711cdf03ec9e872a1726611792459a Mon Sep 17 00:00:00 2001 From: Viktor64 Date: Mon, 24 Mar 2025 18:10:55 +0400 Subject: [PATCH 1/4] =?UTF-8?q?=D0=A1=D0=BE=D0=B7=D0=B4=D0=B0=D0=BB=20?= =?UTF-8?q?=D1=81=D0=B5=D1=80=D0=B2=D0=B8=D1=81=20=D0=B4=D0=BB=D1=8F=20?= =?UTF-8?q?=D1=88=D0=B5=D1=80=D0=B8=D0=BD=D0=B3=D0=B0=20ShareIt.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1) Создал ветку: add-controllers. 2) Создал четыре пакета: item, booking, request и user. 3) Создал DTO-объекты и мапперы для сущностей: ItemDto, UserDto, BookingDto, ItemRequestDto 4) Создал тесты на новую функциональность. --- .../ru/practicum/shareit/booking/Booking.java | 7 - .../shareit/booking/BookingStatus.java | 11 + .../{ => controller}/BookingController.java | 4 +- .../shareit/booking/dto/BookingDto.java | 25 +- .../booking/exception/ShareItException.java | 31 +++ .../shareit/booking/model/Booking.java | 28 ++ .../shareit/item/Impl/ItemRepositoryImpl.java | 34 +++ .../shareit/item/Impl/ItemServiceImpl.java | 107 ++++++++ .../shareit/item/ItemController.java | 12 - .../ru/practicum/shareit/item/ItemMapper.java | 26 ++ .../item/controller/ItemController.java | 62 +++++ .../practicum/shareit/item/dto/ItemDto.java | 25 +- .../ru/practicum/shareit/item/model/Item.java | 28 +- .../item/repository/AbstractRepository.java | 28 ++ .../item/repository/ItemRepository.java | 18 ++ .../shareit/item/service/ItemService.java | 19 ++ .../shareit/request/ItemRequest.java | 7 - .../ItemRequestController.java | 4 +- .../shareit/request/dto/ItemRequestDto.java | 23 +- .../shareit/request/model/ItemRequest.java | 25 ++ .../shareit/user/Impl/UserRepositoryImpl.java | 34 +++ .../shareit/user/Impl/UserServiceImpl.java | 77 ++++++ .../java/ru/practicum/shareit/user/User.java | 7 - .../shareit/user/UserController.java | 12 - .../ru/practicum/shareit/user/UserMapper.java | 24 ++ .../user/controller/UserController.java | 55 ++++ .../practicum/shareit/user/dto/UserDto.java | 22 ++ .../ru/practicum/shareit/user/model/User.java | 25 ++ .../user/repository/UserRepository.java | 18 ++ .../shareit/user/service/UserService.java | 18 ++ .../item/controller/ItemControllerTest.java | 252 ++++++++++++++++++ .../user/controller/UserControllerTest.java | 173 ++++++++++++ 32 files changed, 1188 insertions(+), 53 deletions(-) delete mode 100644 src/main/java/ru/practicum/shareit/booking/Booking.java create mode 100644 src/main/java/ru/practicum/shareit/booking/BookingStatus.java rename src/main/java/ru/practicum/shareit/booking/{ => controller}/BookingController.java (83%) create mode 100644 src/main/java/ru/practicum/shareit/booking/exception/ShareItException.java create mode 100644 src/main/java/ru/practicum/shareit/booking/model/Booking.java create mode 100644 src/main/java/ru/practicum/shareit/item/Impl/ItemRepositoryImpl.java create mode 100644 src/main/java/ru/practicum/shareit/item/Impl/ItemServiceImpl.java delete mode 100644 src/main/java/ru/practicum/shareit/item/ItemController.java create mode 100644 src/main/java/ru/practicum/shareit/item/ItemMapper.java create mode 100644 src/main/java/ru/practicum/shareit/item/controller/ItemController.java create mode 100644 src/main/java/ru/practicum/shareit/item/repository/AbstractRepository.java create mode 100644 src/main/java/ru/practicum/shareit/item/repository/ItemRepository.java create mode 100644 src/main/java/ru/practicum/shareit/item/service/ItemService.java delete mode 100644 src/main/java/ru/practicum/shareit/request/ItemRequest.java rename src/main/java/ru/practicum/shareit/request/{ => controller}/ItemRequestController.java (83%) create mode 100644 src/main/java/ru/practicum/shareit/request/model/ItemRequest.java create mode 100644 src/main/java/ru/practicum/shareit/user/Impl/UserRepositoryImpl.java create mode 100644 src/main/java/ru/practicum/shareit/user/Impl/UserServiceImpl.java delete mode 100644 src/main/java/ru/practicum/shareit/user/User.java delete mode 100644 src/main/java/ru/practicum/shareit/user/UserController.java create mode 100644 src/main/java/ru/practicum/shareit/user/UserMapper.java create mode 100644 src/main/java/ru/practicum/shareit/user/controller/UserController.java create mode 100644 src/main/java/ru/practicum/shareit/user/dto/UserDto.java create mode 100644 src/main/java/ru/practicum/shareit/user/model/User.java create mode 100644 src/main/java/ru/practicum/shareit/user/repository/UserRepository.java create mode 100644 src/main/java/ru/practicum/shareit/user/service/UserService.java create mode 100644 src/test/java/ru/practicum/shareit/item/controller/ItemControllerTest.java create mode 100644 src/test/java/ru/practicum/shareit/user/controller/UserControllerTest.java 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 2d9c666..0000000 --- a/src/main/java/ru/practicum/shareit/booking/Booking.java +++ /dev/null @@ -1,7 +0,0 @@ -package ru.practicum.shareit.booking; - -/** - * TODO Sprint add-bookings. - */ -public class Booking { -} diff --git a/src/main/java/ru/practicum/shareit/booking/BookingStatus.java b/src/main/java/ru/practicum/shareit/booking/BookingStatus.java new file mode 100644 index 0000000..1be1bce --- /dev/null +++ b/src/main/java/ru/practicum/shareit/booking/BookingStatus.java @@ -0,0 +1,11 @@ +package ru.practicum.shareit.booking; + +public enum BookingStatus { + WAITING, + + APPROVED, + + REJECTED, + + CANCELED +} \ No newline at end of file diff --git a/src/main/java/ru/practicum/shareit/booking/BookingController.java b/src/main/java/ru/practicum/shareit/booking/controller/BookingController.java similarity index 83% rename from src/main/java/ru/practicum/shareit/booking/BookingController.java rename to src/main/java/ru/practicum/shareit/booking/controller/BookingController.java index b94493d..c3b557f 100644 --- a/src/main/java/ru/practicum/shareit/booking/BookingController.java +++ b/src/main/java/ru/practicum/shareit/booking/controller/BookingController.java @@ -1,4 +1,4 @@ -package ru.practicum.shareit.booking; +package ru.practicum.shareit.booking.controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @@ -9,4 +9,4 @@ @RestController @RequestMapping(path = "/bookings") public class BookingController { -} +} \ No newline at end of file diff --git a/src/main/java/ru/practicum/shareit/booking/dto/BookingDto.java b/src/main/java/ru/practicum/shareit/booking/dto/BookingDto.java index 861de9e..9c703a3 100644 --- a/src/main/java/ru/practicum/shareit/booking/dto/BookingDto.java +++ b/src/main/java/ru/practicum/shareit/booking/dto/BookingDto.java @@ -1,7 +1,30 @@ package ru.practicum.shareit.booking.dto; +import lombok.Builder; +import lombok.Getter; +import lombok.Setter; +import ru.practicum.shareit.booking.BookingStatus; +import ru.practicum.shareit.item.dto.ItemDto; +import ru.practicum.shareit.user.dto.UserDto; + +import java.time.LocalDateTime; + /** * TODO Sprint add-bookings. */ +@Getter +@Setter +@Builder(toBuilder = true) public class BookingDto { -} + private Long id; + + private LocalDateTime start; + + private LocalDateTime end; + + private ItemDto item; + + private UserDto booker; + + private BookingStatus status; +} \ No newline at end of file diff --git a/src/main/java/ru/practicum/shareit/booking/exception/ShareItException.java b/src/main/java/ru/practicum/shareit/booking/exception/ShareItException.java new file mode 100644 index 0000000..db4ad68 --- /dev/null +++ b/src/main/java/ru/practicum/shareit/booking/exception/ShareItException.java @@ -0,0 +1,31 @@ +package ru.practicum.shareit.booking.exception; + +import org.springframework.http.HttpStatus; +import org.springframework.web.bind.annotation.ResponseStatus; + +public class ShareItException extends RuntimeException { + private final HttpStatus status; + + public ShareItException(String message, HttpStatus status) { + super(message); + this.status = status; + } + + public HttpStatus getStatus() { + return status; + } + + @ResponseStatus(HttpStatus.NOT_FOUND) + public static class NotFoundException extends ShareItException { + public NotFoundException(String message) { + super(message, HttpStatus.NOT_FOUND); + } + } + + @ResponseStatus(HttpStatus.CONFLICT) + public static class ConflictException extends ShareItException { + public ConflictException(String message) { + super(message, HttpStatus.CONFLICT); + } + } +} \ No newline at end of file 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..57b727e --- /dev/null +++ b/src/main/java/ru/practicum/shareit/booking/model/Booking.java @@ -0,0 +1,28 @@ +package ru.practicum.shareit.booking.model; + +import lombok.Getter; +import lombok.Setter; +import ru.practicum.shareit.booking.BookingStatus; +import ru.practicum.shareit.item.model.Item; +import ru.practicum.shareit.user.model.User; + +import java.time.LocalDateTime; + +/** + * TODO Sprint add-bookings. + */ +@Getter +@Setter +public class Booking { + private Long id; + + private LocalDateTime start; + + private LocalDateTime end; + + private Item item; + + private User booker; + + private BookingStatus status; +} \ No newline at end of file diff --git a/src/main/java/ru/practicum/shareit/item/Impl/ItemRepositoryImpl.java b/src/main/java/ru/practicum/shareit/item/Impl/ItemRepositoryImpl.java new file mode 100644 index 0000000..8bb6974 --- /dev/null +++ b/src/main/java/ru/practicum/shareit/item/Impl/ItemRepositoryImpl.java @@ -0,0 +1,34 @@ +package ru.practicum.shareit.item.Impl; + +import org.springframework.stereotype.Component; +import ru.practicum.shareit.item.model.Item; +import ru.practicum.shareit.item.repository.AbstractRepository; +import ru.practicum.shareit.item.repository.ItemRepository; + +@Component +public class ItemRepositoryImpl extends AbstractRepository implements ItemRepository { + + @Override + public Item create(Item item) { + setEntityId(item, nextId); + nextId++; + entities.put(item.getId(), item); + return item; + } + + @Override + public Item update(Item item) { + entities.put(item.getId(), item); + return item; + } + + @Override + protected void setEntityId(Item entity, Long id) { + entity.setId(id); + } + + @Override + protected Long getEntityId(Item entity) { + return entity.getId(); + } +} \ No newline at end of file diff --git a/src/main/java/ru/practicum/shareit/item/Impl/ItemServiceImpl.java b/src/main/java/ru/practicum/shareit/item/Impl/ItemServiceImpl.java new file mode 100644 index 0000000..a15b55f --- /dev/null +++ b/src/main/java/ru/practicum/shareit/item/Impl/ItemServiceImpl.java @@ -0,0 +1,107 @@ +package ru.practicum.shareit.item.Impl; + +import org.springframework.stereotype.Service; +import ru.practicum.shareit.booking.exception.ShareItException; +import ru.practicum.shareit.item.dto.ItemDto; +import ru.practicum.shareit.item.model.Item; +import ru.practicum.shareit.item.repository.ItemRepository; +import ru.practicum.shareit.item.service.ItemService; +import ru.practicum.shareit.user.model.User; +import ru.practicum.shareit.user.repository.UserRepository; + +import java.util.ArrayList; +import java.util.List; + +import static ru.practicum.shareit.item.ItemMapper.toItem; +import static ru.practicum.shareit.item.ItemMapper.toItemDto; + +@Service +public class ItemServiceImpl implements ItemService { + private final ItemRepository itemRepository; + private final UserRepository userRepository; + + public ItemServiceImpl(ItemRepository itemRepository, UserRepository userRepository) { + this.itemRepository = itemRepository; + this.userRepository = userRepository; + } + + @Override + public List getAll(Long userId) { + List items = new ArrayList<>(); + for (Item item : itemRepository.findAll()) { + if (item.getOwner().getId().equals(userId)) { + items.add(toItemDto(item)); + } + } + + return items; + } + + @Override + public ItemDto getById(Long id) { + Item item = itemRepository.findById(id) + .orElseThrow(() -> new ShareItException.NotFoundException("Не найдена вещь с id: " + id)); + + return toItemDto(item); + } + + @Override + public ItemDto create(ItemDto itemDto, Long userId) { + User user = userRepository.findById(userId) + .orElseThrow(() -> new ShareItException.NotFoundException("Невозможно создать вещь - " + + "не найден пользователь с id: " + userId)); + Item item = toItem(itemDto); + item.setOwner(user); + itemRepository.create(item); + + return toItemDto(item); + } + + @Override + public ItemDto update(ItemDto itemDto, Long id, Long userId) { + Item item = itemRepository.findById(id) + .orElseThrow(() -> new ShareItException.NotFoundException("Не найдена вещь с id: " + id)); + if (!item.getOwner().getId().equals(userId)) { + throw new ShareItException.NotFoundException("Невозможно обновить вещь - у пользователя с id: " + userId + "нет такой вещи"); + } + if (itemDto.getName() != null) { + item.setName(itemDto.getName()); + } + if (itemDto.getDescription() != null) { + item.setDescription(itemDto.getDescription()); + } + if (itemDto.getAvailable() != null) { + item.setAvailable(itemDto.getAvailable()); + } + + return toItemDto(itemRepository.update(item)); + } + + @Override + public void delete(Long id) { + getById(id); + itemRepository.delete(id); + } + + @Override + public List search(String text) { + List searchedItems = new ArrayList<>(); + if (text.isBlank()) { + return searchedItems; + } + for (Item item : itemRepository.findAll()) { + if (isSearched(text, item)) { + searchedItems.add(toItemDto(item)); + } + } + + return searchedItems; + } + + private Boolean isSearched(String text, Item item) { + return item.getAvailable() && ( + item.getName().toLowerCase().contains(text.toLowerCase()) || + item.getDescription().toLowerCase().contains(text.toLowerCase()) + ); + } +} \ No newline at end of file diff --git a/src/main/java/ru/practicum/shareit/item/ItemController.java b/src/main/java/ru/practicum/shareit/item/ItemController.java deleted file mode 100644 index bb17668..0000000 --- a/src/main/java/ru/practicum/shareit/item/ItemController.java +++ /dev/null @@ -1,12 +0,0 @@ -package ru.practicum.shareit.item; - -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; - -/** - * TODO Sprint add-controllers. - */ -@RestController -@RequestMapping("/items") -public class ItemController { -} diff --git a/src/main/java/ru/practicum/shareit/item/ItemMapper.java b/src/main/java/ru/practicum/shareit/item/ItemMapper.java new file mode 100644 index 0000000..52400b3 --- /dev/null +++ b/src/main/java/ru/practicum/shareit/item/ItemMapper.java @@ -0,0 +1,26 @@ +package ru.practicum.shareit.item; + +import ru.practicum.shareit.item.dto.ItemDto; +import ru.practicum.shareit.item.model.Item; + +public class ItemMapper { + public static ItemDto toItemDto(Item item) { + return ItemDto.builder() + .id(item.getId()) + .name(item.getName()) + .description(item.getDescription()) + .available(item.getAvailable()) + .request(item.getRequest() != null ? item.getRequest() : null) + .build(); + } + + public static Item toItem(ItemDto itemDto) { + return Item.builder() + .id(itemDto.getId()) + .name(itemDto.getName()) + .description(itemDto.getDescription()) + .available(itemDto.getAvailable()) + .request(itemDto.getRequest()) + .build(); + } +} \ No newline at end of file diff --git a/src/main/java/ru/practicum/shareit/item/controller/ItemController.java b/src/main/java/ru/practicum/shareit/item/controller/ItemController.java new file mode 100644 index 0000000..7a3aa1f --- /dev/null +++ b/src/main/java/ru/practicum/shareit/item/controller/ItemController.java @@ -0,0 +1,62 @@ +package ru.practicum.shareit.item.controller; + +import jakarta.validation.Valid; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PatchMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestHeader; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; +import ru.practicum.shareit.item.dto.ItemDto; +import ru.practicum.shareit.item.service.ItemService; + +import java.util.List; + + +/** + * TODO Sprint add-controllers. + */ +@RestController +@RequestMapping("/items") +public class ItemController { + private final ItemService itemService; + + public ItemController(ItemService itemService) { + this.itemService = itemService; + } + + @GetMapping + public List getAll(@RequestHeader("X-Sharer-User-Id") Long userId) { + return itemService.getAll(userId); + } + + @GetMapping("/{id}") + public ItemDto getById(@PathVariable Long id) { + return itemService.getById(id); + } + + @PostMapping + public ItemDto create(@RequestHeader("X-Sharer-User-Id") Long userId, @Valid @RequestBody ItemDto itemDto) { + return itemService.create(itemDto, userId); + } + + @PatchMapping("/{id}") + public ItemDto update(@RequestBody ItemDto itemDto, @PathVariable Long id, + @RequestHeader("X-Sharer-User-Id") Long userId) { + return itemService.update(itemDto, id, userId); + } + + @DeleteMapping("/{id}") + public void delete(@PathVariable Long id) { + itemService.delete(id); + } + + @GetMapping("/search") + public List search(@RequestParam String text) { + return itemService.search(text); + } +} \ No newline at end of file diff --git a/src/main/java/ru/practicum/shareit/item/dto/ItemDto.java b/src/main/java/ru/practicum/shareit/item/dto/ItemDto.java index 9319d7d..beaae16 100644 --- a/src/main/java/ru/practicum/shareit/item/dto/ItemDto.java +++ b/src/main/java/ru/practicum/shareit/item/dto/ItemDto.java @@ -1,7 +1,30 @@ package ru.practicum.shareit.item.dto; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import lombok.Builder; +import lombok.Getter; +import lombok.Setter; +import ru.practicum.shareit.request.model.ItemRequest; + + /** * TODO Sprint add-controllers. */ +@Getter +@Setter +@Builder(toBuilder = true) public class ItemDto { -} + private Long id; + + @NotBlank + private String name; + + @NotBlank + private String description; + + @NotNull + private Boolean available; + + private ItemRequest request; +} \ 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 44eb73d..76d3704 100644 --- a/src/main/java/ru/practicum/shareit/item/model/Item.java +++ b/src/main/java/ru/practicum/shareit/item/model/Item.java @@ -1,7 +1,33 @@ package ru.practicum.shareit.item.model; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import lombok.Builder; +import lombok.Getter; +import lombok.Setter; +import ru.practicum.shareit.request.model.ItemRequest; +import ru.practicum.shareit.user.model.User; + + /** * TODO Sprint add-controllers. */ +@Getter +@Setter +@Builder public class Item { -} + private Long id; + + @NotBlank + private String name; + + @NotBlank + private String description; + + @NotNull + private Boolean available; + + private User owner; + + private ItemRequest request; +} \ No newline at end of file diff --git a/src/main/java/ru/practicum/shareit/item/repository/AbstractRepository.java b/src/main/java/ru/practicum/shareit/item/repository/AbstractRepository.java new file mode 100644 index 0000000..4f5dd72 --- /dev/null +++ b/src/main/java/ru/practicum/shareit/item/repository/AbstractRepository.java @@ -0,0 +1,28 @@ +package ru.practicum.shareit.item.repository; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; + +public abstract class AbstractRepository { + protected final Map entities = new HashMap<>(); + protected Long nextId = 1L; + + public List findAll() { + return new ArrayList<>(entities.values()); + } + + public Optional findById(K id) { + return entities.containsKey(id) ? Optional.of(entities.get(id)) : Optional.empty(); + } + + public void delete(K id) { + entities.remove(id); + } + + protected abstract void setEntityId(T entity, Long id); + + protected abstract K getEntityId(T entity); +} \ No newline at end of file diff --git a/src/main/java/ru/practicum/shareit/item/repository/ItemRepository.java b/src/main/java/ru/practicum/shareit/item/repository/ItemRepository.java new file mode 100644 index 0000000..9bf5801 --- /dev/null +++ b/src/main/java/ru/practicum/shareit/item/repository/ItemRepository.java @@ -0,0 +1,18 @@ +package ru.practicum.shareit.item.repository; + +import ru.practicum.shareit.item.model.Item; + +import java.util.List; +import java.util.Optional; + +public interface ItemRepository { + List findAll(); + + Optional findById(Long id); + + Item create(Item item); + + Item update(Item item); + + void delete(Long id); +} \ No newline at end of file diff --git a/src/main/java/ru/practicum/shareit/item/service/ItemService.java b/src/main/java/ru/practicum/shareit/item/service/ItemService.java new file mode 100644 index 0000000..07f58b1 --- /dev/null +++ b/src/main/java/ru/practicum/shareit/item/service/ItemService.java @@ -0,0 +1,19 @@ +package ru.practicum.shareit.item.service; + +import ru.practicum.shareit.item.dto.ItemDto; + +import java.util.List; + +public interface ItemService { + List getAll(Long userId); + + ItemDto getById(Long id); + + ItemDto create(ItemDto itemDto, Long userId); + + ItemDto update(ItemDto itemDto, Long id, Long userId); + + void delete(Long id); + + List search(String text); +} \ No newline at end of file diff --git a/src/main/java/ru/practicum/shareit/request/ItemRequest.java b/src/main/java/ru/practicum/shareit/request/ItemRequest.java deleted file mode 100644 index 95d6f23..0000000 --- a/src/main/java/ru/practicum/shareit/request/ItemRequest.java +++ /dev/null @@ -1,7 +0,0 @@ -package ru.practicum.shareit.request; - -/** - * TODO Sprint add-item-requests. - */ -public class ItemRequest { -} diff --git a/src/main/java/ru/practicum/shareit/request/ItemRequestController.java b/src/main/java/ru/practicum/shareit/request/controller/ItemRequestController.java similarity index 83% rename from src/main/java/ru/practicum/shareit/request/ItemRequestController.java rename to src/main/java/ru/practicum/shareit/request/controller/ItemRequestController.java index 064e2e9..40ecfc8 100644 --- a/src/main/java/ru/practicum/shareit/request/ItemRequestController.java +++ b/src/main/java/ru/practicum/shareit/request/controller/ItemRequestController.java @@ -1,4 +1,4 @@ -package ru.practicum.shareit.request; +package ru.practicum.shareit.request.controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @@ -9,4 +9,4 @@ @RestController @RequestMapping(path = "/requests") public class ItemRequestController { -} +} \ No newline at end of file diff --git a/src/main/java/ru/practicum/shareit/request/dto/ItemRequestDto.java b/src/main/java/ru/practicum/shareit/request/dto/ItemRequestDto.java index 7b3ed54..ee39b8a 100644 --- a/src/main/java/ru/practicum/shareit/request/dto/ItemRequestDto.java +++ b/src/main/java/ru/practicum/shareit/request/dto/ItemRequestDto.java @@ -1,7 +1,28 @@ package ru.practicum.shareit.request.dto; +import lombok.Builder; +import lombok.Getter; +import lombok.Setter; +import ru.practicum.shareit.item.dto.ItemDto; +import ru.practicum.shareit.user.dto.UserDto; + +import java.time.LocalDateTime; +import java.util.List; + /** * TODO Sprint add-item-requests. */ +@Getter +@Setter +@Builder(toBuilder = true) public class ItemRequestDto { -} + private Long id; + + private String description; + + private UserDto requestor; + + private LocalDateTime created; + + private List items; +} \ No newline at end of file diff --git a/src/main/java/ru/practicum/shareit/request/model/ItemRequest.java b/src/main/java/ru/practicum/shareit/request/model/ItemRequest.java new file mode 100644 index 0000000..806ae38 --- /dev/null +++ b/src/main/java/ru/practicum/shareit/request/model/ItemRequest.java @@ -0,0 +1,25 @@ +package ru.practicum.shareit.request.model; + +import jakarta.validation.constraints.NotBlank; +import lombok.Getter; +import lombok.Setter; +import ru.practicum.shareit.user.model.User; + +import java.time.LocalDateTime; + + +/** + * TODO Sprint add-item-requests. + */ +@Getter +@Setter +public class ItemRequest { + private Long id; + + @NotBlank + private String description; + + private User requestor; + + private LocalDateTime created; +} \ No newline at end of file diff --git a/src/main/java/ru/practicum/shareit/user/Impl/UserRepositoryImpl.java b/src/main/java/ru/practicum/shareit/user/Impl/UserRepositoryImpl.java new file mode 100644 index 0000000..5f895be --- /dev/null +++ b/src/main/java/ru/practicum/shareit/user/Impl/UserRepositoryImpl.java @@ -0,0 +1,34 @@ +package ru.practicum.shareit.user.Impl; + +import org.springframework.stereotype.Component; +import ru.practicum.shareit.item.repository.AbstractRepository; +import ru.practicum.shareit.user.model.User; +import ru.practicum.shareit.user.repository.UserRepository; + +@Component +public class UserRepositoryImpl extends AbstractRepository implements UserRepository { + + @Override + public User create(User user) { + setEntityId(user, nextId); + nextId++; + entities.put(user.getId(), user); + return user; + } + + @Override + public User update(User user) { + entities.put(user.getId(), user); + return user; + } + + @Override + protected void setEntityId(User entity, Long id) { + entity.setId(id); + } + + @Override + protected Long getEntityId(User entity) { + return entity.getId(); + } +} \ No newline at end of file diff --git a/src/main/java/ru/practicum/shareit/user/Impl/UserServiceImpl.java b/src/main/java/ru/practicum/shareit/user/Impl/UserServiceImpl.java new file mode 100644 index 0000000..024a208 --- /dev/null +++ b/src/main/java/ru/practicum/shareit/user/Impl/UserServiceImpl.java @@ -0,0 +1,77 @@ +package ru.practicum.shareit.user.Impl; + +import org.springframework.stereotype.Service; +import ru.practicum.shareit.booking.exception.ShareItException; +import ru.practicum.shareit.user.dto.UserDto; +import ru.practicum.shareit.user.model.User; +import ru.practicum.shareit.user.repository.UserRepository; +import ru.practicum.shareit.user.service.UserService; + +import java.util.ArrayList; +import java.util.List; + +import static ru.practicum.shareit.user.UserMapper.toUserDto; + +@Service +public class UserServiceImpl implements UserService { + private final UserRepository userRepository; + + public UserServiceImpl(UserRepository userRepository) { + this.userRepository = userRepository; + } + + @Override + public List getAll() { + List users = new ArrayList<>(); + for (User user : userRepository.findAll()) { + users.add(toUserDto(user)); + } + + return users; + } + + @Override + public UserDto getById(Long id) { + User user = userRepository.findById(id) + .orElseThrow(() -> new ShareItException.NotFoundException("Не найден пользователь с id: " + id)); + + return toUserDto(user); + } + + @Override + public UserDto create(User user) { + throwIfEmailNotUnique(user); + + return toUserDto(userRepository.create(user)); + } + + @Override + public UserDto update(User user, Long id) { + User updatedUser = userRepository.findById(id) + .orElseThrow(() -> new ShareItException.NotFoundException("Невозможно обновить данные пользователя. " + + "Не найден пользователь с id: " + id)); + if (user.getEmail() != null) { + throwIfEmailNotUnique(user); + updatedUser.setEmail(user.getEmail()); + } + if (user.getName() != null) { + updatedUser.setName(user.getName()); + } + + return toUserDto(userRepository.update(updatedUser)); + } + + @Override + public void delete(Long id) { + getById(id); + userRepository.delete(id); + } + + private void throwIfEmailNotUnique(User user) { + for (User userCheck : userRepository.findAll()) { + if (user.getEmail().equals(userCheck.getEmail())) { + throw new ShareItException.ConflictException("Пользователь с таким email уже зарегистрирован"); + } + } + } +} \ No newline at end of file diff --git a/src/main/java/ru/practicum/shareit/user/User.java b/src/main/java/ru/practicum/shareit/user/User.java deleted file mode 100644 index ae6e7f3..0000000 --- a/src/main/java/ru/practicum/shareit/user/User.java +++ /dev/null @@ -1,7 +0,0 @@ -package ru.practicum.shareit.user; - -/** - * TODO Sprint add-controllers. - */ -public class User { -} diff --git a/src/main/java/ru/practicum/shareit/user/UserController.java b/src/main/java/ru/practicum/shareit/user/UserController.java deleted file mode 100644 index 03039b9..0000000 --- a/src/main/java/ru/practicum/shareit/user/UserController.java +++ /dev/null @@ -1,12 +0,0 @@ -package ru.practicum.shareit.user; - -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; - -/** - * TODO Sprint add-controllers. - */ -@RestController -@RequestMapping(path = "/users") -public class UserController { -} diff --git a/src/main/java/ru/practicum/shareit/user/UserMapper.java b/src/main/java/ru/practicum/shareit/user/UserMapper.java new file mode 100644 index 0000000..e14c522 --- /dev/null +++ b/src/main/java/ru/practicum/shareit/user/UserMapper.java @@ -0,0 +1,24 @@ +package ru.practicum.shareit.user; + +import ru.practicum.shareit.user.dto.UserDto; +import ru.practicum.shareit.user.model.User; + +public class UserMapper { + public static UserDto toUserDto(User user) { + return UserDto + .builder() + .id(user.getId()) + .name(user.getName()) + .email(user.getEmail()) + .build(); + } + + public static User toUser(UserDto userDto) { + return User + .builder() + .id(userDto.getId()) + .name(userDto.getName()) + .email(userDto.getEmail()) + .build(); + } +} \ No newline at end of file diff --git a/src/main/java/ru/practicum/shareit/user/controller/UserController.java b/src/main/java/ru/practicum/shareit/user/controller/UserController.java new file mode 100644 index 0000000..e4d47d3 --- /dev/null +++ b/src/main/java/ru/practicum/shareit/user/controller/UserController.java @@ -0,0 +1,55 @@ +package ru.practicum.shareit.user.controller; + +import jakarta.validation.Valid; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PatchMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; +import ru.practicum.shareit.user.dto.UserDto; +import ru.practicum.shareit.user.model.User; +import ru.practicum.shareit.user.Impl.UserServiceImpl; + +import java.util.List; + + +/** + * TODO Sprint add-controllers. + */ +@RestController +@RequestMapping(path = "/users") +public class UserController { + private final UserServiceImpl userService; + + public UserController(UserServiceImpl userService) { + this.userService = userService; + } + + @GetMapping + public List getAll() { + return userService.getAll(); + } + + @GetMapping("/{id}") + public UserDto getById(@PathVariable Long id) { + return userService.getById(id); + } + + @PostMapping + public UserDto create(@Valid @RequestBody User user) { + return userService.create(user); + } + + @PatchMapping("/{id}") + public UserDto update(@RequestBody User user, @PathVariable Long id) { + return userService.update(user, id); + } + + @DeleteMapping("/{id}") + public void delete(@PathVariable Long id) { + userService.delete(id); + } +} \ No newline at end of file diff --git a/src/main/java/ru/practicum/shareit/user/dto/UserDto.java b/src/main/java/ru/practicum/shareit/user/dto/UserDto.java new file mode 100644 index 0000000..781f1d1 --- /dev/null +++ b/src/main/java/ru/practicum/shareit/user/dto/UserDto.java @@ -0,0 +1,22 @@ +package ru.practicum.shareit.user.dto; + +import jakarta.validation.constraints.Email; +import jakarta.validation.constraints.NotBlank; +import lombok.Builder; +import lombok.Getter; +import lombok.Setter; + + + +@Getter +@Setter +@Builder(toBuilder = true) +public class UserDto { + private Long id; + + @NotBlank + private String name; + + @Email + private String email; +} \ No newline at end of file diff --git a/src/main/java/ru/practicum/shareit/user/model/User.java b/src/main/java/ru/practicum/shareit/user/model/User.java new file mode 100644 index 0000000..ebcedbd --- /dev/null +++ b/src/main/java/ru/practicum/shareit/user/model/User.java @@ -0,0 +1,25 @@ +package ru.practicum.shareit.user.model; + +import jakarta.validation.constraints.Email; +import jakarta.validation.constraints.NotBlank; +import lombok.Builder; +import lombok.Getter; +import lombok.Setter; + + +/** + * TODO Sprint add-controllers. + */ +@Getter +@Setter +@Builder +public class User { + private Long id; + + @NotBlank + private String name; + + @Email + @NotBlank + private String email; +} \ No newline at end of file diff --git a/src/main/java/ru/practicum/shareit/user/repository/UserRepository.java b/src/main/java/ru/practicum/shareit/user/repository/UserRepository.java new file mode 100644 index 0000000..34465a7 --- /dev/null +++ b/src/main/java/ru/practicum/shareit/user/repository/UserRepository.java @@ -0,0 +1,18 @@ +package ru.practicum.shareit.user.repository; + +import ru.practicum.shareit.user.model.User; + +import java.util.List; +import java.util.Optional; + +public interface UserRepository { + List findAll(); + + Optional findById(Long id); + + User create(User user); + + User update(User user); + + void delete(Long id); +} \ No newline at end of file diff --git a/src/main/java/ru/practicum/shareit/user/service/UserService.java b/src/main/java/ru/practicum/shareit/user/service/UserService.java new file mode 100644 index 0000000..f5f23d4 --- /dev/null +++ b/src/main/java/ru/practicum/shareit/user/service/UserService.java @@ -0,0 +1,18 @@ +package ru.practicum.shareit.user.service; + +import ru.practicum.shareit.user.dto.UserDto; +import ru.practicum.shareit.user.model.User; + +import java.util.List; + +public interface UserService { + List getAll(); + + UserDto getById(Long id); + + UserDto create(User user); + + UserDto update(User user, Long id); + + void delete(Long id); +} \ No newline at end of file diff --git a/src/test/java/ru/practicum/shareit/item/controller/ItemControllerTest.java b/src/test/java/ru/practicum/shareit/item/controller/ItemControllerTest.java new file mode 100644 index 0000000..7020269 --- /dev/null +++ b/src/test/java/ru/practicum/shareit/item/controller/ItemControllerTest.java @@ -0,0 +1,252 @@ +package ru.practicum.shareit.item.controller; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.annotation.DirtiesContext; +import ru.practicum.shareit.booking.exception.ShareItException; +import ru.practicum.shareit.item.dto.ItemDto; +import ru.practicum.shareit.user.UserMapper; +import ru.practicum.shareit.user.controller.UserController; +import ru.practicum.shareit.user.dto.UserDto; + +import java.util.List; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertThrows; + +@SpringBootTest +@DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD) +class ItemControllerTest { + @Autowired + private ItemController itemController; + + @Autowired + private UserController userController; + + private ItemDto itemDto; + private UserDto userDto; + private Long userId; + + @BeforeEach + void setUp() { + userDto = UserDto.builder() + .name("Test Owner") + .email("owner@email.com") + .build(); + UserDto createdUser = userController.create(UserMapper.toUser(userDto)); + userId = createdUser.getId(); + + itemDto = ItemDto.builder() + .name("Test Item") + .description("Test Description") + .available(true) + .build(); + } + + @Nested // Тесты на создание предметов + @DisplayName("Creating items") + class CreateItemTests { + @Test + @DisplayName("Successful creation of an item") + void createItemTest() { + ItemDto createdItem = itemController.create(userId, itemDto); + + assertNotNull(createdItem); + assertEquals(1L, createdItem.getId()); + assertEquals(itemDto.getName(), createdItem.getName()); + assertEquals(itemDto.getDescription(), createdItem.getDescription()); + assertEquals(itemDto.getAvailable(), createdItem.getAvailable()); + } + + @Test + @DisplayName("Error when creating an item with a non-existent user") + void createItemWithNonExistentUserTest() { + assertThrows(ShareItException.NotFoundException.class, + () -> itemController.create(999L, itemDto)); + } + } + + @Nested // Тесты на получение предметов + @DisplayName("Getting items") + class GetItemTests { + @Test + @DisplayName("Getting an item by ID") + void getItemByIdTest() { + ItemDto createdItem = itemController.create(userId, itemDto); + ItemDto retrievedItem = itemController.getById(createdItem.getId()); + + assertNotNull(retrievedItem); + assertEquals(createdItem.getId(), retrievedItem.getId()); + assertEquals(createdItem.getName(), retrievedItem.getName()); + assertEquals(createdItem.getDescription(), retrievedItem.getDescription()); + assertEquals(createdItem.getAvailable(), retrievedItem.getAvailable()); + } + + @Test + @DisplayName("Getting all the user's items") + void getAllUserItemsTest() { + itemController.create(userId, itemDto); + + ItemDto secondItem = ItemDto.builder() + .name("Second Item") + .description("Another Description") + .available(true) + .build(); + itemController.create(userId, secondItem); + + List items = itemController.getAll(userId); + + assertEquals(2, items.size()); + assertEquals("Test Item", items.get(0).getName()); + assertEquals("Second Item", items.get(1).getName()); + } + + @Test + @DisplayName("Error when receiving a non-existent item") + void getNonExistentItemTest() { + assertThrows(ShareItException.NotFoundException.class, + () -> itemController.getById(999L)); + } + } + + @Nested // Тесты на обновление предметов + @DisplayName("Updating items") + class UpdateItemTests { + @Test + @DisplayName("Full item update") + void updateItemTest() { + ItemDto createdItem = itemController.create(userId, itemDto); + + ItemDto updateRequest = ItemDto.builder() + .name("Updated Item") + .description("Updated Description") + .available(false) + .build(); + + ItemDto updatedItem = itemController.update(updateRequest, createdItem.getId(), userId); + + assertEquals("Updated Item", updatedItem.getName()); + assertEquals("Updated Description", updatedItem.getDescription()); + assertEquals(false, updatedItem.getAvailable()); + + ItemDto retrievedItem = itemController.getById(createdItem.getId()); + assertEquals("Updated Item", retrievedItem.getName()); + assertEquals("Updated Description", retrievedItem.getDescription()); + assertEquals(false, retrievedItem.getAvailable()); + } + + @Test + @DisplayName("Partial item update") + void partialUpdateItemTest() { + ItemDto createdItem = itemController.create(userId, itemDto); + ItemDto result; + + result = itemController.update( + ItemDto.builder().name("New Name").build(), + createdItem.getId(), + userId + ); + assertEquals("New Name", result.getName()); + assertEquals(itemDto.getDescription(), result.getDescription()); + assertEquals(itemDto.getAvailable(), result.getAvailable()); + + result = itemController.update( + ItemDto.builder().description("New Description").build(), + createdItem.getId(), + userId + ); + assertEquals("New Name", result.getName()); + assertEquals("New Description", result.getDescription()); + assertEquals(itemDto.getAvailable(), result.getAvailable()); + + result = itemController.update( + ItemDto.builder().available(false).build(), + createdItem.getId(), + userId + ); + assertEquals("New Name", result.getName()); + assertEquals("New Description", result.getDescription()); + assertEquals(false, result.getAvailable()); + } + + @Test + @DisplayName("Error when updating an item by a non-owner") + void updateItemByNonOwnerTest() { + ItemDto createdItem = itemController.create(userId, itemDto); + + UserDto anotherUserDto = UserDto.builder() + .name("Another User") + .email("another@email.com") + .build(); + UserDto anotherUser = userController.create(UserMapper.toUser(anotherUserDto)); + + ItemDto updateRequest = ItemDto.builder() + .name("Unauthorized Update") + .build(); + + assertThrows(ShareItException.NotFoundException.class, + () -> itemController.update(updateRequest, createdItem.getId(), anotherUser.getId())); + } + } + + @Nested // Тесты на удаление предметов + @DisplayName("Deleting items") + class DeleteItemTests { + @Test + @DisplayName("Successful removal of an item") + void deleteItemTest() { + ItemDto createdItem = itemController.create(userId, itemDto); + assertEquals(1, itemController.getAll(userId).size()); + + itemController.delete(createdItem.getId()); + + assertEquals(0, itemController.getAll(userId).size()); + } + } + + @Nested // Тесты на поиск предметов + @DisplayName("Searching for items") + class SearchItemTests { + @Test + @DisplayName("Search for items based on various criteria") + void searchItemsTest() { + itemController.create(userId, itemDto); + + ItemDto secondItem = ItemDto.builder() + .name("Special Item") + .description("Unique features") + .available(true) + .build(); + itemController.create(userId, secondItem); + + ItemDto unavailableItem = ItemDto.builder() + .name("Unavailable Special") + .description("Not for rent") + .available(false) + .build(); + itemController.create(userId, unavailableItem); + + List results = itemController.search("Test"); + assertEquals(1, results.size()); + assertEquals("Test Item", results.get(0).getName()); + + results = itemController.search("Unique"); + assertEquals(1, results.size()); + assertEquals("Special Item", results.get(0).getName()); + + results = itemController.search("Item"); + assertEquals(2, results.size()); + + results = itemController.search("Unavailable"); + assertEquals(0, results.size()); + + results = itemController.search(""); + assertEquals(0, results.size()); + } + } +} \ No newline at end of file diff --git a/src/test/java/ru/practicum/shareit/user/controller/UserControllerTest.java b/src/test/java/ru/practicum/shareit/user/controller/UserControllerTest.java new file mode 100644 index 0000000..fb30a7b --- /dev/null +++ b/src/test/java/ru/practicum/shareit/user/controller/UserControllerTest.java @@ -0,0 +1,173 @@ +package ru.practicum.shareit.user.controller; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.annotation.DirtiesContext; +import ru.practicum.shareit.booking.exception.ShareItException; +import ru.practicum.shareit.user.UserMapper; +import ru.practicum.shareit.user.dto.UserDto; +import ru.practicum.shareit.user.model.User; + +import java.util.List; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertThrows; + +@SpringBootTest +@DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD) +class UserControllerTest { + @Autowired + private UserController userController; + + private UserDto userDto; + private User user; + + @BeforeEach + void setUp() { + userDto = UserDto.builder() + .name("Test User") + .email("test@email.com") + .build(); + + user = UserMapper.toUser(userDto); + } + + @Nested // Тесты на создание пользователей + @DisplayName("Creating Users") + class CreateUserTests { + @Test + @DisplayName("Successful user creation") + void createUserTest() { + UserDto createdUser = userController.create(user); + + assertNotNull(createdUser); + assertEquals(1L, createdUser.getId()); + assertEquals(userDto.getName(), createdUser.getName()); + assertEquals(userDto.getEmail(), createdUser.getEmail()); + } + + @Test + @DisplayName("Error when creating a user with a duplicate email") + void createUserWithDuplicateEmailTest() { + userController.create(user); + + User duplicateUser = User.builder() + .name("Another User") + .email("test@email.com") // Тот же email + .build(); + + assertThrows(ShareItException.ConflictException.class, + () -> userController.create(duplicateUser)); + } + } + + @Nested // Тесты на получение пользователей + @DisplayName("Getting Users") + class GetUserTests { + @Test + @DisplayName("Getting a user by ID") + void getUserByIdTest() { + UserDto createdUser = userController.create(user); + UserDto retrievedUser = userController.getById(createdUser.getId()); + + assertNotNull(retrievedUser); + assertEquals(createdUser.getId(), retrievedUser.getId()); + assertEquals(createdUser.getName(), retrievedUser.getName()); + assertEquals(createdUser.getEmail(), retrievedUser.getEmail()); + } + + @Test + @DisplayName("Getting all users") + void getAllUsersTest() { + userController.create(user); + + // Создаем второго пользователя + UserDto secondUser = UserDto.builder() + .name("Second User") + .email("second@email.com") + .build(); + userController.create(UserMapper.toUser(secondUser)); + + List users = userController.getAll(); + + assertEquals(2, users.size()); + assertEquals("Test User", users.get(0).getName()); + assertEquals("Second User", users.get(1).getName()); + } + + @Test + @DisplayName("Error when receiving a non-existent user") + void getNonExistentUserTest() { + assertThrows(ShareItException.NotFoundException.class, + () -> userController.getById(999L)); + } + } + + @Nested // Тесты на обновление пользователей + @DisplayName("Updating users") + class UpdateUserTests { + @Test + @DisplayName("Full user update") + void updateUserTest() { + UserDto createdUser = userController.create(user); + + User updatedUser = User.builder() + .name("Updated Name") + .email("updated@email.com") + .build(); + + UserDto result = userController.update(updatedUser, createdUser.getId()); + + assertEquals("Updated Name", result.getName()); + assertEquals("updated@email.com", result.getEmail()); + + UserDto retrievedUser = userController.getById(createdUser.getId()); + assertEquals("Updated Name", retrievedUser.getName()); + assertEquals("updated@email.com", retrievedUser.getEmail()); + } + + @Test // Тест на частичное обновление пользователя + @DisplayName("Partial user update") + void partialUpdateUserTest() { + UserDto createdUser = userController.create(user); + UserDto result; + + User nameUpdate = User.builder() + .name("New Name") + .build(); + result = userController.update(nameUpdate, createdUser.getId()); + assertEquals("New Name", result.getName()); + assertEquals(userDto.getEmail(), result.getEmail()); + + User emailUpdate = User.builder() + .email("new@email.com") + .build(); + result = userController.update(emailUpdate, createdUser.getId()); + assertEquals("New Name", result.getName()); + assertEquals("new@email.com", result.getEmail()); + } + } + + @Nested // Тесты на удаление пользователей + @DisplayName("Deleting Users") + class DeleteUserTests { + @Test + @DisplayName("Successful user deletion") + void deleteUserTest() { + UserDto createdUser = userController.create(user); + assertEquals(1, userController.getAll().size()); + + userController.delete(createdUser.getId()); + + assertEquals(0, userController.getAll().size()); + + assertThrows(ShareItException.NotFoundException.class, + () -> userController.getById(createdUser.getId())); + } + } +} \ No newline at end of file From f13b484129e2775224e7cd9a2c3a2842d0131803 Mon Sep 17 00:00:00 2001 From: Viktor64 Date: Wed, 26 Mar 2025 00:32:07 +0400 Subject: [PATCH 2/4] =?UTF-8?q?=D0=94=D0=BE=D1=80=D0=B0=D0=B1=D0=BE=D1=82?= =?UTF-8?q?=D0=B0=D0=BB=20=D0=B2=D0=B5=D1=82=D0=BA=D1=83:=20add-controller?= =?UTF-8?q?s.=201)=20=D0=A3=D0=B1=D1=80=D0=B0=D0=BB=20=D0=BB=D0=B8=D1=88?= =?UTF-8?q?=D0=BD=D0=B8=D0=B5=20TODO.=202)=20=D0=92=D1=8B=D0=B2=D0=B5?= =?UTF-8?q?=D0=BB=20=D0=BF=D0=BE=D0=B2=D1=82=D0=BE=D1=80=D1=8F=D1=8E=D1=89?= =?UTF-8?q?=D0=B8=D0=B9=D1=81=D1=8F=20=D1=85=D1=8D=D0=B4=D0=B5=D1=80=20?= =?UTF-8?q?=D0=B2=20=D0=BE=D1=82=D0=B4=D0=B5=D0=BB=D1=8C=D0=BD=D1=8B=D0=B9?= =?UTF-8?q?=20=D0=BA=D0=BB=D0=B0=D1=81=D1=81.=203)=20=D0=A3=D0=BB=D1=83?= =?UTF-8?q?=D1=87=D1=88=D0=B8=D0=BB=20=D0=BA=D0=BE=D0=B4,=20=D0=B8=D1=81?= =?UTF-8?q?=D0=BF=D0=BE=D0=BB=D1=8C=D0=B7=D1=83=D1=8F=20Stream=20API.=204)?= =?UTF-8?q?=20=D0=92=D1=8B=D0=BD=D0=B5=D1=81=20=D0=BC=D0=B5=D1=82=D0=BE?= =?UTF-8?q?=D0=B4=20=D0=9E=D0=B1=D0=BD=D0=BE=D0=B2=D0=BB=D0=B5=D0=BD=D0=B8?= =?UTF-8?q?=D0=B5=20=D0=BF=D0=BE=D0=BB=D0=B5=D0=B9=20=D0=B2=20=D0=BC=D0=B0?= =?UTF-8?q?=D0=BF=D0=BF=D0=B5=D1=80,=20=D0=BF=D0=BE=D1=81=D0=BB=D0=B5=20?= =?UTF-8?q?=D0=B2=D0=BD=D0=B5=D0=B4=D1=80=D0=B5=D0=BD=D0=B8=D1=8F=20MapStr?= =?UTF-8?q?uct,=20=D0=B3=D0=B5=D0=BD=D0=B5=D1=80=D0=B8=D1=80=D1=83=D0=B5?= =?UTF-8?q?=D1=82=D1=81=D1=8F=20=D0=B0=D0=B2=D1=82=D0=BE=D0=BC=D0=B0=D1=82?= =?UTF-8?q?=D0=B8=D1=87=D0=B5=D1=81=D0=BA=D0=B8.=205)=20=D0=98=D1=81=D0=BF?= =?UTF-8?q?=D0=BE=D0=BB=D1=8C=D0=B7=D0=BE=D0=B2=D0=B0=D0=BB=20stream=20api?= =?UTF-8?q?=20=D0=B2=20=D0=BC=D0=B5=D1=82=D0=BE=D0=B4=D0=B5=20getAll().=20?= =?UTF-8?q?6)=20=D0=9E=D0=BF=D1=82=D0=B8=D0=BC=D0=B8=D0=B7=D0=B8=D1=80?= =?UTF-8?q?=D0=BE=D0=B2=D0=B0=D0=BB=20=D0=BF=D1=80=D0=BE=D0=B2=D0=B5=D1=80?= =?UTF-8?q?=D0=BA=D1=83=20=D1=83=D0=BD=D0=B8=D0=BA=D0=B0=D0=BB=D1=8C=D0=BD?= =?UTF-8?q?=D0=BE=D1=81=D1=82=D0=B8=20email=20=D1=81=20=D0=BF=D0=BE=D0=BC?= =?UTF-8?q?=D0=BE=D1=89=D1=8C=D1=8E=20Set=20=D0=B4=D0=BB=D1=8F=20=D0=B4?= =?UTF-8?q?=D0=BE=D1=81=D1=82=D0=B8=D0=B6=D0=B5=D0=BD=D0=B8=D1=8F=20O(1)?= =?UTF-8?q?=20=D1=81=D0=BB=D0=BE=D0=B6=D0=BD=D0=BE=D1=81=D1=82=D0=B8.=207)?= =?UTF-8?q?=20=D0=92=D0=BD=D0=B5=D0=B4=D1=80=D0=B8=D0=BB=20=D0=B1=D0=B8?= =?UTF-8?q?=D0=B1=D0=BB=D0=B8=D0=BE=D1=82=D0=B5=D0=BA=D0=B8=20MapStruct,?= =?UTF-8?q?=20=D1=82=D0=B5=D0=BF=D0=B5=D1=80=D1=8C=20=D0=BA=D0=BE=D0=B4=20?= =?UTF-8?q?=D0=BC=D0=B0=D0=BF=D0=BF=D0=B8=D0=BD=D0=B3=D0=B0=20=D0=B3=D0=B5?= =?UTF-8?q?=D0=BD=D0=B5=D1=80=D0=B8=D1=80=D1=83=D0=B5=D1=82=D1=81=D1=8F=20?= =?UTF-8?q?=D0=B0=D0=B2=D1=82=D0=BE=D0=BC=D0=B0=D1=82=D0=B8=D1=87=D0=B5?= =?UTF-8?q?=D1=81=D0=BA=D0=B8=20=D0=B8=20=D1=80=D0=B0=D0=B1=D0=BE=D1=82?= =?UTF-8?q?=D0=B0=D0=B5=D1=82=20=D0=B1=D1=8B=D1=81=D1=82=D1=80=D0=B5=D0=B5?= =?UTF-8?q?.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pom.xml | 11 ++++ .../booking/controller/BookingController.java | 4 +- .../shareit/booking/dto/BookingDto.java | 4 +- .../shareit/booking/model/Booking.java | 4 +- .../shareit/item/Impl/ItemServiceImpl.java | 65 +++++++------------ .../ru/practicum/shareit/item/ItemMapper.java | 29 +++------ .../item/controller/ItemController.java | 11 ++-- .../practicum/shareit/item/dto/ItemDto.java | 3 - .../ru/practicum/shareit/item/model/Item.java | 3 - .../shareit/item/util/Constants.java | 5 ++ .../controller/ItemRequestController.java | 4 +- .../shareit/request/dto/ItemRequestDto.java | 4 +- .../shareit/request/model/ItemRequest.java | 3 - .../shareit/user/Impl/UserServiceImpl.java | 48 +++++++++----- .../user/controller/UserController.java | 5 +- .../ru/practicum/shareit/user/model/User.java | 3 - 16 files changed, 90 insertions(+), 116 deletions(-) create mode 100644 src/main/java/ru/practicum/shareit/item/util/Constants.java diff --git a/pom.xml b/pom.xml index 2db888c..6ddbe30 100644 --- a/pom.xml +++ b/pom.xml @@ -60,6 +60,17 @@ org.springframework.boot spring-boot-starter-validation + + org.mapstruct + mapstruct + 1.5.5.Final + + + org.mapstruct + mapstruct-processor + 1.5.5.Final + provided + diff --git a/src/main/java/ru/practicum/shareit/booking/controller/BookingController.java b/src/main/java/ru/practicum/shareit/booking/controller/BookingController.java index c3b557f..a3e0ebb 100644 --- a/src/main/java/ru/practicum/shareit/booking/controller/BookingController.java +++ b/src/main/java/ru/practicum/shareit/booking/controller/BookingController.java @@ -3,9 +3,7 @@ import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; -/** - * TODO Sprint add-bookings. - */ + @RestController @RequestMapping(path = "/bookings") public class BookingController { diff --git a/src/main/java/ru/practicum/shareit/booking/dto/BookingDto.java b/src/main/java/ru/practicum/shareit/booking/dto/BookingDto.java index 9c703a3..393e544 100644 --- a/src/main/java/ru/practicum/shareit/booking/dto/BookingDto.java +++ b/src/main/java/ru/practicum/shareit/booking/dto/BookingDto.java @@ -9,9 +9,7 @@ import java.time.LocalDateTime; -/** - * TODO Sprint add-bookings. - */ + @Getter @Setter @Builder(toBuilder = true) diff --git a/src/main/java/ru/practicum/shareit/booking/model/Booking.java b/src/main/java/ru/practicum/shareit/booking/model/Booking.java index 57b727e..5382265 100644 --- a/src/main/java/ru/practicum/shareit/booking/model/Booking.java +++ b/src/main/java/ru/practicum/shareit/booking/model/Booking.java @@ -8,9 +8,7 @@ import java.time.LocalDateTime; -/** - * TODO Sprint add-bookings. - */ + @Getter @Setter public class Booking { diff --git a/src/main/java/ru/practicum/shareit/item/Impl/ItemServiceImpl.java b/src/main/java/ru/practicum/shareit/item/Impl/ItemServiceImpl.java index a15b55f..0527ae9 100644 --- a/src/main/java/ru/practicum/shareit/item/Impl/ItemServiceImpl.java +++ b/src/main/java/ru/practicum/shareit/item/Impl/ItemServiceImpl.java @@ -2,6 +2,7 @@ import org.springframework.stereotype.Service; import ru.practicum.shareit.booking.exception.ShareItException; +import ru.practicum.shareit.item.ItemMapper; import ru.practicum.shareit.item.dto.ItemDto; import ru.practicum.shareit.item.model.Item; import ru.practicum.shareit.item.repository.ItemRepository; @@ -11,30 +12,26 @@ import java.util.ArrayList; import java.util.List; - -import static ru.practicum.shareit.item.ItemMapper.toItem; -import static ru.practicum.shareit.item.ItemMapper.toItemDto; +import java.util.stream.Collectors; @Service public class ItemServiceImpl implements ItemService { private final ItemRepository itemRepository; private final UserRepository userRepository; + private final ItemMapper itemMapper; - public ItemServiceImpl(ItemRepository itemRepository, UserRepository userRepository) { + public ItemServiceImpl(ItemRepository itemRepository, UserRepository userRepository, ItemMapper itemMapper) { this.itemRepository = itemRepository; this.userRepository = userRepository; + this.itemMapper = itemMapper; } @Override public List getAll(Long userId) { - List items = new ArrayList<>(); - for (Item item : itemRepository.findAll()) { - if (item.getOwner().getId().equals(userId)) { - items.add(toItemDto(item)); - } - } - - return items; + return itemRepository.findAll().stream() + .filter(item -> item.getOwner().getId().equals(userId)) + .map(itemMapper::toItemDto) + .collect(Collectors.toList()); } @Override @@ -42,7 +39,7 @@ public ItemDto getById(Long id) { Item item = itemRepository.findById(id) .orElseThrow(() -> new ShareItException.NotFoundException("Не найдена вещь с id: " + id)); - return toItemDto(item); + return itemMapper.toItemDto(item); } @Override @@ -50,31 +47,24 @@ public ItemDto create(ItemDto itemDto, Long userId) { User user = userRepository.findById(userId) .orElseThrow(() -> new ShareItException.NotFoundException("Невозможно создать вещь - " + "не найден пользователь с id: " + userId)); - Item item = toItem(itemDto); + Item item = itemMapper.toItem(itemDto); item.setOwner(user); itemRepository.create(item); - return toItemDto(item); + return itemMapper.toItemDto(item); } @Override public ItemDto update(ItemDto itemDto, Long id, Long userId) { Item item = itemRepository.findById(id) .orElseThrow(() -> new ShareItException.NotFoundException("Не найдена вещь с id: " + id)); + if (!item.getOwner().getId().equals(userId)) { - throw new ShareItException.NotFoundException("Невозможно обновить вещь - у пользователя с id: " + userId + "нет такой вещи"); - } - if (itemDto.getName() != null) { - item.setName(itemDto.getName()); - } - if (itemDto.getDescription() != null) { - item.setDescription(itemDto.getDescription()); - } - if (itemDto.getAvailable() != null) { - item.setAvailable(itemDto.getAvailable()); + throw new ShareItException.NotFoundException("Невозможно обновить вещь - у пользователя с id: " + userId + " нет такой вещи"); } - return toItemDto(itemRepository.update(item)); + Item updatedItem = itemMapper.updateItemFields(item, itemDto); + return itemMapper.toItemDto(itemRepository.update(updatedItem)); } @Override @@ -85,23 +75,16 @@ public void delete(Long id) { @Override public List search(String text) { - List searchedItems = new ArrayList<>(); if (text.isBlank()) { - return searchedItems; - } - for (Item item : itemRepository.findAll()) { - if (isSearched(text, item)) { - searchedItems.add(toItemDto(item)); - } + return new ArrayList<>(); } - return searchedItems; - } - - private Boolean isSearched(String text, Item item) { - return item.getAvailable() && ( - item.getName().toLowerCase().contains(text.toLowerCase()) || - item.getDescription().toLowerCase().contains(text.toLowerCase()) - ); + String searchText = text.toLowerCase(); + return itemRepository.findAll().stream() + .filter(item -> item.getAvailable() && + (item.getName().toLowerCase().contains(searchText) || + item.getDescription().toLowerCase().contains(searchText))) + .map(itemMapper::toItemDto) + .collect(Collectors.toList()); } } \ No newline at end of file diff --git a/src/main/java/ru/practicum/shareit/item/ItemMapper.java b/src/main/java/ru/practicum/shareit/item/ItemMapper.java index 52400b3..dc3ce84 100644 --- a/src/main/java/ru/practicum/shareit/item/ItemMapper.java +++ b/src/main/java/ru/practicum/shareit/item/ItemMapper.java @@ -1,26 +1,17 @@ package ru.practicum.shareit.item; +import org.mapstruct.Mapper; +import org.mapstruct.Mapping; +import org.mapstruct.MappingTarget; +import org.mapstruct.NullValuePropertyMappingStrategy; import ru.practicum.shareit.item.dto.ItemDto; import ru.practicum.shareit.item.model.Item; -public class ItemMapper { - public static ItemDto toItemDto(Item item) { - return ItemDto.builder() - .id(item.getId()) - .name(item.getName()) - .description(item.getDescription()) - .available(item.getAvailable()) - .request(item.getRequest() != null ? item.getRequest() : null) - .build(); - } - public static Item toItem(ItemDto itemDto) { - return Item.builder() - .id(itemDto.getId()) - .name(itemDto.getName()) - .description(itemDto.getDescription()) - .available(itemDto.getAvailable()) - .request(itemDto.getRequest()) - .build(); - } +@Mapper(componentModel = "spring", nullValuePropertyMappingStrategy = NullValuePropertyMappingStrategy.IGNORE) +public interface ItemMapper { + @Mapping(target = "request", expression = "java(item.getRequest() != null ? item.getRequest() : null)") + ItemDto toItemDto(Item item); + Item toItem(ItemDto itemDto); + Item updateItemFields(@MappingTarget Item targetItem, ItemDto sourceItemDto); } \ No newline at end of file diff --git a/src/main/java/ru/practicum/shareit/item/controller/ItemController.java b/src/main/java/ru/practicum/shareit/item/controller/ItemController.java index 7a3aa1f..d00b6fb 100644 --- a/src/main/java/ru/practicum/shareit/item/controller/ItemController.java +++ b/src/main/java/ru/practicum/shareit/item/controller/ItemController.java @@ -13,13 +13,10 @@ import org.springframework.web.bind.annotation.RestController; import ru.practicum.shareit.item.dto.ItemDto; import ru.practicum.shareit.item.service.ItemService; +import ru.practicum.shareit.item.util.Constants; import java.util.List; - -/** - * TODO Sprint add-controllers. - */ @RestController @RequestMapping("/items") public class ItemController { @@ -30,7 +27,7 @@ public ItemController(ItemService itemService) { } @GetMapping - public List getAll(@RequestHeader("X-Sharer-User-Id") Long userId) { + public List getAll(@RequestHeader(Constants.USER_ID_HEADER) Long userId) { return itemService.getAll(userId); } @@ -40,13 +37,13 @@ public ItemDto getById(@PathVariable Long id) { } @PostMapping - public ItemDto create(@RequestHeader("X-Sharer-User-Id") Long userId, @Valid @RequestBody ItemDto itemDto) { + public ItemDto create(@RequestHeader(Constants.USER_ID_HEADER) Long userId, @Valid @RequestBody ItemDto itemDto) { return itemService.create(itemDto, userId); } @PatchMapping("/{id}") public ItemDto update(@RequestBody ItemDto itemDto, @PathVariable Long id, - @RequestHeader("X-Sharer-User-Id") Long userId) { + @RequestHeader(Constants.USER_ID_HEADER) Long userId) { return itemService.update(itemDto, id, userId); } diff --git a/src/main/java/ru/practicum/shareit/item/dto/ItemDto.java b/src/main/java/ru/practicum/shareit/item/dto/ItemDto.java index beaae16..ed1ea71 100644 --- a/src/main/java/ru/practicum/shareit/item/dto/ItemDto.java +++ b/src/main/java/ru/practicum/shareit/item/dto/ItemDto.java @@ -8,9 +8,6 @@ import ru.practicum.shareit.request.model.ItemRequest; -/** - * TODO Sprint add-controllers. - */ @Getter @Setter @Builder(toBuilder = true) 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 76d3704..7021c25 100644 --- a/src/main/java/ru/practicum/shareit/item/model/Item.java +++ b/src/main/java/ru/practicum/shareit/item/model/Item.java @@ -9,9 +9,6 @@ import ru.practicum.shareit.user.model.User; -/** - * TODO Sprint add-controllers. - */ @Getter @Setter @Builder diff --git a/src/main/java/ru/practicum/shareit/item/util/Constants.java b/src/main/java/ru/practicum/shareit/item/util/Constants.java new file mode 100644 index 0000000..d2d31b8 --- /dev/null +++ b/src/main/java/ru/practicum/shareit/item/util/Constants.java @@ -0,0 +1,5 @@ +package ru.practicum.shareit.item.util; + +public class Constants { + public static final String USER_ID_HEADER = "X-Sharer-User-Id"; +} \ No newline at end of file diff --git a/src/main/java/ru/practicum/shareit/request/controller/ItemRequestController.java b/src/main/java/ru/practicum/shareit/request/controller/ItemRequestController.java index 40ecfc8..5eaee82 100644 --- a/src/main/java/ru/practicum/shareit/request/controller/ItemRequestController.java +++ b/src/main/java/ru/practicum/shareit/request/controller/ItemRequestController.java @@ -3,9 +3,7 @@ import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; -/** - * TODO Sprint add-item-requests. - */ + @RestController @RequestMapping(path = "/requests") public class ItemRequestController { diff --git a/src/main/java/ru/practicum/shareit/request/dto/ItemRequestDto.java b/src/main/java/ru/practicum/shareit/request/dto/ItemRequestDto.java index ee39b8a..d87f428 100644 --- a/src/main/java/ru/practicum/shareit/request/dto/ItemRequestDto.java +++ b/src/main/java/ru/practicum/shareit/request/dto/ItemRequestDto.java @@ -9,9 +9,7 @@ import java.time.LocalDateTime; import java.util.List; -/** - * TODO Sprint add-item-requests. - */ + @Getter @Setter @Builder(toBuilder = true) diff --git a/src/main/java/ru/practicum/shareit/request/model/ItemRequest.java b/src/main/java/ru/practicum/shareit/request/model/ItemRequest.java index 806ae38..5612dda 100644 --- a/src/main/java/ru/practicum/shareit/request/model/ItemRequest.java +++ b/src/main/java/ru/practicum/shareit/request/model/ItemRequest.java @@ -8,9 +8,6 @@ import java.time.LocalDateTime; -/** - * TODO Sprint add-item-requests. - */ @Getter @Setter public class ItemRequest { diff --git a/src/main/java/ru/practicum/shareit/user/Impl/UserServiceImpl.java b/src/main/java/ru/practicum/shareit/user/Impl/UserServiceImpl.java index 024a208..94d26dc 100644 --- a/src/main/java/ru/practicum/shareit/user/Impl/UserServiceImpl.java +++ b/src/main/java/ru/practicum/shareit/user/Impl/UserServiceImpl.java @@ -2,32 +2,34 @@ import org.springframework.stereotype.Service; import ru.practicum.shareit.booking.exception.ShareItException; +import ru.practicum.shareit.user.UserMapper; import ru.practicum.shareit.user.dto.UserDto; import ru.practicum.shareit.user.model.User; import ru.practicum.shareit.user.repository.UserRepository; import ru.practicum.shareit.user.service.UserService; -import java.util.ArrayList; +import java.util.HashSet; import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; import static ru.practicum.shareit.user.UserMapper.toUserDto; @Service public class UserServiceImpl implements UserService { private final UserRepository userRepository; + private final Set emailSet = new HashSet<>(); public UserServiceImpl(UserRepository userRepository) { this.userRepository = userRepository; + userRepository.findAll().forEach(user -> emailSet.add(user.getEmail().toLowerCase())); } @Override public List getAll() { - List users = new ArrayList<>(); - for (User user : userRepository.findAll()) { - users.add(toUserDto(user)); - } - - return users; + return userRepository.findAll().stream() + .map(UserMapper::toUserDto) + .collect(Collectors.toList()); } @Override @@ -40,9 +42,10 @@ public UserDto getById(Long id) { @Override public UserDto create(User user) { - throwIfEmailNotUnique(user); - - return toUserDto(userRepository.create(user)); + checkEmailUniqueness(user); + User createdUser = userRepository.create(user); + emailSet.add(createdUser.getEmail().toLowerCase()); + return toUserDto(createdUser); } @Override @@ -50,10 +53,14 @@ public UserDto update(User user, Long id) { User updatedUser = userRepository.findById(id) .orElseThrow(() -> new ShareItException.NotFoundException("Невозможно обновить данные пользователя. " + "Не найден пользователь с id: " + id)); - if (user.getEmail() != null) { - throwIfEmailNotUnique(user); + + if (user.getEmail() != null && !user.getEmail().equals(updatedUser.getEmail())) { + checkEmailUniqueness(user); + emailSet.remove(updatedUser.getEmail().toLowerCase()); + emailSet.add(user.getEmail().toLowerCase()); updatedUser.setEmail(user.getEmail()); } + if (user.getName() != null) { updatedUser.setName(user.getName()); } @@ -63,15 +70,20 @@ public UserDto update(User user, Long id) { @Override public void delete(Long id) { - getById(id); + User user = userRepository.findById(id) + .orElseThrow(() -> new ShareItException.NotFoundException("Не найден пользователь с id: " + id)); + emailSet.remove(user.getEmail().toLowerCase()); userRepository.delete(id); } - private void throwIfEmailNotUnique(User user) { - for (User userCheck : userRepository.findAll()) { - if (user.getEmail().equals(userCheck.getEmail())) { - throw new ShareItException.ConflictException("Пользователь с таким email уже зарегистрирован"); - } + private void checkEmailUniqueness(User user) { + if (user.getEmail() == null) { + return; + } + + String email = user.getEmail().toLowerCase(); + if (emailSet.contains(email)) { + throw new ShareItException.ConflictException("Пользователь с таким email уже зарегистрирован"); } } } \ No newline at end of file diff --git a/src/main/java/ru/practicum/shareit/user/controller/UserController.java b/src/main/java/ru/practicum/shareit/user/controller/UserController.java index e4d47d3..09f47e1 100644 --- a/src/main/java/ru/practicum/shareit/user/controller/UserController.java +++ b/src/main/java/ru/practicum/shareit/user/controller/UserController.java @@ -9,16 +9,13 @@ import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; +import ru.practicum.shareit.user.Impl.UserServiceImpl; import ru.practicum.shareit.user.dto.UserDto; import ru.practicum.shareit.user.model.User; -import ru.practicum.shareit.user.Impl.UserServiceImpl; import java.util.List; -/** - * TODO Sprint add-controllers. - */ @RestController @RequestMapping(path = "/users") public class UserController { 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 ebcedbd..9647105 100644 --- a/src/main/java/ru/practicum/shareit/user/model/User.java +++ b/src/main/java/ru/practicum/shareit/user/model/User.java @@ -7,9 +7,6 @@ import lombok.Setter; -/** - * TODO Sprint add-controllers. - */ @Getter @Setter @Builder From 32c097cdb67896b6bc6d5b66fbe942529d471f5e Mon Sep 17 00:00:00 2001 From: Viktor64 Date: Wed, 26 Mar 2025 00:41:30 +0400 Subject: [PATCH 3/4] =?UTF-8?q?=D0=94=D0=BE=D1=80=D0=B0=D0=B1=D0=BE=D1=82?= =?UTF-8?q?=D0=B0=D0=BB=20=D0=B2=D0=B5=D1=82=D0=BA=D1=83:=20add-controller?= =?UTF-8?q?s.=201)=20=D0=A3=D0=B1=D1=80=D0=B0=D0=BB=20=D0=BB=D0=B8=D1=88?= =?UTF-8?q?=D0=BD=D0=B8=D0=B5=20TODO.=202)=20=D0=92=D1=8B=D0=B2=D0=B5?= =?UTF-8?q?=D0=BB=20=D0=BF=D0=BE=D0=B2=D1=82=D0=BE=D1=80=D1=8F=D1=8E=D1=89?= =?UTF-8?q?=D0=B8=D0=B9=D1=81=D1=8F=20=D1=85=D1=8D=D0=B4=D0=B5=D1=80=20?= =?UTF-8?q?=D0=B2=20=D0=BE=D1=82=D0=B4=D0=B5=D0=BB=D1=8C=D0=BD=D1=8B=D0=B9?= =?UTF-8?q?=20=D0=BA=D0=BB=D0=B0=D1=81=D1=81.=203)=20=D0=A3=D0=BB=D1=83?= =?UTF-8?q?=D1=87=D1=88=D0=B8=D0=BB=20=D0=BA=D0=BE=D0=B4,=20=D0=B8=D1=81?= =?UTF-8?q?=D0=BF=D0=BE=D0=BB=D1=8C=D0=B7=D1=83=D1=8F=20Stream=20API.=204)?= =?UTF-8?q?=20=D0=92=D1=8B=D0=BD=D0=B5=D1=81=20=D0=BC=D0=B5=D1=82=D0=BE?= =?UTF-8?q?=D0=B4=20=D0=9E=D0=B1=D0=BD=D0=BE=D0=B2=D0=BB=D0=B5=D0=BD=D0=B8?= =?UTF-8?q?=D0=B5=20=D0=BF=D0=BE=D0=BB=D0=B5=D0=B9=20=D0=B2=20=D0=BC=D0=B0?= =?UTF-8?q?=D0=BF=D0=BF=D0=B5=D1=80,=20=D0=BF=D0=BE=D1=81=D0=BB=D0=B5=20?= =?UTF-8?q?=D0=B2=D0=BD=D0=B5=D0=B4=D1=80=D0=B5=D0=BD=D0=B8=D1=8F=20MapStr?= =?UTF-8?q?uct,=20=D0=B3=D0=B5=D0=BD=D0=B5=D1=80=D0=B8=D1=80=D1=83=D0=B5?= =?UTF-8?q?=D1=82=D1=81=D1=8F=20=D0=B0=D0=B2=D1=82=D0=BE=D0=BC=D0=B0=D1=82?= =?UTF-8?q?=D0=B8=D1=87=D0=B5=D1=81=D0=BA=D0=B8.=205)=20=D0=98=D1=81=D0=BF?= =?UTF-8?q?=D0=BE=D0=BB=D1=8C=D0=B7=D0=BE=D0=B2=D0=B0=D0=BB=20stream=20api?= =?UTF-8?q?=20=D0=B2=20=D0=BC=D0=B5=D1=82=D0=BE=D0=B4=D0=B5=20getAll().=20?= =?UTF-8?q?6)=20=D0=9E=D0=BF=D1=82=D0=B8=D0=BC=D0=B8=D0=B7=D0=B8=D1=80?= =?UTF-8?q?=D0=BE=D0=B2=D0=B0=D0=BB=20=D0=BF=D1=80=D0=BE=D0=B2=D0=B5=D1=80?= =?UTF-8?q?=D0=BA=D1=83=20=D1=83=D0=BD=D0=B8=D0=BA=D0=B0=D0=BB=D1=8C=D0=BD?= =?UTF-8?q?=D0=BE=D1=81=D1=82=D0=B8=20email=20=D1=81=20=D0=BF=D0=BE=D0=BC?= =?UTF-8?q?=D0=BE=D1=89=D1=8C=D1=8E=20Set=20=D0=B4=D0=BB=D1=8F=20=D0=B4?= =?UTF-8?q?=D0=BE=D1=81=D1=82=D0=B8=D0=B6=D0=B5=D0=BD=D0=B8=D1=8F=20O(1)?= =?UTF-8?q?=20=D1=81=D0=BB=D0=BE=D0=B6=D0=BD=D0=BE=D1=81=D1=82=D0=B8.=207)?= =?UTF-8?q?=20=D0=92=D0=BD=D0=B5=D0=B4=D1=80=D0=B8=D0=BB=20=D0=B1=D0=B8?= =?UTF-8?q?=D0=B1=D0=BB=D0=B8=D0=BE=D1=82=D0=B5=D0=BA=D0=B8=20MapStruct,?= =?UTF-8?q?=20=D1=82=D0=B5=D0=BF=D0=B5=D1=80=D1=8C=20=D0=BA=D0=BE=D0=B4=20?= =?UTF-8?q?=D0=BC=D0=B0=D0=BF=D0=BF=D0=B8=D0=BD=D0=B3=D0=B0=20=D0=B3=D0=B5?= =?UTF-8?q?=D0=BD=D0=B5=D1=80=D0=B8=D1=80=D1=83=D0=B5=D1=82=D1=81=D1=8F=20?= =?UTF-8?q?=D0=B0=D0=B2=D1=82=D0=BE=D0=BC=D0=B0=D1=82=D0=B8=D1=87=D0=B5?= =?UTF-8?q?=D1=81=D0=BA=D0=B8=20=D0=B8=20=D1=80=D0=B0=D0=B1=D0=BE=D1=82?= =?UTF-8?q?=D0=B0=D0=B5=D1=82=20=D0=B1=D1=8B=D1=81=D1=82=D1=80=D0=B5=D0=B5?= =?UTF-8?q?.=208)=20=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=B8=D0=BB=20=D0=BF?= =?UTF-8?q?=D1=83=D1=81=D1=82=D1=8B=D0=B5=20=D1=81=D1=82=D1=80=D0=BE=D0=BA?= =?UTF-8?q?=D0=B8=20=D0=B4=D0=BB=D1=8F=20=D0=BF=D1=80=D0=BE=D1=85=D0=BE?= =?UTF-8?q?=D0=B6=D0=B4=D0=B5=D0=BD=D0=B8=D1=8F=20=D0=BF=D1=80=D0=BE=D0=B2?= =?UTF-8?q?=D0=B5=D1=80=D0=BA=D0=B8=20Checkstyle.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/ru/practicum/shareit/item/ItemMapper.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/main/java/ru/practicum/shareit/item/ItemMapper.java b/src/main/java/ru/practicum/shareit/item/ItemMapper.java index dc3ce84..ece92a4 100644 --- a/src/main/java/ru/practicum/shareit/item/ItemMapper.java +++ b/src/main/java/ru/practicum/shareit/item/ItemMapper.java @@ -10,8 +10,11 @@ @Mapper(componentModel = "spring", nullValuePropertyMappingStrategy = NullValuePropertyMappingStrategy.IGNORE) public interface ItemMapper { + @Mapping(target = "request", expression = "java(item.getRequest() != null ? item.getRequest() : null)") ItemDto toItemDto(Item item); + Item toItem(ItemDto itemDto); + Item updateItemFields(@MappingTarget Item targetItem, ItemDto sourceItemDto); } \ No newline at end of file From cc36c5bbf287e6a511eba601f08af5cc6398fa16 Mon Sep 17 00:00:00 2001 From: Viktor64 Date: Wed, 26 Mar 2025 19:44:44 +0400 Subject: [PATCH 4/4] =?UTF-8?q?=D0=94=D0=BE=D1=80=D0=B0=D0=B1=D0=BE=D1=82?= =?UTF-8?q?=D0=B0=D0=BB=20=D0=B2=D0=B5=D1=82=D0=BA=D1=83:=20add-controller?= =?UTF-8?q?s.=201)=20=D0=92=D0=BD=D0=B5=D0=B4=D1=80=D0=B8=D0=BB=20=D0=B1?= =?UTF-8?q?=D0=B8=D0=B1=D0=BB=D0=B8=D0=BE=D1=82=D0=B5=D0=BA=D0=B8=20MapStr?= =?UTF-8?q?uct=20=D0=B2=20UserMapper,=20=D1=82=D0=B5=D0=BF=D0=B5=D1=80?= =?UTF-8?q?=D1=8C=20=D0=BA=D0=BE=D0=B4=20=D1=81=D1=82=D0=B0=D0=BB=20=D0=B1?= =?UTF-8?q?=D0=BE=D0=BB=D0=B5=D0=B5=20=D0=B5=D0=B4=D0=B8=D0=BD=D0=BE=D0=BE?= =?UTF-8?q?=D0=B1=D1=80=D0=B0=D0=B7=D0=BD=D1=8B=D0=BC.=202)=20=D0=9E=D0=B1?= =?UTF-8?q?=D0=BD=D0=BE=D0=B2=D0=B8=D0=BB=20=D1=82=D0=B5=D1=81=D1=82=D1=8B?= =?UTF-8?q?=20=D0=B8=20=D0=BA=D0=BE=D0=BD=D1=81=D1=82=D1=80=D1=83=D0=BA?= =?UTF-8?q?=D1=82=D0=BE=D1=80=20=D0=BF=D0=BE=D0=B4=20MapStruct.=203)=20?= =?UTF-8?q?=D0=A3=D0=B1=D1=80=D0=B0=D0=BB=20=D0=BB=D0=B8=D1=88=D0=BD=D0=B5?= =?UTF-8?q?=D0=B5=20=D0=BF=D1=80=D0=B5=D0=B4=D0=B7=D0=B0=D0=BF=D0=BE=D0=BB?= =?UTF-8?q?=D0=BD=D0=B5=D0=BD=D0=B8=D0=B5=20=D0=B8=D0=B7=20UserServiceImpl?= =?UTF-8?q?.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../shareit/user/Impl/UserServiceImpl.java | 21 ++++++-------- .../ru/practicum/shareit/user/UserMapper.java | 28 ++++++++----------- .../item/controller/ItemControllerTest.java | 7 +++-- .../user/controller/UserControllerTest.java | 7 +++-- 4 files changed, 29 insertions(+), 34 deletions(-) diff --git a/src/main/java/ru/practicum/shareit/user/Impl/UserServiceImpl.java b/src/main/java/ru/practicum/shareit/user/Impl/UserServiceImpl.java index 94d26dc..ac0e48b 100644 --- a/src/main/java/ru/practicum/shareit/user/Impl/UserServiceImpl.java +++ b/src/main/java/ru/practicum/shareit/user/Impl/UserServiceImpl.java @@ -13,22 +13,21 @@ import java.util.Set; import java.util.stream.Collectors; -import static ru.practicum.shareit.user.UserMapper.toUserDto; - @Service public class UserServiceImpl implements UserService { private final UserRepository userRepository; + private final UserMapper userMapper; private final Set emailSet = new HashSet<>(); - public UserServiceImpl(UserRepository userRepository) { + public UserServiceImpl(UserRepository userRepository, UserMapper userMapper) { this.userRepository = userRepository; - userRepository.findAll().forEach(user -> emailSet.add(user.getEmail().toLowerCase())); + this.userMapper = userMapper; } @Override public List getAll() { return userRepository.findAll().stream() - .map(UserMapper::toUserDto) + .map(userMapper::toUserDto) .collect(Collectors.toList()); } @@ -37,7 +36,7 @@ public UserDto getById(Long id) { User user = userRepository.findById(id) .orElseThrow(() -> new ShareItException.NotFoundException("Не найден пользователь с id: " + id)); - return toUserDto(user); + return userMapper.toUserDto(user); } @Override @@ -45,7 +44,7 @@ public UserDto create(User user) { checkEmailUniqueness(user); User createdUser = userRepository.create(user); emailSet.add(createdUser.getEmail().toLowerCase()); - return toUserDto(createdUser); + return userMapper.toUserDto(createdUser); } @Override @@ -58,14 +57,10 @@ public UserDto update(User user, Long id) { checkEmailUniqueness(user); emailSet.remove(updatedUser.getEmail().toLowerCase()); emailSet.add(user.getEmail().toLowerCase()); - updatedUser.setEmail(user.getEmail()); - } - - if (user.getName() != null) { - updatedUser.setName(user.getName()); } - return toUserDto(userRepository.update(updatedUser)); + User updated = userMapper.updateUserFields(updatedUser, userMapper.toUserDto(user)); + return userMapper.toUserDto(userRepository.update(updated)); } @Override diff --git a/src/main/java/ru/practicum/shareit/user/UserMapper.java b/src/main/java/ru/practicum/shareit/user/UserMapper.java index e14c522..6dcdc52 100644 --- a/src/main/java/ru/practicum/shareit/user/UserMapper.java +++ b/src/main/java/ru/practicum/shareit/user/UserMapper.java @@ -1,24 +1,18 @@ package ru.practicum.shareit.user; +import org.mapstruct.Mapper; +import org.mapstruct.MappingTarget; +import org.mapstruct.NullValuePropertyMappingStrategy; import ru.practicum.shareit.user.dto.UserDto; import ru.practicum.shareit.user.model.User; -public class UserMapper { - public static UserDto toUserDto(User user) { - return UserDto - .builder() - .id(user.getId()) - .name(user.getName()) - .email(user.getEmail()) - .build(); - } - public static User toUser(UserDto userDto) { - return User - .builder() - .id(userDto.getId()) - .name(userDto.getName()) - .email(userDto.getEmail()) - .build(); - } +@Mapper(componentModel = "spring", nullValuePropertyMappingStrategy = NullValuePropertyMappingStrategy.IGNORE) +public interface UserMapper { + + UserDto toUserDto(User user); + + User toUser(UserDto userDto); + + User updateUserFields(@MappingTarget User targetUser, UserDto sourceUserDto); } \ No newline at end of file diff --git a/src/test/java/ru/practicum/shareit/item/controller/ItemControllerTest.java b/src/test/java/ru/practicum/shareit/item/controller/ItemControllerTest.java index 7020269..ead826a 100644 --- a/src/test/java/ru/practicum/shareit/item/controller/ItemControllerTest.java +++ b/src/test/java/ru/practicum/shareit/item/controller/ItemControllerTest.java @@ -28,6 +28,9 @@ class ItemControllerTest { @Autowired private UserController userController; + @Autowired + private UserMapper userMapper; + private ItemDto itemDto; private UserDto userDto; private Long userId; @@ -38,7 +41,7 @@ void setUp() { .name("Test Owner") .email("owner@email.com") .build(); - UserDto createdUser = userController.create(UserMapper.toUser(userDto)); + UserDto createdUser = userController.create(userMapper.toUser(userDto)); userId = createdUser.getId(); itemDto = ItemDto.builder() @@ -183,7 +186,7 @@ void updateItemByNonOwnerTest() { .name("Another User") .email("another@email.com") .build(); - UserDto anotherUser = userController.create(UserMapper.toUser(anotherUserDto)); + UserDto anotherUser = userController.create(userMapper.toUser(anotherUserDto)); ItemDto updateRequest = ItemDto.builder() .name("Unauthorized Update") diff --git a/src/test/java/ru/practicum/shareit/user/controller/UserControllerTest.java b/src/test/java/ru/practicum/shareit/user/controller/UserControllerTest.java index fb30a7b..c1c5962 100644 --- a/src/test/java/ru/practicum/shareit/user/controller/UserControllerTest.java +++ b/src/test/java/ru/practicum/shareit/user/controller/UserControllerTest.java @@ -24,6 +24,9 @@ class UserControllerTest { @Autowired private UserController userController; + @Autowired + private UserMapper userMapper; + private UserDto userDto; private User user; @@ -34,7 +37,7 @@ void setUp() { .email("test@email.com") .build(); - user = UserMapper.toUser(userDto); + user = userMapper.toUser(userDto); } @Nested // Тесты на создание пользователей @@ -91,7 +94,7 @@ void getAllUsersTest() { .name("Second User") .email("second@email.com") .build(); - userController.create(UserMapper.toUser(secondUser)); + userController.create(userMapper.toUser(secondUser)); List users = userController.getAll();