-
Notifications
You must be signed in to change notification settings - Fork 0
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add bookings #4
Add bookings #4
Changes from 1 commit
1535b24
64380a7
40dd118
8dc1079
5adcb0c
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
This file was deleted.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,12 +1,71 @@ | ||
package ru.practicum.shareit.booking; | ||
|
||
import jakarta.validation.Valid; | ||
import lombok.RequiredArgsConstructor; | ||
import org.springframework.validation.annotation.Validated; | ||
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.booking.dto.BookingDtoResponse; | ||
import ru.practicum.shareit.booking.dto.NewBookingDtoRequest; | ||
import ru.practicum.shareit.booking.model.BookingState; | ||
import ru.practicum.shareit.booking.service.BookingService; | ||
import ru.practicum.shareit.validationMarker.Marker; | ||
|
||
import java.util.List; | ||
|
||
/** | ||
* TODO Sprint add-bookings. | ||
*/ | ||
@RestController | ||
@RequiredArgsConstructor | ||
@RequestMapping(path = "/bookings") | ||
@Validated | ||
public class BookingController { | ||
private final BookingService bookingService; | ||
private static final String USER_ID = "X-Sharer-User-Id"; | ||
|
||
@PostMapping | ||
@Validated(Marker.OnCreate.class) | ||
public BookingDtoResponse createBooking(@RequestBody @Valid NewBookingDtoRequest dto, | ||
@RequestHeader(USER_ID) long userId) { | ||
dto.setBookerId(userId); | ||
return bookingService.createBooking(dto); | ||
} | ||
|
||
@PatchMapping("/{bookingId}") | ||
public BookingDtoResponse decideRent(@PathVariable long bookingId, | ||
@RequestHeader(USER_ID) long userId, | ||
@RequestParam boolean approved) { | ||
if (approved) { | ||
return bookingService.approveBooking(bookingId, userId); | ||
} else | ||
return bookingService.rejectBooking(bookingId, userId); | ||
} | ||
|
||
@GetMapping("/{bookingId}") | ||
public BookingDtoResponse getBookingByIdOfBookerOrOwner(@PathVariable long bookingId, | ||
@RequestHeader(USER_ID) long userId) { | ||
return bookingService.getBookingByIdOfBookerOrOwner(bookingId, userId); | ||
} | ||
|
||
@GetMapping | ||
public List<BookingDtoResponse> getAllBookingsByBooker(@RequestHeader(USER_ID) long userId, | ||
@RequestParam(name = "state", defaultValue = "ALL") String stateParam) { | ||
BookingState state = BookingState.parseString(stateParam); | ||
return bookingService.getAllBookingsByBooker(userId, state); | ||
} | ||
|
||
@GetMapping("/owner") | ||
public List<BookingDtoResponse> getAllBookingsByOwner(@RequestHeader(USER_ID) long userId, | ||
@RequestParam(name = "state", defaultValue = "ALL") String stateParam) { | ||
BookingState state = BookingState.parseString(stateParam); | ||
return bookingService.getAllBookingsByOwner(userId, state); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
package ru.practicum.shareit.booking; | ||
|
||
import org.springframework.data.jpa.repository.JpaRepository; | ||
import org.springframework.data.jpa.repository.Query; | ||
import org.springframework.data.querydsl.QuerydslPredicateExecutor; | ||
import ru.practicum.shareit.booking.model.Booking; | ||
|
||
import java.time.LocalDateTime; | ||
import java.util.List; | ||
import java.util.Optional; | ||
|
||
public interface BookingRepository extends JpaRepository<Booking, Long>, QuerydslPredicateExecutor<Booking> { | ||
@Query(value = """ | ||
select b from Booking as b where b.id=?1 and (b.booker.id=?2 or b.item.owner.id=?2) | ||
""") | ||
Optional<Booking> findById(long bookingId, long userId); | ||
|
||
@Query(value = """ | ||
select b from Booking as b where b.item.id in ?1 | ||
and b.status='APPROVED' | ||
and b.startTime < ?2 | ||
order by b.startTime desc | ||
limit 1 | ||
""") | ||
Optional<Booking> findByItemLastBooking(Long itemId, LocalDateTime now); | ||
|
||
@Query(value = """ | ||
select b from Booking as b where b.item.id in ?1 | ||
and b.status='APPROVED' | ||
and b.startTime > ?2 | ||
order by b.startTime asc | ||
limit 1 | ||
""") | ||
Optional<Booking> findByItemNextBooking(Long itemId, LocalDateTime now); | ||
|
||
@Query(value = """ | ||
select b from Booking as b where b.item.id in ?1 | ||
and b.status='APPROVED' | ||
and b.startTime < ?2 | ||
order by b.startTime desc | ||
""") | ||
List<Booking> findAllByItemsLastBooking(List<Long> itemIds, LocalDateTime now); | ||
|
||
@Query(value = """ | ||
select b from Booking as b where b.item.id in ?1 | ||
and b.status='APPROVED' | ||
and b.startTime > ?2 | ||
order by b.startTime asc | ||
""") | ||
List<Booking> findAllByItemsNextBooking(List<Long> itemIds, LocalDateTime now); | ||
|
||
List<Booking> findAllByItemId(Long itemId); | ||
} | ||
|
This file was deleted.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
package ru.practicum.shareit.booking.dto; | ||
|
||
import lombok.AllArgsConstructor; | ||
import lombok.Builder; | ||
import lombok.Getter; | ||
import lombok.Setter; | ||
|
||
import java.time.LocalDateTime; | ||
|
||
/** | ||
* TODO Sprint add-bookings. | ||
*/ | ||
@Getter | ||
@Setter | ||
@Builder | ||
public class BookingDtoResponse { | ||
private long id; | ||
private ItemDtoResponse item; | ||
private UserDtoResponse booker; | ||
private LocalDateTime start; | ||
private LocalDateTime end; | ||
private String status; | ||
|
||
@Setter | ||
@Getter | ||
@Builder | ||
static class ItemDtoResponse { | ||
private long id; | ||
private String name; | ||
} | ||
|
||
@Setter | ||
@Getter | ||
@AllArgsConstructor | ||
static class UserDtoResponse { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. а вместо этого long userId There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. здесь так же по тестам проверяется booker.id. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. а тут тогда BookerDto booker |
||
private long id; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
package ru.practicum.shareit.booking.dto; | ||
|
||
import org.springframework.stereotype.Component; | ||
import ru.practicum.shareit.booking.model.Booking; | ||
import ru.practicum.shareit.booking.model.Status; | ||
import ru.practicum.shareit.item.Item; | ||
import ru.practicum.shareit.user.User; | ||
|
||
import java.util.List; | ||
|
||
@Component | ||
public class BookingMapper { | ||
|
||
public Booking toNewBooking(NewBookingDtoRequest dto, Item item, User booker) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. хорошо бы проверять на null входящие в метод параметры There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. если проверю дто на нулл, этого же достаточно будет? item и booker если будет нулл то NPE не должно быть, методы их не вызываем. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. да достаточно проверить объект |
||
return Booking.builder() | ||
.item(item) | ||
.booker(booker) | ||
.startTime(dto.getStart()) | ||
.endTime(dto.getEnd()) | ||
.status(Status.WAITING) | ||
.build(); | ||
} | ||
|
||
public BookingDtoResponse toBookingDtoResponse(Booking booking) { | ||
return BookingDtoResponse.builder() | ||
.id(booking.getId()) | ||
.item(BookingDtoResponse.ItemDtoResponse.builder() | ||
.id(booking.getItem().getId()) | ||
.name(booking.getItem().getName()) | ||
.build()) | ||
.booker(new BookingDtoResponse.UserDtoResponse(booking.getBooker().getId())) | ||
.start(booking.getStartTime()) | ||
.end(booking.getEndTime()) | ||
.status(booking.getStatus().toString()) | ||
Nikolaev-Java marked this conversation as resolved.
Show resolved
Hide resolved
|
||
.build(); | ||
} | ||
|
||
public List<BookingDtoResponse> toBookingDtoResponse(List<Booking> bookings) { | ||
return bookings.stream().map(this::toBookingDtoResponse).toList(); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
package ru.practicum.shareit.booking.dto; | ||
|
||
import jakarta.validation.constraints.Future; | ||
import jakarta.validation.constraints.FutureOrPresent; | ||
import jakarta.validation.constraints.NotNull; | ||
import lombok.Builder; | ||
import lombok.Getter; | ||
import lombok.Setter; | ||
import ru.practicum.shareit.booking.validation.StartBeforeEnd; | ||
import ru.practicum.shareit.validationMarker.Marker; | ||
|
||
import java.time.LocalDateTime; | ||
|
||
@Getter | ||
@Setter | ||
@Builder | ||
@StartBeforeEnd | ||
public class NewBookingDtoRequest { | ||
@NotNull(message = "Item id must not be null") | ||
private Long itemId; | ||
private long bookerId; | ||
@NotNull(message = "Start time booking must not be null", groups = Marker.OnCreate.class) | ||
@FutureOrPresent(message = "Start time cannot be in the past", groups = Marker.OnCreate.class) | ||
private LocalDateTime start; | ||
@NotNull(message = "End time booking must not be null", groups = Marker.OnCreate.class) | ||
@Future(message = "End time cannot be in the past", groups = Marker.OnCreate.class) | ||
private LocalDateTime end; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
package ru.practicum.shareit.booking.model; | ||
|
||
import jakarta.persistence.Column; | ||
import jakarta.persistence.Entity; | ||
import jakarta.persistence.EnumType; | ||
import jakarta.persistence.Enumerated; | ||
import jakarta.persistence.FetchType; | ||
import jakarta.persistence.GeneratedValue; | ||
import jakarta.persistence.GenerationType; | ||
import jakarta.persistence.Id; | ||
import jakarta.persistence.JoinColumn; | ||
import jakarta.persistence.ManyToOne; | ||
import jakarta.persistence.Table; | ||
import lombok.AllArgsConstructor; | ||
import lombok.Builder; | ||
import lombok.EqualsAndHashCode; | ||
import lombok.Getter; | ||
import lombok.NoArgsConstructor; | ||
import lombok.Setter; | ||
import ru.practicum.shareit.item.Item; | ||
import ru.practicum.shareit.user.User; | ||
|
||
import java.time.LocalDateTime; | ||
|
||
/** | ||
* TODO Sprint add-bookings. | ||
*/ | ||
@Getter | ||
@Setter | ||
@Builder | ||
@NoArgsConstructor | ||
@AllArgsConstructor | ||
@EqualsAndHashCode(of = "id") | ||
@Entity | ||
@Table(name = "bookings") | ||
public class Booking { | ||
@Id | ||
@GeneratedValue(strategy = GenerationType.IDENTITY) | ||
private Long id; | ||
@ManyToOne(fetch = FetchType.LAZY) | ||
@JoinColumn(name = "item_id") | ||
private Item item; | ||
@ManyToOne(fetch = FetchType.LAZY) | ||
@JoinColumn(name = "user_id") | ||
private User booker; | ||
@Column(name = "start_time") | ||
private LocalDateTime startTime; | ||
@Column(name = "end_time") | ||
private LocalDateTime endTime; | ||
@Enumerated(EnumType.STRING) | ||
private Status status; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
package ru.practicum.shareit.booking.model; | ||
|
||
public enum BookingState { | ||
ALL, CURRENT, PAST, FUTURE, WAITING, REJECTED; | ||
|
||
public static BookingState parseString(String state) { | ||
return switch (state.toUpperCase()) { | ||
case "ALL" -> ALL; | ||
case "CURRENT" -> CURRENT; | ||
case "PAST" -> PAST; | ||
case "FUTURE" -> FUTURE; | ||
case "WAITING" -> WAITING; | ||
case "REJECTED" -> REJECTED; | ||
default -> throw new IllegalArgumentException("Unknown state: " + state); | ||
}; | ||
} | ||
Nikolaev-Java marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
package ru.practicum.shareit.booking.model; | ||
|
||
public enum Status { | ||
WAITING, APPROVED, REJECTED, CANCELLED | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
может тут использовать поле с типом ItemDto просто?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
дело в том что в тестах постман проверяются поля item.id и item.name. То есть в json должен объект с такими полями.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ну так оно и будет, если сделать ItemDto item
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ну в ItemDto есть еще поля description и available, а они в выводе не нужны, поэтому и внутренний класс в котором полей меньше. Я просто сделал дополнительные ДТО с меньшим количеством полей, только те которые проверяются в постман тестах
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
не нужны, но ты не должен создавать дто под каждую необходимость, используй те поля, которые нужны. Так как ты делаешь сейчас ты перегружаешь свою сущность. В общем так не делают)