diff --git a/pom.xml b/pom.xml index 2db888c..a3b4a77 100644 --- a/pom.xml +++ b/pom.xml @@ -17,6 +17,8 @@ 21 + 1.6.3 + 0.2.0 @@ -60,6 +62,19 @@ org.springframework.boot spring-boot-starter-validation + + + org.mapstruct + mapstruct + ${org.mapstruct.version} + + + + org.projectlombok + lombok-mapstruct-binding + ${lombok-mapstruct-binding.version} + + @@ -120,6 +135,32 @@ + + org.apache.maven.plugins + maven-compiler-plugin + 3.8.1 + + 1.8 + 1.8 + + + org.projectlombok + lombok + ${lombok.version} + + + org.mapstruct + mapstruct-processor + ${org.mapstruct.version} + + + org.projectlombok + lombok-mapstruct-binding + ${lombok-mapstruct-binding.version} + + + + com.github.spotbugs spotbugs-maven-plugin diff --git a/src/main/java/ru/practicum/shareit/booking/Booking.java b/src/main/java/ru/practicum/shareit/booking/Booking.java index 2d9c666..8facd50 100644 --- a/src/main/java/ru/practicum/shareit/booking/Booking.java +++ b/src/main/java/ru/practicum/shareit/booking/Booking.java @@ -1,7 +1,16 @@ 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/BookingStatus.java b/src/main/java/ru/practicum/shareit/booking/BookingStatus.java new file mode 100644 index 0000000..51269e0 --- /dev/null +++ b/src/main/java/ru/practicum/shareit/booking/BookingStatus.java @@ -0,0 +1,8 @@ +package ru.practicum.shareit.booking; + +public enum BookingStatus { + WAITING, + APPROVED, + REJECTED, + CANCELED +} diff --git a/src/main/java/ru/practicum/shareit/exception/AnotherUserException.java b/src/main/java/ru/practicum/shareit/exception/AnotherUserException.java new file mode 100644 index 0000000..6fc8434 --- /dev/null +++ b/src/main/java/ru/practicum/shareit/exception/AnotherUserException.java @@ -0,0 +1,8 @@ +package ru.practicum.shareit.exception; + +public class AnotherUserException extends RuntimeException { + + public AnotherUserException(String message) { + super(message); + } +} diff --git a/src/main/java/ru/practicum/shareit/exception/DuplicatedDataException.java b/src/main/java/ru/practicum/shareit/exception/DuplicatedDataException.java new file mode 100644 index 0000000..3aef12f --- /dev/null +++ b/src/main/java/ru/practicum/shareit/exception/DuplicatedDataException.java @@ -0,0 +1,8 @@ +package ru.practicum.shareit.exception; + +public class DuplicatedDataException extends RuntimeException { + + public DuplicatedDataException(String message) { + super(message); + } +} diff --git a/src/main/java/ru/practicum/shareit/exception/ErrorHandler.java b/src/main/java/ru/practicum/shareit/exception/ErrorHandler.java new file mode 100644 index 0000000..d118158 --- /dev/null +++ b/src/main/java/ru/practicum/shareit/exception/ErrorHandler.java @@ -0,0 +1,33 @@ +package ru.practicum.shareit.exception; + +import lombok.extern.slf4j.Slf4j; +import org.springframework.http.HttpStatus; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.ResponseStatus; +import org.springframework.web.bind.annotation.RestControllerAdvice; + +@RestControllerAdvice +@Slf4j +public class ErrorHandler { + + @ExceptionHandler(DuplicatedDataException.class) + @ResponseStatus(HttpStatus.CONFLICT) + public ErrorResponse handleDuplicatedDataException(final DuplicatedDataException e) { + log.error("Duplicated: {}", e.getMessage()); + return new ErrorResponse(e.getMessage(), HttpStatus.CONFLICT); + } + + @ExceptionHandler(NotFoundException.class) + @ResponseStatus(HttpStatus.NOT_FOUND) + public ErrorResponse handleNotFoundException(final NotFoundException e) { + log.error("Not found: {}", e.getMessage()); + return new ErrorResponse(e.getMessage(), HttpStatus.NOT_FOUND); + } + + @ExceptionHandler + @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR) + public ErrorResponse handleException(final RuntimeException e) { + log.error("ServerError: {}", e.getMessage()); + return new ErrorResponse(e.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR); + } +} diff --git a/src/main/java/ru/practicum/shareit/exception/ErrorResponse.java b/src/main/java/ru/practicum/shareit/exception/ErrorResponse.java new file mode 100644 index 0000000..40e1fb8 --- /dev/null +++ b/src/main/java/ru/practicum/shareit/exception/ErrorResponse.java @@ -0,0 +1,16 @@ +package ru.practicum.shareit.exception; + +import lombok.Getter; +import org.springframework.http.HttpStatus; + +@Getter +public class ErrorResponse { + String error; + HttpStatus status; + + public ErrorResponse(String error, HttpStatus status) { + this.error = error; + this.status = status; + } + +} diff --git a/src/main/java/ru/practicum/shareit/exception/NotFoundException.java b/src/main/java/ru/practicum/shareit/exception/NotFoundException.java new file mode 100644 index 0000000..89a2ad0 --- /dev/null +++ b/src/main/java/ru/practicum/shareit/exception/NotFoundException.java @@ -0,0 +1,10 @@ +package ru.practicum.shareit.exception; + +public class NotFoundException extends RuntimeException { + + public NotFoundException(String message) { + super(message); + } + +} + diff --git a/src/main/java/ru/practicum/shareit/exception/ValidationException.java b/src/main/java/ru/practicum/shareit/exception/ValidationException.java new file mode 100644 index 0000000..56cb5a8 --- /dev/null +++ b/src/main/java/ru/practicum/shareit/exception/ValidationException.java @@ -0,0 +1,8 @@ +package ru.practicum.shareit.exception; + +public class ValidationException extends RuntimeException { + + public ValidationException(String message) { + super(message); + } +} diff --git a/src/main/java/ru/practicum/shareit/item/ItemController.java b/src/main/java/ru/practicum/shareit/item/ItemController.java index bb17668..d033939 100644 --- a/src/main/java/ru/practicum/shareit/item/ItemController.java +++ b/src/main/java/ru/practicum/shareit/item/ItemController.java @@ -1,12 +1,53 @@ package ru.practicum.shareit.item; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; -/** - * TODO Sprint add-controllers. - */ +import jakarta.validation.Valid; +import lombok.RequiredArgsConstructor; +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 java.util.Collection; + @RestController @RequestMapping("/items") +@RequiredArgsConstructor +@Slf4j +@Validated public class ItemController { + + public static final String OWNER_ID = "X-Sharer-User-Id"; + private final ItemService itemService; + + @PostMapping + public ItemResponseDto create(@RequestHeader(OWNER_ID) Long ownerId, + @Valid @RequestBody ItemRequestDto item) { + return itemService.createItem(item, ownerId); + } + + @PatchMapping("/{itemId}") + public ItemResponseDto update(@RequestBody ItemRequestDto item, + @PathVariable Long itemId, + @RequestHeader(OWNER_ID) Long ownerId) { + return itemService.updateItem(itemId, item, ownerId); + } + + @GetMapping("/{itemId}") + public ItemResponseDto getItemById(@PathVariable Long itemId) { + return itemService.getItemById(itemId); + } + + @GetMapping + public Collection getAllItemsForOwner( + @RequestHeader(OWNER_ID) Long ownerId) { + return itemService.getAllItemsForOwner(ownerId); + } + + @GetMapping("/search") + public Collection searchItems(@RequestParam String text) { + return itemService.searchByText(text); + } + } diff --git a/src/main/java/ru/practicum/shareit/item/ItemService.java b/src/main/java/ru/practicum/shareit/item/ItemService.java new file mode 100644 index 0000000..9dd0d0c --- /dev/null +++ b/src/main/java/ru/practicum/shareit/item/ItemService.java @@ -0,0 +1,77 @@ +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/ItemStorage.java b/src/main/java/ru/practicum/shareit/item/ItemStorage.java new file mode 100644 index 0000000..6b234d5 --- /dev/null +++ b/src/main/java/ru/practicum/shareit/item/ItemStorage.java @@ -0,0 +1,67 @@ +package ru.practicum.shareit.item; + +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Repository; +import ru.practicum.shareit.item.interfaces.ItemStorageInterface; +import ru.practicum.shareit.item.model.Item; + +import java.util.*; +import java.util.stream.Collectors; + +@Repository +@RequiredArgsConstructor +public class ItemStorage implements ItemStorageInterface { + + private Long nextItemId = 1L; + private final Map items = new HashMap<>(); + + public Item createItem(Item item) { + item.setItemId(nextItemId++); + items.put(item.getItemId(), item); + return item; + } + + public Optional getItemById(Long id) { + return Optional.ofNullable(items.get(id)); + } + + public Item updateItem(Item item) { + Item oldItem = items.get(item.getItemId()); + + if (oldItem != null) { + + if (item.getItemName() != null) { + oldItem.setItemName(item.getItemName()); + } + + if (item.getItemDescription() != null) { + oldItem.setItemDescription(item.getItemDescription()); + } + + if (item.getIsAvailable() != null) { + oldItem.setIsAvailable(item.getIsAvailable()); + } + + } + return oldItem; + } + + public Collection getAllItemsForOwner(Long ownerId) { + return items.values() + .stream() + .filter(item -> Objects.equals(item.getOwnerId(), ownerId)) + .collect(Collectors.toList()); + } + + public Collection searchByText(String text) { + Collection itemCollection = new ArrayList<>(); + for (Item item : items.values()) { + if (item.getItemName().toLowerCase().contains(text.toLowerCase())) { + itemCollection.add(item); + } else if (item.getItemDescription().toLowerCase().contains(text.toLowerCase())) { + itemCollection.add(item); + } + } + return itemCollection; + } +} diff --git a/src/main/java/ru/practicum/shareit/item/dto/ItemDto.java b/src/main/java/ru/practicum/shareit/item/dto/ItemDto.java deleted file mode 100644 index 9319d7d..0000000 --- a/src/main/java/ru/practicum/shareit/item/dto/ItemDto.java +++ /dev/null @@ -1,7 +0,0 @@ -package ru.practicum.shareit.item.dto; - -/** - * TODO Sprint add-controllers. - */ -public class ItemDto { -} diff --git a/src/main/java/ru/practicum/shareit/item/dto/ItemRequestDto.java b/src/main/java/ru/practicum/shareit/item/dto/ItemRequestDto.java new file mode 100644 index 0000000..3b77b82 --- /dev/null +++ b/src/main/java/ru/practicum/shareit/item/dto/ItemRequestDto.java @@ -0,0 +1,33 @@ +package ru.practicum.shareit.item.dto; + +import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.hibernate.validator.constraints.Length; + +@Data +@AllArgsConstructor +@NoArgsConstructor +public class ItemRequestDto { + @JsonProperty("id") + private Long itemId; + + @NotEmpty + @JsonProperty("name") + private String itemName; + + @NotEmpty + @Length(max = 150) + @JsonProperty("description") + private String itemDescription; + + @NotNull + @JsonProperty("available") + private Boolean isAvailable; + + private Long requestId; + +} diff --git a/src/main/java/ru/practicum/shareit/item/dto/ItemResponseDto.java b/src/main/java/ru/practicum/shareit/item/dto/ItemResponseDto.java new file mode 100644 index 0000000..9b50b2b --- /dev/null +++ b/src/main/java/ru/practicum/shareit/item/dto/ItemResponseDto.java @@ -0,0 +1,31 @@ +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; + +@Data +@AllArgsConstructor +@NoArgsConstructor +public class ItemResponseDto { + + @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; +} diff --git a/src/main/java/ru/practicum/shareit/item/interfaces/ItemServiceInterface.java b/src/main/java/ru/practicum/shareit/item/interfaces/ItemServiceInterface.java new file mode 100644 index 0000000..053d40c --- /dev/null +++ b/src/main/java/ru/practicum/shareit/item/interfaces/ItemServiceInterface.java @@ -0,0 +1,19 @@ +package ru.practicum.shareit.item.interfaces; + +import ru.practicum.shareit.item.dto.ItemRequestDto; +import ru.practicum.shareit.item.dto.ItemResponseDto; + +import java.util.Collection; + +public interface ItemServiceInterface { + ItemResponseDto createItem(ItemRequestDto item, Long ownerId); + + ItemResponseDto getItemById(Long id); + + ItemResponseDto updateItem(Long itemId, ItemRequestDto item, Long ownerId); + + Collection getAllItemsForOwner(Long ownerId); + + Collection searchByText(String text); + +} diff --git a/src/main/java/ru/practicum/shareit/item/interfaces/ItemStorageInterface.java b/src/main/java/ru/practicum/shareit/item/interfaces/ItemStorageInterface.java new file mode 100644 index 0000000..0376243 --- /dev/null +++ b/src/main/java/ru/practicum/shareit/item/interfaces/ItemStorageInterface.java @@ -0,0 +1,19 @@ +package ru.practicum.shareit.item.interfaces; + +import ru.practicum.shareit.item.model.Item; + +import java.util.Collection; +import java.util.Optional; + +public interface ItemStorageInterface { + Item createItem(Item item); + + Optional getItemById(Long id); + + Item updateItem(Item item); + + Collection getAllItemsForOwner(Long ownerId); + + Collection searchByText(String text); + +} diff --git a/src/main/java/ru/practicum/shareit/item/mapper/ItemMapper.java b/src/main/java/ru/practicum/shareit/item/mapper/ItemMapper.java new file mode 100644 index 0000000..6835d2c --- /dev/null +++ b/src/main/java/ru/practicum/shareit/item/mapper/ItemMapper.java @@ -0,0 +1,19 @@ +package ru.practicum.shareit.item.mapper; + +import org.mapstruct.Mapper; +import org.mapstruct.MappingConstants; +import ru.practicum.shareit.item.dto.ItemRequestDto; +import ru.practicum.shareit.item.dto.ItemResponseDto; +import ru.practicum.shareit.item.model.Item; + +@Mapper(componentModel = MappingConstants.ComponentModel.SPRING) +public interface ItemMapper { + ItemResponseDto toItemResponseDto(ItemRequestDto itemRequestDto); + + ItemRequestDto toItemRequestDto(ItemResponseDto itemDtoResponseDto); + + Item toItem(ItemRequestDto itemRequestDto); + + ItemResponseDto toItemResponseDto(Item item); + +} 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..6fcf2d1 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,20 @@ package ru.practicum.shareit.item.model; -/** - * TODO Sprint add-controllers. - */ +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + + +@Data +@NoArgsConstructor +@AllArgsConstructor public class Item { + + private Long itemId; + private String itemName; + private String itemDescription; + private Boolean isAvailable; + private Long ownerId; + private Long requestId; + } diff --git a/src/main/java/ru/practicum/shareit/request/ItemRequest.java b/src/main/java/ru/practicum/shareit/request/ItemRequest.java index 95d6f23..c12fab1 100644 --- a/src/main/java/ru/practicum/shareit/request/ItemRequest.java +++ b/src/main/java/ru/practicum/shareit/request/ItemRequest.java @@ -1,7 +1,13 @@ package ru.practicum.shareit.request; +import java.time.LocalDate; + /** * TODO Sprint add-item-requests. */ public class ItemRequest { + private Long itemRequestId; + private String requestDescription; + private Long requesterId; + private LocalDate requestDate; } 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 index 03039b9..4c334a4 100644 --- a/src/main/java/ru/practicum/shareit/user/UserController.java +++ b/src/main/java/ru/practicum/shareit/user/UserController.java @@ -1,12 +1,42 @@ package ru.practicum.shareit.user; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; +import jakarta.validation.Valid; +import lombok.RequiredArgsConstructor; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; +import ru.practicum.shareit.user.dto.UserRequestDto; +import ru.practicum.shareit.user.dto.UserResponseDto; -/** - * TODO Sprint add-controllers. - */ @RestController +@Validated @RequestMapping(path = "/users") +@RequiredArgsConstructor public class UserController { + private final UserService userService; + + @PostMapping + public UserResponseDto createUser(@Valid @RequestBody UserRequestDto user) { + return userService.createUser(user); + } + + @GetMapping("/{id}") + public UserResponseDto getUser(@PathVariable long id) { + return userService.getUserById(id); + } + + @PatchMapping("/{id}") + public UserResponseDto updateUser(@PathVariable long id, @RequestBody UserRequestDto user) { + return userService.updateUser(id, user); + } + + @DeleteMapping("/{id}") + public void deleteUser(@PathVariable long id) { + userService.deleteUser(id); + } + + @DeleteMapping + public void deleteUser() { + userService.deleteAllUsers(); + } + } diff --git a/src/main/java/ru/practicum/shareit/user/UserService.java b/src/main/java/ru/practicum/shareit/user/UserService.java new file mode 100644 index 0000000..e4c8802 --- /dev/null +++ b/src/main/java/ru/practicum/shareit/user/UserService.java @@ -0,0 +1,63 @@ +package ru.practicum.shareit.user; + +import lombok.AllArgsConstructor; +import org.springframework.stereotype.Service; +import ru.practicum.shareit.exception.DuplicatedDataException; +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.UserServiceInterface; +import ru.practicum.shareit.user.mapper.UserMapper; +import ru.practicum.shareit.user.model.User; + +import java.util.Collection; +import java.util.Optional; + +@Service +@AllArgsConstructor +public class UserService implements UserServiceInterface { + + private final UserStorage userStorage; + private final UserMapper userMapper; + + public UserResponseDto createUser(UserRequestDto user) { + validateEmail(user.getUserEmail()); + User newUser = userMapper.toUser(user); + return userMapper.toUserResponseDto(userStorage.createUser(newUser)); + } + + public UserResponseDto getUserById(Long userId) throws NotFoundException { + return userMapper.toUserResponseDto(userStorage.getUserById(userId) + .orElseThrow(() -> new NotFoundException("User not found, id = " + userId))); + } + + public UserResponseDto updateUser(Long userId, UserRequestDto user) throws NotFoundException { + validateEmail(user.getUserEmail()); + return userMapper.toUserResponseDto(userStorage.updateUser(userId, userMapper.toUser(user))); + } + + public void deleteUser(Long userId) throws NotFoundException { + getUserById(userId); + userStorage.deleteUser(userId); + } + + public void deleteAllUsers() { + userStorage.deleteAllUsers(); + } + + private void validateEmail(String email) { + Collection users = userStorage.getAllUsers(); + + if (!users.isEmpty()) { + Optional first = + userStorage.getAllUsers().stream() + .map(User::getUserEmail) + .filter(userEmail -> userEmail.equals(email)) + .findFirst(); + + if (first.isPresent()) { + throw new DuplicatedDataException("User with email " + email + " already exists"); + } + } + } +} diff --git a/src/main/java/ru/practicum/shareit/user/UserStorage.java b/src/main/java/ru/practicum/shareit/user/UserStorage.java new file mode 100644 index 0000000..040839d --- /dev/null +++ b/src/main/java/ru/practicum/shareit/user/UserStorage.java @@ -0,0 +1,53 @@ +package ru.practicum.shareit.user; + +import org.springframework.stereotype.Repository; +import ru.practicum.shareit.user.interfaces.UserStorageInterface; +import ru.practicum.shareit.user.model.User; + +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; + +@Repository +public class UserStorage implements UserStorageInterface { + + private final Map users = new HashMap<>(); + private Long nextUserId = 1L; + + public User createUser(User user) { + user.setUserId(nextUserId++); + users.put(user.getUserId(), user); + return user; + } + + public Optional getUserById(Long userId) { + return Optional.ofNullable(users.get(userId)); + } + + public User updateUser(Long userId, User user) { + User oldUser = users.get(userId); + + if (user.getUserName() != null) { + oldUser.setUserName(user.getUserName()); + } + + if (user.getUserEmail() != null) { + oldUser.setUserEmail(user.getUserEmail()); + } + + return oldUser; + } + + public Collection getAllUsers() { + return users.values(); + } + + public void deleteUser(Long userId) { + users.remove(userId); + } + + public void deleteAllUsers() { + users.clear(); + } +} diff --git a/src/main/java/ru/practicum/shareit/user/dto/UserRequestDto.java b/src/main/java/ru/practicum/shareit/user/dto/UserRequestDto.java new file mode 100644 index 0000000..b396c14 --- /dev/null +++ b/src/main/java/ru/practicum/shareit/user/dto/UserRequestDto.java @@ -0,0 +1,27 @@ +package ru.practicum.shareit.user.dto; + +import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.constraints.Email; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@NoArgsConstructor +@AllArgsConstructor +public class UserRequestDto { + + @JsonProperty("id") + private Long userId; + + @NotBlank + @JsonProperty("name") + private String userName; + + @NotNull + @Email + @JsonProperty("email") + private String userEmail; +} diff --git a/src/main/java/ru/practicum/shareit/user/dto/UserResponseDto.java b/src/main/java/ru/practicum/shareit/user/dto/UserResponseDto.java new file mode 100644 index 0000000..bed79f2 --- /dev/null +++ b/src/main/java/ru/practicum/shareit/user/dto/UserResponseDto.java @@ -0,0 +1,22 @@ +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 +@NoArgsConstructor +@AllArgsConstructor +public class UserResponseDto { + @NotNull + @JsonProperty("id") + private Long userId; + + @JsonProperty("name") + private String userName; + + @JsonProperty("email") + private String userEmail; +} diff --git a/src/main/java/ru/practicum/shareit/user/interfaces/UserServiceInterface.java b/src/main/java/ru/practicum/shareit/user/interfaces/UserServiceInterface.java new file mode 100644 index 0000000..1ca30dc --- /dev/null +++ b/src/main/java/ru/practicum/shareit/user/interfaces/UserServiceInterface.java @@ -0,0 +1,16 @@ +package ru.practicum.shareit.user.interfaces; + +import ru.practicum.shareit.user.dto.UserRequestDto; +import ru.practicum.shareit.user.dto.UserResponseDto; + +public interface UserServiceInterface { + UserResponseDto createUser(UserRequestDto user); + + UserResponseDto getUserById(Long userId); + + UserResponseDto updateUser(Long userId, UserRequestDto user); + + void deleteUser(Long userId); + + void deleteAllUsers(); +} diff --git a/src/main/java/ru/practicum/shareit/user/interfaces/UserStorageInterface.java b/src/main/java/ru/practicum/shareit/user/interfaces/UserStorageInterface.java new file mode 100644 index 0000000..dafdbf4 --- /dev/null +++ b/src/main/java/ru/practicum/shareit/user/interfaces/UserStorageInterface.java @@ -0,0 +1,20 @@ +package ru.practicum.shareit.user.interfaces; + +import ru.practicum.shareit.user.model.User; + +import java.util.Collection; +import java.util.Optional; + +public interface UserStorageInterface { + User createUser(User user); + + Optional getUserById(Long userId); + + User updateUser(Long userId, User user); + + Collection getAllUsers(); + + void deleteUser(Long userId); + + void deleteAllUsers(); +} diff --git a/src/main/java/ru/practicum/shareit/user/mapper/UserMapper.java b/src/main/java/ru/practicum/shareit/user/mapper/UserMapper.java new file mode 100644 index 0000000..086a773 --- /dev/null +++ b/src/main/java/ru/practicum/shareit/user/mapper/UserMapper.java @@ -0,0 +1,20 @@ +package ru.practicum.shareit.user.mapper; + +import org.mapstruct.InjectionStrategy; +import org.mapstruct.Mapper; +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) +public interface UserMapper { + + UserRequestDto toUserRequestDto(User user); + + User toUser(UserRequestDto userDto); + + UserResponseDto toUserResponseDto(User user); + + User toUser(UserResponseDto userDto); +} 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..c7c00cc --- /dev/null +++ b/src/main/java/ru/practicum/shareit/user/model/User.java @@ -0,0 +1,14 @@ +package ru.practicum.shareit.user.model; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@NoArgsConstructor +@AllArgsConstructor +public class User { + private Long userId; + private String userName; + private String userEmail; +} diff --git a/src/test/java/ru/practicum/shareit/ItemMapperTest.java b/src/test/java/ru/practicum/shareit/ItemMapperTest.java new file mode 100644 index 0000000..05ba9ca --- /dev/null +++ b/src/test/java/ru/practicum/shareit/ItemMapperTest.java @@ -0,0 +1,81 @@ +package ru.practicum.shareit; + +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.mapper.ItemMapper; +import ru.practicum.shareit.item.model.Item; + +import static org.junit.jupiter.api.Assertions.*; + +@SpringBootTest +public class ItemMapperTest { + + @Autowired + private ItemMapper itemMapper; + + @Test + public void itemRequestDtoToItemTest() { + ItemRequestDto itemRequestDto = new ItemRequestDto( + 1L, "TestName", "Test description", true, 1L); + + Item item = itemMapper.toItem(itemRequestDto); + + assertAll(() -> { + assertEquals(1L, item.getItemId()); + assertEquals("TestName", item.getItemName()); + assertEquals("Test description", item.getItemDescription()); + assertEquals(true, item.getIsAvailable()); + assertNull(item.getOwnerId()); + assertEquals(1L, item.getRequestId()); + }); + } + + @Test + public void itemToItemResponseDtoTest() { + Item item = new Item(2L, "TestName2", "Test description2", true, 2L, 2L); + + ItemResponseDto itemResponseDto = itemMapper.toItemResponseDto(item); + assertAll(() -> { + assertEquals(2L, itemResponseDto.getItemId()); + assertEquals("TestName2", itemResponseDto.getItemName()); + assertEquals("Test description2", itemResponseDto.getItemDescription()); + assertEquals(true, itemResponseDto.getIsAvailable()); + assertEquals(2L, itemResponseDto.getOwnerId()); + assertEquals(2L, itemResponseDto.getRequestId()); + }); + } + + @Test + public void itemRequestDtoToItemResponseDtoTest() { + ItemRequestDto item = new ItemRequestDto( + 3L, "TestName3", "Test description3", false, 3L); + + ItemResponseDto itemResponseDto = itemMapper.toItemResponseDto(item); + assertAll(() -> { + assertEquals(3L, itemResponseDto.getItemId()); + assertEquals("TestName3", itemResponseDto.getItemName()); + assertEquals("Test description3", itemResponseDto.getItemDescription()); + assertEquals(false, itemResponseDto.getIsAvailable()); + assertNull(itemResponseDto.getOwnerId()); + assertEquals(3L, itemResponseDto.getRequestId()); + }); + } + + @Test + public void itemResponseDtoToItemRequestDtoTest() { + ItemResponseDto itemResponseDto = new ItemResponseDto( + 4L, "TestName4", "Test description4", false, 4L, 4L); + ItemRequestDto itemRequestDto = itemMapper.toItemRequestDto(itemResponseDto); + assertAll(() -> { + assertEquals(4L, itemRequestDto.getItemId()); + assertEquals("TestName4", itemRequestDto.getItemName()); + assertEquals("Test description4", itemRequestDto.getItemDescription()); + assertEquals(false, itemRequestDto.getIsAvailable()); + assertEquals(4L, itemRequestDto.getRequestId()); + }); + } + +} diff --git a/src/test/java/ru/practicum/shareit/UserMapperTest.java b/src/test/java/ru/practicum/shareit/UserMapperTest.java new file mode 100644 index 0000000..0bd6da2 --- /dev/null +++ b/src/test/java/ru/practicum/shareit/UserMapperTest.java @@ -0,0 +1,65 @@ +package ru.practicum.shareit; + +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.UserRequestDto; +import ru.practicum.shareit.user.dto.UserResponseDto; +import ru.practicum.shareit.user.mapper.UserMapper; +import ru.practicum.shareit.user.model.User; + +import static org.junit.jupiter.api.Assertions.assertAll; +import static org.junit.jupiter.api.Assertions.assertEquals; + +@SpringBootTest +public class UserMapperTest { + + @Autowired + private UserMapper userMapper; + + @Test + public void userToUserRequestDtoTest() { + User user = new User(1L, "TestName", "test@test.com"); + + UserRequestDto userRequestDto = userMapper.toUserRequestDto(user); + + assertAll(() -> { + assertEquals(1L, userRequestDto.getUserId()); + assertEquals("TestName", userRequestDto.getUserName()); + assertEquals("test@test.com", userRequestDto.getUserEmail()); + }); + } + + @Test + public void userRequestDtoToUserTest() { + UserRequestDto userRequestDto = new UserRequestDto(2L, "TestName2", "test2@test.com"); + User user = userMapper.toUser(userRequestDto); + assertAll(() -> { + assertEquals(2L, user.getUserId()); + assertEquals("TestName2", user.getUserName()); + assertEquals("test2@test.com", user.getUserEmail()); + }); + } + + @Test + public void userResponseDtoToUserTest() { + UserResponseDto userResponseDto = new UserResponseDto(3L, "TestName3", "test3@test.com"); + User user = userMapper.toUser(userResponseDto); + assertAll(() -> { + assertEquals(3L, user.getUserId()); + assertEquals("TestName3", user.getUserName()); + assertEquals("test3@test.com", user.getUserEmail()); + }); + } + + @Test + public void userToUserResponseDtoTest() { + User user = new User(4L, "TestName4", "test4@test.com"); + UserResponseDto userResponseDto = userMapper.toUserResponseDto(user); + assertAll(() -> { + assertEquals(4L, userResponseDto.getUserId()); + assertEquals("TestName4", userResponseDto.getUserName()); + assertEquals("test4@test.com", userResponseDto.getUserEmail()); + }); + } +}