diff --git a/ewm-main-service/pom.xml b/ewm-main-service/pom.xml index dba2a53..233e90f 100644 --- a/ewm-main-service/pom.xml +++ b/ewm-main-service/pom.xml @@ -44,7 +44,6 @@ org.springframework.boot spring-boot-starter-validation - 3.5.14 org.springframework.boot diff --git a/ewm-main-service/src/main/java/ru/practicum/ewm/EwmApplication.java b/ewm-main-service/src/main/java/ru/practicum/ewm/EwmApplication.java index f1dfbc9..9c35c42 100644 --- a/ewm-main-service/src/main/java/ru/practicum/ewm/EwmApplication.java +++ b/ewm-main-service/src/main/java/ru/practicum/ewm/EwmApplication.java @@ -2,8 +2,10 @@ import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.annotation.ComponentScan; @SpringBootApplication +@ComponentScan(basePackages = {"ru.practicum.ewm", "ru.practicum.client"}) // Добавь это! public class EwmApplication { public static void main(String[] args) { SpringApplication.run(EwmApplication.class, args); diff --git a/ewm-main-service/src/main/java/ru/practicum/ewm/controller/ErrorHandler.java b/ewm-main-service/src/main/java/ru/practicum/ewm/controller/ErrorHandler.java new file mode 100644 index 0000000..4233366 --- /dev/null +++ b/ewm-main-service/src/main/java/ru/practicum/ewm/controller/ErrorHandler.java @@ -0,0 +1,69 @@ +package ru.practicum.ewm.controller; + +import lombok.extern.slf4j.Slf4j; +import org.springframework.dao.DataIntegrityViolationException; +import org.springframework.http.HttpStatus; +import org.springframework.web.bind.MethodArgumentNotValidException; +import org.springframework.web.bind.MissingServletRequestParameterException; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.ResponseStatus; +import org.springframework.web.bind.annotation.RestControllerAdvice; +import ru.practicum.ewm.dto.response.ApiError; +import ru.practicum.ewm.exception.BadRequestException; +import ru.practicum.ewm.exception.ConflictException; +import ru.practicum.ewm.exception.NotFoundException; + +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.util.stream.Collectors; + +@Slf4j +@RestControllerAdvice +public class ErrorHandler { + + private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); + + @ExceptionHandler(NotFoundException.class) + @ResponseStatus(HttpStatus.NOT_FOUND) + public ApiError handleNotFound(final NotFoundException e) { + return createApiError(HttpStatus.NOT_FOUND, "The required object was not found.", e.getMessage()); + } + + @ExceptionHandler({ConflictException.class, DataIntegrityViolationException.class}) + @ResponseStatus(HttpStatus.CONFLICT) + public ApiError handleConflict(final Exception e) { + return createApiError(HttpStatus.CONFLICT, "For the requested operation the conditions are not met.", e.getMessage()); + } + + @ExceptionHandler(MethodArgumentNotValidException.class) + @ResponseStatus(HttpStatus.BAD_REQUEST) + public ApiError handleMethodArgumentNotValid(final MethodArgumentNotValidException e) { + String message = e.getBindingResult().getFieldErrors().stream() + .map(error -> "Field: " + error.getField() + ". Error: " + error.getDefaultMessage() + ". Value: " + error.getRejectedValue()) + .collect(Collectors.joining(", ")); + return createApiError(HttpStatus.BAD_REQUEST, "Incorrectly made request.", message); + } + + @ExceptionHandler({BadRequestException.class, MissingServletRequestParameterException.class}) + @ResponseStatus(HttpStatus.BAD_REQUEST) + public ApiError handleBadRequest(final Exception e) { + return createApiError(HttpStatus.BAD_REQUEST, "Incorrectly made request.", e.getMessage()); + } + + @ExceptionHandler(Throwable.class) + @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR) + public ApiError handleThrowable(final Throwable e) { + log.error("500 Error: ", e); + return createApiError(HttpStatus.INTERNAL_SERVER_ERROR, "Error occurred", e.getMessage()); + } + + private ApiError createApiError(HttpStatus status, String reason, String message) { + return ApiError.builder() + .status(status.name()) + .reason(reason) + .message(message != null ? message : "No message available") + .timestamp(LocalDateTime.now().format(FORMATTER)) + .errors(java.util.List.of()) + .build(); + } +} \ No newline at end of file diff --git a/ewm-main-service/src/main/java/ru/practicum/ewm/controller/admin/AdminCategoryController.java b/ewm-main-service/src/main/java/ru/practicum/ewm/controller/admin/AdminCategoryController.java new file mode 100644 index 0000000..524ec14 --- /dev/null +++ b/ewm-main-service/src/main/java/ru/practicum/ewm/controller/admin/AdminCategoryController.java @@ -0,0 +1,36 @@ +package ru.practicum.ewm.controller.admin; + +import jakarta.validation.Valid; +import lombok.RequiredArgsConstructor; +import org.springframework.http.HttpStatus; +import org.springframework.web.bind.annotation.*; +import ru.practicum.ewm.dto.request.NewCategoryDto; +import ru.practicum.ewm.dto.response.CategoryDto; +import ru.practicum.ewm.service.CategoryService; + +@RestController +@RequestMapping("/admin/categories") +@RequiredArgsConstructor +public class AdminCategoryController { + + private final CategoryService categoryService; + private static final String CAT_ID_PATH = "/{catId}"; + + @PostMapping + @ResponseStatus(HttpStatus.CREATED) + public CategoryDto createCategory(@Valid @RequestBody NewCategoryDto newCategoryDto) { + return categoryService.createCategory(newCategoryDto); + } + + @PatchMapping(CAT_ID_PATH) + public CategoryDto updateCategory(@PathVariable Long catId, + @Valid @RequestBody CategoryDto categoryDto) { + return categoryService.updateCategory(catId, categoryDto); + } + + @DeleteMapping(CAT_ID_PATH) + @ResponseStatus(HttpStatus.NO_CONTENT) + public void deleteCategory(@PathVariable Long catId) { + categoryService.deleteCategory(catId); + } +} \ No newline at end of file diff --git a/ewm-main-service/src/main/java/ru/practicum/ewm/controller/admin/AdminCompilationController.java b/ewm-main-service/src/main/java/ru/practicum/ewm/controller/admin/AdminCompilationController.java new file mode 100644 index 0000000..f0b9069 --- /dev/null +++ b/ewm-main-service/src/main/java/ru/practicum/ewm/controller/admin/AdminCompilationController.java @@ -0,0 +1,38 @@ +package ru.practicum.ewm.controller.admin; + +import lombok.RequiredArgsConstructor; +import org.springframework.http.HttpStatus; +import org.springframework.web.bind.annotation.*; +import ru.practicum.ewm.dto.request.NewCompilationDto; +import ru.practicum.ewm.dto.request.UpdateCompilationRequest; +import ru.practicum.ewm.dto.response.CompilationDto; +import ru.practicum.ewm.service.CompilationService; + +import jakarta.validation.Valid; + +@RestController +@RequestMapping("/admin/compilations") +@RequiredArgsConstructor +public class AdminCompilationController { + + private final CompilationService compilationService; + private static final String COMP_ID_PATH = "/{compId}"; + + @PostMapping + @ResponseStatus(HttpStatus.CREATED) + public CompilationDto addCompilation(@Valid @RequestBody NewCompilationDto newCompilationDto) { + return compilationService.addCompilation(newCompilationDto); + } + + @DeleteMapping(COMP_ID_PATH) + @ResponseStatus(HttpStatus.NO_CONTENT) + public void deleteCompilation(@PathVariable Long compId) { + compilationService.deleteCompilation(compId); + } + + @PatchMapping(COMP_ID_PATH) + public CompilationDto updateCompilation(@PathVariable Long compId, + @Valid @RequestBody UpdateCompilationRequest updateRequest) { + return compilationService.updateCompilation(compId, updateRequest); + } +} \ No newline at end of file diff --git a/ewm-main-service/src/main/java/ru/practicum/ewm/controller/admin/AdminEventController.java b/ewm-main-service/src/main/java/ru/practicum/ewm/controller/admin/AdminEventController.java new file mode 100644 index 0000000..1502ee3 --- /dev/null +++ b/ewm-main-service/src/main/java/ru/practicum/ewm/controller/admin/AdminEventController.java @@ -0,0 +1,39 @@ +package ru.practicum.ewm.controller.admin; + +import jakarta.validation.Valid; +import lombok.RequiredArgsConstructor; +import org.springframework.format.annotation.DateTimeFormat; +import org.springframework.web.bind.annotation.*; +import ru.practicum.ewm.dto.request.UpdateEventAdmin; +import ru.practicum.ewm.dto.response.EventFullDto; +import ru.practicum.ewm.model.EventState; +import ru.practicum.ewm.service.EventService; + +import java.time.LocalDateTime; +import java.util.List; + +@RestController +@RequestMapping("/admin/events") +@RequiredArgsConstructor +public class AdminEventController { + + private final EventService eventService; + + @GetMapping + public List getEvents( + @RequestParam(required = false) List users, + @RequestParam(required = false) List states, + @RequestParam(required = false) List categories, + @RequestParam(required = false) @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") LocalDateTime rangeStart, + @RequestParam(required = false) @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") LocalDateTime rangeEnd, + @RequestParam(defaultValue = "0") int from, + @RequestParam(defaultValue = "10") int size) { + return eventService.getEventsByAdmin(users, states, categories, rangeStart, rangeEnd, from, size); + } + + @PatchMapping("/{eventId}") + public EventFullDto updateEvent(@PathVariable Long eventId, + @Valid @RequestBody UpdateEventAdmin updateRequest) { + return eventService.updateEventByAdmin(eventId, updateRequest); + } +} \ No newline at end of file diff --git a/ewm-main-service/src/main/java/ru/practicum/ewm/controller/admin/AdminLocationController.java b/ewm-main-service/src/main/java/ru/practicum/ewm/controller/admin/AdminLocationController.java new file mode 100644 index 0000000..1c77e55 --- /dev/null +++ b/ewm-main-service/src/main/java/ru/practicum/ewm/controller/admin/AdminLocationController.java @@ -0,0 +1,41 @@ +package ru.practicum.ewm.controller.admin; + +import jakarta.validation.Valid; +import lombok.RequiredArgsConstructor; +import org.springframework.http.HttpStatus; +import org.springframework.web.bind.annotation.*; +import ru.practicum.ewm.dto.request.NewLocationDto; +import ru.practicum.ewm.dto.response.LocationDto; +import ru.practicum.ewm.service.LocationService; + +import java.util.List; + +@RestController +@RequestMapping("/admin/locations") +@RequiredArgsConstructor +public class AdminLocationController { + + private final LocationService locationService; + + @PostMapping + @ResponseStatus(HttpStatus.CREATED) + public LocationDto createLocation(@Valid @RequestBody NewLocationDto locationDto) { + return locationService.createLocation(locationDto); + } + + @GetMapping + public List getAllLocations() { + return locationService.getAllLocations(); + } + + @GetMapping("/{locationId}") + public LocationDto getLocation(@PathVariable Long locationId) { + return locationService.getLocation(locationId); + } + + @DeleteMapping("/{locationId}") + @ResponseStatus(HttpStatus.NO_CONTENT) + public void deleteLocation(@PathVariable Long locationId) { + locationService.deleteLocation(locationId); + } +} \ No newline at end of file diff --git a/ewm-main-service/src/main/java/ru/practicum/ewm/controller/admin/AdminUserController.java b/ewm-main-service/src/main/java/ru/practicum/ewm/controller/admin/AdminUserController.java new file mode 100644 index 0000000..0ac13b1 --- /dev/null +++ b/ewm-main-service/src/main/java/ru/practicum/ewm/controller/admin/AdminUserController.java @@ -0,0 +1,42 @@ +package ru.practicum.ewm.controller.admin; + +import lombok.RequiredArgsConstructor; +import org.springframework.http.HttpStatus; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; +import ru.practicum.ewm.dto.request.NewUserRequest; +import ru.practicum.ewm.dto.response.UserDto; +import ru.practicum.ewm.service.UserService; + +import jakarta.validation.Valid; +import jakarta.validation.constraints.Positive; +import jakarta.validation.constraints.PositiveOrZero; +import java.util.List; + +@RestController +@RequestMapping("/admin/users") +@RequiredArgsConstructor +@Validated +public class AdminUserController { + + private final UserService userService; + + @GetMapping + public List getUsers(@RequestParam(required = false) List ids, + @RequestParam(defaultValue = "0") @PositiveOrZero int from, + @RequestParam(defaultValue = "10") @Positive int size) { + return userService.getUsers(ids, from, size); + } + + @PostMapping + @ResponseStatus(HttpStatus.CREATED) + public UserDto createUser(@Valid @RequestBody NewUserRequest newUserRequest) { + return userService.createUser(newUserRequest); + } + + @DeleteMapping("/{userId}") + @ResponseStatus(HttpStatus.NO_CONTENT) + public void deleteUser(@PathVariable Long userId) { + userService.deleteUser(userId); + } +} \ No newline at end of file diff --git a/ewm-main-service/src/main/java/ru/practicum/ewm/controller/priv/PrivateEventController.java b/ewm-main-service/src/main/java/ru/practicum/ewm/controller/priv/PrivateEventController.java new file mode 100644 index 0000000..9750beb --- /dev/null +++ b/ewm-main-service/src/main/java/ru/practicum/ewm/controller/priv/PrivateEventController.java @@ -0,0 +1,65 @@ +package ru.practicum.ewm.controller.priv; + +import jakarta.validation.Valid; +import lombok.RequiredArgsConstructor; +import org.springframework.http.HttpStatus; +import org.springframework.web.bind.annotation.*; +import ru.practicum.ewm.dto.request.NewEventDto; +import ru.practicum.ewm.dto.request.UpdateEventUser; +import ru.practicum.ewm.dto.request.RequestStatusUpdate; +import ru.practicum.ewm.dto.response.EventFullDto; +import ru.practicum.ewm.dto.response.EventShortDto; +import ru.practicum.ewm.dto.response.RequestDto; +import ru.practicum.ewm.dto.response.RequestStatusUpdateResult; +import ru.practicum.ewm.service.EventService; +import ru.practicum.ewm.service.RequestService; +import java.util.List; + +@RestController +@RequestMapping("/users/{userId}/events") +@RequiredArgsConstructor +public class PrivateEventController { + + private final EventService eventService; + private final RequestService requestService; // Добавлено поле для внедрения + + @GetMapping + public List getEvents(@PathVariable Long userId, + @RequestParam(defaultValue = "0") int from, + @RequestParam(defaultValue = "10") int size) { + return eventService.getEventsByUserId(userId, from, size); + } + + @PostMapping + @ResponseStatus(HttpStatus.CREATED) + public EventFullDto createEvent(@PathVariable Long userId, @Valid @RequestBody NewEventDto newEventDto) { + return eventService.createEvent(userId, newEventDto); + } + + @GetMapping("/{eventId}") + public EventFullDto getEvent(@PathVariable Long userId, @PathVariable Long eventId) { + return eventService.getEventByIdAndUserId(userId, eventId); + } + + @PatchMapping("/{eventId}") + public EventFullDto updateEvent(@PathVariable Long userId, @PathVariable Long eventId, + @Valid @RequestBody UpdateEventUser updateRequest) { + return eventService.updateEventByUserId(userId, eventId, updateRequest); + } + + // --- Методы для работы с запросами на участие в событии (организатор) --- + + @GetMapping("/{eventId}/requests") + public List getEventRequests(@PathVariable Long userId, @PathVariable Long eventId) { + + return requestService.getEventRequests(userId, eventId); + } + + @PatchMapping("/{eventId}/requests") + public RequestStatusUpdateResult updateRequestStatus(@PathVariable Long userId, + @PathVariable Long eventId, + @Valid @RequestBody RequestStatusUpdate updateRequest) { + + return requestService.updateRequestStatus(userId, eventId, updateRequest); + } +} \ No newline at end of file diff --git a/ewm-main-service/src/main/java/ru/practicum/ewm/controller/priv/PrivateRequestController.java b/ewm-main-service/src/main/java/ru/practicum/ewm/controller/priv/PrivateRequestController.java new file mode 100644 index 0000000..6ab26b1 --- /dev/null +++ b/ewm-main-service/src/main/java/ru/practicum/ewm/controller/priv/PrivateRequestController.java @@ -0,0 +1,33 @@ +package ru.practicum.ewm.controller.priv; + +import lombok.RequiredArgsConstructor; +import org.springframework.http.HttpStatus; +import org.springframework.web.bind.annotation.*; +import ru.practicum.ewm.dto.response.RequestDto; +import ru.practicum.ewm.service.RequestService; + +import java.util.List; + +@RestController +@RequestMapping("/users/{userId}/requests") +@RequiredArgsConstructor +public class PrivateRequestController { + + private final RequestService requestService; + + @GetMapping + public List getRequests(@PathVariable Long userId) { + return requestService.getRequestsByUserId(userId); + } + + @PostMapping + @ResponseStatus(HttpStatus.CREATED) + public RequestDto createRequest(@PathVariable Long userId, @RequestParam Long eventId) { + return requestService.createRequest(userId, eventId); + } + + @PatchMapping("/{requestId}/cancel") + public RequestDto cancelRequest(@PathVariable Long userId, @PathVariable Long requestId) { + return requestService.cancelRequest(userId, requestId); + } +} \ No newline at end of file diff --git a/ewm-main-service/src/main/java/ru/practicum/ewm/controller/pub/PublicCategoryController.java b/ewm-main-service/src/main/java/ru/practicum/ewm/controller/pub/PublicCategoryController.java new file mode 100644 index 0000000..3ee31ae --- /dev/null +++ b/ewm-main-service/src/main/java/ru/practicum/ewm/controller/pub/PublicCategoryController.java @@ -0,0 +1,27 @@ +package ru.practicum.ewm.controller.pub; + +import lombok.RequiredArgsConstructor; +import org.springframework.web.bind.annotation.*; +import ru.practicum.ewm.dto.response.CategoryDto; +import ru.practicum.ewm.service.CategoryService; + +import java.util.List; + +@RestController +@RequestMapping("/categories") +@RequiredArgsConstructor +public class PublicCategoryController { + + private final CategoryService categoryService; + + @GetMapping + public List getCategories(@RequestParam(defaultValue = "0") int from, + @RequestParam(defaultValue = "10") int size) { + return categoryService.getCategories(from, size); + } + + @GetMapping("/{catId}") + public CategoryDto getCategory(@PathVariable Long catId) { + return categoryService.getCategory(catId); + } +} \ No newline at end of file diff --git a/ewm-main-service/src/main/java/ru/practicum/ewm/controller/pub/PublicCompilationController.java b/ewm-main-service/src/main/java/ru/practicum/ewm/controller/pub/PublicCompilationController.java new file mode 100644 index 0000000..576e8ed --- /dev/null +++ b/ewm-main-service/src/main/java/ru/practicum/ewm/controller/pub/PublicCompilationController.java @@ -0,0 +1,28 @@ +package ru.practicum.ewm.controller.pub; + +import lombok.RequiredArgsConstructor; +import org.springframework.web.bind.annotation.*; +import ru.practicum.ewm.dto.response.CompilationDto; +import ru.practicum.ewm.service.CompilationService; + +import java.util.List; + +@RestController +@RequestMapping("/compilations") +@RequiredArgsConstructor +public class PublicCompilationController { + + private final CompilationService compilationService; + + @GetMapping + public List getCompilations(@RequestParam(required = false) Boolean pinned, + @RequestParam(defaultValue = "0") int from, + @RequestParam(defaultValue = "10") int size) { + return compilationService.getCompilations(pinned, from, size); + } + + @GetMapping("/{compId}") + public CompilationDto getCompilationById(@PathVariable Long compId) { + return compilationService.getCompilationById(compId); + } +} \ No newline at end of file diff --git a/ewm-main-service/src/main/java/ru/practicum/ewm/controller/pub/PublicEventController.java b/ewm-main-service/src/main/java/ru/practicum/ewm/controller/pub/PublicEventController.java new file mode 100644 index 0000000..4eed182 --- /dev/null +++ b/ewm-main-service/src/main/java/ru/practicum/ewm/controller/pub/PublicEventController.java @@ -0,0 +1,44 @@ +package ru.practicum.ewm.controller.pub; + +import jakarta.servlet.http.HttpServletRequest; +import jakarta.validation.constraints.Positive; +import jakarta.validation.constraints.PositiveOrZero; +import lombok.RequiredArgsConstructor; +import org.springframework.format.annotation.DateTimeFormat; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; +import ru.practicum.ewm.dto.response.EventFullDto; +import ru.practicum.ewm.dto.response.EventShortDto; +import ru.practicum.ewm.service.EventService; + +import java.time.LocalDateTime; +import java.util.List; + +@RestController +@RequestMapping("/events") +@RequiredArgsConstructor +@Validated +public class PublicEventController { + + private final EventService eventService; + + @GetMapping + public List getEvents( + @RequestParam(required = false) String text, + @RequestParam(required = false) List categories, + @RequestParam(required = false) Boolean paid, + @RequestParam(required = false) @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") LocalDateTime rangeStart, + @RequestParam(required = false) @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") LocalDateTime rangeEnd, + @RequestParam(defaultValue = "false") Boolean onlyAvailable, + @RequestParam(required = false) String sort, + @RequestParam(defaultValue = "0") @PositiveOrZero int from, + @RequestParam(defaultValue = "10") @Positive int size, + HttpServletRequest request) { + return eventService.getEventsPublic(text, categories, paid, rangeStart, rangeEnd, onlyAvailable, sort, from, size, request); + } + + @GetMapping("/{id}") + public EventFullDto getEvent(@PathVariable Long id, HttpServletRequest request) { + return eventService.getEventByIdPublic(id, request); + } +} \ No newline at end of file diff --git a/ewm-main-service/src/main/java/ru/practicum/ewm/controller/pub/PublicLocationController.java b/ewm-main-service/src/main/java/ru/practicum/ewm/controller/pub/PublicLocationController.java new file mode 100644 index 0000000..cca0008 --- /dev/null +++ b/ewm-main-service/src/main/java/ru/practicum/ewm/controller/pub/PublicLocationController.java @@ -0,0 +1,29 @@ +package ru.practicum.ewm.controller.pub; + +import lombok.RequiredArgsConstructor; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; +import ru.practicum.ewm.dto.response.LocationDto; +import ru.practicum.ewm.service.LocationService; + +import java.util.List; + +@RestController +@RequestMapping("/locations") +@RequiredArgsConstructor +public class PublicLocationController { + + private final LocationService locationService; + + @GetMapping + public List getAllLocations() { + return locationService.getAllLocations(); + } + + @GetMapping("/{locationId}") + public LocationDto getLocation(@PathVariable Long locationId) { + return locationService.getLocation(locationId); + } +} \ No newline at end of file diff --git a/ewm-main-service/src/main/java/ru/practicum/ewm/dto/request/NewEventDto.java b/ewm-main-service/src/main/java/ru/practicum/ewm/dto/request/NewEventDto.java index cfb19ff..9f7a7f3 100644 --- a/ewm-main-service/src/main/java/ru/practicum/ewm/dto/request/NewEventDto.java +++ b/ewm-main-service/src/main/java/ru/practicum/ewm/dto/request/NewEventDto.java @@ -6,6 +6,7 @@ import lombok.Getter; import lombok.Setter; import lombok.experimental.FieldDefaults; +import ru.practicum.ewm.dto.response.LocationDto; import java.time.LocalDateTime; @@ -30,7 +31,7 @@ public class NewEventDto { Long category; @NotNull - Long location; + LocationDto location; @NotNull @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") diff --git a/ewm-main-service/src/main/java/ru/practicum/ewm/dto/request/UpdateEventAdmin.java b/ewm-main-service/src/main/java/ru/practicum/ewm/dto/request/UpdateEventAdmin.java index b707545..2673a71 100644 --- a/ewm-main-service/src/main/java/ru/practicum/ewm/dto/request/UpdateEventAdmin.java +++ b/ewm-main-service/src/main/java/ru/practicum/ewm/dto/request/UpdateEventAdmin.java @@ -6,6 +6,7 @@ import lombok.Getter; import lombok.Setter; import lombok.experimental.FieldDefaults; +import ru.practicum.ewm.dto.response.LocationDto; import java.time.LocalDateTime; @@ -24,7 +25,7 @@ public class UpdateEventAdmin { String description; Long category; - Long location; + LocationDto location; @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") LocalDateTime eventDate; diff --git a/ewm-main-service/src/main/java/ru/practicum/ewm/dto/request/UpdateEventUser.java b/ewm-main-service/src/main/java/ru/practicum/ewm/dto/request/UpdateEventUser.java index cdcc376..12385b5 100644 --- a/ewm-main-service/src/main/java/ru/practicum/ewm/dto/request/UpdateEventUser.java +++ b/ewm-main-service/src/main/java/ru/practicum/ewm/dto/request/UpdateEventUser.java @@ -6,6 +6,7 @@ import lombok.Getter; import lombok.Setter; import lombok.experimental.FieldDefaults; +import ru.practicum.ewm.dto.response.LocationDto; import java.time.LocalDateTime; @@ -24,7 +25,7 @@ public class UpdateEventUser { String description; Long category; - Long location; + LocationDto location; @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") LocalDateTime eventDate; diff --git a/ewm-main-service/src/main/java/ru/practicum/ewm/dto/response/ApiError.java b/ewm-main-service/src/main/java/ru/practicum/ewm/dto/response/ApiError.java new file mode 100644 index 0000000..ce9b904 --- /dev/null +++ b/ewm-main-service/src/main/java/ru/practicum/ewm/dto/response/ApiError.java @@ -0,0 +1,19 @@ +package ru.practicum.ewm.dto.response; + +import lombok.*; +import lombok.experimental.FieldDefaults; + +import java.util.List; + +@Data +@Builder +@AllArgsConstructor +@NoArgsConstructor +@FieldDefaults(level = AccessLevel.PRIVATE) +public class ApiError { + List errors; + String message; + String reason; + String status; + String timestamp; +} \ No newline at end of file diff --git a/ewm-main-service/src/main/java/ru/practicum/ewm/dto/response/CategoryDto.java b/ewm-main-service/src/main/java/ru/practicum/ewm/dto/response/CategoryDto.java index 5cd4ece..fa2945c 100644 --- a/ewm-main-service/src/main/java/ru/practicum/ewm/dto/response/CategoryDto.java +++ b/ewm-main-service/src/main/java/ru/practicum/ewm/dto/response/CategoryDto.java @@ -1,14 +1,19 @@ package ru.practicum.ewm.dto.response; -import lombok.AccessLevel; -import lombok.Getter; -import lombok.Setter; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.Size; +import lombok.*; import lombok.experimental.FieldDefaults; -@Getter -@Setter +@Data +@Builder +@AllArgsConstructor +@NoArgsConstructor @FieldDefaults(level = AccessLevel.PRIVATE) public class CategoryDto { Long id; - String name; + + @NotBlank + @Size(min = 1, max = 50) + String name; } \ No newline at end of file diff --git a/ewm-main-service/src/main/java/ru/practicum/ewm/exception/BadRequestException.java b/ewm-main-service/src/main/java/ru/practicum/ewm/exception/BadRequestException.java new file mode 100644 index 0000000..7dc9124 --- /dev/null +++ b/ewm-main-service/src/main/java/ru/practicum/ewm/exception/BadRequestException.java @@ -0,0 +1,7 @@ +package ru.practicum.ewm.exception; + +public class BadRequestException extends RuntimeException { + public BadRequestException(String message) { + super(message); + } +} \ No newline at end of file diff --git a/ewm-main-service/src/main/java/ru/practicum/ewm/exception/ConflictException.java b/ewm-main-service/src/main/java/ru/practicum/ewm/exception/ConflictException.java new file mode 100644 index 0000000..2603c54 --- /dev/null +++ b/ewm-main-service/src/main/java/ru/practicum/ewm/exception/ConflictException.java @@ -0,0 +1,7 @@ +package ru.practicum.ewm.exception; + +public class ConflictException extends RuntimeException { + public ConflictException(String message) { + super(message); + } +} \ No newline at end of file diff --git a/ewm-main-service/src/main/java/ru/practicum/ewm/exception/NotFoundException.java b/ewm-main-service/src/main/java/ru/practicum/ewm/exception/NotFoundException.java new file mode 100644 index 0000000..ef340c6 --- /dev/null +++ b/ewm-main-service/src/main/java/ru/practicum/ewm/exception/NotFoundException.java @@ -0,0 +1,7 @@ +package ru.practicum.ewm.exception; + +public class NotFoundException extends RuntimeException { + public NotFoundException(String message) { + super(message); + } +} \ No newline at end of file diff --git a/ewm-main-service/src/main/java/ru/practicum/ewm/mapper/CompilationMapper.java b/ewm-main-service/src/main/java/ru/practicum/ewm/mapper/CompilationMapper.java new file mode 100644 index 0000000..cdce13d --- /dev/null +++ b/ewm-main-service/src/main/java/ru/practicum/ewm/mapper/CompilationMapper.java @@ -0,0 +1,35 @@ +package ru.practicum.ewm.mapper; + +import ru.practicum.ewm.dto.request.NewCompilationDto; +import ru.practicum.ewm.dto.response.CompilationDto; +import ru.practicum.ewm.model.Compilation; +import ru.practicum.ewm.model.Event; + +import java.util.Set; +import java.util.stream.Collectors; + +public class CompilationMapper { + + public static Compilation toCompilation(NewCompilationDto dto, Set events) { + Compilation compilation = new Compilation(); + compilation.setTitle(dto.getTitle()); + compilation.setEvents(events); + compilation.setPinned(dto.getPinned() != null ? dto.getPinned() : false); + return compilation; + } + + public static CompilationDto toDto(Compilation compilation) { + CompilationDto dto = new CompilationDto(); + dto.setId(compilation.getId()); + dto.setTitle(compilation.getTitle()); + dto.setPinned(compilation.getPinned()); + + if (compilation.getEvents() != null) { + + dto.setEvents(compilation.getEvents().stream() + .map(EventMapper::toShortDto) + .collect(Collectors.toSet())); + } + return dto; + } +} \ No newline at end of file diff --git a/ewm-main-service/src/main/java/ru/practicum/ewm/mapper/EventMapper.java b/ewm-main-service/src/main/java/ru/practicum/ewm/mapper/EventMapper.java new file mode 100644 index 0000000..6a8bee9 --- /dev/null +++ b/ewm-main-service/src/main/java/ru/practicum/ewm/mapper/EventMapper.java @@ -0,0 +1,60 @@ +package ru.practicum.ewm.mapper; + +import ru.practicum.ewm.dto.response.EventFullDto; +import ru.practicum.ewm.dto.response.EventShortDto; +import ru.practicum.ewm.dto.request.NewEventDto; +import ru.practicum.ewm.model.Event; + +public class EventMapper { + + public static EventShortDto toShortDto(Event event) { + EventShortDto eventShortDto = new EventShortDto(); + eventShortDto.setId(event.getId()); + eventShortDto.setTitle(event.getTitle()); + eventShortDto.setAnnotation(event.getAnnotation()); + eventShortDto.setCategory(CategoryMapper.toDto(event.getCategory())); + eventShortDto.setEventDate(event.getEventDate()); + eventShortDto.setInitiator(UserMapper.toDto(event.getInitiator())); + eventShortDto.setPaid(event.getPaid()); + eventShortDto.setConfirmedRequests(event.getConfirmedRequests() != null ? event.getConfirmedRequests() : 0L); + eventShortDto.setViews(event.getViews() != null ? event.getViews() : 0L); + return eventShortDto; + } + + public static EventFullDto toFullDto(Event event) { + EventFullDto eventFullDto = new EventFullDto(); + eventFullDto.setId(event.getId()); + eventFullDto.setTitle(event.getTitle()); + eventFullDto.setAnnotation(event.getAnnotation()); + eventFullDto.setDescription(event.getDescription()); + eventFullDto.setCategory(CategoryMapper.toDto(event.getCategory())); + eventFullDto.setEventDate(event.getEventDate()); + eventFullDto.setInitiator(UserMapper.toDto(event.getInitiator())); + + if (event.getLocation() != null) { + eventFullDto.setLocation(LocationMapper.toDto(event.getLocation())); + } + + eventFullDto.setCreatedOn(event.getCreatedOn()); + eventFullDto.setPublishedOn(event.getPublishedOn()); + eventFullDto.setState(event.getState()); + eventFullDto.setPaid(event.getPaid()); + eventFullDto.setParticipantLimit(event.getParticipantLimit()); + eventFullDto.setRequestModeration(event.getRequestModeration()); + eventFullDto.setConfirmedRequests(event.getConfirmedRequests() != null ? event.getConfirmedRequests() : 0L); + eventFullDto.setViews(event.getViews() != null ? event.getViews() : 0L); + return eventFullDto; + } + + public static Event toEvent(NewEventDto newEventDto) { + Event event = new Event(); + event.setTitle(newEventDto.getTitle()); + event.setAnnotation(newEventDto.getAnnotation()); + event.setDescription(newEventDto.getDescription()); + event.setEventDate(newEventDto.getEventDate()); + event.setPaid(newEventDto.getPaid()); + event.setParticipantLimit(newEventDto.getParticipantLimit()); + event.setRequestModeration(newEventDto.getRequestModeration()); + return event; + } +} \ No newline at end of file diff --git a/ewm-main-service/src/main/java/ru/practicum/ewm/mapper/LocationMapper.java b/ewm-main-service/src/main/java/ru/practicum/ewm/mapper/LocationMapper.java index 22fab6f..be4ad71 100644 --- a/ewm-main-service/src/main/java/ru/practicum/ewm/mapper/LocationMapper.java +++ b/ewm-main-service/src/main/java/ru/practicum/ewm/mapper/LocationMapper.java @@ -7,6 +7,7 @@ public class LocationMapper { public static LocationDto toDto(Location location) { + if (location == null) return null; LocationDto locationDto = new LocationDto(); locationDto.setId(location.getId()); locationDto.setName(location.getName()); @@ -17,6 +18,7 @@ public static LocationDto toDto(Location location) { } public static Location toLocation(NewLocationDto request) { + if (request == null) return null; Location location = new Location(); location.setName(request.getName()); location.setLat(request.getLat()); @@ -24,4 +26,12 @@ public static Location toLocation(NewLocationDto request) { location.setRadius(request.getRadius()); return location; } + + public static Location toLocation(LocationDto dto) { + if (dto == null) return null; + Location location = new Location(); + location.setLat(dto.getLat()); + location.setLon(dto.getLon()); + return location; + } } \ No newline at end of file diff --git a/ewm-main-service/src/main/java/ru/practicum/ewm/mapper/RequestMapper.java b/ewm-main-service/src/main/java/ru/practicum/ewm/mapper/RequestMapper.java new file mode 100644 index 0000000..f9932b4 --- /dev/null +++ b/ewm-main-service/src/main/java/ru/practicum/ewm/mapper/RequestMapper.java @@ -0,0 +1,17 @@ +package ru.practicum.ewm.mapper; + +import ru.practicum.ewm.dto.response.RequestDto; +import ru.practicum.ewm.model.ParticipationRequest; + +public class RequestMapper { + + public static RequestDto toDto(ParticipationRequest request) { + RequestDto requestDto = new RequestDto(); + requestDto.setId(request.getId()); + requestDto.setEvent(request.getEvent().getId()); + requestDto.setRequester(request.getRequester().getId()); + requestDto.setStatus(request.getStatus()); + requestDto.setCreated(request.getCreated()); + return requestDto; + } +} \ No newline at end of file diff --git a/ewm-main-service/src/main/java/ru/practicum/ewm/model/Event.java b/ewm-main-service/src/main/java/ru/practicum/ewm/model/Event.java index 84d8aea..a536bdd 100644 --- a/ewm-main-service/src/main/java/ru/practicum/ewm/model/Event.java +++ b/ewm-main-service/src/main/java/ru/practicum/ewm/model/Event.java @@ -22,10 +22,10 @@ public class Event { @Column(nullable = false) String title; - @Column(nullable = false) + @Column(nullable = false, length = 2000) String annotation; - @Column(nullable = false, columnDefinition = "TEXT") + @Column(nullable = false, length = 7000) String description; @ManyToOne diff --git a/ewm-main-service/src/main/java/ru/practicum/ewm/model/Location.java b/ewm-main-service/src/main/java/ru/practicum/ewm/model/Location.java index 981754a..9d03cb1 100644 --- a/ewm-main-service/src/main/java/ru/practicum/ewm/model/Location.java +++ b/ewm-main-service/src/main/java/ru/practicum/ewm/model/Location.java @@ -17,7 +17,7 @@ public class Location { @GeneratedValue(strategy = GenerationType.IDENTITY) Long id; - @Column(nullable = false) + @Column String name; @Column(nullable = false) @@ -26,6 +26,6 @@ public class Location { @Column(nullable = false) Float lon; - @Column(nullable = false) + @Column Float radius; } \ No newline at end of file diff --git a/ewm-main-service/src/main/java/ru/practicum/ewm/repository/CategoryRepository.java b/ewm-main-service/src/main/java/ru/practicum/ewm/repository/CategoryRepository.java new file mode 100644 index 0000000..6902215 --- /dev/null +++ b/ewm-main-service/src/main/java/ru/practicum/ewm/repository/CategoryRepository.java @@ -0,0 +1,7 @@ +package ru.practicum.ewm.repository; + +import org.springframework.data.jpa.repository.JpaRepository; +import ru.practicum.ewm.model.Category; + +public interface CategoryRepository extends JpaRepository { +} \ No newline at end of file diff --git a/ewm-main-service/src/main/java/ru/practicum/ewm/repository/CompilationRepository.java b/ewm-main-service/src/main/java/ru/practicum/ewm/repository/CompilationRepository.java new file mode 100644 index 0000000..e1e88b1 --- /dev/null +++ b/ewm-main-service/src/main/java/ru/practicum/ewm/repository/CompilationRepository.java @@ -0,0 +1,11 @@ +package ru.practicum.ewm.repository; + +import org.springframework.data.domain.Pageable; +import org.springframework.data.jpa.repository.JpaRepository; +import ru.practicum.ewm.model.Compilation; + +import java.util.List; + +public interface CompilationRepository extends JpaRepository { + List findAllByPinned(Boolean pinned, Pageable pageable); +} \ No newline at end of file diff --git a/ewm-main-service/src/main/java/ru/practicum/ewm/repository/EventRepository.java b/ewm-main-service/src/main/java/ru/practicum/ewm/repository/EventRepository.java new file mode 100644 index 0000000..464f914 --- /dev/null +++ b/ewm-main-service/src/main/java/ru/practicum/ewm/repository/EventRepository.java @@ -0,0 +1,56 @@ +package ru.practicum.ewm.repository; + +import org.springframework.data.domain.Pageable; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; +import ru.practicum.ewm.model.Event; +import ru.practicum.ewm.model.EventState; + +import java.time.LocalDateTime; +import java.util.List; +import java.util.Optional; + +public interface EventRepository extends JpaRepository { + + @Query("SELECT COUNT(e) > 0 FROM Event e WHERE e.category.id = :catId") + boolean existsByCategoryId(@Param("catId") Long catId); + + List findAllByInitiatorId(Long initiatorId, Pageable pageable); + + Optional findByIdAndInitiatorId(Long eventId, Long initiatorId); + + @Query("SELECT e FROM Event e " + + "WHERE (:users IS NULL OR e.initiator.id IN :users) " + + "AND (:states IS NULL OR e.state IN :states) " + + "AND (:categories IS NULL OR e.category.id IN :categories) " + + "AND (CAST(:rangeStart AS timestamp) IS NULL OR e.eventDate >= :rangeStart) " + + "AND (CAST(:rangeEnd AS timestamp) IS NULL OR e.eventDate <= :rangeEnd)") + List findEventsByAdmin( + @Param("users") List users, + @Param("states") List states, + @Param("categories") List categories, + @Param("rangeStart") LocalDateTime rangeStart, + @Param("rangeEnd") LocalDateTime rangeEnd, + Pageable pageable); + + @Query(value = "SELECT * FROM events e " + + "WHERE e.state = :state " + + "AND (:text IS NULL OR (e.annotation ILIKE CONCAT('%', :text, '%') OR e.description ILIKE CONCAT('%', :text, '%'))) " + + "AND (:categories IS NULL OR e.category_id IN :categories) " + + "AND (:paid IS NULL OR e.paid = :paid) " + + "AND (e.event_date >= :rangeStart) " + + "AND (e.event_date <= :rangeEnd) " + + "AND (:onlyAvailable = false OR e.participant_limit = 0 OR e.confirmed_requests < e.participant_limit)", + nativeQuery = true) + List findPublishedEvents( + @Param("state") String state, // <-- теперь String, не EventState + @Param("text") String text, + @Param("categories") List categories, + @Param("paid") Boolean paid, + @Param("rangeStart") LocalDateTime rangeStart, + @Param("rangeEnd") LocalDateTime rangeEnd, + @Param("onlyAvailable") Boolean onlyAvailable, + Pageable pageable); + Optional findByIdAndState(Long id, EventState state); +} \ No newline at end of file diff --git a/ewm-main-service/src/main/java/ru/practicum/ewm/repository/LocationRepository.java b/ewm-main-service/src/main/java/ru/practicum/ewm/repository/LocationRepository.java new file mode 100644 index 0000000..d45fc8a --- /dev/null +++ b/ewm-main-service/src/main/java/ru/practicum/ewm/repository/LocationRepository.java @@ -0,0 +1,7 @@ +package ru.practicum.ewm.repository; + +import org.springframework.data.jpa.repository.JpaRepository; +import ru.practicum.ewm.model.Location; + +public interface LocationRepository extends JpaRepository { +} \ No newline at end of file diff --git a/ewm-main-service/src/main/java/ru/practicum/ewm/repository/ParticipationRequestRepository.java b/ewm-main-service/src/main/java/ru/practicum/ewm/repository/ParticipationRequestRepository.java new file mode 100644 index 0000000..161190e --- /dev/null +++ b/ewm-main-service/src/main/java/ru/practicum/ewm/repository/ParticipationRequestRepository.java @@ -0,0 +1,18 @@ +package ru.practicum.ewm.repository; + +import org.springframework.data.jpa.repository.JpaRepository; +import ru.practicum.ewm.model.ParticipationRequest; +import ru.practicum.ewm.model.RequestStatus; + +import java.util.List; + +public interface ParticipationRequestRepository extends JpaRepository { + + List findAllByRequesterId(Long requesterId); + + List findAllByEventId(Long eventId); + + Long countByEventIdAndStatus(Long eventId, RequestStatus status); + + boolean existsByRequesterIdAndEventId(Long requesterId, Long eventId); +} \ No newline at end of file diff --git a/ewm-main-service/src/main/java/ru/practicum/ewm/repository/UserRepository.java b/ewm-main-service/src/main/java/ru/practicum/ewm/repository/UserRepository.java new file mode 100644 index 0000000..f2ac76c --- /dev/null +++ b/ewm-main-service/src/main/java/ru/practicum/ewm/repository/UserRepository.java @@ -0,0 +1,7 @@ +package ru.practicum.ewm.repository; + +import org.springframework.data.jpa.repository.JpaRepository; +import ru.practicum.ewm.model.User; + +public interface UserRepository extends JpaRepository { +} \ No newline at end of file diff --git a/ewm-main-service/src/main/java/ru/practicum/ewm/service/CategoryService.java b/ewm-main-service/src/main/java/ru/practicum/ewm/service/CategoryService.java new file mode 100644 index 0000000..fbc0808 --- /dev/null +++ b/ewm-main-service/src/main/java/ru/practicum/ewm/service/CategoryService.java @@ -0,0 +1,19 @@ +package ru.practicum.ewm.service; + +import ru.practicum.ewm.dto.request.NewCategoryDto; +import ru.practicum.ewm.dto.response.CategoryDto; + +import java.util.List; + +public interface CategoryService { + + CategoryDto createCategory(NewCategoryDto newCategoryDto); + + CategoryDto updateCategory(Long catId, CategoryDto categoryDto); + + void deleteCategory(Long catId); + + List getCategories(int from, int size); + + CategoryDto getCategory(Long catId); +} \ No newline at end of file diff --git a/ewm-main-service/src/main/java/ru/practicum/ewm/service/CategoryServiceImpl.java b/ewm-main-service/src/main/java/ru/practicum/ewm/service/CategoryServiceImpl.java new file mode 100644 index 0000000..1087e7c --- /dev/null +++ b/ewm-main-service/src/main/java/ru/practicum/ewm/service/CategoryServiceImpl.java @@ -0,0 +1,77 @@ +package ru.practicum.ewm.service; + +import lombok.AccessLevel; +import lombok.RequiredArgsConstructor; +import lombok.experimental.FieldDefaults; +import org.springframework.data.domain.PageRequest; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import ru.practicum.ewm.dto.request.NewCategoryDto; +import ru.practicum.ewm.dto.response.CategoryDto; +import ru.practicum.ewm.exception.ConflictException; +import ru.practicum.ewm.exception.NotFoundException; +import ru.practicum.ewm.mapper.CategoryMapper; +import ru.practicum.ewm.model.Category; +import ru.practicum.ewm.repository.CategoryRepository; +import ru.practicum.ewm.repository.EventRepository; + +import java.util.List; +import java.util.stream.Collectors; + +@Service +@RequiredArgsConstructor +@FieldDefaults(level = AccessLevel.PRIVATE, makeFinal = true) +@Transactional(readOnly = true) +public class CategoryServiceImpl implements CategoryService { + + CategoryRepository categoryRepository; + + @Override + @Transactional + public CategoryDto createCategory(NewCategoryDto newCategoryDto) { + Category category = CategoryMapper.toCategory(newCategoryDto); + Category savedCategory = categoryRepository.save(category); + return CategoryMapper.toDto(savedCategory); + } + + @Override + @Transactional + public CategoryDto updateCategory(Long catId, CategoryDto categoryDto) { + Category category = categoryRepository.findById(catId) + .orElseThrow(() -> new NotFoundException("Category not found")); + category.setName(categoryDto.getName()); + Category updatedCategory = categoryRepository.save(category); + return CategoryMapper.toDto(updatedCategory); + } + + @Override + public List getCategories(int from, int size) { + PageRequest pageRequest = PageRequest.of(from / size, size); + return categoryRepository.findAll(pageRequest).stream() + .map(CategoryMapper::toDto) + .collect(Collectors.toList()); + } + + @Override + public CategoryDto getCategory(Long catId) { + return categoryRepository.findById(catId) + .map(CategoryMapper::toDto) + .orElseThrow(() -> new NotFoundException("Category with id=" + catId + " was not found")); + } + + + private final EventRepository eventRepository; + + @Override + @Transactional + public void deleteCategory(Long catId) { + if (!categoryRepository.existsById(catId)) { + throw new NotFoundException("Category not found"); + } + + if (eventRepository.existsByCategoryId(catId)) { + throw new ConflictException("The category is not empty"); + } + categoryRepository.deleteById(catId); + } +} \ No newline at end of file diff --git a/ewm-main-service/src/main/java/ru/practicum/ewm/service/CompilationService.java b/ewm-main-service/src/main/java/ru/practicum/ewm/service/CompilationService.java new file mode 100644 index 0000000..7dc1424 --- /dev/null +++ b/ewm-main-service/src/main/java/ru/practicum/ewm/service/CompilationService.java @@ -0,0 +1,18 @@ +package ru.practicum.ewm.service; + +import ru.practicum.ewm.dto.request.NewCompilationDto; +import ru.practicum.ewm.dto.request.UpdateCompilationRequest; +import ru.practicum.ewm.dto.response.CompilationDto; + +import java.util.List; + +public interface CompilationService { + // Admin API + CompilationDto addCompilation(NewCompilationDto newCompilationDto); + void deleteCompilation(Long compId); + CompilationDto updateCompilation(Long compId, UpdateCompilationRequest updateRequest); + + // Public API + List getCompilations(Boolean pinned, int from, int size); + CompilationDto getCompilationById(Long compId); +} \ No newline at end of file diff --git a/ewm-main-service/src/main/java/ru/practicum/ewm/service/CompilationServiceImpl.java b/ewm-main-service/src/main/java/ru/practicum/ewm/service/CompilationServiceImpl.java new file mode 100644 index 0000000..e0bf398 --- /dev/null +++ b/ewm-main-service/src/main/java/ru/practicum/ewm/service/CompilationServiceImpl.java @@ -0,0 +1,107 @@ +package ru.practicum.ewm.service; + +import lombok.AccessLevel; +import lombok.RequiredArgsConstructor; +import lombok.experimental.FieldDefaults; +import org.springframework.data.domain.PageRequest; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import ru.practicum.ewm.dto.request.NewCompilationDto; +import ru.practicum.ewm.dto.request.UpdateCompilationRequest; +import ru.practicum.ewm.dto.response.CompilationDto; +import ru.practicum.ewm.exception.NotFoundException; +import ru.practicum.ewm.mapper.CompilationMapper; +import ru.practicum.ewm.model.Compilation; +import ru.practicum.ewm.model.Event; +import ru.practicum.ewm.repository.CompilationRepository; +import ru.practicum.ewm.repository.EventRepository; + +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; + +@Service +@RequiredArgsConstructor +@FieldDefaults(level = AccessLevel.PRIVATE, makeFinal = true) +@Transactional(readOnly = true) +public class CompilationServiceImpl implements CompilationService { + + CompilationRepository compilationRepository; + EventRepository eventRepository; + + @Override + @Transactional + public CompilationDto addCompilation(NewCompilationDto newCompilationDto) { + Set events = new HashSet<>(); + + if (newCompilationDto.getEvents() != null && !newCompilationDto.getEvents().isEmpty()) { + events = new HashSet<>(eventRepository.findAllById(newCompilationDto.getEvents())); + } + + Compilation compilation = CompilationMapper.toCompilation(newCompilationDto, events); + + if (compilation.getPinned() == null) { + compilation.setPinned(false); + } + + return CompilationMapper.toDto(compilationRepository.save(compilation)); + } + @Override + @Transactional + public void deleteCompilation(Long compId) { + if (!compilationRepository.existsById(compId)) { + throw new RuntimeException("Compilation not found"); + } + compilationRepository.deleteById(compId); + } + + @Override + @Transactional + public CompilationDto updateCompilation(Long compId, UpdateCompilationRequest updateRequest) { + Compilation compilation = compilationRepository.findById(compId) + .orElseThrow(() -> new NotFoundException("Compilation with id=" + compId + " was not found")); + + + if (updateRequest.getEvents() != null) { + Set events = new HashSet<>(eventRepository.findAllById(updateRequest.getEvents())); + compilation.setEvents(events); + } + + + if (updateRequest.getPinned() != null) { + compilation.setPinned(updateRequest.getPinned()); + } + + + if (updateRequest.getTitle() != null && !updateRequest.getTitle().isBlank()) { + compilation.setTitle(updateRequest.getTitle()); + } + + Compilation updatedCompilation = compilationRepository.save(compilation); + return CompilationMapper.toDto(updatedCompilation); + } + + @Override + public List getCompilations(Boolean pinned, int from, int size) { + PageRequest pageRequest = PageRequest.of(from / size, size); + List compilations; + + if (pinned != null) { + compilations = compilationRepository.findAllByPinned(pinned, pageRequest); + } else { + compilations = compilationRepository.findAll(pageRequest).getContent(); + } + + return compilations.stream() + .map(CompilationMapper::toDto) + .collect(Collectors.toList()); + } + + @Override + public CompilationDto getCompilationById(Long compId) { + Compilation compilation = compilationRepository.findById(compId) + .orElseThrow(() -> new RuntimeException("Compilation not found")); + return CompilationMapper.toDto(compilation); + } +} \ No newline at end of file diff --git a/ewm-main-service/src/main/java/ru/practicum/ewm/service/EventService.java b/ewm-main-service/src/main/java/ru/practicum/ewm/service/EventService.java new file mode 100644 index 0000000..c74227b --- /dev/null +++ b/ewm-main-service/src/main/java/ru/practicum/ewm/service/EventService.java @@ -0,0 +1,32 @@ +package ru.practicum.ewm.service; + +import jakarta.servlet.http.HttpServletRequest; +import ru.practicum.ewm.dto.request.NewEventDto; +import ru.practicum.ewm.dto.request.UpdateEventAdmin; +import ru.practicum.ewm.dto.request.UpdateEventUser; +import ru.practicum.ewm.dto.response.EventFullDto; +import ru.practicum.ewm.dto.response.EventShortDto; +import ru.practicum.ewm.model.EventState; + +import java.time.LocalDateTime; +import java.util.List; + +public interface EventService { + // Private + List getEventsByUserId(Long userId, int from, int size); + EventFullDto createEvent(Long userId, NewEventDto newEventDto); + EventFullDto getEventByIdAndUserId(Long userId, Long eventId); + EventFullDto updateEventByUserId(Long userId, Long eventId, UpdateEventUser updateRequest); + + // Admin + List getEventsByAdmin(List users, List states, List categories, + LocalDateTime rangeStart, LocalDateTime rangeEnd, int from, int size); + EventFullDto updateEventByAdmin(Long eventId, UpdateEventAdmin updateRequest); + + // Public + List getEventsPublic(String text, List categories, Boolean paid, + LocalDateTime rangeStart, LocalDateTime rangeEnd, + Boolean onlyAvailable, String sort, int from, int size, + HttpServletRequest request); + EventFullDto getEventByIdPublic(Long id, HttpServletRequest request); +} \ No newline at end of file diff --git a/ewm-main-service/src/main/java/ru/practicum/ewm/service/EventServiceImpl.java b/ewm-main-service/src/main/java/ru/practicum/ewm/service/EventServiceImpl.java new file mode 100644 index 0000000..b0d46ab --- /dev/null +++ b/ewm-main-service/src/main/java/ru/practicum/ewm/service/EventServiceImpl.java @@ -0,0 +1,259 @@ +package ru.practicum.ewm.service; + +import jakarta.servlet.http.HttpServletRequest; +import lombok.AccessLevel; +import lombok.RequiredArgsConstructor; +import lombok.experimental.FieldDefaults; +import lombok.extern.slf4j.Slf4j; +import org.springframework.data.domain.PageRequest; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import ru.practicum.client.StatsClient; +import ru.practicum.ewm.dto.request.NewEventDto; +import ru.practicum.ewm.dto.request.UpdateEventAdmin; +import ru.practicum.ewm.dto.request.UpdateEventUser; +import ru.practicum.ewm.dto.response.EventFullDto; +import ru.practicum.ewm.dto.response.EventShortDto; +import ru.practicum.ewm.dto.response.LocationDto; +import ru.practicum.ewm.exception.BadRequestException; +import ru.practicum.ewm.exception.ConflictException; +import ru.practicum.ewm.exception.NotFoundException; +import ru.practicum.ewm.mapper.EventMapper; +import ru.practicum.ewm.mapper.LocationMapper; +import ru.practicum.ewm.model.*; +import ru.practicum.ewm.repository.*; + +import java.time.LocalDateTime; +import java.util.List; +import java.util.stream.Collectors; + +@Service +@Slf4j +@RequiredArgsConstructor +@FieldDefaults(level = AccessLevel.PRIVATE, makeFinal = true) +@Transactional(readOnly = true) +public class EventServiceImpl implements EventService { + + EventRepository eventRepository; + UserRepository userRepository; + CategoryRepository categoryRepository; + LocationRepository locationRepository; + StatsClient statsClient; + + static String APP_NAME = "ewm-main-service"; + + // --- PRIVATE API --- + + @Override + @Transactional + public EventFullDto createEvent(Long userId, NewEventDto dto) { + + if (dto.getEventDate().isBefore(LocalDateTime.now().plusHours(2))) { + throw new BadRequestException("Event date must be at least 2 hours in the future."); + } + + User initiator = userRepository.findById(userId) + .orElseThrow(() -> new NotFoundException("User with id=" + userId + " was not found")); + Category category = categoryRepository.findById(dto.getCategory()) + .orElseThrow(() -> new NotFoundException("Category with id=" + dto.getCategory() + " was not found")); + + + Location location = locationRepository.save(LocationMapper.toLocation(dto.getLocation())); + + Event event = EventMapper.toEvent(dto); + event.setInitiator(initiator); + event.setCategory(category); + event.setLocation(location); + event.setCreatedOn(LocalDateTime.now()); + event.setState(EventState.PENDING); + event.setConfirmedRequests(0L); + event.setViews(0L); + + + if (event.getPaid() == null) event.setPaid(false); + if (event.getParticipantLimit() == null) event.setParticipantLimit(0); + if (event.getRequestModeration() == null) event.setRequestModeration(true); + + return EventMapper.toFullDto(eventRepository.save(event)); + } + + @Override + public List getEventsByUserId(Long userId, int from, int size) { + return eventRepository.findAllByInitiatorId(userId, PageRequest.of(from / size, size)) + .stream().map(EventMapper::toShortDto).collect(Collectors.toList()); + } + + @Override + public EventFullDto getEventByIdAndUserId(Long userId, Long eventId) { + Event event = eventRepository.findByIdAndInitiatorId(eventId, userId) + .orElseThrow(() -> new NotFoundException("Event with id=" + eventId + " not found")); + return EventMapper.toFullDto(event); + } + + @Override + @Transactional + public EventFullDto updateEventByUserId(Long userId, Long eventId, UpdateEventUser request) { + Event event = eventRepository.findByIdAndInitiatorId(eventId, userId) + .orElseThrow(() -> new NotFoundException("Event with id=" + eventId + " was not found")); + + if (event.getState() == EventState.PUBLISHED) { + throw new ConflictException("Only pending or canceled events can be changed"); + } + + if (request.getEventDate() != null) { + + if (request.getEventDate().isBefore(LocalDateTime.now().plusHours(2))) { + throw new BadRequestException("Event date must be at least 2 hours in the future."); + } + event.setEventDate(request.getEventDate()); + } + + if (request.getStateAction() != null) { + if (request.getStateAction().equals("SEND_TO_REVIEW")) { + event.setState(EventState.PENDING); + } else if (request.getStateAction().equals("CANCEL_REVIEW")) { + event.setState(EventState.CANCELED); + } + } + + + updateEventCommonFields(event, request.getAnnotation(), request.getCategory(), request.getDescription(), + request.getLocation(), request.getPaid(), request.getParticipantLimit(), request.getRequestModeration(), request.getTitle()); + + return EventMapper.toFullDto(eventRepository.save(event)); + } + + // --- ADMIN API --- + + @Override + public List getEventsByAdmin(List users, List states, List categories, + LocalDateTime start, LocalDateTime end, int from, int size) { + return eventRepository.findEventsByAdmin(users, states, categories, start, end, PageRequest.of(from / size, size)) + .stream().map(EventMapper::toFullDto).collect(Collectors.toList()); + } + + @Override + @Transactional + public EventFullDto updateEventByAdmin(Long eventId, UpdateEventAdmin request) { + Event event = eventRepository.findById(eventId) + .orElseThrow(() -> new NotFoundException("Event with id=" + eventId + " was not found")); + + if (request.getEventDate() != null) { + if (request.getEventDate().isBefore(LocalDateTime.now().plusHours(1))) { + throw new BadRequestException("Event date must be at least 1 hour before publication."); + } + event.setEventDate(request.getEventDate()); + } + + if (request.getStateAction() != null) { + if (request.getStateAction().equals("PUBLISH_EVENT")) { + if (event.getState() != EventState.PENDING) { + throw new ConflictException("Cannot publish the event because it's not in the PENDING state."); + } + event.setState(EventState.PUBLISHED); + event.setPublishedOn(LocalDateTime.now()); + } else if (request.getStateAction().equals("REJECT_EVENT")) { + if (event.getState() == EventState.PUBLISHED) { + throw new ConflictException("Cannot reject the event because it's already published."); + } + event.setState(EventState.CANCELED); + } + } + + updateEventCommonFields(event, request.getAnnotation(), request.getCategory(), request.getDescription(), + request.getLocation(), request.getPaid(), request.getParticipantLimit(), request.getRequestModeration(), request.getTitle()); + + return EventMapper.toFullDto(eventRepository.save(event)); + } + + // --- PUBLIC API --- + + @Override + public List getEventsPublic(String text, List categories, Boolean paid, + LocalDateTime rangeStart, LocalDateTime rangeEnd, + Boolean onlyAvailable, String sort, int from, int size, + HttpServletRequest request) { + + if (rangeStart != null && rangeEnd != null && rangeStart.isAfter(rangeEnd)) { + throw new BadRequestException("Start date must be before end date"); + } + + List categoryIds = (categories != null && categories.isEmpty()) ? null : categories; + + LocalDateTime start = (rangeStart != null) ? rangeStart : LocalDateTime.now().minusSeconds(1); + LocalDateTime end = (rangeEnd != null) ? rangeEnd : LocalDateTime.now().plusYears(100); + + sendStats(request); + + int pageSize = (size > 0) ? size : 10; + int pageNum = from / pageSize; + PageRequest pageable = PageRequest.of(pageNum, pageSize); + + List events = eventRepository.findPublishedEvents( + EventState.PUBLISHED.name(), text, categoryIds, paid, start, end, + (onlyAvailable != null && onlyAvailable), pageable); + if (sort != null) { + if (sort.equalsIgnoreCase("VIEWS")) { + events = events.stream() + .sorted((e1, e2) -> Long.compare( + e2.getViews() != null ? e2.getViews() : 0, + e1.getViews() != null ? e1.getViews() : 0)) + .collect(Collectors.toList()); + } else if (sort.equalsIgnoreCase("EVENT_DATE")) { + events = events.stream() + .sorted((e1, e2) -> e1.getEventDate().compareTo(e2.getEventDate())) + .collect(Collectors.toList()); + } + } + + return events.stream().map(EventMapper::toShortDto).collect(Collectors.toList()); + } + @Override + public EventFullDto getEventByIdPublic(Long id, HttpServletRequest request) { + Event event = eventRepository.findByIdAndState(id, EventState.PUBLISHED) + .orElseThrow(() -> new NotFoundException("Published event not found")); + + sendStats(request); + event.setViews(event.getViews() + 1); + eventRepository.save(event); + + return EventMapper.toFullDto(event); + } + + + + private void updateEventCommonFields(Event event, String annotation, Long catId, String description, + LocationDto locationDto, Boolean paid, Integer partLimit, Boolean reqMod, String title) { + if (annotation != null && !annotation.isBlank()) event.setAnnotation(annotation); + if (catId != null) { + event.setCategory(categoryRepository.findById(catId) + .orElseThrow(() -> new NotFoundException("Category not found"))); + } + if (description != null && !description.isBlank()) event.setDescription(description); + + + if (locationDto != null) { + Location location = locationRepository.save(LocationMapper.toLocation(locationDto)); + event.setLocation(location); + } + + if (paid != null) event.setPaid(paid); + if (partLimit != null) { + if (partLimit < 0) { + throw new BadRequestException("Participant limit cannot be negative"); + } + event.setParticipantLimit(partLimit); + } + if (reqMod != null) event.setRequestModeration(reqMod); + if (title != null && !title.isBlank()) event.setTitle(title); + } + + + private void sendStats(HttpServletRequest request) { + try { + statsClient.hit(APP_NAME, request.getRequestURI(), request.getRemoteAddr(), LocalDateTime.now()); + } catch (Exception e) { + log.error("Ошибка статистики: {}", e.getMessage()); + } + } +} \ No newline at end of file diff --git a/ewm-main-service/src/main/java/ru/practicum/ewm/service/LocationService.java b/ewm-main-service/src/main/java/ru/practicum/ewm/service/LocationService.java new file mode 100644 index 0000000..05f12f7 --- /dev/null +++ b/ewm-main-service/src/main/java/ru/practicum/ewm/service/LocationService.java @@ -0,0 +1,17 @@ +package ru.practicum.ewm.service; + +import ru.practicum.ewm.dto.request.NewLocationDto; +import ru.practicum.ewm.dto.response.LocationDto; + +import java.util.List; + +public interface LocationService { + + LocationDto createLocation(NewLocationDto newLocationDto); + + LocationDto getLocation(Long locationId); + + List getAllLocations(); + + void deleteLocation(Long locationId); +} \ No newline at end of file diff --git a/ewm-main-service/src/main/java/ru/practicum/ewm/service/LocationServiceImpl.java b/ewm-main-service/src/main/java/ru/practicum/ewm/service/LocationServiceImpl.java new file mode 100644 index 0000000..e1464f4 --- /dev/null +++ b/ewm-main-service/src/main/java/ru/practicum/ewm/service/LocationServiceImpl.java @@ -0,0 +1,51 @@ +package ru.practicum.ewm.service; + +import lombok.AccessLevel; +import lombok.RequiredArgsConstructor; +import lombok.experimental.FieldDefaults; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import ru.practicum.ewm.dto.request.NewLocationDto; +import ru.practicum.ewm.dto.response.LocationDto; +import ru.practicum.ewm.mapper.LocationMapper; +import ru.practicum.ewm.model.Location; +import ru.practicum.ewm.repository.LocationRepository; + +import java.util.List; +import java.util.stream.Collectors; + +@Service +@RequiredArgsConstructor +@FieldDefaults(level = AccessLevel.PRIVATE, makeFinal = true) +@Transactional(readOnly = true) +public class LocationServiceImpl implements LocationService { + + LocationRepository locationRepository; + + @Override + @Transactional + public LocationDto createLocation(NewLocationDto newLocationDto) { + Location location = LocationMapper.toLocation(newLocationDto); + Location savedLocation = locationRepository.save(location); + return LocationMapper.toDto(savedLocation); + } + @Override + public LocationDto getLocation(Long locationId) { + Location location = locationRepository.findById(locationId) + .orElseThrow(() -> new RuntimeException("Location not found")); + return LocationMapper.toDto(location); + } + + @Override + public List getAllLocations() { + return locationRepository.findAll().stream() + .map(LocationMapper::toDto) + .collect(Collectors.toList()); + } + + @Override + @Transactional + public void deleteLocation(Long locationId) { + locationRepository.deleteById(locationId); + } +} \ No newline at end of file diff --git a/ewm-main-service/src/main/java/ru/practicum/ewm/service/RequestService.java b/ewm-main-service/src/main/java/ru/practicum/ewm/service/RequestService.java new file mode 100644 index 0000000..93679df --- /dev/null +++ b/ewm-main-service/src/main/java/ru/practicum/ewm/service/RequestService.java @@ -0,0 +1,18 @@ +package ru.practicum.ewm.service; + +import ru.practicum.ewm.dto.request.RequestStatusUpdate; +import ru.practicum.ewm.dto.response.RequestDto; +import ru.practicum.ewm.dto.response.RequestStatusUpdateResult; + +import java.util.List; + +public interface RequestService { + // Для тех, кто подает заявку (Requester) + List getRequestsByUserId(Long userId); + RequestDto createRequest(Long userId, Long eventId); + RequestDto cancelRequest(Long userId, Long requestId); + + // Для организатора события (Initiator) + List getEventRequests(Long userId, Long eventId); + RequestStatusUpdateResult updateRequestStatus(Long userId, Long eventId, RequestStatusUpdate updateRequest); +} \ No newline at end of file diff --git a/ewm-main-service/src/main/java/ru/practicum/ewm/service/RequestServiceImpl.java b/ewm-main-service/src/main/java/ru/practicum/ewm/service/RequestServiceImpl.java new file mode 100644 index 0000000..8ec0140 --- /dev/null +++ b/ewm-main-service/src/main/java/ru/practicum/ewm/service/RequestServiceImpl.java @@ -0,0 +1,144 @@ +package ru.practicum.ewm.service; + +import lombok.AccessLevel; +import lombok.RequiredArgsConstructor; +import lombok.experimental.FieldDefaults; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import ru.practicum.ewm.dto.request.RequestStatusUpdate; +import ru.practicum.ewm.dto.response.RequestDto; +import ru.practicum.ewm.dto.response.RequestStatusUpdateResult; +import ru.practicum.ewm.exception.ConflictException; +import ru.practicum.ewm.exception.NotFoundException; +import ru.practicum.ewm.mapper.RequestMapper; +import ru.practicum.ewm.model.*; +import ru.practicum.ewm.repository.EventRepository; +import ru.practicum.ewm.repository.ParticipationRequestRepository; +import ru.practicum.ewm.repository.UserRepository; + +import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; + +@Service +@RequiredArgsConstructor +@FieldDefaults(level = AccessLevel.PRIVATE, makeFinal = true) +@Transactional(readOnly = true) +public class RequestServiceImpl implements RequestService { + + ParticipationRequestRepository requestRepository; + EventRepository eventRepository; + UserRepository userRepository; + + @Override + public List getRequestsByUserId(Long userId) { + if (!userRepository.existsById(userId)) throw new NotFoundException("User not found"); + return requestRepository.findAllByRequesterId(userId).stream() + .map(RequestMapper::toDto).collect(Collectors.toList()); + } + + @Override + @Transactional + public RequestDto createRequest(Long userId, Long eventId) { + User requester = userRepository.findById(userId).orElseThrow(() -> new NotFoundException("User not found")); + Event event = eventRepository.findById(eventId).orElseThrow(() -> new NotFoundException("Event not found")); + + if (requestRepository.existsByRequesterIdAndEventId(userId, eventId)) { + throw new ConflictException("Request already exists"); + } + if (event.getInitiator().getId().equals(userId)) { + throw new ConflictException("Initiator cannot request participation in their own event"); + } + if (event.getState() != EventState.PUBLISHED) { + throw new ConflictException("Cannot participate in unpublished event"); + } + if (event.getParticipantLimit() > 0 && event.getConfirmedRequests() >= event.getParticipantLimit()) { + throw new ConflictException("Participant limit reached"); + } + + ParticipationRequest request = new ParticipationRequest(); + request.setCreated(LocalDateTime.now()); + request.setEvent(event); + request.setRequester(requester); + + if (!event.getRequestModeration() || event.getParticipantLimit() == 0) { + request.setStatus(RequestStatus.CONFIRMED); + event.setConfirmedRequests(event.getConfirmedRequests() + 1); + eventRepository.save(event); + } else { + request.setStatus(RequestStatus.PENDING); + } + + return RequestMapper.toDto(requestRepository.save(request)); + } + + @Override + @Transactional + public RequestDto cancelRequest(Long userId, Long requestId) { + ParticipationRequest request = requestRepository.findById(requestId) + .orElseThrow(() -> new NotFoundException("Request with id=" + requestId + " was not found")); + + if (!request.getRequester().getId().equals(userId)) { + throw new ConflictException("You can only cancel your own requests"); + } + + if (request.getStatus() != RequestStatus.PENDING) { + throw new ConflictException("Cannot cancel request with status: " + request.getStatus()); + } + + request.setStatus(RequestStatus.CANCELED); + + if (request.getStatus() == RequestStatus.CONFIRMED) { + throw new ConflictException("Cannot cancel a confirmed request"); + } + + return RequestMapper.toDto(requestRepository.save(request)); + + } + + @Override + public List getEventRequests(Long userId, Long eventId) { + Event event = eventRepository.findById(eventId).orElseThrow(() -> new NotFoundException("Event not found")); + if (!event.getInitiator().getId().equals(userId)) throw new ConflictException("Not your event"); + + return requestRepository.findAllByEventId(eventId).stream() + .map(RequestMapper::toDto).collect(Collectors.toList()); + } + + @Override + @Transactional + public RequestStatusUpdateResult updateRequestStatus(Long userId, Long eventId, RequestStatusUpdate update) { + Event event = eventRepository.findById(eventId).orElseThrow(() -> new NotFoundException("Event not found")); + if (!event.getInitiator().getId().equals(userId)) throw new ConflictException("Not your event"); + + List requests = requestRepository.findAllById(update.getRequestIds()); + + RequestStatusUpdateResult result = new RequestStatusUpdateResult(); + result.setConfirmedRequests(new ArrayList<>()); + result.setRejectedRequests(new ArrayList<>()); + + for (ParticipationRequest req : requests) { + if (req.getStatus() != RequestStatus.PENDING) { + throw new ConflictException("Request must be in status PENDING"); + } + + if (update.getStatus() == RequestStatus.REJECTED) { + req.setStatus(RequestStatus.REJECTED); + result.getRejectedRequests().add(RequestMapper.toDto(requestRepository.save(req))); + } else { + if (event.getParticipantLimit() == 0 || event.getConfirmedRequests() < event.getParticipantLimit()) { + req.setStatus(RequestStatus.CONFIRMED); + event.setConfirmedRequests(event.getConfirmedRequests() + 1); + result.getConfirmedRequests().add(RequestMapper.toDto(requestRepository.save(req))); + } else { + req.setStatus(RequestStatus.REJECTED); + result.getRejectedRequests().add(RequestMapper.toDto(requestRepository.save(req))); + throw new ConflictException("Participant limit reached"); + } + } + } + eventRepository.save(event); + return result; + } +} \ No newline at end of file diff --git a/ewm-main-service/src/main/java/ru/practicum/ewm/service/UserService.java b/ewm-main-service/src/main/java/ru/practicum/ewm/service/UserService.java new file mode 100644 index 0000000..534a248 --- /dev/null +++ b/ewm-main-service/src/main/java/ru/practicum/ewm/service/UserService.java @@ -0,0 +1,15 @@ +package ru.practicum.ewm.service; + +import ru.practicum.ewm.dto.request.NewUserRequest; +import ru.practicum.ewm.dto.response.UserDto; + +import java.util.List; + +public interface UserService { + + UserDto createUser(NewUserRequest newUserRequest); + + List getUsers(List ids, int from, int size); + + void deleteUser(Long userId); +} \ No newline at end of file diff --git a/ewm-main-service/src/main/java/ru/practicum/ewm/service/UserServiceImpl.java b/ewm-main-service/src/main/java/ru/practicum/ewm/service/UserServiceImpl.java new file mode 100644 index 0000000..81a4b1f --- /dev/null +++ b/ewm-main-service/src/main/java/ru/practicum/ewm/service/UserServiceImpl.java @@ -0,0 +1,54 @@ +package ru.practicum.ewm.service; + +import lombok.AccessLevel; +import lombok.RequiredArgsConstructor; +import lombok.experimental.FieldDefaults; +import org.springframework.data.domain.PageRequest; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import ru.practicum.ewm.dto.request.NewUserRequest; +import ru.practicum.ewm.dto.response.UserDto; +import ru.practicum.ewm.mapper.UserMapper; +import ru.practicum.ewm.model.User; +import ru.practicum.ewm.repository.UserRepository; + +import java.util.List; +import java.util.stream.Collectors; + +@Service +@RequiredArgsConstructor +@FieldDefaults(level = AccessLevel.PRIVATE, makeFinal = true) +@Transactional(readOnly = true) +public class UserServiceImpl implements UserService { + + UserRepository userRepository; + + @Override + @Transactional + public UserDto createUser(NewUserRequest newUserRequest) { + User user = UserMapper.toUser(newUserRequest); + User savedUser = userRepository.save(user); + return UserMapper.toDto(savedUser); + } + + @Override + public List getUsers(List ids, int from, int size) { + PageRequest pageRequest = PageRequest.of(from / size, size); + + if (ids == null || ids.isEmpty()) { + return userRepository.findAll(pageRequest).stream() + .map(UserMapper::toDto) + .collect(Collectors.toList()); + } + + return userRepository.findAllById(ids).stream() + .map(UserMapper::toDto) + .collect(Collectors.toList()); + } + + @Override + @Transactional + public void deleteUser(Long userId) { + userRepository.deleteById(userId); + } +} \ No newline at end of file