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
26 changes: 21 additions & 5 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
Expand Down Expand Up @@ -63,11 +67,11 @@
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>

<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct</artifactId>
<version>${org.mapstruct.version}</version>
</dependency>
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct</artifactId>
<version>${org.mapstruct.version}</version>
</dependency>

<dependency>
<groupId>org.projectlombok</groupId>
Expand Down Expand Up @@ -159,6 +163,18 @@
<version>${lombok-mapstruct-binding.version}</version>
</path>
</annotationProcessorPaths>
<showWarnings>true</showWarnings>
<compilerArgs>
<arg>
-Amapstruct.suppressGeneratorTimestamp=true
</arg>
<arg>
-Amapstruct.suppressGeneratorVersionInfoComment=true
</arg>
<arg>
-Amapstruct.verbose=true
</arg>
</compilerArgs>
</configuration>
</plugin>
<plugin>
Expand Down
66 changes: 66 additions & 0 deletions src/main/java/ru/practicum/shareit/PersistenceConfig.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
package ru.practicum.shareit;

import jakarta.persistence.EntityManagerFactory;
import lombok.RequiredArgsConstructor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;
import org.springframework.transaction.annotation.EnableTransactionManagement;

import javax.sql.DataSource;
import java.util.Properties;

@Configuration
@RequiredArgsConstructor
@EnableTransactionManagement
@EnableJpaRepositories(basePackages = "ru.practicum")
public class PersistenceConfig {
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Хорошо что попробовала сделать конфиг, но все это плюс-минус сделается по умолчанию, если в зависимостях добавлен spring-boot-starter-data-jpa (а у тебя он добавлен). Можешь оставить.

private final Environment environment;

@Bean
public DataSource dataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName(environment.getRequiredProperty("spring.datasource.driverClassName"));
dataSource.setUrl(environment.getRequiredProperty("spring.datasource.url"));
dataSource.setUsername(environment.getRequiredProperty("spring.datasource.username"));
dataSource.setPassword(environment.getRequiredProperty("spring.datasource.password"));
return dataSource;
}

private Properties hibernateProperties() {
Properties properties = new Properties();
properties.put("spring.jpa.properties.hibernate.jdbc.time_zone",
environment.getRequiredProperty("spring.jpa.properties.hibernate.jdbc.time_zone"));
properties.put("spring.jpa.properties.hibernate.format_sql",
environment.getProperty("spring.jpa.properties.hibernate.format_sql", "false"));
return properties;
}

@Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory(DataSource dataSource) {
final HibernateJpaVendorAdapter vendorAdapter =
new HibernateJpaVendorAdapter();

final LocalContainerEntityManagerFactoryBean emf =
new LocalContainerEntityManagerFactoryBean();

emf.setDataSource(dataSource);
emf.setJpaVendorAdapter(vendorAdapter);
emf.setPackagesToScan("ru.practicum");
emf.setJpaProperties(hibernateProperties());

return emf;
}

@Bean
public JpaTransactionManager transactionManager(EntityManagerFactory entityManagerFactory) {
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(entityManagerFactory);
return transactionManager;
}
}
16 changes: 0 additions & 16 deletions src/main/java/ru/practicum/shareit/booking/Booking.java

This file was deleted.

47 changes: 42 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,49 @@
package ru.practicum.shareit.booking;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.*;
import ru.practicum.shareit.booking.dto.BookingRequestDto;
import ru.practicum.shareit.booking.dto.BookingResponseDto;
import ru.practicum.shareit.booking.intrfaces.BookingServiceInterface;

import java.util.Collection;

/**
* TODO Sprint add-bookings.
*/
@RestController
@RequestMapping(path = "/bookings")
@RequiredArgsConstructor
public class BookingController {
private final BookingServiceInterface bookingService;
public static final String USER_ID = "X-Sharer-User-Id";

@PostMapping
public BookingResponseDto addBooking(@RequestBody @Valid BookingRequestDto booking,
@RequestHeader(USER_ID) Long bookerId) {
return bookingService.addBooking(booking, bookerId);
}

@PatchMapping("/{bookingId}")
public BookingResponseDto bookingApprove(@PathVariable Long bookingId,
@RequestHeader (USER_ID) Long ownerId,
@RequestParam Boolean approved) {
return bookingService.bookingApprove(bookingId, ownerId, approved);
}

@GetMapping("/{bookingId}")
public BookingResponseDto getBooking(@PathVariable Long bookingId,
@RequestHeader(USER_ID) Long userId) {
return bookingService.getBookingByBookingId(bookingId, userId);
}

@GetMapping
public Collection<BookingResponseDto> getBookingsByUser(@RequestHeader (USER_ID) Long userId,
@RequestParam(name = "state", defaultValue = "all") String state) {
return bookingService.getBookingsByUser(userId, state);
}

@GetMapping("/owner")
public Collection<BookingResponseDto> getBookingsByOwner(@RequestHeader (USER_ID) Long userId,
@RequestParam(name = "state", defaultValue = "all") String state) {
return bookingService.getBookingsByOwner(userId, state);
}
}
Comment thread
NadezhdaTA marked this conversation as resolved.
198 changes: 198 additions & 0 deletions src/main/java/ru/practicum/shareit/booking/BookingServiceImpl.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,198 @@
package ru.practicum.shareit.booking;

import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import ru.practicum.shareit.booking.dto.BookingRequestDto;
import ru.practicum.shareit.booking.dto.BookingResponseDto;
import ru.practicum.shareit.booking.intrfaces.BookingRepository;
import ru.practicum.shareit.booking.intrfaces.BookingServiceInterface;
import ru.practicum.shareit.booking.mapper.BookingMapper;
import ru.practicum.shareit.booking.model.Booking;
import ru.practicum.shareit.booking.model.BookingStatus;
import ru.practicum.shareit.exception.AnotherUserException;
import ru.practicum.shareit.exception.NotFoundException;
import ru.practicum.shareit.exception.ValidationException;
import ru.practicum.shareit.item.interfaces.ItemRepository;
import ru.practicum.shareit.item.mapper.ItemMapper;
import ru.practicum.shareit.item.model.Item;
import ru.practicum.shareit.user.interfaces.UserRepository;
import ru.practicum.shareit.user.mapper.UserMapper;
import ru.practicum.shareit.user.model.User;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Comparator;

@Service
@RequiredArgsConstructor
public class BookingServiceImpl implements BookingServiceInterface {
private final BookingRepository storage;
private final UserRepository userStorage;
private final ItemRepository itemStorage;

private final ItemMapper itemMapper;
private final UserMapper userMapper;
private final BookingRepository bookingRepository;
private final BookingMapper bookingMapper;


@Override
public BookingResponseDto addBooking(BookingRequestDto booking, Long bookerId) {
Item item = itemStorage.findById(booking.getItemId())
.orElseThrow(() -> new NotFoundException("Item not found"));

User booker = userStorage.getUserByUserId(bookerId)
.orElseThrow(() -> new NotFoundException("User not found"));

Booking saved = bookingMapper.bookingRequestDtoToBooking(booking);
saved.setBooker(booker);
saved.setItem(item);

if (item.getIsAvailable().equals(false)) {
saved.setStatus(BookingStatus.REJECTED);
storage.save(saved);
throw new RuntimeException("Booking is rejected, item is not available");
} else {
saved.setStatus(BookingStatus.WAITING);
storage.save(saved);
}

return mapBookerAndItemToBooking(saved);
}

@Override
public BookingResponseDto bookingApprove(Long bookingId, Long ownerId, Boolean isAvailable) {
Booking booking = bookingRepository.getBookingByBookingId(bookingId)
.orElseThrow(() -> new NotFoundException("Booking not found"));

Item item = itemStorage.getItemByItemId(booking.getItem().getItemId())
.orElseThrow(() -> new NotFoundException("Item not found"));

if (!item.getOwner().getUserId().equals(ownerId)) {
throw new AnotherUserException("You are not allowed to approve this booking");
}

if (item.getIsAvailable().equals(false)) {
booking.setStatus(BookingStatus.REJECTED);
throw new ValidationException("Booking item is rejected");
} else {
booking.setStatus(BookingStatus.APPROVED);
bookingRepository.save(booking);
}

return mapBookerAndItemToBooking(booking);
}

@Override
public BookingResponseDto getBookingByBookingId(Long bookingId, Long userId) {
Booking booking = bookingRepository.getBookingByBookingId(bookingId)
.orElseThrow(() -> new NotFoundException("Booking not found"));

if (booking.getBooker().getUserId().equals(userId) ||
booking.getItem().getOwner().getUserId().equals(userId)) {
return mapBookerAndItemToBooking(booking);
} else {
throw new AnotherUserException("You are not allowed to view this booking");
}
}

@Override
public Collection<BookingResponseDto> getBookingsByUser(Long userId, String state) {
User user = userStorage.getUserByUserId(userId)
.orElseThrow(() -> new NotFoundException("User not found"));

LocalDateTime date = LocalDateTime.now();

Collection<Booking> bookings = new ArrayList<>();

if (state.equalsIgnoreCase("ALL")) {
bookings = bookingRepository.getBookingsByBooker_UserId(userId);

} else if (state.equalsIgnoreCase("CURRENT") ||
state.equalsIgnoreCase("PAST") ||
state.equalsIgnoreCase("FUTURE")) {

bookings = getBookingsByTimeState(date, state).stream()
.filter(booking -> booking.getBooker().getUserId().equals(userId))
.toList();

} else if (state.equalsIgnoreCase("WAITING") ||
state.equalsIgnoreCase("REJECTED")) {

if (state.equalsIgnoreCase("WAITING")) {
bookings = bookingRepository.getBookingsByBooker_UserIdAndStatus(userId, BookingStatus.WAITING);
} else {
bookings = bookingRepository.getBookingsByBooker_UserIdAndStatus(userId, BookingStatus.REJECTED);
}
}

return bookings.stream()
.map(this::mapBookerAndItemToBooking)
.sorted(Comparator.comparing(BookingResponseDto::getStart))
.toList()
.reversed();
}

@Override
public Collection<BookingResponseDto> getBookingsByOwner(Long userId, String state) {
User user = userStorage.getUserByUserId(userId)
.orElseThrow(() -> new NotFoundException("User not found"));

Item item = itemStorage.getItemsByOwner_UserId(userId).stream()
.findFirst()
.orElseThrow(() -> new NotFoundException("User with userId = " + userId + " has no Item"));

LocalDateTime date = LocalDateTime.now();

Collection<Booking> bookings = new ArrayList<>();

if (state.equalsIgnoreCase("ALL")) {
bookings = bookingRepository.getBookingsByOwnerId(userId);
} else if (state.equalsIgnoreCase("CURRENT") ||
state.equalsIgnoreCase("PAST") ||
state.equalsIgnoreCase("FUTURE")) {

bookings = getBookingsByTimeState(date, state).stream()
.filter(booking -> booking.getItem().getOwner().getUserId().equals(userId))
.toList();

} else if (state.equalsIgnoreCase("WAITING") ||
state.equalsIgnoreCase("REJECTED")) {

if (state.equalsIgnoreCase("WAITING")) {
bookings = bookingRepository.getBookingsByStatus(BookingStatus.WAITING).stream()
.filter(booking -> booking.getItem().getOwner().getUserId().equals(userId))
.toList();
} else {
bookings = bookingRepository.getBookingsByStatus(BookingStatus.REJECTED).stream()
.filter(booking -> booking.getItem().getOwner().getUserId().equals(userId))
.toList();
}
}
return bookings.stream()
.map(this::mapBookerAndItemToBooking)
.sorted(Comparator.comparing(BookingResponseDto::getStart))
.toList()
.reversed();
}


private BookingResponseDto mapBookerAndItemToBooking(Booking booking) {
BookingResponseDto bookingDto = bookingMapper.bookingToBookingResponseDto(booking);
bookingDto.setBooker(userMapper.toUserBookingDto(booking.getBooker()));
bookingDto.setItem(itemMapper.toItemBookerDto(booking.getItem()));
return bookingDto;
}

private Collection<Booking> getBookingsByTimeState(LocalDateTime date, String state) {
Collection<Booking> bookings = new ArrayList<>();
switch (state.toUpperCase()) {
case "CURRENT" -> bookings = bookingRepository.getBookingsByBooker_UserIdCurrent(date);
case "PAST" -> bookings = bookingRepository.getBookingsByBooker_UserIdPast(date);
case "FUTURE" -> bookings = bookingRepository.getBookingsByBooker_UserIdFuture(date);
}
return bookings;
}
}

This file was deleted.

Loading