Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions compose.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
services:
db:
image: postgres:16.1
container_name: postgres
ports:
- "5432:5432"
environment:
- POSTGRES_PASSWORD=12345
- POSTGRES_USER=shareit
- POSTGRES_DB=shareit
- TZ=Europe/Moscow

13 changes: 9 additions & 4 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,10 @@
</properties>

<dependencies>
<!-- <dependency>-->
<!-- <groupId>org.springframework.boot</groupId>-->
<!-- <artifactId>spring-boot-starter-jdbc</artifactId>-->
<!-- </dependency>-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
Expand All @@ -49,6 +49,11 @@
<scope>runtime</scope>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>

<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
Expand Down
36 changes: 31 additions & 5 deletions src/main/java/ru/practicum/shareit/booking/Booking.java
Original file line number Diff line number Diff line change
@@ -1,15 +1,41 @@
package ru.practicum.shareit.booking;

import lombok.Data;
import jakarta.persistence.*;
import lombok.*;
import ru.practicum.shareit.item.model.Item;
import ru.practicum.shareit.user.User;

import java.time.LocalDateTime;

@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
@Getter
@Setter
@ToString
@Entity
@Table(name = "booking")
public class Booking {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

@Column(name = "start_time", nullable = false)
private LocalDateTime start;

@Column(name = "end_time", nullable = false)
private LocalDateTime end;
private Long itemId;
private Long booker;
private Status status;

@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "item_id")
private Item item;

@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "booker_id")
private User booker;

@Enumerated(EnumType.STRING)
private BookingStatus status;


}
49 changes: 44 additions & 5 deletions src/main/java/ru/practicum/shareit/booking/BookingController.java
Original file line number Diff line number Diff line change
@@ -1,12 +1,51 @@
package ru.practicum.shareit.booking;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import lombok.RequiredArgsConstructor;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import ru.practicum.shareit.booking.dto.BookingCreateDto;
import ru.practicum.shareit.booking.dto.BookingDto;
import ru.practicum.shareit.booking.service.BookingService;

/**
* TODO Sprint add-bookings.
*/
import java.util.List;


@Validated
@RestController
@RequiredArgsConstructor
@RequestMapping(path = "/bookings")
public class BookingController {
private final BookingService bookingService;
private final BookingCreateDto createDto;

@PostMapping
public BookingDto setBookingItem(@RequestHeader("X-Sharer-User-Id") Long userId,
@Validated @RequestBody BookingCreateDto createDto) {
createDto.normalizeTimestamps();
return bookingService.setBookingItem(createDto, userId);
}

@PatchMapping("/{bookingId}")
public BookingDto setBookingStatus(@RequestHeader("X-Sharer-User-Id") Long userId,
@PathVariable Long bookingId, @RequestParam boolean approved) {
return bookingService.setBookingStatus(userId, bookingId, approved);
}

@GetMapping("/{bookingId}")
public BookingDto getBookingById(@RequestHeader("X-Sharer-User-Id") Long userId, @PathVariable Long bookingId) {
return bookingService.getBookingById(userId, bookingId);
}

@GetMapping
public List<BookingDto> getBookingByBookerIdWhereTime(@RequestHeader("X-Sharer-User-Id") Long userId,
@RequestParam(defaultValue = "ALL") String state) {
return bookingService.getBookingByBookerIdWhereTime(userId, state);
}

@GetMapping("/owner")
List<BookingDto> getBookingByOwnerIdWhereTime(@RequestHeader("X-Sharer-User-Id") Long userId,
@RequestParam(defaultValue = "ALL") String state) {
return bookingService.getBookingByOwnerIdWhereTime(userId, state);
}

}
47 changes: 47 additions & 0 deletions src/main/java/ru/practicum/shareit/booking/BookingMapper.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package ru.practicum.shareit.booking;

import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Component;
import ru.practicum.shareit.booking.dto.BookingCreateDto;
import ru.practicum.shareit.booking.dto.BookingDto;
import ru.practicum.shareit.item.ItemMapper;
import ru.practicum.shareit.user.UserMapper;

import java.util.ArrayList;
import java.util.List;

@RequiredArgsConstructor
@Component
public class BookingMapper {
private final ItemMapper itemMapper;
private final UserMapper userMapper;

public Booking bookingCreateDtoToModel(BookingCreateDto dto) {
return Booking.builder()
.start(dto.getStart())
.end(dto.getEnd())
.status(BookingStatus.WAITING)
.build();
}

public BookingDto modelToDto(Booking booking) {
return BookingDto.builder()
.id(booking.getId())
.start(booking.getStart())
.end(booking.getEnd())
.item(itemMapper.modelToItemDto(booking.getItem()))
.booker(userMapper.modelToDto(booking.getBooker()))
.status(booking.getStatus())
.build();
}

public List<BookingDto> listModelToDto(List<Booking> bookings) {
List<BookingDto> bookingDto = new ArrayList<>();
for (Booking booking : bookings) {
bookingDto.add(modelToDto(booking));
}
return bookingDto;
}


}
69 changes: 69 additions & 0 deletions src/main/java/ru/practicum/shareit/booking/BookingRepository.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
package ru.practicum.shareit.booking;

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;

import java.time.LocalDateTime;
import java.util.List;

public interface BookingRepository extends JpaRepository<Booking, Long> {

@Query(value = """
SELECT EXISTS (
SELECT 1 FROM booking
WHERE item_id = :itemId
AND booker_id = :userId
AND status = 'APPROVED'
AND end_time < CURRENT_TIMESTAMP
)""",
nativeQuery = true)
boolean hasUserBookedItem(@Param("userId") Long userId, @Param("itemId") Long itemId);

@Query("""
SELECT COUNT(b) > 0
FROM Booking b
WHERE b.item.id = :itemId
AND b.status IN ('APPROVED', 'WAITING')
AND (
(b.start BETWEEN :start AND :end) OR
(b.end BETWEEN :start AND :end) OR
(b.start <= :start AND b.end >= :end)
)
""")
boolean existsByItemIdAndTimeRange(@Param("itemId") Long itemId,
@Param("start") LocalDateTime start,
@Param("end") LocalDateTime end);

@Query(value = """
SELECT * FROM booking
WHERE booker_id = :bookerId
AND (
(:state = 'ALL') OR
(:state = 'CURRENT' AND start_time <= NOW() AND end_time >= NOW()) OR
(:state = 'PAST' AND end_time < NOW()) OR
(:state = 'FUTURE' AND start_time > NOW()) OR
(:state = 'WAITING' AND status = 'WAITING') OR
(:state = 'REJECTED' AND status = 'REJECTED')
)
ORDER BY start_time DESC""",
nativeQuery = true)
List<Booking> getBookingByBookerIdWhereTime(@Param("bookerId") Long bookerId, @Param("state") String state);


@Query(value = """
SELECT b.* FROM booking b
JOIN items i ON b.item_id = i.id
WHERE i.owner_id = :ownerId
AND (
(:state = 'ALL') OR
(:state = 'CURRENT' AND NOW() BETWEEN b.start_time AND b.end_time) OR
(:state = 'PAST' AND b.end_time < NOW()) OR
(:state = 'FUTURE' AND b.start_time > NOW()) OR
(:state = b.status)
)
ORDER BY b.start_time DESC""",
nativeQuery = true)
List<Booking> getBookingByOwnerIdWhereTime(@Param("ownerId") Long ownerId, @Param("state") String state);

}
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
package ru.practicum.shareit.booking;

public enum Status {
public enum BookingStatus {
WAITING,
APPROVED,
REJECTED,
CANCELED;
CANCELED
}
Original file line number Diff line number Diff line change
@@ -1,21 +1,40 @@
package ru.practicum.shareit.booking.dto;

import jakarta.validation.constraints.Null;
import jakarta.validation.constraints.AssertTrue;
import jakarta.validation.constraints.Future;
import jakarta.validation.constraints.FutureOrPresent;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
import ru.practicum.shareit.booking.Status;
import org.springframework.stereotype.Component;

import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;

@Component
@Data
public class BookingCreateDto {
private Long id;
@Null
@NotNull
@FutureOrPresent
private LocalDateTime start;
@Null
@NotNull
@Future
private LocalDateTime end;
@Null
@NotNull
private Long itemId;
@Null
private Long booker;
private Status status;

@AssertTrue(message = "Дата окончания должна быть позже даты начала")
boolean isStartBeforeEnd() {
return start != null &&
end != null &&
start.isBefore(end);
}

public void normalizeTimestamps() {
if (start != null) {
start = start.truncatedTo(ChronoUnit.SECONDS);
}
if (end != null) {
end = end.truncatedTo(ChronoUnit.SECONDS);
}
}
}
14 changes: 9 additions & 5 deletions src/main/java/ru/practicum/shareit/booking/dto/BookingDto.java
Original file line number Diff line number Diff line change
@@ -1,16 +1,20 @@
package ru.practicum.shareit.booking.dto;

import lombok.Builder;
import lombok.Data;
import ru.practicum.shareit.booking.Status;
import ru.practicum.shareit.booking.BookingStatus;
import ru.practicum.shareit.item.dto.ItemDto;
import ru.practicum.shareit.user.dto.UserDto;

import java.time.LocalDateTime;

@Builder
@Data
public class BookingDto {
public class BookingDto {
private Long id;
private LocalDateTime start;
private LocalDateTime end;
private Long itemId;
private Long booker;
private Status status;
private ItemDto item;
private UserDto booker;
private BookingStatus status;
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
package ru.practicum.shareit.booking.dto;

import jakarta.validation.constraints.AssertTrue;
import jakarta.validation.constraints.Null;
import lombok.Data;
import ru.practicum.shareit.booking.Status;
import ru.practicum.shareit.booking.BookingStatus;

import java.time.LocalDateTime;

Expand All @@ -14,5 +15,12 @@ public class BookingUpdateDto {
private LocalDateTime end;
private Long itemId;
private Long booker;
private Status status;
private BookingStatus bookingStatus;

@AssertTrue(message = "Дата окончания должна быть позже даты начала")
boolean isStartBeforeEnd() {
return start != null &&
end != null &&
start.isBefore(end);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package ru.practicum.shareit.booking.service;

import ru.practicum.shareit.booking.dto.BookingCreateDto;
import ru.practicum.shareit.booking.dto.BookingDto;

import java.util.List;

public interface BookingService {
BookingDto setBookingItem(BookingCreateDto createDto, long bookerId);

BookingDto setBookingStatus(long userId, long bookingId, boolean approve);

BookingDto getBookingById(long userId, long bookingId);

List<BookingDto> getBookingByBookerIdWhereTime(long booker, String state);

List<BookingDto> getBookingByOwnerIdWhereTime(long ownerId, String state);
}
Loading