Skip to content

Commit f2b74a4

Browse files
committed
Update BookingResponseDto, comment check, and item last/next visibility
1 parent 6987872 commit f2b74a4

34 files changed

Lines changed: 701 additions & 336 deletions

pom.xml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,17 @@
6060
<groupId>org.springframework.boot</groupId>
6161
<artifactId>spring-boot-starter-validation</artifactId>
6262
</dependency>
63+
64+
<dependency>
65+
<groupId>org.springframework.boot</groupId>
66+
<artifactId>spring-boot-starter-data-jpa</artifactId>
67+
</dependency>
68+
69+
<dependency>
70+
<groupId>org.postgresql</groupId>
71+
<artifactId>postgresql</artifactId>
72+
<scope>runtime</scope>
73+
</dependency>
6374
</dependencies>
6475

6576
<build>

src/main/java/ru/practicum/shareit/booking/controller/BookingController.java

Lines changed: 23 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,11 @@
55
import org.springframework.web.bind.annotation.*;
66
import ru.practicum.shareit.booking.dto.BookingCreateRequest;
77
import ru.practicum.shareit.booking.dto.BookingResponseDto;
8-
import ru.practicum.shareit.booking.dto.BookingUpdateRequest;
8+
import ru.practicum.shareit.booking.dto.BookingState;
99
import ru.practicum.shareit.booking.service.BookingService;
1010

11+
import java.util.List;
12+
1113
@RestController
1214
@RequestMapping(path = "/bookings")
1315
@RequiredArgsConstructor
@@ -21,13 +23,27 @@ public BookingResponseDto createBooking(@Valid @RequestBody BookingCreateRequest
2123
}
2224

2325
@PatchMapping("/{bookingId}")
24-
public BookingResponseDto updateBooking(@PathVariable Long bookingId,
25-
@RequestBody BookingUpdateRequest updateRequest) {
26-
return bookingService.updateBooking(bookingId, updateRequest);
26+
public BookingResponseDto approveBooking(@PathVariable Long bookingId,
27+
@RequestParam boolean approved,
28+
@RequestHeader("X-Sharer-User-Id") Long userId) {
29+
return bookingService.approveBooking(bookingId, approved, userId);
2730
}
2831

2932
@GetMapping("/{bookingId}")
30-
public BookingResponseDto getBookingById(@PathVariable Long bookingId) {
31-
return bookingService.getBookingById(bookingId);
33+
public BookingResponseDto getBookingById(@PathVariable Long bookingId,
34+
@RequestHeader("X-Sharer-User-Id") Long userId) {
35+
return bookingService.getBookingById(bookingId, userId);
36+
}
37+
38+
@GetMapping
39+
public List<BookingResponseDto> getUserBookings(@RequestParam(defaultValue = "ALL") BookingState state,
40+
@RequestHeader("X-Sharer-User-Id") Long userId) {
41+
return bookingService.getUserBookings(userId, state);
42+
}
43+
44+
@GetMapping("/owner")
45+
public List<BookingResponseDto> getOwnerBookings(@RequestParam(defaultValue = "ALL") BookingState state,
46+
@RequestHeader("X-Sharer-User-Id") Long ownerId) {
47+
return bookingService.getOwnerBookings(ownerId, state);
3248
}
33-
}
49+
}
Lines changed: 4 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
package ru.practicum.shareit.booking.dto;
22

33
import ru.practicum.shareit.booking.model.Booking;
4+
import ru.practicum.shareit.item.dto.ItemMapper;
45
import ru.practicum.shareit.item.model.Item;
6+
import ru.practicum.shareit.user.dto.UserMapper;
57
import ru.practicum.shareit.user.model.User;
68

79
public class BookingMapper {
@@ -11,8 +13,8 @@ public static BookingResponseDto toResponseDto(Booking booking) {
1113
dto.setId(booking.getId());
1214
dto.setStart(booking.getStart());
1315
dto.setEnd(booking.getEnd());
14-
dto.setItemId(booking.getItem() != null ? booking.getItem().getId() : null);
15-
dto.setBookerId(booking.getBooker() != null ? booking.getBooker().getId() : null);
16+
dto.setItem(ItemMapper.toResponseDto(booking.getItem()));
17+
dto.setBooker(UserMapper.toResponseDto(booking.getBooker()));
1618
dto.setStatus(booking.getStatus());
1719
return dto;
1820
}
@@ -25,16 +27,4 @@ public static Booking fromCreateRequest(BookingCreateRequest bookingCreateReques
2527
booking.setBooker(booker);
2628
return booking;
2729
}
28-
29-
public static void updateBookingFromRequest(BookingUpdateRequest request, Booking booking) {
30-
if (request.getStart() != null) {
31-
booking.setStart(request.getStart());
32-
}
33-
if (request.getEnd() != null) {
34-
booking.setEnd(request.getEnd());
35-
}
36-
if (request.getStatus() != null) {
37-
booking.setStatus(request.getStatus());
38-
}
39-
}
4030
}

src/main/java/ru/practicum/shareit/booking/dto/BookingResponseDto.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
import lombok.Data;
44
import ru.practicum.shareit.booking.model.BookingStatus;
5+
import ru.practicum.shareit.item.dto.ItemResponseDto;
6+
import ru.practicum.shareit.user.dto.UserResponseDto;
57

68
import java.time.LocalDateTime;
79

@@ -10,7 +12,7 @@ public class BookingResponseDto {
1012
private Long id;
1113
private LocalDateTime start;
1214
private LocalDateTime end;
13-
private Long itemId;
14-
private Long bookerId;
15+
private ItemResponseDto item;
16+
private UserResponseDto booker;
1517
private BookingStatus status;
1618
}

src/main/java/ru/practicum/shareit/booking/dto/BookingUpdateRequest.java renamed to src/main/java/ru/practicum/shareit/booking/dto/BookingShortDto.java

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,12 @@
11
package ru.practicum.shareit.booking.dto;
22

33
import lombok.Data;
4-
import ru.practicum.shareit.booking.model.BookingStatus;
5-
64
import java.time.LocalDateTime;
75

86
@Data
9-
public class BookingUpdateRequest {
7+
public class BookingShortDto {
8+
private Long id;
109
private LocalDateTime start;
1110
private LocalDateTime end;
12-
private BookingStatus status;
11+
private Long bookerId;
1312
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
package ru.practicum.shareit.booking.dto;
2+
3+
public enum BookingState {
4+
ALL,
5+
CURRENT,
6+
PAST,
7+
FUTURE,
8+
WAITING,
9+
REJECTED
10+
}
Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,38 @@
11
package ru.practicum.shareit.booking.model;
22

3-
import lombok.AllArgsConstructor;
3+
import jakarta.persistence.*;
44
import lombok.Data;
55
import lombok.NoArgsConstructor;
6+
import lombok.AllArgsConstructor;
67
import ru.practicum.shareit.item.model.Item;
78
import ru.practicum.shareit.user.model.User;
8-
99
import java.time.LocalDateTime;
1010

11+
@Entity
12+
@Table(name = "bookings")
1113
@Data
1214
@NoArgsConstructor
1315
@AllArgsConstructor
1416
public class Booking {
17+
@Id
18+
@GeneratedValue(strategy = GenerationType.IDENTITY)
1519
private Long id;
20+
21+
@Column(name = "start_date", nullable = false)
1622
private LocalDateTime start;
23+
24+
@Column(name = "end_date", nullable = false)
1725
private LocalDateTime end;
26+
27+
@ManyToOne
28+
@JoinColumn(name = "item_id", nullable = false)
1829
private Item item;
30+
31+
@ManyToOne
32+
@JoinColumn(name = "booker_id", nullable = false)
1933
private User booker;
34+
35+
@Enumerated(EnumType.STRING)
36+
@Column(length = 20, nullable = false)
2037
private BookingStatus status;
2138
}

src/main/java/ru/practicum/shareit/booking/service/BookingService.java

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,18 @@
22

33
import ru.practicum.shareit.booking.dto.BookingCreateRequest;
44
import ru.practicum.shareit.booking.dto.BookingResponseDto;
5-
import ru.practicum.shareit.booking.dto.BookingUpdateRequest;
5+
import ru.practicum.shareit.booking.dto.BookingState;
6+
7+
import java.util.List;
68

79
public interface BookingService {
810
BookingResponseDto createBooking(BookingCreateRequest createRequest, Long bookerId);
911

10-
BookingResponseDto updateBooking(Long bookingId, BookingUpdateRequest updateRequest);
12+
BookingResponseDto approveBooking(Long bookingId, boolean approved, Long userId);
13+
14+
BookingResponseDto getBookingById(Long bookingId, Long userId);
15+
16+
List<BookingResponseDto> getUserBookings(Long userId, BookingState state);
1117

12-
BookingResponseDto getBookingById(Long bookingId);
18+
List<BookingResponseDto> getOwnerBookings(Long ownerId, BookingState state);
1319
}
Lines changed: 116 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,41 @@
11
package ru.practicum.shareit.booking.service;
22

33
import lombok.RequiredArgsConstructor;
4+
import org.springframework.data.domain.Sort;
45
import org.springframework.stereotype.Service;
6+
import ru.practicum.shareit.booking.dto.*;
57
import ru.practicum.shareit.booking.model.Booking;
68
import ru.practicum.shareit.booking.model.BookingStatus;
7-
import ru.practicum.shareit.booking.dto.BookingCreateRequest;
8-
import ru.practicum.shareit.booking.dto.BookingResponseDto;
9-
import ru.practicum.shareit.booking.dto.BookingUpdateRequest;
10-
import ru.practicum.shareit.booking.dto.BookingMapper;
11-
import ru.practicum.shareit.booking.storage.InMemoryBookingStorage;
9+
import ru.practicum.shareit.booking.storage.BookingRepository;
10+
import ru.practicum.shareit.exception.AccessDeniedException;
1211
import ru.practicum.shareit.exception.NotFoundException;
1312
import ru.practicum.shareit.exception.ValidationException;
14-
import ru.practicum.shareit.exception.AccessDeniedException;
1513
import ru.practicum.shareit.item.model.Item;
16-
import ru.practicum.shareit.item.storage.InMemoryItemStorage;
14+
import ru.practicum.shareit.item.storage.ItemRepository;
1715
import ru.practicum.shareit.user.model.User;
18-
import ru.practicum.shareit.user.storage.InMemoryUserStorage;
16+
import ru.practicum.shareit.user.storage.UserRepository;
17+
18+
import java.time.LocalDateTime;
19+
import java.util.List;
20+
import java.util.stream.Collectors;
1921

2022
@Service
2123
@RequiredArgsConstructor
2224
public class BookingServiceImpl implements BookingService {
23-
private final InMemoryBookingStorage bookingStorage;
24-
private final InMemoryUserStorage userStorage;
25-
private final InMemoryItemStorage itemStorage;
25+
private final BookingRepository bookingRepository;
26+
private final UserRepository userRepository;
27+
private final ItemRepository itemRepository;
2628

2729
@Override
2830
public BookingResponseDto createBooking(BookingCreateRequest createRequest, Long bookerId) {
29-
User booker = userStorage.findById(bookerId)
31+
if (createRequest.getEnd().isBefore(createRequest.getStart()) || createRequest.getEnd().equals(createRequest.getStart())) {
32+
throw new ValidationException("Дата окончания должна быть после даты начала");
33+
}
34+
35+
User booker = userRepository.findById(bookerId)
3036
.orElseThrow(() -> new NotFoundException("Пользователь с id " + bookerId + " не найден"));
3137

32-
Item item = itemStorage.findById(createRequest.getItemId())
38+
Item item = itemRepository.findById(createRequest.getItemId())
3339
.orElseThrow(() -> new NotFoundException("Вещь с id " + createRequest.getItemId() + " не найдена"));
3440

3541
if (!Boolean.TRUE.equals(item.getAvailable())) {
@@ -42,25 +48,111 @@ public BookingResponseDto createBooking(BookingCreateRequest createRequest, Long
4248

4349
Booking booking = BookingMapper.fromCreateRequest(createRequest, item, booker);
4450
booking.setStatus(BookingStatus.WAITING);
45-
Booking createdBooking = bookingStorage.create(booking);
46-
return BookingMapper.toResponseDto(createdBooking);
51+
Booking saved = bookingRepository.save(booking);
52+
return BookingMapper.toResponseDto(saved);
4753
}
4854

4955
@Override
50-
public BookingResponseDto updateBooking(Long bookingId, BookingUpdateRequest updateRequest) {
51-
Booking existingBooking = bookingStorage.findById(bookingId)
56+
public BookingResponseDto getBookingById(Long bookingId, Long userId) {
57+
Booking booking = bookingRepository.findById(bookingId)
5258
.orElseThrow(() -> new NotFoundException("Бронирование с id " + bookingId + " не найдено"));
5359

54-
BookingMapper.updateBookingFromRequest(updateRequest, existingBooking);
60+
if (!booking.getBooker().getId().equals(userId) && !booking.getItem().getOwner().getId().equals(userId)) {
61+
throw new AccessDeniedException("Просмотр бронирования доступен только автору или владельцу вещи");
62+
}
5563

56-
Booking updatedBooking = bookingStorage.update(existingBooking);
57-
return BookingMapper.toResponseDto(updatedBooking);
64+
return BookingMapper.toResponseDto(booking);
5865
}
5966

6067
@Override
61-
public BookingResponseDto getBookingById(Long bookingId) {
62-
Booking booking = bookingStorage.findById(bookingId)
68+
public BookingResponseDto approveBooking(Long bookingId, boolean approved, Long userId) {
69+
Booking booking = bookingRepository.findById(bookingId)
6370
.orElseThrow(() -> new NotFoundException("Бронирование с id " + bookingId + " не найдено"));
64-
return BookingMapper.toResponseDto(booking);
71+
72+
if (!booking.getItem().getOwner().getId().equals(userId)) {
73+
throw new AccessDeniedException("Только владелец вещи может подтвердить или отклонить бронирование");
74+
}
75+
76+
if (booking.getStatus() != BookingStatus.WAITING) {
77+
throw new ValidationException("Бронирование уже обработано");
78+
}
79+
80+
booking.setStatus(approved ? BookingStatus.APPROVED : BookingStatus.REJECTED);
81+
Booking updated = bookingRepository.save(booking);
82+
return BookingMapper.toResponseDto(updated);
83+
}
84+
85+
@Override
86+
public List<BookingResponseDto> getUserBookings(Long userId, BookingState state) {
87+
userRepository.findById(userId)
88+
.orElseThrow(() -> new NotFoundException("Пользователь с id " + userId + " не найден"));
89+
90+
LocalDateTime now = LocalDateTime.now();
91+
Sort sort = Sort.by(Sort.Direction.DESC, "start");
92+
List<Booking> bookings;
93+
94+
switch (state) {
95+
case ALL:
96+
bookings = bookingRepository.findByBookerId(userId, sort);
97+
break;
98+
case CURRENT:
99+
bookings = bookingRepository.findCurrentByBooker(userId, now, sort);
100+
break;
101+
case PAST:
102+
bookings = bookingRepository.findByBookerIdAndEndBefore(userId, now, sort);
103+
break;
104+
case FUTURE:
105+
bookings = bookingRepository.findByBookerIdAndStartAfter(userId, now, sort);
106+
break;
107+
case WAITING:
108+
bookings = bookingRepository.findByBookerIdAndStatus(userId, BookingStatus.WAITING, sort);
109+
break;
110+
case REJECTED:
111+
bookings = bookingRepository.findByBookerIdAndStatus(userId, BookingStatus.REJECTED, sort);
112+
break;
113+
default:
114+
throw new IllegalArgumentException("Неизвестный state: " + state);
115+
}
116+
117+
return bookings.stream()
118+
.map(BookingMapper::toResponseDto)
119+
.collect(Collectors.toList());
120+
}
121+
122+
@Override
123+
public List<BookingResponseDto> getOwnerBookings(Long ownerId, BookingState state) {
124+
userRepository.findById(ownerId)
125+
.orElseThrow(() -> new NotFoundException("Пользователь с id " + ownerId + " не найден"));
126+
127+
LocalDateTime now = LocalDateTime.now();
128+
Sort sort = Sort.by(Sort.Direction.DESC, "start");
129+
List<Booking> bookings;
130+
131+
switch (state) {
132+
case ALL:
133+
bookings = bookingRepository.findByItemOwnerId(ownerId, sort);
134+
break;
135+
case CURRENT:
136+
bookings = bookingRepository.findCurrentByOwner(ownerId, now, sort);
137+
break;
138+
case PAST:
139+
bookings = bookingRepository.findByItemOwnerIdAndEndBefore(ownerId, now, sort);
140+
break;
141+
case FUTURE:
142+
bookings = bookingRepository.findByItemOwnerIdAndStartAfter(ownerId, now, sort);
143+
break;
144+
case WAITING:
145+
bookings = bookingRepository.findByItemOwnerIdAndStatus(ownerId, BookingStatus.WAITING, sort);
146+
break;
147+
case REJECTED:
148+
bookings = bookingRepository.findByItemOwnerIdAndStatus(ownerId, BookingStatus.REJECTED, sort);
149+
break;
150+
default:
151+
throw new IllegalArgumentException("Неизвестный state: " + state);
152+
}
153+
154+
return bookings.stream()
155+
.map(BookingMapper::toResponseDto)
156+
.collect(Collectors.toList());
65157
}
66-
}
158+
}

0 commit comments

Comments
 (0)