diff --git a/README.md b/README.md
index 3671fb5..1ad19c3 100644
--- a/README.md
+++ b/README.md
@@ -1,57 +1,65 @@
-# Комментарии — API (техническое задание)
-
-Краткое описание: набор REST-эндпоинтов для управления комментариями. Три уровня доступа:
-- Admin — администраторские операции (удаление комментария по его идентификатору).
-- Private — операции пользователя над собственными комментариями (создать, изменить, удалить, получить все свои комментарии).
-- Public — публичный доступ (просмотр комментариев конкретного события).
-
----
-
-## AdminCommentController
-Цель: операции управления всеми комментариями.
-
-- DELETE `/admin/comments/{commentId}`
- - Описание: удалить комментарий (жёсткое удаление) по его идентификатору.
- - Ограничения: без модерации комментариев.
- - Права: только админ.
- - Ответ: `204 No Content` при успехе.
-
----
-
-## PrivateCommentController
-Цель: пользовательские операции над собственными комментариями.
-
-- POST `/users/{userId}/comments/{eventId}`
- - Описание: создать новый комментарий от имени пользователя `userId`.
- - Ограничения: длина комментария 5000 символов, проверка существования идентификаторов события и пользователя.
- - Права: только аутентифицированный пользователь.
- - Ответ: `201 Created` с созданным объектом.
-
-- PATCH `/users/{userId}/comments/{eventId}/{commentId}`
- - Описание: обновить собственный комментарий.
- - Ограничения: длина комментария 5000 символов, проверка существования идентификаторов комментария, события и пользователя.
- - Права: только автор комментария.
- - Ответ: обновлённый объект комментария.
-
-- DELETE `/users/{userId}/comments/{commentId}`
- - Описание: удалить собственный комментарий (жёсткое удаление).
- - Ограничения: проверка существования идентификаторов комментария и пользователя.
- - Права: только автор комментария.
- - Ответ: `204 No Content`.
-
-- GET `/users/{userId}/comments`
- - Описание: получить список собственных комментариев.
- - Ограничения: организовать пагинацию (по умолчанию по 10 комментариев на странице).
- - Права: только аутентифицированный пользователь.
- - Ответ: список комментариев.
-
----
-
-## PublicCommentController
-Цель: публичный просмотр комментариев.
-
-- GET `/comments/event/{eventId}`
- - Описание: получить публичный список комментариев к событию.
- - Ограничения: организовать пагинацию (по умолчанию по 10 комментариев на странице).
- - Доступ: публичный (без авторизации).
- - Ответ: список публичных комментариев.
\ No newline at end of file
+## ExploreWithMe
+
+### Общая информация
+Это микросервисная реализация приложения ExploreWithMe для поиска событий и участия в них.
+Исходный монолит разделен на несколько независимых сервисов, взаимодействующих через API Gateway и Feign-клиенты.
+
+**Технологический стек**: Java 21, Spring Boot, Spring Cloud(Eureka, Gateway, OpenFeign, Config), MapStruct, Lombok, Apache Maven, Docker, PostgreSQL, Postman.
+
+## Основные сервисы
+1. **event-service** - сервис управления событиями, категориями, подборками;
+2. **user-service** - сервис управления пользователями.;
+3. **request-service** - сервис управления запросами на участие в событии;
+4. **comment-service** - сервис управления комментариями;
+5. **stats-service** - сервис сбора и предоставления статистики;
+6. **discovery-server** (Eureka) - регистрация и обнаружение сервисов;
+7. **config-server** - централизованное хранение конфигураций для всех сервисов;
+8. **gateway-server** - единая точка входа (API Gateway).
+
+### Вспомогательный модуль
+- **interaction-api** - общие DTO, Feign-клиенты, исключения, перечисления
+
+### Конфигурация
+Все настройки хранятся в **config-server**:
+- `gateway-server.yml` - маршрутизация Gateway
+- `user-service.yml` - настройки user-service
+- `event-service.yml` - настройки event-service
+- `request-service.yml` - настройки request-service
+- `comment-service.yml` - настройки comment-service
+- `stats-service.yml` - настройки stats-service
+
+Приложение имеет общую базу данных. Каждый сервис имеет собственную schema.sql, обеспечивая изоляцию данных.
+
+## Внутренний API для взаимодействия сервисов
+Для взаимодействия между микросервисами используются Feign Clients и Internal Endpoints:
+- GET /internal/events/{eventId} - возвращает полное описание события;
+- GET /internal/requests/event/{eventId}/count/{status} - возвращает количество заявок события с определенным статусом;
+- GET /internal/users/{userId} - возвращает краткую информацию о пользователе.
+
+## Внешний API
+Взаимодействие с внешними запросами происходит через API Gateway, который перенаправляет внешние запросы к нужным сервисам.
+Примеры основных эндопинтов:
+### Публичные(доступны всем):
+- GET /comments/events/{eventId} - поиск опубликованных комментариев к событию;
+- GET /events - поиск событий;
+- GET /categories - категории событий;
+- GET /compilations/{compId} - поиск подборки по id;
+### Приватные(доступны для авторизованных пользователей):
+- POST /users/{userId}/comments - добавить комментарий к событию;
+- PATCH /users/{userId}/comments/{commentId} - изменить комментарий;
+- GET /users/{userId}/events - события пользователя;
+- GET /users/{userId}/events/{eventId}/requests - все заявки на участие в событии;
+- PATCH /users/{userId}/requests/{requestId}/cancel - отмена заявки на участие;
+
+### Административные(доступны только администраторам):
+- GET /admin/comments - поиск комментариев;
+- DELETE /admin/comments/{commentId} - удалить комментарий;
+- POST /admin/categories - создать категорию;
+- PATCH /admin/compilations/{compId} - изменить подборку;
+- GET /admin/events - расширенный поиск событий с фильтрами;
+- POST /admin/users/ - создать пользователя;
+- DELETE /admin/users/{userId} - удалить пользователя.
+
+### Полная спецификация OpenAPI доступна в файлах:
+1. [ewm-main-service-spec.json](./ewm-main-service-spec.json) - основная спецификация
+2. [ewm-stat-service-spec.json](./ewm-stat-service-spec.json) - спецификация статистики
\ No newline at end of file
diff --git a/core/comment-service/pom.xml b/core/comment-service/pom.xml
new file mode 100644
index 0000000..d017437
--- /dev/null
+++ b/core/comment-service/pom.xml
@@ -0,0 +1,157 @@
+
+
+ 4.0.0
+
+ ru.yandex.practicum
+ core
+ 0.0.1-SNAPSHOT
+
+
+ comment-service
+
+
+ 21
+ 21
+ UTF-8
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+
+
+
+ org.springframework.boot
+ spring-boot-starter-validation
+
+
+
+ org.springframework.boot
+ spring-boot-starter-actuator
+
+
+
+ org.springframework.boot
+ spring-boot-starter-data-jpa
+
+
+
+ org.springframework.boot
+ spring-boot-starter-aop
+
+
+
+ ru.yandex.practicum
+ interaction-api
+ ${project.version}
+
+
+
+ ru.yandex.practicum
+ stats-client
+ ${project.version}
+
+
+
+ ru.yandex.practicum
+ stats-dto
+ ${project.version}
+
+
+
+ org.projectlombok
+ lombok
+ provided
+
+
+
+ org.postgresql
+ postgresql
+
+
+
+ org.springframework.cloud
+ spring-cloud-starter-config
+
+
+
+ org.springframework.cloud
+ spring-cloud-starter-netflix-eureka-client
+
+
+
+ org.springframework.cloud
+ spring-cloud-starter-openfeign
+
+
+
+ org.springframework.cloud
+ spring-cloud-starter-loadbalancer
+
+
+
+ org.springframework.retry
+ spring-retry
+ 2.0.5
+
+
+
+ io.github.openfeign
+ feign-okhttp
+
+
+
+ org.mapstruct
+ mapstruct
+ ${mapstruct.version}
+
+
+
+ com.h2database
+ h2
+ runtime
+
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+
+
+
+ org.projectlombok
+ lombok
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+ 3.11.0
+
+ 21
+ 21
+
+
+ org.projectlombok
+ lombok
+ ${lombok.version}
+
+
+ org.mapstruct
+ mapstruct-processor
+ ${mapstruct.version}
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/core/comment-service/src/main/java/ru/yandex/practicum/CommentServiceApp.java b/core/comment-service/src/main/java/ru/yandex/practicum/CommentServiceApp.java
new file mode 100644
index 0000000..6b423d4
--- /dev/null
+++ b/core/comment-service/src/main/java/ru/yandex/practicum/CommentServiceApp.java
@@ -0,0 +1,13 @@
+package ru.yandex.practicum;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.cloud.openfeign.EnableFeignClients;
+
+@SpringBootApplication
+@EnableFeignClients
+public class CommentServiceApp {
+ public static void main(String[] args) {
+ SpringApplication.run(CommentServiceApp.class, args);
+ }
+}
diff --git a/core/comment-service/src/main/java/ru/yandex/practicum/controller/AdminCommentController.java b/core/comment-service/src/main/java/ru/yandex/practicum/controller/AdminCommentController.java
new file mode 100644
index 0000000..ad6995c
--- /dev/null
+++ b/core/comment-service/src/main/java/ru/yandex/practicum/controller/AdminCommentController.java
@@ -0,0 +1,62 @@
+package ru.yandex.practicum.controller;
+
+import jakarta.validation.Valid;
+import jakarta.validation.constraints.Min;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.format.annotation.DateTimeFormat;
+import org.springframework.http.HttpStatus;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+import ru.yandex.practicum.dto.comment.*;
+import ru.yandex.practicum.enums.CommentStatus;
+import ru.yandex.practicum.service.CommentService;
+
+import java.time.LocalDateTime;
+import java.util.List;
+
+@Slf4j
+@Validated
+@RestController
+@RequestMapping("/admin/comments")
+@RequiredArgsConstructor
+public class AdminCommentController {
+ private final CommentService commentService;
+
+ @GetMapping
+ public List adminSearch(
+ @RequestParam(required = false) CommentStatus status,
+ @RequestParam(required = false) Long eventId,
+ @RequestParam(required = false) Long userId,
+ @RequestParam(required = false) @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") LocalDateTime start,
+ @RequestParam(required = false) @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") LocalDateTime end,
+ @RequestParam(defaultValue = "0") @Min(0) int from,
+ @RequestParam(defaultValue = "10") @Min(1) int size) {
+
+ log.info("Admin search: status={}, eventId={}, userId={}, start={}, end={}, from={}, size={}",
+ status, eventId, userId, start, end, from, size);
+
+ return commentService.adminSearch(status, eventId, userId, start, end, from, size);
+ }
+
+ @PatchMapping("/{commentId}")
+ public CommentDto updateCommentByAdmin(@PathVariable Long commentId,
+ @RequestBody @Valid CommentAdminDto commentAdminDto) {
+ log.info("Admin update comment: id={}, data={}", commentId, commentAdminDto);
+ return commentService.updateCommentByAdmin(commentId, commentAdminDto);
+ }
+
+ @DeleteMapping("/{commentId}")
+ @ResponseStatus(HttpStatus.NO_CONTENT)
+ public void deleteCommentByAdmin(@PathVariable Long commentId) {
+ log.info("Admin delete comment: id={}", commentId);
+ commentService.deleteCommentByAdmin(commentId);
+ }
+
+ @GetMapping("/events/{eventId}")
+ public List getCommentsByEventAndStatus(@PathVariable Long eventId,
+ @RequestParam CommentStatus status) {
+ log.info("Get comments by event and status: eventId={}, status={}", eventId, status);
+ return commentService.getCommentByStatus(eventId, status);
+ }
+}
diff --git a/core/comment-service/src/main/java/ru/yandex/practicum/controller/PrivateCommentController.java b/core/comment-service/src/main/java/ru/yandex/practicum/controller/PrivateCommentController.java
new file mode 100644
index 0000000..80f4dbe
--- /dev/null
+++ b/core/comment-service/src/main/java/ru/yandex/practicum/controller/PrivateCommentController.java
@@ -0,0 +1,55 @@
+package ru.yandex.practicum.controller;
+
+import jakarta.validation.Valid;
+import jakarta.validation.constraints.Min;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.http.HttpStatus;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+import ru.yandex.practicum.dto.comment.*;
+import ru.yandex.practicum.service.CommentService;
+
+import java.util.List;
+
+@Slf4j
+@Validated
+@RestController
+@RequestMapping("/users/{userId}/comments")
+@RequiredArgsConstructor
+public class PrivateCommentController {
+ private final CommentService commentService;
+
+ @PostMapping
+ @ResponseStatus(HttpStatus.CREATED)
+ public CommentDto createComment(@PathVariable Long userId,
+ @RequestParam Long eventId,
+ @RequestBody @Valid NewCommentDto newCommentDto) {
+ log.info("Create comment: userId={}, eventId={}", userId, eventId);
+ return commentService.createComment(userId, eventId, newCommentDto);
+ }
+
+ @PatchMapping("/{commentId}")
+ public CommentDto updateCommentByUser(@PathVariable Long userId,
+ @PathVariable Long commentId,
+ @RequestBody @Valid UpdateCommentDto updateCommentDto) {
+ log.info("Update comment: userId={}, commentId={}", userId, commentId);
+ return commentService.updateComment(userId, commentId, updateCommentDto);
+ }
+
+ @DeleteMapping("/{commentId}")
+ @ResponseStatus(HttpStatus.NO_CONTENT)
+ public void deleteCommentByUser(@PathVariable Long userId,
+ @PathVariable Long commentId) {
+ log.info("Delete comment: userId={}, commentId={}", userId, commentId);
+ commentService.deleteComment(userId, commentId);
+ }
+
+ @GetMapping
+ public List getUserComments(@PathVariable Long userId,
+ @RequestParam(defaultValue = "0") @Min(0) int from,
+ @RequestParam(defaultValue = "10") @Min(1) int size) {
+ log.info("Get user comments: userId={}, from={}, size={}", userId, from, size);
+ return commentService.getUserComments(userId, from, size);
+ }
+}
diff --git a/core/comment-service/src/main/java/ru/yandex/practicum/controller/PublicCommentController.java b/core/comment-service/src/main/java/ru/yandex/practicum/controller/PublicCommentController.java
new file mode 100644
index 0000000..e63b769
--- /dev/null
+++ b/core/comment-service/src/main/java/ru/yandex/practicum/controller/PublicCommentController.java
@@ -0,0 +1,28 @@
+package ru.yandex.practicum.controller;
+
+import jakarta.validation.constraints.Min;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+import ru.yandex.practicum.dto.comment.CommentDto;
+import ru.yandex.practicum.service.CommentService;
+
+import java.util.List;
+
+@Slf4j
+@Validated
+@RestController
+@RequestMapping("/comments")
+@RequiredArgsConstructor
+public class PublicCommentController {
+ private final CommentService commentService;
+
+ @GetMapping("/events/{eventId}")
+ public List getPublishedCommentsByEvent(@PathVariable Long eventId,
+ @RequestParam(defaultValue = "0") @Min(0) int from,
+ @RequestParam(defaultValue = "10") @Min(1) int size) {
+ log.info("Get published comments: eventId={}, from={}, size={}", eventId, from, size);
+ return commentService.getPublishedCommentsByEvent(eventId, from, size);
+ }
+}
diff --git a/core/main-service/src/main/java/ru/yandex/practicum/exception/ErrorHandler.java b/core/comment-service/src/main/java/ru/yandex/practicum/handler/ErrorHandler.java
similarity index 81%
rename from core/main-service/src/main/java/ru/yandex/practicum/exception/ErrorHandler.java
rename to core/comment-service/src/main/java/ru/yandex/practicum/handler/ErrorHandler.java
index 3dfd3d2..19f22c2 100644
--- a/core/main-service/src/main/java/ru/yandex/practicum/exception/ErrorHandler.java
+++ b/core/comment-service/src/main/java/ru/yandex/practicum/handler/ErrorHandler.java
@@ -1,4 +1,4 @@
-package ru.yandex.practicum.exception;
+package ru.yandex.practicum.handler;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.validation.ConstraintViolationException;
@@ -14,6 +14,7 @@
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.method.annotation.HandlerMethodValidationException;
import org.springframework.web.servlet.NoHandlerFoundException;
+import ru.yandex.practicum.exception.*;
import java.util.stream.Collectors;
@@ -53,7 +54,8 @@ public ErrorResponse handleValidationException(ValidationException exception, Ht
@ExceptionHandler(ConstraintViolationException.class)
@ResponseStatus(HttpStatus.BAD_REQUEST)
- public ErrorResponse handleConstraintViolation(ConstraintViolationException ex, HttpServletRequest request) {
+ public ErrorResponse handleConstraintViolation(
+ ConstraintViolationException ex, HttpServletRequest request) {
String violations = ex.getConstraintViolations().stream()
.map(violation -> violation.getPropertyPath() + ": " + violation.getMessage())
.collect(Collectors.joining("; "));
@@ -64,7 +66,8 @@ public ErrorResponse handleConstraintViolation(ConstraintViolationException ex,
@ExceptionHandler(MethodArgumentNotValidException.class)
@ResponseStatus(HttpStatus.BAD_REQUEST)
- public ErrorResponse handleMethodArgumentNotValid(MethodArgumentNotValidException ex, HttpServletRequest request) {
+ public ErrorResponse handleMethodArgumentNotValid(
+ MethodArgumentNotValidException ex, HttpServletRequest request) {
String validationErrors = ex.getBindingResult().getFieldErrors().stream()
.map(error -> error.getField() + ": " + error.getDefaultMessage())
.collect(Collectors.joining("; "));
@@ -76,7 +79,8 @@ public ErrorResponse handleMethodArgumentNotValid(MethodArgumentNotValidExceptio
@ExceptionHandler(HandlerMethodValidationException.class)
@ResponseStatus(HttpStatus.BAD_REQUEST)
- public ErrorResponse handleHandlerMethodValidation(HandlerMethodValidationException ex, HttpServletRequest request) {
+ public ErrorResponse handleHandlerMethodValidation(
+ HandlerMethodValidationException ex, HttpServletRequest request) {
String validationErrors = ex.getAllErrors().stream()
.map(MessageSourceResolvable::getDefaultMessage)
.collect(Collectors.joining("; "));
@@ -88,25 +92,29 @@ public ErrorResponse handleHandlerMethodValidation(HandlerMethodValidationExcept
@ExceptionHandler(ServletRequestBindingException.class)
@ResponseStatus(HttpStatus.BAD_REQUEST)
- public ErrorResponse handleServletRequestBindingException(ServletRequestBindingException ex, HttpServletRequest request) {
+ public ErrorResponse handleServletRequestBindingException(
+ ServletRequestBindingException ex, HttpServletRequest request) {
return buildResponse(HttpStatus.BAD_REQUEST, ex.getMessage(), null, request);
}
@ExceptionHandler(HttpRequestMethodNotSupportedException.class)
@ResponseStatus(HttpStatus.METHOD_NOT_ALLOWED)
- public ErrorResponse handleHttpRequestMethodNotSupported(HttpRequestMethodNotSupportedException ex, HttpServletRequest request) {
+ public ErrorResponse handleHttpRequestMethodNotSupported(
+ HttpRequestMethodNotSupportedException ex, HttpServletRequest request) {
return buildResponse(HttpStatus.METHOD_NOT_ALLOWED, ex.getMessage(), null, request);
}
@ExceptionHandler(HttpMediaTypeNotSupportedException.class)
@ResponseStatus(HttpStatus.UNSUPPORTED_MEDIA_TYPE)
- public ErrorResponse handleHttpMediaTypeNotSupported(HttpMediaTypeNotSupportedException ex, HttpServletRequest request) {
+ public ErrorResponse handleHttpMediaTypeNotSupported(
+ HttpMediaTypeNotSupportedException ex, HttpServletRequest request) {
return buildResponse(HttpStatus.UNSUPPORTED_MEDIA_TYPE, ex.getMessage(), null, request);
}
@ExceptionHandler(NoHandlerFoundException.class)
@ResponseStatus(HttpStatus.NOT_FOUND)
- public ErrorResponse handleNoHandlerFoundException(NoHandlerFoundException ex, HttpServletRequest request) {
+ public ErrorResponse handleNoHandlerFoundException(
+ NoHandlerFoundException ex, HttpServletRequest request) {
return buildResponse(HttpStatus.NOT_FOUND, ex.getMessage(), null, request);
}
@@ -116,11 +124,13 @@ public ErrorResponse handleUnexpected(Exception exception, HttpServletRequest re
return buildResponse(HttpStatus.INTERNAL_SERVER_ERROR, exception, request);
}
- private ErrorResponse buildResponse(HttpStatus httpStatus, Exception exception, HttpServletRequest request) {
+ private ErrorResponse buildResponse(
+ HttpStatus httpStatus,Exception exception, HttpServletRequest request) {
return buildResponse(httpStatus, exception.getMessage(), exception, request);
}
- private ErrorResponse buildResponse(HttpStatus httpStatus, String message, Exception exception, HttpServletRequest request) {
+ private ErrorResponse buildResponse(
+ HttpStatus httpStatus, String message, Exception exception, HttpServletRequest request) {
String path = request.getRequestURI();
String httpMethod = request.getMethod();
int statusCode = httpStatus.value();
diff --git a/core/comment-service/src/main/java/ru/yandex/practicum/mapper/CommentMapper.java b/core/comment-service/src/main/java/ru/yandex/practicum/mapper/CommentMapper.java
new file mode 100644
index 0000000..2c8f779
--- /dev/null
+++ b/core/comment-service/src/main/java/ru/yandex/practicum/mapper/CommentMapper.java
@@ -0,0 +1,40 @@
+package ru.yandex.practicum.mapper;
+
+import org.mapstruct.*;
+import ru.yandex.practicum.dto.comment.*;
+import ru.yandex.practicum.model.Comment;
+
+@Mapper(componentModel = "spring")
+public interface CommentMapper {
+
+ @Mapping(target = "id", ignore = true)
+ @Mapping(target = "createdDate", ignore = true)
+ @Mapping(target = "updatedDate", ignore = true)
+ @Mapping(target = "userId", source = "userId")
+ @Mapping(target = "eventId", source = "eventId")
+ @Mapping(target = "status", expression = "java(CommentStatus.PENDING)")
+ Comment toComment(NewCommentDto newCommentDto, Long userId, Long eventId);
+
+ @Mapping(target = "userId", source = "userId")
+ @Mapping(target = "eventId", source = "eventId")
+ CommentDto toDto(Comment comment);
+
+ @BeanMapping(nullValuePropertyMappingStrategy = NullValuePropertyMappingStrategy.IGNORE)
+ @Mapping(target = "id", ignore = true)
+ @Mapping(target = "userId", ignore = true)
+ @Mapping(target = "eventId", ignore = true)
+ @Mapping(target = "createdDate", ignore = true)
+ @Mapping(target = "updatedDate", ignore = true)
+ @Mapping(target = "status", ignore = true)
+ void updateCommentFromDto(UpdateCommentDto dto, @MappingTarget Comment comment);
+
+ @BeanMapping(nullValuePropertyMappingStrategy = NullValuePropertyMappingStrategy.IGNORE)
+ @Mapping(target = "id", ignore = true)
+ @Mapping(target = "createdDate", ignore = true)
+ @Mapping(target = "updatedDate", ignore = true)
+ @Mapping(target = "userId", ignore = true)
+ @Mapping(target = "eventId", ignore = true)
+ @Mapping(target = "text", source = "text")
+ @Mapping(target = "status", source = "status")
+ void updateFromAdminDto(CommentAdminDto commentAdminDto, @MappingTarget Comment comment);
+}
diff --git a/core/comment-service/src/main/java/ru/yandex/practicum/model/Comment.java b/core/comment-service/src/main/java/ru/yandex/practicum/model/Comment.java
new file mode 100644
index 0000000..a50b6b9
--- /dev/null
+++ b/core/comment-service/src/main/java/ru/yandex/practicum/model/Comment.java
@@ -0,0 +1,44 @@
+package ru.yandex.practicum.model;
+
+import jakarta.persistence.*;
+import lombok.*;
+import org.hibernate.annotations.CreationTimestamp;
+import ru.yandex.practicum.enums.CommentStatus;
+
+import java.time.LocalDateTime;
+
+@Entity
+@Table(name = "comments")
+@Getter
+@Setter
+@AllArgsConstructor
+@NoArgsConstructor
+@Builder
+@ToString
+public class Comment {
+
+ @Id
+ @GeneratedValue(strategy = GenerationType.IDENTITY)
+ private Long id;
+
+ @Column(nullable = false, length = 5000)
+ private String text;
+
+ @Column(name = "user_id", nullable = false)
+ private Long userId;
+
+ @Column(name = "event_id", nullable = false)
+ private Long eventId;
+
+ @Column(name = "created_date", nullable = false)
+ @CreationTimestamp
+ private LocalDateTime createdDate;
+
+ @Column(name = "updated_date")
+ @CreationTimestamp
+ private LocalDateTime updatedDate;
+
+ @Enumerated(EnumType.STRING)
+ @Column(nullable = false)
+ private CommentStatus status;
+}
diff --git a/core/comment-service/src/main/java/ru/yandex/practicum/repository/CommentRepository.java b/core/comment-service/src/main/java/ru/yandex/practicum/repository/CommentRepository.java
new file mode 100644
index 0000000..d48ce3b
--- /dev/null
+++ b/core/comment-service/src/main/java/ru/yandex/practicum/repository/CommentRepository.java
@@ -0,0 +1,72 @@
+package ru.yandex.practicum.repository;
+
+import org.springframework.data.domain.Page;
+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.yandex.practicum.enums.CommentStatus;
+import ru.yandex.practicum.model.Comment;
+
+import java.time.LocalDateTime;
+import java.util.List;
+import java.util.Optional;
+
+public interface CommentRepository extends JpaRepository {
+
+ // Поиск опубликованных комментов события
+ @Query("""
+ SELECT c FROM Comment c
+ WHERE c.eventId = :eventId AND c.status = ru.yandex.practicum.enums.CommentStatus.PUBLISHED
+ ORDER BY c.createdDate DESC
+ """)
+ List findPublishedByEvent(@Param("eventId") Long eventId, Pageable pageable);
+
+ // Поиск комментария по его ID и ID автора
+ Optional findByIdAndUserId(Long id, Long userId);
+
+ // Расширенный поиск комментариев по фильтрам (без фильтрации по датам) для модерации
+ @Query("""
+ SELECT c FROM Comment c
+ WHERE (:status IS NULL OR c.status = :status)
+ AND (:eventId IS NULL OR c.eventId = :eventId)
+ AND (:userId IS NULL OR c.userId = :userId)
+ ORDER BY c.createdDate DESC
+ """)
+ Page searchWithoutDates(@Param("status") CommentStatus status,
+ @Param("eventId") Long eventId,
+ @Param("userId") Long userId,
+ Pageable pageable);
+
+ // Расширенный поиск комментариев по фильтрам (с фильтрацией по датам) для модерации
+ @Query("""
+ SELECT c FROM Comment c
+ WHERE (:status IS NULL OR c.status = :status)
+ AND (:eventId IS NULL OR c.eventId = :eventId)
+ AND (:userId IS NULL OR c.userId = :userId)
+ AND (c.createdDate >= :start)
+ AND (c.createdDate <= :end)
+ ORDER BY c.createdDate DESC
+ """)
+ Page searchWithDates(@Param("status") CommentStatus status,
+ @Param("eventId") Long eventId,
+ @Param("userId") Long userId,
+ @Param("start") LocalDateTime start,
+ @Param("end") LocalDateTime end,
+ Pageable pageable);
+
+ // Поиск комментариев к событию по статусу
+ @Query("""
+ SELECT c FROM Comment c
+ WHERE c.eventId = :eventId AND c.status = :status
+ ORDER BY c.createdDate DESC
+ """)
+ List findByEventIdAndStatus(@Param("eventId") Long eventId,
+ @Param("status") CommentStatus status);
+
+ // Поиск всех комментариев к событию
+ List findByEventId(Long eventId, Pageable pageable);
+
+ // Поиск всех комментариев пользователя
+ List findByUserId(Long userId, Pageable pageable);
+}
diff --git a/core/comment-service/src/main/java/ru/yandex/practicum/service/CommentService.java b/core/comment-service/src/main/java/ru/yandex/practicum/service/CommentService.java
new file mode 100644
index 0000000..706f90c
--- /dev/null
+++ b/core/comment-service/src/main/java/ru/yandex/practicum/service/CommentService.java
@@ -0,0 +1,33 @@
+package ru.yandex.practicum.service;
+
+import ru.yandex.practicum.dto.comment.*;
+import ru.yandex.practicum.enums.CommentStatus;
+
+import java.time.LocalDateTime;
+import java.util.List;
+
+public interface CommentService {
+ CommentDto createComment(Long userId, Long eventId, NewCommentDto newCommentDto);
+
+ CommentDto updateComment(Long userId, Long commentId, UpdateCommentDto updateCommentDto);
+
+ void deleteComment(Long userId, Long commentId);
+
+ CommentDto updateCommentByAdmin(Long commentId, CommentAdminDto commentAdminDto);
+
+ void deleteCommentByAdmin(Long commentId);
+
+ List getCommentByStatus(Long eventId, CommentStatus status);
+
+ List getPublishedCommentsByEvent(Long eventId, int from, int size);
+
+ List adminSearch(CommentStatus status,
+ Long eventId,
+ Long userId,
+ LocalDateTime start,
+ LocalDateTime end,
+ int from,
+ int size);
+
+ public List getUserComments(Long userId, int from, int size);
+}
diff --git a/core/comment-service/src/main/java/ru/yandex/practicum/service/CommentServiceImpl.java b/core/comment-service/src/main/java/ru/yandex/practicum/service/CommentServiceImpl.java
new file mode 100644
index 0000000..1e94992
--- /dev/null
+++ b/core/comment-service/src/main/java/ru/yandex/practicum/service/CommentServiceImpl.java
@@ -0,0 +1,201 @@
+package ru.yandex.practicum.service;
+
+import feign.FeignException;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.PageRequest;
+import org.springframework.data.domain.Pageable;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import ru.yandex.practicum.client.EventClient;
+import ru.yandex.practicum.client.UserClient;
+import ru.yandex.practicum.dto.comment.*;
+import ru.yandex.practicum.dto.event.EventFullDto;
+import ru.yandex.practicum.enums.CommentStatus;
+import ru.yandex.practicum.enums.EventState;
+import ru.yandex.practicum.exception.*;
+import ru.yandex.practicum.mapper.CommentMapper;
+import ru.yandex.practicum.model.Comment;
+import ru.yandex.practicum.repository.CommentRepository;
+
+import java.time.LocalDateTime;
+import java.util.List;
+
+@Slf4j
+@Service
+@Transactional(readOnly = true)
+@RequiredArgsConstructor
+public class CommentServiceImpl implements CommentService {
+ private final CommentRepository commentRepository;
+ private final EventClient eventClient;
+ private final UserClient userClient;
+ private final CommentMapper commentMapper;
+
+ @Override
+ @Transactional
+ public CommentDto createComment(Long userId, Long eventId, NewCommentDto newCommentDto) {
+ checkUserExists(userId);
+ EventFullDto event = eventClient.getEvent(eventId);
+
+ if (event.getState() != EventState.PUBLISHED) {
+ throw new ConflictException("Нельзя комментировать неопубликованное событие");
+ }
+
+ Comment comment = commentMapper.toComment(newCommentDto, userId, eventId);
+ Comment saved = commentRepository.save(comment);
+
+ log.info("Создан комментарий: id={}, userId={}, eventId={}", saved.getId(), userId, eventId);
+ return commentMapper.toDto(saved);
+ }
+
+ @Override
+ @Transactional
+ public CommentDto updateComment(Long userId, Long commentId, UpdateCommentDto updateCommentDto) {
+ Comment comment = getCommentOrThrow(commentId, userId);
+
+ if (comment.getStatus() != CommentStatus.PENDING) {
+ throw new ConflictException("Можно редактировать только комментарии в статусе PENDING");
+ }
+
+ commentMapper.updateCommentFromDto(updateCommentDto, comment);
+ comment.setUpdatedDate(LocalDateTime.now());
+
+ log.info("Комментарий обновлен пользователем: commentId={}, userId={}", commentId, userId);
+ return commentMapper.toDto(commentRepository.save(comment));
+ }
+
+ @Override
+ @Transactional
+ public void deleteComment(Long userId, Long commentId) {
+ Comment comment = getCommentOrThrow(commentId, userId);
+
+ comment.setStatus(CommentStatus.REJECTED);
+ comment.setUpdatedDate(LocalDateTime.now());
+ commentRepository.save(comment);
+
+ log.info("Комментарий помечен как удаленный пользователем: commentId={}, userId={}", commentId, userId);
+ }
+
+ @Override
+ @Transactional
+ public CommentDto updateCommentByAdmin(Long commentId, CommentAdminDto commentAdminDto) {
+ Comment comment = commentRepository.findById(commentId)
+ .orElseThrow(() -> new NotFoundException("Комментарий с id=" + commentId + " не найден"));
+
+ if (commentAdminDto.status() == CommentStatus.PENDING) {
+ throw new ConflictException("Целевой статус модерации не может быть PENDING");
+ }
+
+ commentMapper.updateFromAdminDto(commentAdminDto, comment);
+ comment.setUpdatedDate(LocalDateTime.now());
+
+ log.info("Комментарий обновлен администратором: commentId={}", commentId);
+ return commentMapper.toDto(commentRepository.save(comment));
+ }
+
+ @Override
+ @Transactional
+ public void deleteCommentByAdmin(Long commentId) {
+ if (!commentRepository.existsById(commentId)) {
+ throw new NotFoundException("Комментарий с id=" + commentId + " не найден");
+ }
+
+ commentRepository.deleteById(commentId);
+ log.info("Комментарий удален администратором: commentId={}", commentId);
+ }
+
+ @Override
+ @Transactional(readOnly = true)
+ public List getCommentByStatus(Long eventId, CommentStatus status) {
+ checkEventExists(eventId);
+
+ log.info("Получение комментариев по статусу: eventId={}, status={}", eventId, status);
+ return commentRepository.findByEventIdAndStatus(eventId, status)
+ .stream()
+ .map(commentMapper::toDto)
+ .toList();
+ }
+
+ @Override
+ @Transactional(readOnly = true)
+ public List getPublishedCommentsByEvent(Long eventId, int from, int size) {
+ checkEventExists(eventId);
+
+ Pageable pageable = PageRequest.of(from / size, size);
+ log.info("Получение опубликованных комментариев: eventId={}, from={}, size={}", eventId, from, size);
+
+ return commentRepository.findPublishedByEvent(eventId, pageable)
+ .stream()
+ .map(commentMapper::toDto)
+ .toList();
+ }
+
+ @Override
+ @Transactional(readOnly = true)
+ public List adminSearch(CommentStatus status,
+ Long eventId,
+ Long userId,
+ LocalDateTime start,
+ LocalDateTime end,
+ int from, int size) {
+
+ Pageable pageable = PageRequest.of(from / size, size);
+ Page result;
+
+ if (start == null && end == null) {
+ result = commentRepository.searchWithoutDates(status, eventId, userId, pageable);
+ } else if (start == null) {
+ result = commentRepository.searchWithDates(status, eventId, userId, LocalDateTime.MIN, end, pageable);
+ } else if (end == null) {
+ result = commentRepository.searchWithDates(status, eventId, userId, start, LocalDateTime.MAX, pageable);
+ } else {
+ result = commentRepository.searchWithDates(status, eventId, userId, start, end, pageable);
+ }
+
+ log.info("Поиск администратором: status={}, eventId={}, userId={}, from={}, size={}",
+ status, eventId, userId, from, size);
+
+ return result.getContent()
+ .stream()
+ .map(commentMapper::toDto)
+ .toList();
+ }
+
+ @Override
+ @Transactional(readOnly = true)
+ public List getUserComments(Long userId, int from, int size) {
+ checkUserExists(userId);
+
+ Pageable pageable = PageRequest.of(from / size, size);
+ log.info("Получение комментариев пользователя: userId={}, from={}, size={}", userId, from, size);
+
+ return commentRepository.findByUserId(userId, pageable)
+ .stream()
+ .map(commentMapper::toDto)
+ .toList();
+ }
+
+ private Comment getCommentOrThrow(Long commentId, Long userId) {
+ return commentRepository.findByIdAndUserId(commentId, userId)
+ .orElseThrow(() -> new NotFoundException(
+ "Комментарий с id=" + commentId + " от пользователя с id=" + userId + " не найден"
+ ));
+ }
+
+ private void checkUserExists(Long userId) {
+ try {
+ userClient.getUser(userId);
+ } catch (FeignException.NotFound e) {
+ throw new NotFoundException("Пользователь с id=" + userId + " не найден");
+ }
+ }
+
+ private void checkEventExists(Long eventId) {
+ try {
+ eventClient.getEvent(eventId);
+ } catch (FeignException.NotFound e) {
+ throw new NotFoundException("Событие с id=" + eventId + " не найден");
+ }
+ }
+}
diff --git a/core/comment-service/src/main/resources/application.yaml b/core/comment-service/src/main/resources/application.yaml
new file mode 100644
index 0000000..cfae722
--- /dev/null
+++ b/core/comment-service/src/main/resources/application.yaml
@@ -0,0 +1,29 @@
+spring:
+ application:
+ name: comment-service
+ config:
+ import: "configserver:"
+ cloud:
+ loadbalancer:
+ retry:
+ enabled: true
+ config:
+ fail-fast: true
+ discovery:
+ enabled: true
+ serviceId: config-server
+ retry:
+ useRandomPolicy: true
+ max-interval: 6000
+
+server:
+ port: 0
+
+eureka:
+ instance:
+ instanceId: ${spring.application.name}:${spring.application.instance_id:${random.value}}
+ client:
+ healthcheck:
+ enabled: true
+ serviceUrl:
+ defaultZone: http://localhost:8761/eureka
\ No newline at end of file
diff --git a/core/comment-service/src/main/resources/schema.sql b/core/comment-service/src/main/resources/schema.sql
new file mode 100644
index 0000000..7cc6630
--- /dev/null
+++ b/core/comment-service/src/main/resources/schema.sql
@@ -0,0 +1,17 @@
+DROP TABLE IF EXISTS comments CASCADE;
+
+--Создание таблицы комментариев
+create TABLE IF NOT EXISTS comments (
+ id BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
+ text TEXT NOT NULL,
+ user_id BIGINT NOT NULL,
+ event_id BIGINT NOT NULL,
+ created_date TIMESTAMP WITHOUT TIME ZONE NOT NULL,
+ updated_date TIMESTAMP WITHOUT TIME ZONE,
+ status VARCHAR(20) NOT NULL
+);
+
+--Индекс для поиска комментариев к событию
+CREATE INDEX IF NOT EXISTS idx_comments_event_id ON comments(event_id);
+--Индекс для поиска комментариев пользователя
+CREATE INDEX IF NOT EXISTS idx_comments_user_id ON comments(user_id);
\ No newline at end of file
diff --git a/core/event-service/pom.xml b/core/event-service/pom.xml
new file mode 100644
index 0000000..fc467b1
--- /dev/null
+++ b/core/event-service/pom.xml
@@ -0,0 +1,157 @@
+
+
+ 4.0.0
+
+ ru.yandex.practicum
+ core
+ 0.0.1-SNAPSHOT
+
+
+ event-service
+
+
+ 21
+ 21
+ UTF-8
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+
+
+
+ org.springframework.boot
+ spring-boot-starter-validation
+
+
+
+ org.springframework.boot
+ spring-boot-starter-actuator
+
+
+
+ org.springframework.boot
+ spring-boot-starter-data-jpa
+
+
+
+ org.springframework.boot
+ spring-boot-starter-aop
+
+
+
+ ru.yandex.practicum
+ interaction-api
+ ${project.version}
+
+
+
+ ru.yandex.practicum
+ stats-client
+ ${project.version}
+
+
+
+ ru.yandex.practicum
+ stats-dto
+ ${project.version}
+
+
+
+ org.projectlombok
+ lombok
+ provided
+
+
+
+ org.postgresql
+ postgresql
+
+
+
+ org.springframework.cloud
+ spring-cloud-starter-config
+
+
+
+ org.springframework.cloud
+ spring-cloud-starter-netflix-eureka-client
+
+
+
+ org.springframework.cloud
+ spring-cloud-starter-openfeign
+
+
+
+ org.springframework.cloud
+ spring-cloud-starter-loadbalancer
+
+
+
+ org.springframework.retry
+ spring-retry
+ 2.0.5
+
+
+
+ io.github.openfeign
+ feign-okhttp
+
+
+
+ org.mapstruct
+ mapstruct
+ ${mapstruct.version}
+
+
+
+ com.h2database
+ h2
+ runtime
+
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+
+
+
+ org.projectlombok
+ lombok
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+ 3.11.0
+
+ 21
+ 21
+
+
+ org.projectlombok
+ lombok
+ ${lombok.version}
+
+
+ org.mapstruct
+ mapstruct-processor
+ ${mapstruct.version}
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/core/main-service/src/main/java/ru/yandex/practicum/MainApplication.java b/core/event-service/src/main/java/ru/yandex/practicum/EventServiceApp.java
similarity index 71%
rename from core/main-service/src/main/java/ru/yandex/practicum/MainApplication.java
rename to core/event-service/src/main/java/ru/yandex/practicum/EventServiceApp.java
index 17b4ca6..62b1f20 100644
--- a/core/main-service/src/main/java/ru/yandex/practicum/MainApplication.java
+++ b/core/event-service/src/main/java/ru/yandex/practicum/EventServiceApp.java
@@ -5,11 +5,11 @@
import org.springframework.boot.context.properties.ConfigurationPropertiesScan;
import org.springframework.cloud.openfeign.EnableFeignClients;
-@ConfigurationPropertiesScan
-@EnableFeignClients
@SpringBootApplication
-public class MainApplication {
+@EnableFeignClients(basePackages = "ru.yandex.practicum.client")
+@ConfigurationPropertiesScan
+public class EventServiceApp {
public static void main(String[] args) {
- SpringApplication.run(MainApplication.class, args);
+ SpringApplication.run(EventServiceApp.class, args);
}
}
diff --git a/core/main-service/src/main/java/ru/yandex/practicum/category/controller/AdminCategoryController.java b/core/event-service/src/main/java/ru/yandex/practicum/controller/AdminCategoryController.java
similarity index 74%
rename from core/main-service/src/main/java/ru/yandex/practicum/category/controller/AdminCategoryController.java
rename to core/event-service/src/main/java/ru/yandex/practicum/controller/AdminCategoryController.java
index d09cc16..99082b1 100644
--- a/core/main-service/src/main/java/ru/yandex/practicum/category/controller/AdminCategoryController.java
+++ b/core/event-service/src/main/java/ru/yandex/practicum/controller/AdminCategoryController.java
@@ -1,4 +1,4 @@
-package ru.yandex.practicum.category.controller;
+package ru.yandex.practicum.controller;
import jakarta.validation.Valid;
import jakarta.validation.constraints.Positive;
@@ -7,9 +7,8 @@
import org.springframework.http.HttpStatus;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
-import ru.yandex.practicum.category.dto.CategoryDto;
-import ru.yandex.practicum.category.dto.NewCategoryDto;
-import ru.yandex.practicum.category.service.CategoryService;
+import ru.yandex.practicum.dto.category.*;
+import ru.yandex.practicum.service.CategoryService;
@Slf4j
@Validated
@@ -35,8 +34,8 @@ public void deleteCategory(@PathVariable @Positive Long categoryId) {
@PatchMapping("/{categoryId}")
public CategoryDto updateCategory(@PathVariable @Positive Long categoryId,
- @RequestBody @Valid NewCategoryDto newCategoryDto) {
- log.debug("Controller: updateCategory categoryId={}, data={}", categoryId, newCategoryDto);
- return categoryService.updateCategory(categoryId, newCategoryDto);
+ @RequestBody @Valid UpdateCategoryDto updateCategoryDto) {
+ log.debug("Controller: updateCategory categoryId={}, data={}", categoryId, updateCategoryDto);
+ return categoryService.updateCategory(categoryId, updateCategoryDto);
}
}
diff --git a/core/main-service/src/main/java/ru/yandex/practicum/compilation/controller/AdminCompilationController.java b/core/event-service/src/main/java/ru/yandex/practicum/controller/AdminCompilationController.java
similarity index 82%
rename from core/main-service/src/main/java/ru/yandex/practicum/compilation/controller/AdminCompilationController.java
rename to core/event-service/src/main/java/ru/yandex/practicum/controller/AdminCompilationController.java
index 4a50145..c2c8e84 100644
--- a/core/main-service/src/main/java/ru/yandex/practicum/compilation/controller/AdminCompilationController.java
+++ b/core/event-service/src/main/java/ru/yandex/practicum/controller/AdminCompilationController.java
@@ -1,4 +1,4 @@
-package ru.yandex.practicum.compilation.controller;
+package ru.yandex.practicum.controller;
import jakarta.validation.Valid;
import jakarta.validation.constraints.Positive;
@@ -7,10 +7,8 @@
import org.springframework.http.HttpStatus;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
-import ru.yandex.practicum.compilation.dto.CompilationDto;
-import ru.yandex.practicum.compilation.dto.NewCompilationDto;
-import ru.yandex.practicum.compilation.dto.UpdateCompilationRequest;
-import ru.yandex.practicum.compilation.service.CompilationService;
+import ru.yandex.practicum.dto.compilation.*;
+import ru.yandex.practicum.service.CompilationService;
@Slf4j
@Validated
diff --git a/core/main-service/src/main/java/ru/yandex/practicum/event/controller/AdminEventController.java b/core/event-service/src/main/java/ru/yandex/practicum/controller/AdminEventController.java
similarity index 83%
rename from core/main-service/src/main/java/ru/yandex/practicum/event/controller/AdminEventController.java
rename to core/event-service/src/main/java/ru/yandex/practicum/controller/AdminEventController.java
index 92f3945..2078aa9 100644
--- a/core/main-service/src/main/java/ru/yandex/practicum/event/controller/AdminEventController.java
+++ b/core/event-service/src/main/java/ru/yandex/practicum/controller/AdminEventController.java
@@ -1,4 +1,4 @@
-package ru.yandex.practicum.event.controller;
+package ru.yandex.practicum.controller;
import jakarta.validation.Valid;
import jakarta.validation.constraints.Positive;
@@ -7,10 +7,8 @@
import org.springframework.data.domain.PageRequest;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
-import ru.yandex.practicum.event.dto.EventFullDto;
-import ru.yandex.practicum.event.dto.SearchEventAdminRequest;
-import ru.yandex.practicum.event.dto.UpdateEventAdminRequest;
-import ru.yandex.practicum.event.service.EventService;
+import ru.yandex.practicum.dto.event.*;
+import ru.yandex.practicum.service.EventService;
import java.util.List;
diff --git a/core/event-service/src/main/java/ru/yandex/practicum/controller/InternalEventController.java b/core/event-service/src/main/java/ru/yandex/practicum/controller/InternalEventController.java
new file mode 100644
index 0000000..00ff0a3
--- /dev/null
+++ b/core/event-service/src/main/java/ru/yandex/practicum/controller/InternalEventController.java
@@ -0,0 +1,39 @@
+package ru.yandex.practicum.controller;
+
+import jakarta.validation.constraints.Positive;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+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.yandex.practicum.client.UserClient;
+import ru.yandex.practicum.dto.event.EventFullDto;
+import ru.yandex.practicum.exception.NotFoundException;
+import ru.yandex.practicum.mapper.EventMapper;
+import ru.yandex.practicum.model.Event;
+import ru.yandex.practicum.repository.EventRepository;
+
+@Slf4j
+@RestController
+@RequestMapping("/internal/events")
+@RequiredArgsConstructor
+public class InternalEventController {
+
+ private final EventRepository eventRepository;
+ private final EventMapper eventMapper;
+ private final UserClient userClient;
+
+ @GetMapping("/{eventId}")
+ public EventFullDto getEvent(@PathVariable @Positive Long eventId) {
+ log.debug("Controller: getEvent eventId={}", eventId);
+
+ Event event = eventRepository.findById(eventId)
+ .orElseThrow(() -> new NotFoundException("Event not found with id: " + eventId));
+
+ EventFullDto dto = eventMapper.toFullDto(event);
+ dto.setInitiator(userClient.getUser(event.getInitiatorId()));
+
+ return dto;
+ }
+}
diff --git a/core/main-service/src/main/java/ru/yandex/practicum/event/controller/PrivateEventController.java b/core/event-service/src/main/java/ru/yandex/practicum/controller/PrivateEventController.java
similarity index 60%
rename from core/main-service/src/main/java/ru/yandex/practicum/event/controller/PrivateEventController.java
rename to core/event-service/src/main/java/ru/yandex/practicum/controller/PrivateEventController.java
index f089a95..a4dda89 100644
--- a/core/main-service/src/main/java/ru/yandex/practicum/event/controller/PrivateEventController.java
+++ b/core/event-service/src/main/java/ru/yandex/practicum/controller/PrivateEventController.java
@@ -1,4 +1,4 @@
-package ru.yandex.practicum.event.controller;
+package ru.yandex.practicum.controller;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.validation.Valid;
@@ -11,15 +11,8 @@
import org.springframework.http.HttpStatus;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
-import ru.yandex.practicum.event.dto.EventFullDto;
-import ru.yandex.practicum.event.dto.EventShortDto;
-import ru.yandex.practicum.event.dto.NewEventDto;
-import ru.yandex.practicum.event.dto.UpdateEventUserRequest;
-import ru.yandex.practicum.event.service.EventService;
-import ru.yandex.practicum.request.dto.EventRequestStatusUpdateRequest;
-import ru.yandex.practicum.request.dto.EventRequestStatusUpdateResult;
-import ru.yandex.practicum.request.dto.ParticipationRequestDto;
-import ru.yandex.practicum.request.service.RequestService;
+import ru.yandex.practicum.dto.event.*;
+import ru.yandex.practicum.service.EventService;
import java.util.List;
@@ -30,7 +23,6 @@
@RequiredArgsConstructor
public class PrivateEventController {
private final EventService eventService;
- private final RequestService requestService;
@GetMapping
public List getEvents(@PathVariable("userId") @Positive Long userId,
@@ -68,21 +60,4 @@ public EventFullDto updateEvent(@PathVariable("userId") @Positive Long userId,
log.debug("Controller: updateEvent userId={}, eventId={}, data={}", userId, eventId, request);
return eventService.updateEvent(userId, eventId, request);
}
-
- @GetMapping("/{eventId}/requests")
- public List getRequestsByEvent(@PathVariable("userId") @Positive Long userId,
- @PathVariable("eventId") @Positive Long eventId
- ) {
- log.debug("Controller: getRequestsByEvent userId={}, eventId={}", userId, eventId);
- return requestService.getRequestsByEvent(userId, eventId);
- }
-
- @PatchMapping("/{eventId}/requests")
- public EventRequestStatusUpdateResult updateRequestStatus(@PathVariable("userId") @Positive Long userId,
- @PathVariable("eventId") @Positive Long eventId,
- @RequestBody EventRequestStatusUpdateRequest request
- ) {
- log.debug("Controller: updateRequestStatus userId={}, eventId={}, data={}", userId, eventId, request);
- return requestService.updateRequestStatus(userId, eventId, request);
- }
}
diff --git a/core/main-service/src/main/java/ru/yandex/practicum/category/controller/PublicCategoryController.java b/core/event-service/src/main/java/ru/yandex/practicum/controller/PublicCategoryController.java
similarity index 88%
rename from core/main-service/src/main/java/ru/yandex/practicum/category/controller/PublicCategoryController.java
rename to core/event-service/src/main/java/ru/yandex/practicum/controller/PublicCategoryController.java
index 39a6fc9..9422bb5 100644
--- a/core/main-service/src/main/java/ru/yandex/practicum/category/controller/PublicCategoryController.java
+++ b/core/event-service/src/main/java/ru/yandex/practicum/controller/PublicCategoryController.java
@@ -1,4 +1,4 @@
-package ru.yandex.practicum.category.controller;
+package ru.yandex.practicum.controller;
import jakarta.validation.constraints.Positive;
import jakarta.validation.constraints.PositiveOrZero;
@@ -8,8 +8,8 @@
import org.springframework.data.domain.Pageable;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
-import ru.yandex.practicum.category.dto.CategoryDto;
-import ru.yandex.practicum.category.service.CategoryService;
+import ru.yandex.practicum.dto.category.CategoryDto;
+import ru.yandex.practicum.service.CategoryService;
import java.util.List;
diff --git a/core/main-service/src/main/java/ru/yandex/practicum/compilation/controller/PublicCompilationController.java b/core/event-service/src/main/java/ru/yandex/practicum/controller/PublicCompilationController.java
similarity index 88%
rename from core/main-service/src/main/java/ru/yandex/practicum/compilation/controller/PublicCompilationController.java
rename to core/event-service/src/main/java/ru/yandex/practicum/controller/PublicCompilationController.java
index c902fae..73b9bcc 100644
--- a/core/main-service/src/main/java/ru/yandex/practicum/compilation/controller/PublicCompilationController.java
+++ b/core/event-service/src/main/java/ru/yandex/practicum/controller/PublicCompilationController.java
@@ -1,4 +1,4 @@
-package ru.yandex.practicum.compilation.controller;
+package ru.yandex.practicum.controller;
import jakarta.validation.constraints.Positive;
import jakarta.validation.constraints.PositiveOrZero;
@@ -8,8 +8,8 @@
import org.springframework.data.domain.Pageable;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
-import ru.yandex.practicum.compilation.dto.CompilationDto;
-import ru.yandex.practicum.compilation.service.CompilationService;
+import ru.yandex.practicum.dto.compilation.CompilationDto;
+import ru.yandex.practicum.service.CompilationService;
import java.util.List;
diff --git a/core/main-service/src/main/java/ru/yandex/practicum/event/controller/PublicEventController.java b/core/event-service/src/main/java/ru/yandex/practicum/controller/PublicEventController.java
similarity index 85%
rename from core/main-service/src/main/java/ru/yandex/practicum/event/controller/PublicEventController.java
rename to core/event-service/src/main/java/ru/yandex/practicum/controller/PublicEventController.java
index dcbec45..cfe01a4 100644
--- a/core/main-service/src/main/java/ru/yandex/practicum/event/controller/PublicEventController.java
+++ b/core/event-service/src/main/java/ru/yandex/practicum/controller/PublicEventController.java
@@ -1,4 +1,4 @@
-package ru.yandex.practicum.event.controller;
+package ru.yandex.practicum.controller;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.validation.Valid;
@@ -8,10 +8,8 @@
import org.springframework.data.domain.PageRequest;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
-import ru.yandex.practicum.event.dto.EventFullDto;
-import ru.yandex.practicum.event.dto.EventShortDto;
-import ru.yandex.practicum.event.dto.SearchEventPublicRequest;
-import ru.yandex.practicum.event.service.EventService;
+import ru.yandex.practicum.dto.event.*;
+import ru.yandex.practicum.service.EventService;
import java.util.List;
diff --git a/core/event-service/src/main/java/ru/yandex/practicum/handler/ErrorHandler.java b/core/event-service/src/main/java/ru/yandex/practicum/handler/ErrorHandler.java
new file mode 100644
index 0000000..6c1ca58
--- /dev/null
+++ b/core/event-service/src/main/java/ru/yandex/practicum/handler/ErrorHandler.java
@@ -0,0 +1,149 @@
+package ru.yandex.practicum.handler;
+
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.validation.ConstraintViolationException;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.context.MessageSourceResolvable;
+import org.springframework.http.HttpStatus;
+import org.springframework.web.HttpMediaTypeNotSupportedException;
+import org.springframework.web.HttpRequestMethodNotSupportedException;
+import org.springframework.web.bind.MethodArgumentNotValidException;
+import org.springframework.web.bind.ServletRequestBindingException;
+import org.springframework.web.bind.annotation.ExceptionHandler;
+import org.springframework.web.bind.annotation.ResponseStatus;
+import org.springframework.web.bind.annotation.RestControllerAdvice;
+import org.springframework.web.method.annotation.HandlerMethodValidationException;
+import org.springframework.web.servlet.NoHandlerFoundException;
+import ru.yandex.practicum.exception.*;
+
+import java.util.stream.Collectors;
+
+@Slf4j
+@RestControllerAdvice
+public class ErrorHandler {
+
+ @ExceptionHandler(NotFoundException.class)
+ @ResponseStatus(HttpStatus.NOT_FOUND)
+ public ErrorResponse handleNotFoundException(NotFoundException exception, HttpServletRequest request) {
+ return buildResponse(HttpStatus.NOT_FOUND, exception, request);
+ }
+
+ @ExceptionHandler(BadRequestException.class)
+ @ResponseStatus(HttpStatus.BAD_REQUEST)
+ public ErrorResponse handleBadRequestException(BadRequestException exception, HttpServletRequest request) {
+ return buildResponse(HttpStatus.BAD_REQUEST, exception, request);
+ }
+
+ @ExceptionHandler(ForbiddenException.class)
+ @ResponseStatus(HttpStatus.FORBIDDEN)
+ public ErrorResponse handleForbiddenException(ForbiddenException exception, HttpServletRequest request) {
+ return buildResponse(HttpStatus.FORBIDDEN, exception, request);
+ }
+
+ @ExceptionHandler(ConflictException.class)
+ @ResponseStatus(HttpStatus.CONFLICT)
+ public ErrorResponse handleConflictException(ConflictException exception, HttpServletRequest request) {
+ return buildResponse(HttpStatus.CONFLICT, exception, request);
+ }
+
+ @ExceptionHandler(ValidationException.class)
+ @ResponseStatus(HttpStatus.CONFLICT)
+ public ErrorResponse handleValidationException(ValidationException exception, HttpServletRequest request) {
+ return buildResponse(HttpStatus.CONFLICT, exception, request);
+ }
+
+ @ExceptionHandler(ConstraintViolationException.class)
+ @ResponseStatus(HttpStatus.BAD_REQUEST)
+ public ErrorResponse handleConstraintViolation(
+ ConstraintViolationException ex, HttpServletRequest request) {
+ String violations = ex.getConstraintViolations().stream()
+ .map(violation -> violation.getPropertyPath() + ": " + violation.getMessage())
+ .collect(Collectors.joining("; "));
+
+ String message = violations.isEmpty() ? "Constraint violation" : violations;
+ return buildResponse(HttpStatus.BAD_REQUEST, message, null, request);
+ }
+
+ @ExceptionHandler(MethodArgumentNotValidException.class)
+ @ResponseStatus(HttpStatus.BAD_REQUEST)
+ public ErrorResponse handleMethodArgumentNotValid(
+ MethodArgumentNotValidException ex, HttpServletRequest request) {
+ String validationErrors = ex.getBindingResult().getFieldErrors().stream()
+ .map(error -> error.getField() + ": " + error.getDefaultMessage())
+ .collect(Collectors.joining("; "));
+
+ String message = validationErrors.isEmpty() ? "Validation failed" : validationErrors;
+
+ return buildResponse(HttpStatus.BAD_REQUEST, message, null, request);
+ }
+
+ @ExceptionHandler(HandlerMethodValidationException.class)
+ @ResponseStatus(HttpStatus.BAD_REQUEST)
+ public ErrorResponse handleHandlerMethodValidation(
+ HandlerMethodValidationException ex, HttpServletRequest request) {
+ String validationErrors = ex.getAllErrors().stream()
+ .map(MessageSourceResolvable::getDefaultMessage)
+ .collect(Collectors.joining("; "));
+
+ String message = validationErrors.isEmpty() ? "Validation failed" : validationErrors;
+
+ return buildResponse(HttpStatus.BAD_REQUEST, message, null, request);
+ }
+
+ @ExceptionHandler(ServletRequestBindingException.class)
+ @ResponseStatus(HttpStatus.BAD_REQUEST)
+ public ErrorResponse handleServletRequestBindingException(
+ ServletRequestBindingException ex, HttpServletRequest request) {
+ return buildResponse(HttpStatus.BAD_REQUEST, ex.getMessage(), null, request);
+ }
+
+ @ExceptionHandler(HttpRequestMethodNotSupportedException.class)
+ @ResponseStatus(HttpStatus.METHOD_NOT_ALLOWED)
+ public ErrorResponse handleHttpRequestMethodNotSupported(
+ HttpRequestMethodNotSupportedException ex, HttpServletRequest request) {
+ return buildResponse(HttpStatus.METHOD_NOT_ALLOWED, ex.getMessage(), null, request);
+ }
+
+ @ExceptionHandler(HttpMediaTypeNotSupportedException.class)
+ @ResponseStatus(HttpStatus.UNSUPPORTED_MEDIA_TYPE)
+ public ErrorResponse handleHttpMediaTypeNotSupported(
+ HttpMediaTypeNotSupportedException ex, HttpServletRequest request) {
+ return buildResponse(HttpStatus.UNSUPPORTED_MEDIA_TYPE, ex.getMessage(), null, request);
+ }
+
+ @ExceptionHandler(NoHandlerFoundException.class)
+ @ResponseStatus(HttpStatus.NOT_FOUND)
+ public ErrorResponse handleNoHandlerFoundException(
+ NoHandlerFoundException ex, HttpServletRequest request) {
+ return buildResponse(HttpStatus.NOT_FOUND, ex.getMessage(), null, request);
+ }
+
+ @ExceptionHandler(Exception.class)
+ @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
+ public ErrorResponse handleUnexpected(Exception exception, HttpServletRequest request) {
+ return buildResponse(HttpStatus.INTERNAL_SERVER_ERROR, exception, request);
+ }
+
+ private ErrorResponse buildResponse(
+ HttpStatus httpStatus, Exception exception, HttpServletRequest request) {
+ return buildResponse(httpStatus, exception.getMessage(), exception, request);
+ }
+
+ private ErrorResponse buildResponse(
+ HttpStatus httpStatus, String message, Exception exception, HttpServletRequest request) {
+ String path = request.getRequestURI();
+ String httpMethod = request.getMethod();
+ int statusCode = httpStatus.value();
+ String error = httpStatus.getReasonPhrase();
+
+ String logMessage = String.format("Path: %s %s, '%d' %s — %s", httpMethod, path, statusCode, error, message);
+
+ if (statusCode >= 500) {
+ log.error(logMessage, exception);
+ } else {
+ log.warn(logMessage);
+ }
+
+ return new ErrorResponse(path, httpMethod, statusCode, error, message);
+ }
+}
diff --git a/core/main-service/src/main/java/ru/yandex/practicum/category/mapper/CategoryMapper.java b/core/event-service/src/main/java/ru/yandex/practicum/mapper/CategoryMapper.java
similarity index 50%
rename from core/main-service/src/main/java/ru/yandex/practicum/category/mapper/CategoryMapper.java
rename to core/event-service/src/main/java/ru/yandex/practicum/mapper/CategoryMapper.java
index c62518c..9c48596 100644
--- a/core/main-service/src/main/java/ru/yandex/practicum/category/mapper/CategoryMapper.java
+++ b/core/event-service/src/main/java/ru/yandex/practicum/mapper/CategoryMapper.java
@@ -1,11 +1,10 @@
-package ru.yandex.practicum.category.mapper;
+package ru.yandex.practicum.mapper;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.MappingTarget;
-import ru.yandex.practicum.category.dto.CategoryDto;
-import ru.yandex.practicum.category.dto.NewCategoryDto;
-import ru.yandex.practicum.category.model.Category;
+import ru.yandex.practicum.dto.category.*;
+import ru.yandex.practicum.model.Category;
@Mapper(componentModel = "spring")
public interface CategoryMapper {
@@ -16,7 +15,5 @@ public interface CategoryMapper {
CategoryDto toDto(Category category);
@Mapping(target = "id", ignore = true)
- void updateCategoryFromDto(NewCategoryDto dto, @MappingTarget Category category);
-
- Category toEntityFromDto(CategoryDto dto);
+ void updateCategoryFromDto(UpdateCategoryDto updateCategoryDto, @MappingTarget Category category);
}
diff --git a/core/event-service/src/main/java/ru/yandex/practicum/mapper/CompilationMapper.java b/core/event-service/src/main/java/ru/yandex/practicum/mapper/CompilationMapper.java
new file mode 100644
index 0000000..5781c84
--- /dev/null
+++ b/core/event-service/src/main/java/ru/yandex/practicum/mapper/CompilationMapper.java
@@ -0,0 +1,20 @@
+package ru.yandex.practicum.mapper;
+
+import org.mapstruct.*;
+import ru.yandex.practicum.dto.compilation.*;
+import ru.yandex.practicum.model.Compilation;
+
+@Mapper(componentModel = "spring")
+public interface CompilationMapper {
+
+ @Mapping(target = "id", ignore = true)
+ @Mapping(target = "events", ignore = true)
+ Compilation toEntity(NewCompilationDto newCompilationDto);
+
+ CompilationDto toDto(Compilation compilation);
+
+ @Mapping(target = "id", ignore = true)
+ @Mapping(target = "events", ignore = true)
+ @BeanMapping(nullValuePropertyMappingStrategy = NullValuePropertyMappingStrategy.IGNORE)
+ void updateCompilationFromRequest(UpdateCompilationRequest request, @MappingTarget Compilation compilation);
+}
diff --git a/core/main-service/src/main/java/ru/yandex/practicum/event/mapper/EventMapper.java b/core/event-service/src/main/java/ru/yandex/practicum/mapper/EventMapper.java
similarity index 59%
rename from core/main-service/src/main/java/ru/yandex/practicum/event/mapper/EventMapper.java
rename to core/event-service/src/main/java/ru/yandex/practicum/mapper/EventMapper.java
index d3d046e..18dcf68 100644
--- a/core/main-service/src/main/java/ru/yandex/practicum/event/mapper/EventMapper.java
+++ b/core/event-service/src/main/java/ru/yandex/practicum/mapper/EventMapper.java
@@ -1,45 +1,50 @@
-package ru.yandex.practicum.event.mapper;
+package ru.yandex.practicum.mapper;
import org.mapstruct.*;
-import ru.yandex.practicum.category.model.Category;
-import ru.yandex.practicum.event.dto.*;
-import ru.yandex.practicum.event.model.Event;
-import ru.yandex.practicum.event.model.EventState;
-import ru.yandex.practicum.user.model.User;
+import ru.yandex.practicum.dto.event.*;
+import ru.yandex.practicum.model.Category;
+import ru.yandex.practicum.model.Event;
-@Mapper(componentModel = "spring", uses = {LocationMapper.class})
+@Mapper(componentModel = "spring", uses = {LocationMapper.class, CategoryMapper.class})
public interface EventMapper {
@Mapping(target = "id", ignore = true)
- @Mapping(target = "publishedOn", ignore = true)
- @Mapping(target = "createdOn", ignore = true)
@Mapping(target = "category", source = "category")
- Event fromNewEvent(NewEventDto dto, User initiator, Category category, EventState state);
-
- EventShortDto toEventShortDto(Event event, Integer confirmedRequests, Long views);
-
- @Named("toEventShortWithoutStats")
+ @Mapping(target = "initiatorId", source = "initiatorId")
+ @Mapping(target = "state", constant = "PENDING")
+ @Mapping(target = "createdOn", ignore = true)
+ @Mapping(target = "publishedOn", ignore = true)
@Mapping(target = "confirmedRequests", ignore = true)
@Mapping(target = "views", ignore = true)
- EventShortDto toEventShortWithoutStats(Event event);
+ Event toEntity(NewEventDto dto, Long initiatorId, Category category);
- EventFullDto toEventFullDto(Event event, Integer confirmedRequests, Long views);
+ @Mapping(target = "initiator", ignore = true)
+ @Mapping(target = "category", source = "category")
+ EventShortDto toShortDto(Event event);
- @Mapping(target = "id", ignore = true)
@Mapping(target = "initiator", ignore = true)
+ @Mapping(target = "category", source = "category")
+ EventFullDto toFullDto(Event event);
+
+ @Mapping(target = "id", ignore = true)
+ @Mapping(target = "initiatorId", ignore = true)
@Mapping(target = "createdOn", ignore = true)
@Mapping(target = "publishedOn", ignore = true)
@Mapping(target = "state", ignore = true)
- @Mapping(target = "category", source = "category")
+ @Mapping(target = "category", ignore = true)
+ @Mapping(target = "views", ignore = true)
+ @Mapping(target = "confirmedRequests", ignore = true)
@BeanMapping(nullValuePropertyMappingStrategy = NullValuePropertyMappingStrategy.IGNORE)
void updateEventFromUserRequest(UpdateEventUserRequest request, @MappingTarget Event event, Category category);
@Mapping(target = "id", ignore = true)
- @Mapping(target = "initiator", ignore = true)
+ @Mapping(target = "category", ignore = true)
+ @Mapping(target = "initiatorId", ignore = true)
@Mapping(target = "createdOn", ignore = true)
@Mapping(target = "publishedOn", ignore = true)
@Mapping(target = "state", ignore = true)
- @Mapping(target = "category", source = "category")
+ @Mapping(target = "views", ignore = true)
+ @Mapping(target = "confirmedRequests", ignore = true)
@BeanMapping(nullValuePropertyMappingStrategy = NullValuePropertyMappingStrategy.IGNORE)
void updateEventFromAdminRequest(UpdateEventAdminRequest request, @MappingTarget Event event, Category category);
}
diff --git a/core/event-service/src/main/java/ru/yandex/practicum/mapper/LocationMapper.java b/core/event-service/src/main/java/ru/yandex/practicum/mapper/LocationMapper.java
new file mode 100644
index 0000000..70a2515
--- /dev/null
+++ b/core/event-service/src/main/java/ru/yandex/practicum/mapper/LocationMapper.java
@@ -0,0 +1,12 @@
+package ru.yandex.practicum.mapper;
+
+import org.mapstruct.Mapper;
+import ru.yandex.practicum.dto.event.LocationDto;
+import ru.yandex.practicum.model.Location;
+
+@Mapper(componentModel = "spring")
+public interface LocationMapper {
+ Location toLocation(LocationDto dto);
+
+ LocationDto toDto(Location entity);
+}
diff --git a/core/main-service/src/main/java/ru/yandex/practicum/category/model/Category.java b/core/event-service/src/main/java/ru/yandex/practicum/model/Category.java
similarity index 57%
rename from core/main-service/src/main/java/ru/yandex/practicum/category/model/Category.java
rename to core/event-service/src/main/java/ru/yandex/practicum/model/Category.java
index 0d13352..d57a849 100644
--- a/core/main-service/src/main/java/ru/yandex/practicum/category/model/Category.java
+++ b/core/event-service/src/main/java/ru/yandex/practicum/model/Category.java
@@ -1,21 +1,20 @@
-package ru.yandex.practicum.category.model;
+package ru.yandex.practicum.model;
import jakarta.persistence.*;
-import lombok.EqualsAndHashCode;
-import lombok.Getter;
-import lombok.Setter;
-import lombok.ToString;
+import lombok.*;
@Entity
@Table(name = "categories")
@Getter
@Setter
+@AllArgsConstructor
+@NoArgsConstructor
+@Builder
@ToString
-@EqualsAndHashCode(onlyExplicitlyIncluded = true)
public class Category {
+
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
- @EqualsAndHashCode.Include
private Long id;
@Column(name = "name", unique = true, nullable = false, length = 50)
diff --git a/core/main-service/src/main/java/ru/yandex/practicum/compilation/model/Compilation.java b/core/event-service/src/main/java/ru/yandex/practicum/model/Compilation.java
similarity index 66%
rename from core/main-service/src/main/java/ru/yandex/practicum/compilation/model/Compilation.java
rename to core/event-service/src/main/java/ru/yandex/practicum/model/Compilation.java
index 1e50a3f..8b80ece 100644
--- a/core/main-service/src/main/java/ru/yandex/practicum/compilation/model/Compilation.java
+++ b/core/event-service/src/main/java/ru/yandex/practicum/model/Compilation.java
@@ -1,10 +1,7 @@
-package ru.yandex.practicum.compilation.model;
+package ru.yandex.practicum.model;
import jakarta.persistence.*;
-import lombok.EqualsAndHashCode;
-import lombok.Getter;
-import lombok.Setter;
-import ru.yandex.practicum.event.model.Event;
+import lombok.*;
import java.util.Set;
@@ -12,14 +9,17 @@
@Table(name = "compilations")
@Getter
@Setter
-@EqualsAndHashCode(onlyExplicitlyIncluded = true)
+@AllArgsConstructor
+@NoArgsConstructor
+@Builder
+@ToString
public class Compilation {
+
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
- @EqualsAndHashCode.Include
private Long id;
- @Column(nullable = false, length = 50)
+ @Column(nullable = false, unique = true, length = 50)
private String title;
@Column(nullable = false)
diff --git a/core/main-service/src/main/java/ru/yandex/practicum/event/model/Event.java b/core/event-service/src/main/java/ru/yandex/practicum/model/Event.java
similarity index 75%
rename from core/main-service/src/main/java/ru/yandex/practicum/event/model/Event.java
rename to core/event-service/src/main/java/ru/yandex/practicum/model/Event.java
index 0ab14ac..a33d87f 100644
--- a/core/main-service/src/main/java/ru/yandex/practicum/event/model/Event.java
+++ b/core/event-service/src/main/java/ru/yandex/practicum/model/Event.java
@@ -1,12 +1,9 @@
-package ru.yandex.practicum.event.model;
+package ru.yandex.practicum.model;
import jakarta.persistence.*;
-import lombok.EqualsAndHashCode;
-import lombok.Getter;
-import lombok.Setter;
+import lombok.*;
import org.hibernate.annotations.CreationTimestamp;
-import ru.yandex.practicum.category.model.Category;
-import ru.yandex.practicum.user.model.User;
+import ru.yandex.practicum.enums.EventState;
import java.time.LocalDateTime;
@@ -14,11 +11,14 @@
@Table(name = "events")
@Getter
@Setter
-@EqualsAndHashCode(onlyExplicitlyIncluded = true)
+@AllArgsConstructor
+@NoArgsConstructor
+@Builder
+@ToString
public class Event {
+
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
- @EqualsAndHashCode.Include
private Long id;
@Column(nullable = false, length = 120)
@@ -34,9 +34,8 @@ public class Event {
@JoinColumn(name = "category_id")
private Category category;
- @ManyToOne(fetch = FetchType.LAZY)
- @JoinColumn(name = "initiator_id")
- private User initiator;
+ @Column(name = "initiator_id")
+ private Long initiatorId;
@Column(name = "created_on", nullable = false)
@CreationTimestamp
@@ -53,21 +52,29 @@ public class Event {
@AttributeOverride(name = "lat", column = @Column(name = "lat")),
@AttributeOverride(name = "lon", column = @Column(name = "lon"))
})
- private EventLocation location;
+ private Location location;
@Column(nullable = false)
- private boolean paid;
+ private Boolean paid = false;
@Column(name = "participant_limit", nullable = false)
private Integer participantLimit;
@Column(name = "request_moderation", nullable = false)
- private boolean requestModeration;
+ private Boolean requestModeration;
@Column(nullable = false, length = 20)
@Enumerated(EnumType.STRING)
private EventState state;
+ @Column(name = "confirmed_requests", nullable = false)
+ @Builder.Default
+ private Integer confirmedRequests = 0;
+
+ @Column(name = "views", nullable = false)
+ @Builder.Default
+ private Long views = 0L;
+
public void pending() {
this.state = EventState.PENDING;
}
diff --git a/core/main-service/src/main/java/ru/yandex/practicum/event/model/EventLocation.java b/core/event-service/src/main/java/ru/yandex/practicum/model/Location.java
similarity index 71%
rename from core/main-service/src/main/java/ru/yandex/practicum/event/model/EventLocation.java
rename to core/event-service/src/main/java/ru/yandex/practicum/model/Location.java
index 670d836..d7db8ec 100644
--- a/core/main-service/src/main/java/ru/yandex/practicum/event/model/EventLocation.java
+++ b/core/event-service/src/main/java/ru/yandex/practicum/model/Location.java
@@ -1,14 +1,16 @@
-package ru.yandex.practicum.event.model;
+package ru.yandex.practicum.model;
import jakarta.persistence.Embeddable;
import jakarta.validation.constraints.NotNull;
-import lombok.Getter;
-import lombok.Setter;
+import lombok.*;
@Embeddable
@Getter
@Setter
-public class EventLocation {
+@NoArgsConstructor
+@AllArgsConstructor
+@Builder
+public class Location {
@NotNull(message = "Широта не может быть null")
private Float lat;
diff --git a/core/main-service/src/main/java/ru/yandex/practicum/category/repository/CategoryRepository.java b/core/event-service/src/main/java/ru/yandex/practicum/repository/CategoryRepository.java
similarity index 66%
rename from core/main-service/src/main/java/ru/yandex/practicum/category/repository/CategoryRepository.java
rename to core/event-service/src/main/java/ru/yandex/practicum/repository/CategoryRepository.java
index 6744789..059404e 100644
--- a/core/main-service/src/main/java/ru/yandex/practicum/category/repository/CategoryRepository.java
+++ b/core/event-service/src/main/java/ru/yandex/practicum/repository/CategoryRepository.java
@@ -1,10 +1,10 @@
-package ru.yandex.practicum.category.repository;
+package ru.yandex.practicum.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.yandex.practicum.category.model.Category;
+import ru.yandex.practicum.model.Category;
import java.util.List;
import java.util.Optional;
@@ -17,4 +17,8 @@ public interface CategoryRepository extends JpaRepository {
@Query("SELECT c FROM Category c")
List findAllList(Pageable pageable);
+
+ @Query("SELECT CASE WHEN COUNT(c) > 0 THEN true ELSE false END" +
+ " FROM Category c WHERE LOWER(TRIM(c.name)) = LOWER(TRIM(:name))")
+ boolean existsByNameIgnoreCaseAndTrim(@Param("name") String name);
}
diff --git a/core/event-service/src/main/java/ru/yandex/practicum/repository/CompilationRepository.java b/core/event-service/src/main/java/ru/yandex/practicum/repository/CompilationRepository.java
new file mode 100644
index 0000000..7ad701c
--- /dev/null
+++ b/core/event-service/src/main/java/ru/yandex/practicum/repository/CompilationRepository.java
@@ -0,0 +1,24 @@
+package ru.yandex.practicum.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.yandex.practicum.model.Compilation;
+
+import java.util.List;
+import java.util.Optional;
+
+public interface CompilationRepository extends JpaRepository {
+
+ @Query("SELECT DISTINCT c FROM Compilation c LEFT JOIN FETCH c.events WHERE c.id = :compId")
+ Optional findByIdWithEvents(@Param("compId") Long compId);
+
+ boolean existsByTitle(String title);
+
+ @Query("SELECT c.id FROM Compilation c WHERE (:pinned IS NULL OR c.pinned = :pinned)")
+ List findIdsByPinned(@Param("pinned") Boolean pinned, Pageable pageable);
+
+ @Query("SELECT DISTINCT c FROM Compilation c LEFT JOIN FETCH c.events WHERE c.id IN :ids")
+ List findAllByIdInWithEvents(@Param("ids") List ids);
+}
diff --git a/core/main-service/src/main/java/ru/yandex/practicum/event/repository/EventRepository.java b/core/event-service/src/main/java/ru/yandex/practicum/repository/EventRepository.java
similarity index 64%
rename from core/main-service/src/main/java/ru/yandex/practicum/event/repository/EventRepository.java
rename to core/event-service/src/main/java/ru/yandex/practicum/repository/EventRepository.java
index 7038c64..1c98c36 100644
--- a/core/main-service/src/main/java/ru/yandex/practicum/event/repository/EventRepository.java
+++ b/core/event-service/src/main/java/ru/yandex/practicum/repository/EventRepository.java
@@ -1,11 +1,11 @@
-package ru.yandex.practicum.event.repository;
+package ru.yandex.practicum.repository;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
-import ru.yandex.practicum.event.model.Event;
+import ru.yandex.practicum.model.Event;
import java.util.List;
import java.util.Optional;
@@ -16,20 +16,10 @@ public interface EventRepository extends JpaRepository, JpaSpecific
Event findFirstByOrderByCreatedOnAsc();
- @Query("""
- SELECT e FROM Event e
- LEFT JOIN FETCH e.category
- LEFT JOIN FETCH e.initiator
- WHERE e.id IN :eventIds"""
- )
+ @Query("SELECT e FROM Event e LEFT JOIN FETCH e.category WHERE e.id IN :eventIds")
List findAllByEventIds(@Param("eventIds") List eventIds);
- @Query("""
- SELECT e FROM Event e
- LEFT JOIN FETCH e.category
- LEFT JOIN FETCH e.initiator
- WHERE e.id = :eventId"""
- )
+ @Query("SELECT e FROM Event e LEFT JOIN FETCH e.category WHERE e.id = :eventId")
Optional findByIdNew(@Param("eventId") Long eventId);
boolean existsByCategoryId(@Param("categoryId") Long categoryId);
diff --git a/core/main-service/src/main/java/ru/yandex/practicum/event/repository/SearchEventSpecifications.java b/core/event-service/src/main/java/ru/yandex/practicum/repository/SearchEventSpecifications.java
similarity index 91%
rename from core/main-service/src/main/java/ru/yandex/practicum/event/repository/SearchEventSpecifications.java
rename to core/event-service/src/main/java/ru/yandex/practicum/repository/SearchEventSpecifications.java
index ef62273..139a2d2 100644
--- a/core/main-service/src/main/java/ru/yandex/practicum/event/repository/SearchEventSpecifications.java
+++ b/core/event-service/src/main/java/ru/yandex/practicum/repository/SearchEventSpecifications.java
@@ -1,12 +1,12 @@
-package ru.yandex.practicum.event.repository;
+package ru.yandex.practicum.repository;
+import feign.Request;
import jakarta.persistence.criteria.Root;
import jakarta.persistence.criteria.Subquery;
import org.springframework.data.jpa.domain.Specification;
-import ru.yandex.practicum.event.model.Event;
-import ru.yandex.practicum.event.model.EventState;
-import ru.yandex.practicum.request.model.Request;
-import ru.yandex.practicum.request.model.RequestStatus;
+import ru.yandex.practicum.enums.EventState;
+import ru.yandex.practicum.enums.RequestStatus;
+import ru.yandex.practicum.model.Event;
import java.time.LocalDateTime;
import java.util.List;
@@ -20,7 +20,7 @@ public static Specification addWhereNull() {
public static Specification addWhereUsers(List userIds) {
return (root, query, criteriaBuilder) -> {
if (userIds == null || userIds.isEmpty()) return criteriaBuilder.conjunction();
- return root.get("initiator").get("id").in(userIds);
+ return root.get("initiatorId").in(userIds);
};
}
@@ -79,7 +79,7 @@ public static Specification addWhereAvailableSlots() {
subquery.select(criteriaBuilder.count(requestRoot));
subquery.where(
criteriaBuilder.and(
- criteriaBuilder.equal(requestRoot.get("event"), root),
+ criteriaBuilder.equal(requestRoot.get("eventId"), root.get("id")),
criteriaBuilder.equal(requestRoot.get("status"), RequestStatus.CONFIRMED)
)
);
diff --git a/core/event-service/src/main/java/ru/yandex/practicum/service/CategoryService.java b/core/event-service/src/main/java/ru/yandex/practicum/service/CategoryService.java
new file mode 100644
index 0000000..7ce6787
--- /dev/null
+++ b/core/event-service/src/main/java/ru/yandex/practicum/service/CategoryService.java
@@ -0,0 +1,19 @@
+package ru.yandex.practicum.service;
+
+import org.springframework.data.domain.Pageable;
+import ru.yandex.practicum.dto.category.*;
+
+import java.util.List;
+
+public interface CategoryService {
+
+ CategoryDto createCategory(NewCategoryDto newCategoryDto);
+
+ void deleteCategory(Long categoryId);
+
+ CategoryDto updateCategory(Long categoryId, UpdateCategoryDto updateCategoryDto);
+
+ List getCategories(Pageable pageable);
+
+ CategoryDto getCategoryById(Long categoryId);
+}
diff --git a/core/main-service/src/main/java/ru/yandex/practicum/category/service/CategoryServiceImpl.java b/core/event-service/src/main/java/ru/yandex/practicum/service/CategoryServiceImpl.java
similarity index 61%
rename from core/main-service/src/main/java/ru/yandex/practicum/category/service/CategoryServiceImpl.java
rename to core/event-service/src/main/java/ru/yandex/practicum/service/CategoryServiceImpl.java
index 4aca28d..2fa5ae2 100644
--- a/core/main-service/src/main/java/ru/yandex/practicum/category/service/CategoryServiceImpl.java
+++ b/core/event-service/src/main/java/ru/yandex/practicum/service/CategoryServiceImpl.java
@@ -1,21 +1,18 @@
-package ru.yandex.practicum.category.service;
+package ru.yandex.practicum.service;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
-import ru.yandex.practicum.category.dto.CategoryDto;
-import ru.yandex.practicum.category.dto.NewCategoryDto;
-import ru.yandex.practicum.category.mapper.CategoryMapper;
-import ru.yandex.practicum.category.model.Category;
-import ru.yandex.practicum.category.repository.CategoryRepository;
-import ru.yandex.practicum.event.repository.EventRepository;
-import ru.yandex.practicum.exception.ConflictException;
-import ru.yandex.practicum.exception.NotFoundException;
+import ru.yandex.practicum.dto.category.*;
+import ru.yandex.practicum.exception.*;
+import ru.yandex.practicum.mapper.CategoryMapper;
+import ru.yandex.practicum.model.Category;
+import ru.yandex.practicum.repository.CategoryRepository;
+import ru.yandex.practicum.repository.EventRepository;
import java.util.List;
-import java.util.Optional;
@Slf4j
@Service
@@ -29,10 +26,11 @@ public class CategoryServiceImpl implements CategoryService {
@Override
@Transactional
public CategoryDto createCategory(NewCategoryDto newCategoryDto) {
- checkCategoryNameUnique(newCategoryDto.name(), null);
+ if (categoryRepository.existsByNameIgnoreCaseAndTrim(newCategoryDto.name())) {
+ throw new ConflictException("Категория с таким названием уже существует");
+ }
Category category = categoryMapper.toEntity(newCategoryDto);
-
Category savedCategory = categoryRepository.save(category);
log.info("Создана категория: {}", savedCategory);
@@ -54,15 +52,17 @@ public void deleteCategory(Long categoryId) {
@Override
@Transactional
- public CategoryDto updateCategory(Long categoryId, NewCategoryDto newCategoryDto) {
+ public CategoryDto updateCategory(Long categoryId, UpdateCategoryDto updateCategoryDto) {
Category category = getCategoryByIdOrThrow(categoryId);
- checkCategoryNameUnique(newCategoryDto.name(), categoryId);
+ if (categoryRepository.findByNameAndIdNot(updateCategoryDto.name(), categoryId).isPresent()) {
+ throw new ConflictException("Категория с таким названием уже существует");
+ }
- categoryMapper.updateCategoryFromDto(newCategoryDto, category);
+ categoryMapper.updateCategoryFromDto(updateCategoryDto, category);
Category updatedCategory = categoryRepository.save(category);
- log.info("Обновлена категория: {}", updatedCategory);
+ log.info("Обновлена категория {}", updatedCategory);
return categoryMapper.toDto(updatedCategory);
}
@@ -78,7 +78,7 @@ public List getCategories(Pageable pageable) {
.map(categoryMapper::toDto)
.toList();
- log.info("Найдено {} категорий", result.size());
+ log.debug("Найдено {} категорий", result.size());
return result;
}
@@ -88,19 +88,9 @@ public CategoryDto getCategoryById(Long categoryId) {
return categoryMapper.toDto(category);
}
- @Override
- public Category getCategoryByIdOrThrow(Long categoryId) {
+
+ private Category getCategoryByIdOrThrow(Long categoryId) {
return categoryRepository.findById(categoryId)
.orElseThrow(() -> new NotFoundException("Категория с id " + categoryId + " не найдена"));
}
-
- private void checkCategoryNameUnique(String name, Long excludedId) {
- Optional existingCategory = (excludedId == null)
- ? categoryRepository.findByName(name)
- : categoryRepository.findByNameAndIdNot(name, excludedId);
-
- existingCategory.ifPresent(category -> {
- throw new ConflictException("Категория с названием '" + name + "' уже существует");
- });
- }
}
diff --git a/core/main-service/src/main/java/ru/yandex/practicum/compilation/service/CompilationService.java b/core/event-service/src/main/java/ru/yandex/practicum/service/CompilationService.java
similarity index 64%
rename from core/main-service/src/main/java/ru/yandex/practicum/compilation/service/CompilationService.java
rename to core/event-service/src/main/java/ru/yandex/practicum/service/CompilationService.java
index 103ff8a..0fadc05 100644
--- a/core/main-service/src/main/java/ru/yandex/practicum/compilation/service/CompilationService.java
+++ b/core/event-service/src/main/java/ru/yandex/practicum/service/CompilationService.java
@@ -1,9 +1,7 @@
-package ru.yandex.practicum.compilation.service;
+package ru.yandex.practicum.service;
import org.springframework.data.domain.Pageable;
-import ru.yandex.practicum.compilation.dto.CompilationDto;
-import ru.yandex.practicum.compilation.dto.NewCompilationDto;
-import ru.yandex.practicum.compilation.dto.UpdateCompilationRequest;
+import ru.yandex.practicum.dto.compilation.*;
import java.util.List;
diff --git a/core/main-service/src/main/java/ru/yandex/practicum/compilation/service/CompilationServiceImpl.java b/core/event-service/src/main/java/ru/yandex/practicum/service/CompilationServiceImpl.java
similarity index 88%
rename from core/main-service/src/main/java/ru/yandex/practicum/compilation/service/CompilationServiceImpl.java
rename to core/event-service/src/main/java/ru/yandex/practicum/service/CompilationServiceImpl.java
index 4364de1..443e2c8 100644
--- a/core/main-service/src/main/java/ru/yandex/practicum/compilation/service/CompilationServiceImpl.java
+++ b/core/event-service/src/main/java/ru/yandex/practicum/service/CompilationServiceImpl.java
@@ -1,4 +1,4 @@
-package ru.yandex.practicum.compilation.service;
+package ru.yandex.practicum.service;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
@@ -7,16 +7,13 @@
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
-import ru.yandex.practicum.compilation.dto.CompilationDto;
-import ru.yandex.practicum.compilation.dto.NewCompilationDto;
-import ru.yandex.practicum.compilation.dto.UpdateCompilationRequest;
-import ru.yandex.practicum.compilation.mapper.CompilationMapper;
-import ru.yandex.practicum.compilation.model.Compilation;
-import ru.yandex.practicum.compilation.repository.CompilationRepository;
-import ru.yandex.practicum.event.model.Event;
-import ru.yandex.practicum.event.repository.EventRepository;
-import ru.yandex.practicum.exception.ConflictException;
-import ru.yandex.practicum.exception.NotFoundException;
+import ru.yandex.practicum.dto.compilation.*;
+import ru.yandex.practicum.exception.*;
+import ru.yandex.practicum.mapper.CompilationMapper;
+import ru.yandex.practicum.model.Compilation;
+import ru.yandex.practicum.model.Event;
+import ru.yandex.practicum.repository.CompilationRepository;
+import ru.yandex.practicum.repository.EventRepository;
import java.util.*;
import java.util.function.Function;
diff --git a/core/main-service/src/main/java/ru/yandex/practicum/event/service/EventService.java b/core/event-service/src/main/java/ru/yandex/practicum/service/EventService.java
similarity index 86%
rename from core/main-service/src/main/java/ru/yandex/practicum/event/service/EventService.java
rename to core/event-service/src/main/java/ru/yandex/practicum/service/EventService.java
index ba9cc3a..934e08e 100644
--- a/core/main-service/src/main/java/ru/yandex/practicum/event/service/EventService.java
+++ b/core/event-service/src/main/java/ru/yandex/practicum/service/EventService.java
@@ -1,8 +1,8 @@
-package ru.yandex.practicum.event.service;
+package ru.yandex.practicum.service;
import org.springframework.data.domain.Pageable;
-import ru.yandex.practicum.event.dto.*;
-import ru.yandex.practicum.event.model.Event;
+import ru.yandex.practicum.dto.event.*;
+import ru.yandex.practicum.model.Event;
import java.util.List;
diff --git a/core/main-service/src/main/java/ru/yandex/practicum/event/service/EventServiceImpl.java b/core/event-service/src/main/java/ru/yandex/practicum/service/EventServiceImpl.java
similarity index 53%
rename from core/main-service/src/main/java/ru/yandex/practicum/event/service/EventServiceImpl.java
rename to core/event-service/src/main/java/ru/yandex/practicum/service/EventServiceImpl.java
index 565f009..1000ecc 100644
--- a/core/main-service/src/main/java/ru/yandex/practicum/event/service/EventServiceImpl.java
+++ b/core/event-service/src/main/java/ru/yandex/practicum/service/EventServiceImpl.java
@@ -1,4 +1,4 @@
-package ru.yandex.practicum.event.service;
+package ru.yandex.practicum.service;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
@@ -10,62 +10,58 @@
import ru.yandex.practicum.CreateEndpointHitDto;
import ru.yandex.practicum.StatsClientApp;
import ru.yandex.practicum.ViewStatsDto;
-import ru.yandex.practicum.category.dto.CategoryDto;
-import ru.yandex.practicum.category.mapper.CategoryMapper;
-import ru.yandex.practicum.category.model.Category;
-import ru.yandex.practicum.category.service.CategoryService;
-import ru.yandex.practicum.event.dto.*;
-import ru.yandex.practicum.event.mapper.EventMapper;
-import ru.yandex.practicum.event.model.*;
-import ru.yandex.practicum.event.repository.EventRepository;
-import ru.yandex.practicum.event.repository.SearchEventSpecifications;
-import ru.yandex.practicum.exception.BadRequestException;
-import ru.yandex.practicum.exception.ConflictException;
-import ru.yandex.practicum.exception.NotFoundException;
-import ru.yandex.practicum.exception.ValidationException;
-import ru.yandex.practicum.request.repository.RequestRepository;
-import ru.yandex.practicum.user.model.User;
-import ru.yandex.practicum.user.service.UserService;
+import ru.yandex.practicum.client.RequestClient;
+import ru.yandex.practicum.client.UserClient;
+import ru.yandex.practicum.dto.event.*;
+import ru.yandex.practicum.dto.user.UserShortDto;
+import ru.yandex.practicum.enums.*;
+import ru.yandex.practicum.exception.*;
+import ru.yandex.practicum.mapper.EventMapper;
+import ru.yandex.practicum.model.Category;
+import ru.yandex.practicum.model.Event;
+import ru.yandex.practicum.repository.*;
import java.time.LocalDateTime;
-import java.util.Comparator;
-import java.util.List;
-import java.util.Map;
+import java.util.*;
import java.util.stream.Collectors;
@Slf4j
@Service
-@Transactional(readOnly = true)
@RequiredArgsConstructor
public class EventServiceImpl implements EventService {
private final EventRepository eventRepository;
private final EventMapper eventMapper;
- private final UserService userService;
- private final RequestRepository requestRepository;
+ private final UserClient userClient;
+ private final RequestClient requestClient;
private final StatsClientApp statsClient;
- private final CategoryService categoryService;
- private final CategoryMapper categoryMapper;
+ private final CategoryRepository categoryRepository;
@Override
@Transactional
public EventFullDto createEvent(Long userId, NewEventDto newEventDto) {
validateDateEvent(newEventDto.eventDate(), 2);
- User user = userService.getUserById(userId);
+ checkUserExists(userId);
- CategoryDto categoryDto = categoryService.getCategoryById(newEventDto.category());
- Category category = categoryMapper.toEntityFromDto(categoryDto);
+ Category category = categoryRepository.findById(newEventDto.category())
+ .orElseThrow(() -> new NotFoundException("Категория с id=" + newEventDto.category() + " не найдена"));
- Event event = eventMapper.fromNewEvent(newEventDto, user, category, EventState.PENDING);
+ Event event = eventMapper.toEntity(newEventDto, userId, category);
event = eventRepository.save(event);
log.info("Создано событие с id={}, title={}, initiatorId={}", event.getId(), event.getTitle(), userId);
- return eventMapper.toEventFullDto(event, 0, 0L);
+
+ EventFullDto dto = eventMapper.toFullDto(event);
+ dto.setInitiator(getUserShortDto(userId));
+ dto.setConfirmedRequests(0L);
+ dto.setViews(0L);
+ return dto;
}
@Override
public List getEvents(Long userId, Pageable pageable) {
- userService.getUserById(userId);
+ checkUserExists(userId);
+
List events = eventRepository.findAllByInitiatorIdOrderByCreatedOnDesc(userId, pageable);
if (events.isEmpty()) return List.of();
@@ -76,46 +72,66 @@ public List getEvents(Long userId, Pageable pageable) {
EventStatistics stats = getEventStatistics(eventIds);
+ Map userCache = new HashMap<>();
+
return events.stream()
- .map(event -> eventMapper.toEventShortDto(
- event,
- stats.confirmedRequests().getOrDefault(event.getId(), 0),
- stats.views().getOrDefault(event.getId(), 0L)
- ))
+ .map(event -> {
+ EventShortDto dto = eventMapper.toShortDto(event);
+ dto.setConfirmedRequests(stats.confirmedRequests().getOrDefault(event.getId(), 0L));
+ dto.setViews(stats.views().getOrDefault(event.getId(), 0L));
+
+ UserShortDto initiatorDto = userCache.computeIfAbsent(
+ event.getInitiatorId(),
+ this::getUserShortDto
+ );
+ dto.setInitiator(initiatorDto);
+ return dto;
+ })
.toList();
}
@Override
public EventFullDto getEvent(Long userId, Long eventId, String ip) {
- userService.getUserByIdOrThrow(userId);
- Event event = getEventOrThrow(eventId);
+ try {
+ userClient.getUser(userId);
+ Event event = getEventOrThrow(eventId);
- if (!event.getInitiator().getId().equals(userId)) {
- throw new NotFoundException("Событие c id " + eventId + " не найдено у пользователя с id " + userId);
- }
+ if (!event.getInitiatorId().equals(userId)) {
+ throw new NotFoundException("Событие c id " + eventId + " не найдено у пользователя с id " + userId);
+ }
- saveHit("/events/" + eventId, ip);
+ saveHit("/events/" + eventId, ip);
+ return buildFullDto(event);
- return buildFullDto(event);
+ } catch (Exception e) {
+ log.warn("Сервис пользователей недоступен или пользователь не найден, userId={}", userId);
+ Event event = getEventOrThrow(eventId);
+ saveHit("/events/" + eventId, ip);
+ return buildFullDto(event);
+ }
}
@Override
@Transactional
public EventFullDto updateEvent(Long userId, Long eventId, UpdateEventUserRequest request) {
- userService.getUserByIdOrThrow(userId);
+ checkUserExists(userId);
+
Event event = getEventOrThrow(eventId);
- if (!event.getInitiator().getId().equals(userId))
+ if (!event.getInitiatorId().equals(userId))
throw new ValidationException("Пользователь не является инициатором события и не может его редактировать");
if (event.getState() == EventState.PUBLISHED)
throw new ValidationException("Изменять можно только не опубликованные события");
- validateDateEvent(request.eventDate(), 2);
+ if (request.eventDate() != null) {
+ validateDateEvent(request.eventDate(), 2);
+ }
Category category = null;
if (request.category() != null) {
- category = categoryService.getCategoryByIdOrThrow(request.category());
+ category = categoryRepository.findById(request.category())
+ .orElseThrow(() -> new NotFoundException("Категория с id=" + request.category() + " не найдена"));
}
eventMapper.updateEventFromUserRequest(request, event, category);
@@ -132,7 +148,7 @@ public EventFullDto updateEvent(Long userId, Long eventId, UpdateEventUserReques
@Override
public Event getEventOrThrow(Long eventId) {
- return eventRepository.findById(eventId)
+ return eventRepository.findByIdNew(eventId)
.orElseThrow(() -> new NotFoundException("Событие c id " + eventId + " не найдено"));
}
@@ -154,26 +170,37 @@ public List getEventsAdmin(SearchEventAdminRequest request, Pageab
if (request.rangeStart() == null && request.rangeEnd() == null)
specification = specification.and(SearchEventSpecifications.addWhereStartsBefore(LocalDateTime.now()));
- Page eventIdsPage = eventRepository.findAll(specification, pageable).map(Event::getId);
- List eventIds = eventIdsPage.getContent();
+ Page eventsPage = eventRepository.findAll(specification, pageable);
+ List eventIds = eventsPage.getContent().stream()
+ .map(Event::getId)
+ .toList();
- if (eventIds.isEmpty()) return List.of();
- List events = eventRepository.findAllByEventIds(eventIds);
+ if (eventIds.isEmpty()) {
+ return List.of();
+ }
- if (events.isEmpty()) return List.of();
+ List events = eventsPage.getContent();
List searchEventIds = events.stream()
.map(Event::getId)
.toList();
EventStatistics stats = getEventStatistics(searchEventIds);
+ Map userCache = new HashMap<>();
return events.stream()
- .map(event -> eventMapper.toEventFullDto(
- event,
- stats.confirmedRequests().getOrDefault(event.getId(), 0),
- stats.views().getOrDefault(event.getId(), 0L)
- ))
+ .map(event -> {
+ EventFullDto dto = eventMapper.toFullDto(event);
+ dto.setConfirmedRequests(stats.confirmedRequests().getOrDefault(event.getId(), 0L));
+ dto.setViews(stats.views().getOrDefault(event.getId(), 0L));
+
+ UserShortDto initiatorDto = userCache.computeIfAbsent(
+ event.getInitiatorId(),
+ this::getUserShortDto
+ );
+ dto.setInitiator(initiatorDto);
+ return dto;
+ })
.toList();
}
@@ -189,8 +216,11 @@ public EventFullDto updateEventAdmin(Long eventId, UpdateEventAdminRequest reque
if (stateActionAdmin == StateActionAdmin.PUBLISH_EVENT) {
if (currentState != EventState.PENDING)
- throw new ConflictException("Событие можно опубликовать только если оно в состоянии ожидания публикации");
- validateDateEvent(event.getEventDate(), 1);
+ throw new ConflictException(
+ "Событие можно опубликовать только если оно в состоянии ожидания публикации");
+ if (event.getEventDate() != null) {
+ validateDateEvent(event.getEventDate(), 1);
+ }
event.publish();
}
if (stateActionAdmin == StateActionAdmin.REJECT_EVENT) {
@@ -202,19 +232,23 @@ public EventFullDto updateEventAdmin(Long eventId, UpdateEventAdminRequest reque
Category category = null;
if (request.category() != null) {
- category = categoryService.getCategoryByIdOrThrow(request.category());
+ category = categoryRepository.findById(request.category())
+ .orElseThrow(() -> new NotFoundException("Категория с id=" + request.category() + " не найдена"));
}
eventMapper.updateEventFromAdminRequest(request, event, category);
Event updatedEvent = eventRepository.save(event);
log.info("Обновлено событие с id={}, title={}, initiatorId={}",
- updatedEvent.getId(), updatedEvent.getTitle(), updatedEvent.getInitiator().getId());
+ updatedEvent.getId(), updatedEvent.getTitle(), updatedEvent.getInitiatorId());
+
return buildFullDto(updatedEvent);
}
@Override
- public List getEventsPublic(SearchEventPublicRequest request, Pageable pageable, String ip) {
+ public List getEventsPublic(
+ SearchEventPublicRequest request, Pageable pageable, String ip) {
+
validateRangeStartAndEnd(request.rangeStart(), request.rangeEnd());
Specification specification = SearchEventSpecifications.addWhereNull();
@@ -242,24 +276,32 @@ public List getEventsPublic(SearchEventPublicRequest request, Pag
.toList();
EventStatistics stats = getEventStatistics(eventIds);
+ Map userCache = new HashMap<>();
List result = events.stream()
- .map(event -> eventMapper.toEventShortDto(
- event,
- stats.confirmedRequests().getOrDefault(event.getId(), 0),
- stats.views().getOrDefault(event.getId(), 0L)
- ))
+ .map(event -> {
+ EventShortDto dto = eventMapper.toShortDto(event);
+ dto.setConfirmedRequests(stats.confirmedRequests().getOrDefault(event.getId(), 0L));
+ dto.setViews(stats.views().getOrDefault(event.getId(), 0L));
+
+ UserShortDto initiatorDto = userCache.computeIfAbsent(
+ event.getInitiatorId(),
+ this::getUserShortDto
+ );
+ dto.setInitiator(initiatorDto);
+ return dto;
+ })
.toList();
saveHit("/events", ip);
if (SortState.VIEWS.equals(request.sort())) {
return result.stream()
- .sorted(Comparator.comparing(EventShortDto::views).reversed())
+ .sorted(Comparator.comparing(EventShortDto::getViews).reversed())
.toList();
} else if (SortState.EVENT_DATE.equals(request.sort())) {
return result.stream()
- .sorted(Comparator.comparing(EventShortDto::eventDate))
+ .sorted(Comparator.comparing(EventShortDto::getEventDate))
.toList();
}
@@ -278,14 +320,17 @@ public EventFullDto getEventByIdPublic(Long eventId, String ip) {
}
private EventFullDto buildFullDto(Event event) {
- Map confirmedRequests = getConfirmedRequests(List.of(event.getId()));
+ Map confirmedRequests = getConfirmedRequests(List.of(event.getId()));
Map views = getViewsForEvents(List.of(event.getId()));
- return eventMapper.toEventFullDto(
- event,
- confirmedRequests.getOrDefault(event.getId(), 0),
- views.getOrDefault(event.getId(), 0L)
- );
+ EventFullDto dto = eventMapper.toFullDto(event);
+ dto.setConfirmedRequests(confirmedRequests.getOrDefault(event.getId(), 0L));
+ dto.setViews(views.getOrDefault(event.getId(), 0L));
+
+ UserShortDto initiatorDto = getUserShortDto(event.getInitiatorId());
+ dto.setInitiator(initiatorDto);
+
+ return dto;
}
private void validateRangeStartAndEnd(LocalDateTime rangeStart, LocalDateTime rangeEnd) {
@@ -294,50 +339,69 @@ private void validateRangeStartAndEnd(LocalDateTime rangeStart, LocalDateTime ra
}
private void saveHit(String path, String ip) {
- CreateEndpointHitDto endpointHitDto = new CreateEndpointHitDto("main-service", path, ip, LocalDateTime.now());
- statsClient.saveHit(endpointHitDto);
+ try {
+ CreateEndpointHitDto endpointHitDto = new CreateEndpointHitDto(
+ "main-service", path, ip, LocalDateTime.now());
+ statsClient.saveHit(endpointHitDto);
+ } catch (Exception e) {
+ log.warn("Не удалось сохранить статистику для path={}, ip={}", path, ip, e);
+ }
}
private void validateDateEvent(LocalDateTime eventDate, long minHoursBeforeStartEvent) {
if (eventDate != null && eventDate.isBefore(LocalDateTime.now().plusHours(minHoursBeforeStartEvent)))
- throw new ValidationException("Дата начала события не может быть ранее чем через " + minHoursBeforeStartEvent + " часа(ов)");
+ throw new ValidationException(
+ "Дата начала события не может быть ранее чем через " + minHoursBeforeStartEvent + " часа(ов)");
}
- private Map getConfirmedRequests(List eventIds) {
+ private Map getConfirmedRequests(List eventIds) {
if (eventIds.isEmpty()) return Map.of();
- List events = requestRepository.findCountConfirmedRequestsByEventIds(eventIds);
- Map confirmedRequests = eventIds.stream()
- .collect(Collectors.toMap(id -> id, id -> 0));
-
- events.forEach(dto -> confirmedRequests.put(dto.getEventId(), dto.getCountConfirmedRequests()));
+ Map result = new HashMap<>();
+
+ for (Long eventId : eventIds) {
+ try {
+ Long count = requestClient.countByStatus(eventId, RequestStatus.CONFIRMED);
+ result.put(eventId, count != null ? count : 0L);
+ log.debug("Получено {} подтвержденных запросов для события {}", count, eventId);
+ } catch (Exception e) {
+ log.warn("Не удалось получить подтвержденные запросы для события {}: {}",
+ eventId, e.getMessage());
+ result.put(eventId, 0L);
+ }
+ }
- return confirmedRequests;
+ return result;
}
private Map getViewsForEvents(List eventIds) {
if (eventIds.isEmpty()) return Map.of();
- List uris = eventIds.stream()
- .map(id -> "/events/" + id)
- .toList();
+ Map views = eventIds.stream()
+ .collect(Collectors.toMap(id -> id, id -> 0L));
- LocalDateTime start = eventRepository.findFirstByOrderByCreatedOnAsc().getCreatedOn();
- LocalDateTime end = LocalDateTime.now();
+ try {
+ List uris = eventIds.stream()
+ .map(id -> "/events/" + id)
+ .toList();
- List stats = statsClient.getStats(start, end, uris, true);
+ LocalDateTime start = eventRepository.findFirstByOrderByCreatedOnAsc().getCreatedOn();
+ LocalDateTime end = LocalDateTime.now();
- Map views = eventIds.stream()
- .collect(Collectors.toMap(id -> id, id -> 0L));
+ List stats = statsClient.getStats(start, end, uris, true);
- if (stats != null && !stats.isEmpty()) {
- stats.forEach(stat -> {
- Long eventId = getEventIdFromUri(stat.uri());
- if (eventId > -1L) {
- views.put(eventId, stat.hits());
- }
- });
+ if (stats != null && !stats.isEmpty()) {
+ stats.forEach(stat -> {
+ Long eventId = getEventIdFromUri(stat.uri());
+ if (eventId > -1L) {
+ views.put(eventId, stat.hits());
+ }
+ });
+ }
+ } catch (Exception e) {
+ log.warn("Сервис статистики недоступен, используем значение по умолчанию 0. eventIds={}", eventIds);
}
+
return views;
}
@@ -354,9 +418,26 @@ private EventStatistics getEventStatistics(List eventIds) {
return new EventStatistics(Map.of(), Map.of());
}
- Map confirmedRequests = getConfirmedRequests(eventIds);
+ Map confirmedRequests = getConfirmedRequests(eventIds);
Map views = getViewsForEvents(eventIds);
return new EventStatistics(confirmedRequests, views);
}
+
+ private void checkUserExists(Long userId) {
+ try {
+ userClient.getUser(userId);
+ } catch (Exception e) {
+ log.warn("Сервис пользователей недоступен, пропускаем проверку. userId={}", userId);
+ }
+ }
+
+ private UserShortDto getUserShortDto(Long userId) {
+ try {
+ return userClient.getUser(userId);
+ } catch (Exception e) {
+ log.warn("Сервис пользователей недоступен, используем заглушку. userId={}", userId);
+ return new UserShortDto(userId, "Пользователь-" + userId);
+ }
+ }
}
diff --git a/core/event-service/src/main/resources/application.yaml b/core/event-service/src/main/resources/application.yaml
new file mode 100644
index 0000000..ca8a5dc
--- /dev/null
+++ b/core/event-service/src/main/resources/application.yaml
@@ -0,0 +1,26 @@
+spring:
+ application:
+ name: event-service
+ config:
+ import: "configserver:"
+ cloud:
+ config:
+ fail-fast: true
+ discovery:
+ enabled: true
+ serviceId: config-server
+ retry:
+ useRandomPolicy: true
+ max-interval: 6000
+
+server:
+ port: 0
+
+eureka:
+ instance:
+ instanceId: ${spring.application.name}:${spring.application.instance_id:${random.value}}
+ client:
+ healthcheck:
+ enabled: true
+ serviceUrl:
+ defaultZone: http://localhost:8761/eureka
\ No newline at end of file
diff --git a/core/event-service/src/main/resources/schema.sql b/core/event-service/src/main/resources/schema.sql
new file mode 100644
index 0000000..2963e87
--- /dev/null
+++ b/core/event-service/src/main/resources/schema.sql
@@ -0,0 +1,52 @@
+DROP TABLE IF EXISTS compilation_events CASCADE;
+DROP TABLE IF EXISTS compilations CASCADE;
+DROP TABLE IF EXISTS events CASCADE;
+DROP TABLE IF EXISTS categories CASCADE;
+
+-- Создание таблицы категорий
+CREATE TABLE IF NOT EXISTS categories (
+ id BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
+ name VARCHAR(50) NOT NULL UNIQUE
+);
+
+-- Создание таблицы событий
+create TABLE IF NOT EXISTS events (
+ id BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
+ title VARCHAR(120) NOT NULL,
+ annotation VARCHAR(2000) NOT NULL,
+ description VARCHAR(7000) NOT NULL,
+ event_date TIMESTAMP WITHOUT TIME ZONE NOT NULL,
+ created_on TIMESTAMP WITHOUT TIME ZONE NOT NULL,
+ published_on TIMESTAMP WITHOUT TIME ZONE,
+ initiator_id BIGINT,
+ category_id BIGINT REFERENCES categories(id),
+ state VARCHAR(20) NOT NULL,
+ lat FLOAT,
+ lon FLOAT,
+ paid BOOLEAN NOT NULL,
+ participant_limit INTEGER NOT NULL,
+ request_moderation BOOLEAN NOT NULL,
+ confirmed_requests INT NOT NULL,
+ views BIGINT NOT NULL
+);
+
+-- Создание таблицы подборок
+create TABLE IF NOT EXISTS compilations (
+ id BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
+ title VARCHAR(50) NOT NULL UNIQUE,
+ pinned BOOLEAN NOT NULL DEFAULT FALSE
+);
+
+-- Создание таблицы связи подборок и событий
+create TABLE IF NOT EXISTS compilation_events (
+ compilation_id BIGINT NOT NULL REFERENCES compilations (id) ON DELETE CASCADE,
+ event_id BIGINT NOT NULL REFERENCES events (id) ON DELETE CASCADE,
+ CONSTRAINT pk_compilation_events PRIMARY KEY (compilation_id, event_id)
+);
+
+-- Индекс для быстрого поиска событий по категории
+CREATE INDEX IF NOT EXISTS idx_events_category ON events(category_id);
+-- Индекс для быстрого поиска всех событий пользователя
+CREATE INDEX IF NOT EXISTS idx_events_initiator ON events(initiator_id);
+-- Составной индекс по статусу и дате
+CREATE INDEX IF NOT EXISTS idx_events_state_date ON events(state, event_date);
\ No newline at end of file
diff --git a/core/interaction-api/pom.xml b/core/interaction-api/pom.xml
new file mode 100644
index 0000000..fd235dd
--- /dev/null
+++ b/core/interaction-api/pom.xml
@@ -0,0 +1,63 @@
+
+
+ 4.0.0
+
+ ru.yandex.practicum
+ core
+ 0.0.1-SNAPSHOT
+
+
+ interaction-api
+
+
+ 21
+ 21
+ UTF-8
+
+
+
+
+ org.projectlombok
+ lombok
+ true
+
+
+
+ org.springframework.cloud
+ spring-cloud-starter-openfeign
+
+
+
+ org.springframework.data
+ spring-data-commons
+
+
+
+ jakarta.validation
+ jakarta.validation-api
+
+
+
+ io.github.openfeign
+ feign-okhttp
+
+
+
+ org.springframework
+ spring-context
+
+
+
+ jakarta.persistence
+ jakarta.persistence-api
+
+
+
+ com.fasterxml.jackson.core
+ jackson-databind
+
+
+
+
\ No newline at end of file
diff --git a/core/interaction-api/src/main/java/ru/yandex/practicum/client/EventClient.java b/core/interaction-api/src/main/java/ru/yandex/practicum/client/EventClient.java
new file mode 100644
index 0000000..494d803
--- /dev/null
+++ b/core/interaction-api/src/main/java/ru/yandex/practicum/client/EventClient.java
@@ -0,0 +1,19 @@
+package ru.yandex.practicum.client;
+
+import org.springframework.cloud.openfeign.FeignClient;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import ru.yandex.practicum.config.FeignRetryConfig;
+import ru.yandex.practicum.dto.event.EventFullDto;
+
+@FeignClient(
+ name = "event-service",
+ path = "/internal/events",
+ configuration = FeignRetryConfig.class,
+ fallback = EventClientFallback.class
+)
+public interface EventClient {
+
+ @GetMapping("/{eventId}")
+ EventFullDto getEvent(@PathVariable Long eventId);
+}
diff --git a/core/interaction-api/src/main/java/ru/yandex/practicum/client/EventClientFallback.java b/core/interaction-api/src/main/java/ru/yandex/practicum/client/EventClientFallback.java
new file mode 100644
index 0000000..0987a0d
--- /dev/null
+++ b/core/interaction-api/src/main/java/ru/yandex/practicum/client/EventClientFallback.java
@@ -0,0 +1,16 @@
+package ru.yandex.practicum.client;
+
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Component;
+import ru.yandex.practicum.dto.event.EventFullDto;
+
+@Component
+@Slf4j
+public class EventClientFallback implements EventClient {
+
+ @Override
+ public EventFullDto getEvent(Long eventId) {
+ log.warn("Сервис событий недоступен");
+ return null;
+ }
+}
diff --git a/core/interaction-api/src/main/java/ru/yandex/practicum/client/RequestClient.java b/core/interaction-api/src/main/java/ru/yandex/practicum/client/RequestClient.java
new file mode 100644
index 0000000..48c759b
--- /dev/null
+++ b/core/interaction-api/src/main/java/ru/yandex/practicum/client/RequestClient.java
@@ -0,0 +1,24 @@
+package ru.yandex.practicum.client;
+
+import org.springframework.cloud.openfeign.FeignClient;
+import org.springframework.web.bind.annotation.*;
+import ru.yandex.practicum.config.FeignRetryConfig;
+import ru.yandex.practicum.enums.RequestStatus;
+
+import java.util.List;
+import java.util.Map;
+
+@FeignClient(
+ name = "request-service",
+ path = "/internal/requests",
+ configuration = FeignRetryConfig.class,
+ fallback = RequestClientFallback.class
+)
+public interface RequestClient {
+
+ @GetMapping("/event/{eventId}/count/{status}")
+ Long countByStatus(@PathVariable Long eventId, @PathVariable RequestStatus status);
+
+ @PostMapping("/events/count/confirmed")
+ Map getConfirmedRequestsCount(@RequestBody List eventIds);
+}
diff --git a/core/interaction-api/src/main/java/ru/yandex/practicum/client/RequestClientFallback.java b/core/interaction-api/src/main/java/ru/yandex/practicum/client/RequestClientFallback.java
new file mode 100644
index 0000000..6b23c77
--- /dev/null
+++ b/core/interaction-api/src/main/java/ru/yandex/practicum/client/RequestClientFallback.java
@@ -0,0 +1,26 @@
+package ru.yandex.practicum.client;
+
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Component;
+import ru.yandex.practicum.enums.RequestStatus;
+
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+@Component
+@Slf4j
+public class RequestClientFallback implements RequestClient {
+
+ @Override
+ public Long countByStatus(Long eventId, RequestStatus status) {
+ log.warn("Сервис запросов недоступен, eventId={}, status={}", eventId, status);
+ return 0L;
+ }
+
+ @Override
+ public Map getConfirmedRequestsCount(List eventIds) {
+ log.warn("Сервис запросов недоступен для batch, eventIds={}", eventIds);
+ return eventIds.stream().collect(Collectors.toMap(id -> id, id -> 0L));
+ }
+}
diff --git a/core/interaction-api/src/main/java/ru/yandex/practicum/client/UserClient.java b/core/interaction-api/src/main/java/ru/yandex/practicum/client/UserClient.java
new file mode 100644
index 0000000..be0804a
--- /dev/null
+++ b/core/interaction-api/src/main/java/ru/yandex/practicum/client/UserClient.java
@@ -0,0 +1,19 @@
+package ru.yandex.practicum.client;
+
+import org.springframework.cloud.openfeign.FeignClient;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import ru.yandex.practicum.config.FeignRetryConfig;
+import ru.yandex.practicum.dto.user.UserShortDto;
+
+@FeignClient(
+ name = "user-service",
+ path = "/internal/users",
+ configuration = FeignRetryConfig.class,
+ fallback = UserClientFallback.class
+)
+public interface UserClient {
+
+ @GetMapping("/{userId}")
+ UserShortDto getUser(@PathVariable("userId") Long userId);
+}
diff --git a/core/interaction-api/src/main/java/ru/yandex/practicum/client/UserClientFallback.java b/core/interaction-api/src/main/java/ru/yandex/practicum/client/UserClientFallback.java
new file mode 100644
index 0000000..08aa7c7
--- /dev/null
+++ b/core/interaction-api/src/main/java/ru/yandex/practicum/client/UserClientFallback.java
@@ -0,0 +1,16 @@
+package ru.yandex.practicum.client;
+
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Component;
+import ru.yandex.practicum.dto.user.UserShortDto;
+
+@Component
+@Slf4j
+public class UserClientFallback implements UserClient {
+
+ @Override
+ public UserShortDto getUser(Long userId) {
+ log.warn("Сервис пользователей недоступен");
+ return new UserShortDto(userId, "Пользователь-" + userId);
+ }
+}
diff --git a/core/interaction-api/src/main/java/ru/yandex/practicum/config/FeignRetryConfig.java b/core/interaction-api/src/main/java/ru/yandex/practicum/config/FeignRetryConfig.java
new file mode 100644
index 0000000..a1afe8c
--- /dev/null
+++ b/core/interaction-api/src/main/java/ru/yandex/practicum/config/FeignRetryConfig.java
@@ -0,0 +1,16 @@
+package ru.yandex.practicum.config;
+
+import feign.Retryer;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+import java.util.concurrent.TimeUnit;
+
+@Configuration
+public class FeignRetryConfig {
+
+ @Bean
+ public Retryer retryer() {
+ return new Retryer.Default(100, TimeUnit.SECONDS.toMillis(2), 3);
+ }
+}
diff --git a/core/main-service/src/main/java/ru/yandex/practicum/constants/DateTimeConstants.java b/core/interaction-api/src/main/java/ru/yandex/practicum/constants/DateTimeConstants.java
similarity index 100%
rename from core/main-service/src/main/java/ru/yandex/practicum/constants/DateTimeConstants.java
rename to core/interaction-api/src/main/java/ru/yandex/practicum/constants/DateTimeConstants.java
diff --git a/core/main-service/src/main/java/ru/yandex/practicum/category/dto/CategoryDto.java b/core/interaction-api/src/main/java/ru/yandex/practicum/dto/category/CategoryDto.java
similarity index 90%
rename from core/main-service/src/main/java/ru/yandex/practicum/category/dto/CategoryDto.java
rename to core/interaction-api/src/main/java/ru/yandex/practicum/dto/category/CategoryDto.java
index fdf9a17..37cfc42 100644
--- a/core/main-service/src/main/java/ru/yandex/practicum/category/dto/CategoryDto.java
+++ b/core/interaction-api/src/main/java/ru/yandex/practicum/dto/category/CategoryDto.java
@@ -1,9 +1,10 @@
-package ru.yandex.practicum.category.dto;
+package ru.yandex.practicum.dto.category;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.Size;
public record CategoryDto(
+
Long id,
@NotBlank(message = "Название категории не может быть пустым")
diff --git a/core/main-service/src/main/java/ru/yandex/practicum/category/dto/NewCategoryDto.java b/core/interaction-api/src/main/java/ru/yandex/practicum/dto/category/NewCategoryDto.java
similarity index 90%
rename from core/main-service/src/main/java/ru/yandex/practicum/category/dto/NewCategoryDto.java
rename to core/interaction-api/src/main/java/ru/yandex/practicum/dto/category/NewCategoryDto.java
index 971c5cf..f3ca14c 100644
--- a/core/main-service/src/main/java/ru/yandex/practicum/category/dto/NewCategoryDto.java
+++ b/core/interaction-api/src/main/java/ru/yandex/practicum/dto/category/NewCategoryDto.java
@@ -1,9 +1,10 @@
-package ru.yandex.practicum.category.dto;
+package ru.yandex.practicum.dto.category;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.Size;
public record NewCategoryDto(
+
@NotBlank(message = "Название категории не может быть пустым")
@Size(min = 1, max = 50, message = "Название категории должно содержать от {min} до {max} символов")
String name
diff --git a/core/interaction-api/src/main/java/ru/yandex/practicum/dto/category/UpdateCategoryDto.java b/core/interaction-api/src/main/java/ru/yandex/practicum/dto/category/UpdateCategoryDto.java
new file mode 100644
index 0000000..8ef193c
--- /dev/null
+++ b/core/interaction-api/src/main/java/ru/yandex/practicum/dto/category/UpdateCategoryDto.java
@@ -0,0 +1,12 @@
+package ru.yandex.practicum.dto.category;
+
+import jakarta.validation.constraints.NotBlank;
+import jakarta.validation.constraints.Size;
+
+public record UpdateCategoryDto(
+
+ @NotBlank(message = "Название категории не может быть пустым")
+ @Size(min = 1, max = 50, message = "Название категории должно содержать от {min} до {max} символов")
+ String name
+) {
+}
diff --git a/core/interaction-api/src/main/java/ru/yandex/practicum/dto/comment/CommentAdminDto.java b/core/interaction-api/src/main/java/ru/yandex/practicum/dto/comment/CommentAdminDto.java
new file mode 100644
index 0000000..de91f47
--- /dev/null
+++ b/core/interaction-api/src/main/java/ru/yandex/practicum/dto/comment/CommentAdminDto.java
@@ -0,0 +1,17 @@
+package ru.yandex.practicum.dto.comment;
+
+import jakarta.validation.constraints.NotBlank;
+import jakarta.validation.constraints.NotNull;
+import jakarta.validation.constraints.Size;
+import ru.yandex.practicum.enums.CommentStatus;
+
+public record CommentAdminDto(
+
+ @NotBlank(message = "Комментарий не может быть пустым")
+ @Size(min = 1, max = 5000, message = "Комментарий должен содержать от {min} до {max} символов")
+ String text,
+
+ @NotNull
+ CommentStatus status
+) {
+}
diff --git a/core/interaction-api/src/main/java/ru/yandex/practicum/dto/comment/CommentDto.java b/core/interaction-api/src/main/java/ru/yandex/practicum/dto/comment/CommentDto.java
new file mode 100644
index 0000000..f66c333
--- /dev/null
+++ b/core/interaction-api/src/main/java/ru/yandex/practicum/dto/comment/CommentDto.java
@@ -0,0 +1,27 @@
+package ru.yandex.practicum.dto.comment;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import ru.yandex.practicum.constants.DateTimeConstants;
+import ru.yandex.practicum.enums.CommentStatus;
+
+import java.time.LocalDateTime;
+
+public record CommentDto(
+
+ Long id,
+
+ String text,
+
+ Long userId,
+
+ Long eventId,
+
+ @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = DateTimeConstants.DATE_TIME_PATTERN)
+ LocalDateTime createdDate,
+
+ @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = DateTimeConstants.DATE_TIME_PATTERN)
+ LocalDateTime updatedDate,
+
+ CommentStatus status
+) {
+}
diff --git a/core/main-service/src/main/java/ru/yandex/practicum/comment/dto/NewCommentDto.java b/core/interaction-api/src/main/java/ru/yandex/practicum/dto/comment/NewCommentDto.java
similarity index 90%
rename from core/main-service/src/main/java/ru/yandex/practicum/comment/dto/NewCommentDto.java
rename to core/interaction-api/src/main/java/ru/yandex/practicum/dto/comment/NewCommentDto.java
index 805e2d3..e61b424 100644
--- a/core/main-service/src/main/java/ru/yandex/practicum/comment/dto/NewCommentDto.java
+++ b/core/interaction-api/src/main/java/ru/yandex/practicum/dto/comment/NewCommentDto.java
@@ -1,9 +1,10 @@
-package ru.yandex.practicum.comment.dto;
+package ru.yandex.practicum.dto.comment;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.Size;
public record NewCommentDto(
+
@NotBlank(message = "Комментарий не может быть пустым")
@Size(min = 1, max = 5000, message = "Комментарий должен содержать от {min} до {max} символов")
String text
diff --git a/core/main-service/src/main/java/ru/yandex/practicum/comment/dto/UpdateCommentDto.java b/core/interaction-api/src/main/java/ru/yandex/practicum/dto/comment/UpdateCommentDto.java
similarity index 90%
rename from core/main-service/src/main/java/ru/yandex/practicum/comment/dto/UpdateCommentDto.java
rename to core/interaction-api/src/main/java/ru/yandex/practicum/dto/comment/UpdateCommentDto.java
index da8f1db..9f7a777 100644
--- a/core/main-service/src/main/java/ru/yandex/practicum/comment/dto/UpdateCommentDto.java
+++ b/core/interaction-api/src/main/java/ru/yandex/practicum/dto/comment/UpdateCommentDto.java
@@ -1,9 +1,10 @@
-package ru.yandex.practicum.comment.dto;
+package ru.yandex.practicum.dto.comment;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.Size;
public record UpdateCommentDto(
+
@NotBlank(message = "Комментарий не может быть пустым")
@Size(min = 1, max = 5000, message = "Комментарий должен содержать от {min} до {max} символов")
String text
diff --git a/core/main-service/src/main/java/ru/yandex/practicum/compilation/dto/CompilationDto.java b/core/interaction-api/src/main/java/ru/yandex/practicum/dto/compilation/CompilationDto.java
similarity index 61%
rename from core/main-service/src/main/java/ru/yandex/practicum/compilation/dto/CompilationDto.java
rename to core/interaction-api/src/main/java/ru/yandex/practicum/dto/compilation/CompilationDto.java
index a978e5a..fa1797c 100644
--- a/core/main-service/src/main/java/ru/yandex/practicum/compilation/dto/CompilationDto.java
+++ b/core/interaction-api/src/main/java/ru/yandex/practicum/dto/compilation/CompilationDto.java
@@ -1,13 +1,17 @@
-package ru.yandex.practicum.compilation.dto;
+package ru.yandex.practicum.dto.compilation;
-import ru.yandex.practicum.event.dto.EventShortDto;
+import ru.yandex.practicum.dto.event.EventShortDto;
import java.util.Set;
public record CompilationDto(
+
Long id,
+
Set events,
+
boolean pinned,
+
String title
) {
}
diff --git a/core/main-service/src/main/java/ru/yandex/practicum/compilation/dto/NewCompilationDto.java b/core/interaction-api/src/main/java/ru/yandex/practicum/dto/compilation/NewCompilationDto.java
similarity index 91%
rename from core/main-service/src/main/java/ru/yandex/practicum/compilation/dto/NewCompilationDto.java
rename to core/interaction-api/src/main/java/ru/yandex/practicum/dto/compilation/NewCompilationDto.java
index 00b509d..5169fc8 100644
--- a/core/main-service/src/main/java/ru/yandex/practicum/compilation/dto/NewCompilationDto.java
+++ b/core/interaction-api/src/main/java/ru/yandex/practicum/dto/compilation/NewCompilationDto.java
@@ -1,4 +1,4 @@
-package ru.yandex.practicum.compilation.dto;
+package ru.yandex.practicum.dto.compilation;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.Size;
@@ -6,6 +6,7 @@
import java.util.Set;
public record NewCompilationDto(
+
Set events,
boolean pinned,
diff --git a/core/main-service/src/main/java/ru/yandex/practicum/compilation/dto/UpdateCompilationRequest.java b/core/interaction-api/src/main/java/ru/yandex/practicum/dto/compilation/UpdateCompilationRequest.java
similarity index 87%
rename from core/main-service/src/main/java/ru/yandex/practicum/compilation/dto/UpdateCompilationRequest.java
rename to core/interaction-api/src/main/java/ru/yandex/practicum/dto/compilation/UpdateCompilationRequest.java
index 5aeeef1..9e30877 100644
--- a/core/main-service/src/main/java/ru/yandex/practicum/compilation/dto/UpdateCompilationRequest.java
+++ b/core/interaction-api/src/main/java/ru/yandex/practicum/dto/compilation/UpdateCompilationRequest.java
@@ -1,10 +1,11 @@
-package ru.yandex.practicum.compilation.dto;
+package ru.yandex.practicum.dto.compilation;
import jakarta.validation.constraints.Size;
import java.util.Set;
public record UpdateCompilationRequest(
+
Set events,
Boolean pinned,
diff --git a/core/interaction-api/src/main/java/ru/yandex/practicum/dto/event/EventFullDto.java b/core/interaction-api/src/main/java/ru/yandex/practicum/dto/event/EventFullDto.java
new file mode 100644
index 0000000..a785993
--- /dev/null
+++ b/core/interaction-api/src/main/java/ru/yandex/practicum/dto/event/EventFullDto.java
@@ -0,0 +1,55 @@
+package ru.yandex.practicum.dto.event;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import lombok.*;
+import lombok.experimental.FieldDefaults;
+import ru.yandex.practicum.constants.DateTimeConstants;
+import ru.yandex.practicum.dto.category.CategoryDto;
+import ru.yandex.practicum.dto.user.UserShortDto;
+import ru.yandex.practicum.enums.EventState;
+
+import java.time.LocalDateTime;
+
+@Getter
+@Setter
+@NoArgsConstructor
+@AllArgsConstructor
+@Builder
+@FieldDefaults(level = AccessLevel.PRIVATE)
+public class EventFullDto {
+
+ Long id;
+
+ String annotation;
+
+ CategoryDto category;
+
+ Long confirmedRequests;
+
+ @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = DateTimeConstants.DATE_TIME_PATTERN)
+ LocalDateTime createdOn;
+
+ String description;
+
+ @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = DateTimeConstants.DATE_TIME_PATTERN)
+ LocalDateTime eventDate;
+
+ UserShortDto initiator;
+
+ LocationDto location;
+
+ Boolean paid;
+
+ Integer participantLimit;
+
+ @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = DateTimeConstants.DATE_TIME_PATTERN)
+ LocalDateTime publishedOn;
+
+ Boolean requestModeration;
+
+ EventState state;
+
+ String title;
+
+ Long views;
+}
diff --git a/core/interaction-api/src/main/java/ru/yandex/practicum/dto/event/EventShortDto.java b/core/interaction-api/src/main/java/ru/yandex/practicum/dto/event/EventShortDto.java
new file mode 100644
index 0000000..935db89
--- /dev/null
+++ b/core/interaction-api/src/main/java/ru/yandex/practicum/dto/event/EventShortDto.java
@@ -0,0 +1,38 @@
+package ru.yandex.practicum.dto.event;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import lombok.*;
+import lombok.experimental.FieldDefaults;
+import ru.yandex.practicum.constants.DateTimeConstants;
+import ru.yandex.practicum.dto.category.CategoryDto;
+import ru.yandex.practicum.dto.user.UserShortDto;
+
+import java.time.LocalDateTime;
+
+@Getter
+@Setter
+@NoArgsConstructor
+@AllArgsConstructor
+@Builder
+@FieldDefaults(level = AccessLevel.PRIVATE)
+public class EventShortDto {
+
+ Long id;
+
+ String annotation;
+
+ CategoryDto category;
+
+ Long confirmedRequests;
+
+ @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = DateTimeConstants.DATE_TIME_PATTERN)
+ LocalDateTime eventDate;
+
+ UserShortDto initiator;
+
+ Boolean paid;
+
+ String title;
+
+ Long views;
+}
diff --git a/core/main-service/src/main/java/ru/yandex/practicum/event/dto/EventStatistics.java b/core/interaction-api/src/main/java/ru/yandex/practicum/dto/event/EventStatistics.java
similarity index 51%
rename from core/main-service/src/main/java/ru/yandex/practicum/event/dto/EventStatistics.java
rename to core/interaction-api/src/main/java/ru/yandex/practicum/dto/event/EventStatistics.java
index 6ee33b0..3f7201e 100644
--- a/core/main-service/src/main/java/ru/yandex/practicum/event/dto/EventStatistics.java
+++ b/core/interaction-api/src/main/java/ru/yandex/practicum/dto/event/EventStatistics.java
@@ -1,9 +1,11 @@
-package ru.yandex.practicum.event.dto;
+package ru.yandex.practicum.dto.event;
import java.util.Map;
public record EventStatistics(
- Map confirmedRequests,
+
+ Map confirmedRequests,
+
Map views
) {
}
diff --git a/core/main-service/src/main/java/ru/yandex/practicum/event/dto/EventWithCountConfirmedRequests.java b/core/interaction-api/src/main/java/ru/yandex/practicum/dto/event/EventWithCountConfirmedRequests.java
similarity index 91%
rename from core/main-service/src/main/java/ru/yandex/practicum/event/dto/EventWithCountConfirmedRequests.java
rename to core/interaction-api/src/main/java/ru/yandex/practicum/dto/event/EventWithCountConfirmedRequests.java
index 1480e23..bf15456 100644
--- a/core/main-service/src/main/java/ru/yandex/practicum/event/dto/EventWithCountConfirmedRequests.java
+++ b/core/interaction-api/src/main/java/ru/yandex/practicum/dto/event/EventWithCountConfirmedRequests.java
@@ -1,4 +1,4 @@
-package ru.yandex.practicum.event.dto;
+package ru.yandex.practicum.dto.event;
import lombok.Getter;
import lombok.Setter;
@@ -6,7 +6,9 @@
@Getter
@Setter
public class EventWithCountConfirmedRequests {
+
private Long eventId;
+
private int countConfirmedRequests;
public EventWithCountConfirmedRequests(Long eventId, Long countConfirmedRequestsLong) {
diff --git a/core/main-service/src/main/java/ru/yandex/practicum/event/dto/LocationDto.java b/core/interaction-api/src/main/java/ru/yandex/practicum/dto/event/LocationDto.java
similarity index 86%
rename from core/main-service/src/main/java/ru/yandex/practicum/event/dto/LocationDto.java
rename to core/interaction-api/src/main/java/ru/yandex/practicum/dto/event/LocationDto.java
index e6cfcd1..feeec2a 100644
--- a/core/main-service/src/main/java/ru/yandex/practicum/event/dto/LocationDto.java
+++ b/core/interaction-api/src/main/java/ru/yandex/practicum/dto/event/LocationDto.java
@@ -1,8 +1,9 @@
-package ru.yandex.practicum.event.dto;
+package ru.yandex.practicum.dto.event;
import jakarta.validation.constraints.NotNull;
public record LocationDto(
+
@NotNull(message = "Широта не может быть null")
Float lat,
diff --git a/core/main-service/src/main/java/ru/yandex/practicum/event/dto/NewEventDto.java b/core/interaction-api/src/main/java/ru/yandex/practicum/dto/event/NewEventDto.java
similarity index 93%
rename from core/main-service/src/main/java/ru/yandex/practicum/event/dto/NewEventDto.java
rename to core/interaction-api/src/main/java/ru/yandex/practicum/dto/event/NewEventDto.java
index c7563b1..c14e412 100644
--- a/core/main-service/src/main/java/ru/yandex/practicum/event/dto/NewEventDto.java
+++ b/core/interaction-api/src/main/java/ru/yandex/practicum/dto/event/NewEventDto.java
@@ -1,13 +1,13 @@
-package ru.yandex.practicum.event.dto;
+package ru.yandex.practicum.dto.event;
import com.fasterxml.jackson.annotation.JsonFormat;
import jakarta.validation.constraints.*;
+import ru.yandex.practicum.constants.DateTimeConstants;
import java.time.LocalDateTime;
-import static ru.yandex.practicum.constants.DateTimeConstants.DATE_TIME_PATTERN;
-
public record NewEventDto(
+
@NotBlank(message = "Краткое описание не может быть пустым")
@Size(min = 20, max = 2000, message = "Аннотация должна содержать от {min} до {max} символов")
String annotation,
@@ -21,7 +21,7 @@ public record NewEventDto(
@NotNull(message = "Дата события не может быть null")
@Future(message = "Дата события должна быть в будущем")
- @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = DATE_TIME_PATTERN)
+ @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = DateTimeConstants.DATE_TIME_PATTERN)
LocalDateTime eventDate,
@NotNull(message = "Место проведения события не может быть null")
diff --git a/core/main-service/src/main/java/ru/yandex/practicum/event/dto/SearchEventAdminRequest.java b/core/interaction-api/src/main/java/ru/yandex/practicum/dto/event/SearchEventAdminRequest.java
similarity index 56%
rename from core/main-service/src/main/java/ru/yandex/practicum/event/dto/SearchEventAdminRequest.java
rename to core/interaction-api/src/main/java/ru/yandex/practicum/dto/event/SearchEventAdminRequest.java
index 8bc26e4..4166487 100644
--- a/core/main-service/src/main/java/ru/yandex/practicum/event/dto/SearchEventAdminRequest.java
+++ b/core/interaction-api/src/main/java/ru/yandex/practicum/dto/event/SearchEventAdminRequest.java
@@ -1,24 +1,24 @@
-package ru.yandex.practicum.event.dto;
+package ru.yandex.practicum.dto.event;
import org.springframework.format.annotation.DateTimeFormat;
-import ru.yandex.practicum.event.model.EventState;
+import ru.yandex.practicum.constants.DateTimeConstants;
+import ru.yandex.practicum.enums.EventState;
import java.time.LocalDateTime;
import java.util.List;
-import static ru.yandex.practicum.constants.DateTimeConstants.DATE_TIME_PATTERN;
-
public record SearchEventAdminRequest(
+
List users,
List states,
List categories,
- @DateTimeFormat(pattern = DATE_TIME_PATTERN)
+ @DateTimeFormat(pattern = DateTimeConstants.DATE_TIME_PATTERN)
LocalDateTime rangeStart,
- @DateTimeFormat(pattern = DATE_TIME_PATTERN)
+ @DateTimeFormat(pattern = DateTimeConstants.DATE_TIME_PATTERN)
LocalDateTime rangeEnd,
Integer from,
diff --git a/core/main-service/src/main/java/ru/yandex/practicum/event/dto/SearchEventPublicRequest.java b/core/interaction-api/src/main/java/ru/yandex/practicum/dto/event/SearchEventPublicRequest.java
similarity index 72%
rename from core/main-service/src/main/java/ru/yandex/practicum/event/dto/SearchEventPublicRequest.java
rename to core/interaction-api/src/main/java/ru/yandex/practicum/dto/event/SearchEventPublicRequest.java
index 7602285..5b064ab 100644
--- a/core/main-service/src/main/java/ru/yandex/practicum/event/dto/SearchEventPublicRequest.java
+++ b/core/interaction-api/src/main/java/ru/yandex/practicum/dto/event/SearchEventPublicRequest.java
@@ -1,24 +1,24 @@
-package ru.yandex.practicum.event.dto;
+package ru.yandex.practicum.dto.event;
import org.springframework.format.annotation.DateTimeFormat;
-import ru.yandex.practicum.event.model.SortState;
+import ru.yandex.practicum.constants.DateTimeConstants;
+import ru.yandex.practicum.enums.SortState;
import java.time.LocalDateTime;
import java.util.List;
-import static ru.yandex.practicum.constants.DateTimeConstants.DATE_TIME_PATTERN;
-
public record SearchEventPublicRequest(
+
String text,
List categories,
Boolean paid,
- @DateTimeFormat(pattern = DATE_TIME_PATTERN)
+ @DateTimeFormat(pattern = DateTimeConstants.DATE_TIME_PATTERN)
LocalDateTime rangeStart,
- @DateTimeFormat(pattern = DATE_TIME_PATTERN)
+ @DateTimeFormat(pattern = DateTimeConstants.DATE_TIME_PATTERN)
LocalDateTime rangeEnd,
Boolean onlyAvailable,
diff --git a/core/main-service/src/main/java/ru/yandex/practicum/event/dto/UpdateEventAdminRequest.java b/core/interaction-api/src/main/java/ru/yandex/practicum/dto/event/UpdateEventAdminRequest.java
similarity index 86%
rename from core/main-service/src/main/java/ru/yandex/practicum/event/dto/UpdateEventAdminRequest.java
rename to core/interaction-api/src/main/java/ru/yandex/practicum/dto/event/UpdateEventAdminRequest.java
index ec136dc..2eba84a 100644
--- a/core/main-service/src/main/java/ru/yandex/practicum/event/dto/UpdateEventAdminRequest.java
+++ b/core/interaction-api/src/main/java/ru/yandex/practicum/dto/event/UpdateEventAdminRequest.java
@@ -1,16 +1,16 @@
-package ru.yandex.practicum.event.dto;
+package ru.yandex.practicum.dto.event;
import com.fasterxml.jackson.annotation.JsonFormat;
import jakarta.validation.constraints.Future;
import jakarta.validation.constraints.PositiveOrZero;
import jakarta.validation.constraints.Size;
-import ru.yandex.practicum.event.model.StateActionAdmin;
+import ru.yandex.practicum.constants.DateTimeConstants;
+import ru.yandex.practicum.enums.StateActionAdmin;
import java.time.LocalDateTime;
-import static ru.yandex.practicum.constants.DateTimeConstants.DATE_TIME_PATTERN;
-
public record UpdateEventAdminRequest(
+
@Size(min = 20, max = 2000, message = "Недопустимое количество символов")
String annotation,
@@ -20,7 +20,7 @@ public record UpdateEventAdminRequest(
String description,
@Future(message = "Дата события должна быть в будущем")
- @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = DATE_TIME_PATTERN)
+ @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = DateTimeConstants.DATE_TIME_PATTERN)
LocalDateTime eventDate,
LocationDto location,
diff --git a/core/main-service/src/main/java/ru/yandex/practicum/event/dto/UpdateEventUserRequest.java b/core/interaction-api/src/main/java/ru/yandex/practicum/dto/event/UpdateEventUserRequest.java
similarity index 86%
rename from core/main-service/src/main/java/ru/yandex/practicum/event/dto/UpdateEventUserRequest.java
rename to core/interaction-api/src/main/java/ru/yandex/practicum/dto/event/UpdateEventUserRequest.java
index a2045fd..442e763 100644
--- a/core/main-service/src/main/java/ru/yandex/practicum/event/dto/UpdateEventUserRequest.java
+++ b/core/interaction-api/src/main/java/ru/yandex/practicum/dto/event/UpdateEventUserRequest.java
@@ -1,16 +1,16 @@
-package ru.yandex.practicum.event.dto;
+package ru.yandex.practicum.dto.event;
import com.fasterxml.jackson.annotation.JsonFormat;
import jakarta.validation.constraints.Future;
import jakarta.validation.constraints.PositiveOrZero;
import jakarta.validation.constraints.Size;
-import ru.yandex.practicum.event.model.StateActionUser;
+import ru.yandex.practicum.constants.DateTimeConstants;
+import ru.yandex.practicum.enums.StateActionUser;
import java.time.LocalDateTime;
-import static ru.yandex.practicum.constants.DateTimeConstants.DATE_TIME_PATTERN;
-
public record UpdateEventUserRequest(
+
@Size(min = 20, max = 2000, message = "Недопустимое количество символов")
String annotation,
@@ -20,7 +20,7 @@ public record UpdateEventUserRequest(
String description,
@Future(message = "Дата события должна быть в будущем")
- @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = DATE_TIME_PATTERN)
+ @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = DateTimeConstants.DATE_TIME_PATTERN)
LocalDateTime eventDate,
LocationDto location,
diff --git a/core/main-service/src/main/java/ru/yandex/practicum/request/dto/EventRequestStatusUpdateRequest.java b/core/interaction-api/src/main/java/ru/yandex/practicum/dto/request/EventRequestStatusUpdateRequest.java
similarity index 58%
rename from core/main-service/src/main/java/ru/yandex/practicum/request/dto/EventRequestStatusUpdateRequest.java
rename to core/interaction-api/src/main/java/ru/yandex/practicum/dto/request/EventRequestStatusUpdateRequest.java
index d8a18d5..d1a8bbc 100644
--- a/core/main-service/src/main/java/ru/yandex/practicum/request/dto/EventRequestStatusUpdateRequest.java
+++ b/core/interaction-api/src/main/java/ru/yandex/practicum/dto/request/EventRequestStatusUpdateRequest.java
@@ -1,11 +1,13 @@
-package ru.yandex.practicum.request.dto;
+package ru.yandex.practicum.dto.request;
-import ru.yandex.practicum.request.model.RequestStatus;
+import ru.yandex.practicum.enums.RequestStatus;
import java.util.List;
public record EventRequestStatusUpdateRequest(
+
List requestIds,
+
RequestStatus status
) {
}
diff --git a/core/main-service/src/main/java/ru/yandex/practicum/request/dto/EventRequestStatusUpdateResult.java b/core/interaction-api/src/main/java/ru/yandex/practicum/dto/request/EventRequestStatusUpdateResult.java
similarity index 81%
rename from core/main-service/src/main/java/ru/yandex/practicum/request/dto/EventRequestStatusUpdateResult.java
rename to core/interaction-api/src/main/java/ru/yandex/practicum/dto/request/EventRequestStatusUpdateResult.java
index 81b52b4..3809b90 100644
--- a/core/main-service/src/main/java/ru/yandex/practicum/request/dto/EventRequestStatusUpdateResult.java
+++ b/core/interaction-api/src/main/java/ru/yandex/practicum/dto/request/EventRequestStatusUpdateResult.java
@@ -1,9 +1,11 @@
-package ru.yandex.practicum.request.dto;
+package ru.yandex.practicum.dto.request;
import java.util.List;
public record EventRequestStatusUpdateResult(
+
List confirmedRequests,
+
List rejectedRequests
) {
}
diff --git a/core/interaction-api/src/main/java/ru/yandex/practicum/dto/request/ParticipationRequestDto.java b/core/interaction-api/src/main/java/ru/yandex/practicum/dto/request/ParticipationRequestDto.java
new file mode 100644
index 0000000..04de703
--- /dev/null
+++ b/core/interaction-api/src/main/java/ru/yandex/practicum/dto/request/ParticipationRequestDto.java
@@ -0,0 +1,25 @@
+package ru.yandex.practicum.dto.request;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import ru.yandex.practicum.constants.DateTimeConstants;
+import ru.yandex.practicum.enums.RequestStatus;
+
+import java.time.LocalDateTime;
+
+public record ParticipationRequestDto(
+
+ Long id,
+
+ @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = DateTimeConstants.DATE_TIME_PATTERN)
+ LocalDateTime created,
+
+ @JsonProperty("event")
+ Long eventId,
+
+ @JsonProperty("requester")
+ Long requesterId,
+
+ RequestStatus status
+) {
+}
diff --git a/core/main-service/src/main/java/ru/yandex/practicum/user/dto/NewUserRequest.java b/core/interaction-api/src/main/java/ru/yandex/practicum/dto/user/NewUserRequest.java
similarity index 93%
rename from core/main-service/src/main/java/ru/yandex/practicum/user/dto/NewUserRequest.java
rename to core/interaction-api/src/main/java/ru/yandex/practicum/dto/user/NewUserRequest.java
index 2cd824c..dc9ab42 100644
--- a/core/main-service/src/main/java/ru/yandex/practicum/user/dto/NewUserRequest.java
+++ b/core/interaction-api/src/main/java/ru/yandex/practicum/dto/user/NewUserRequest.java
@@ -1,10 +1,11 @@
-package ru.yandex.practicum.user.dto;
+package ru.yandex.practicum.dto.user;
import jakarta.validation.constraints.Email;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.Size;
public record NewUserRequest(
+
@NotBlank(message = "Имя пользователя не может быть пустым")
@Size(min = 2, max = 250)
String name,
diff --git a/core/main-service/src/main/java/ru/yandex/practicum/user/dto/UserDto.java b/core/interaction-api/src/main/java/ru/yandex/practicum/dto/user/UserDto.java
similarity index 68%
rename from core/main-service/src/main/java/ru/yandex/practicum/user/dto/UserDto.java
rename to core/interaction-api/src/main/java/ru/yandex/practicum/dto/user/UserDto.java
index 778ac5e..0a667f6 100644
--- a/core/main-service/src/main/java/ru/yandex/practicum/user/dto/UserDto.java
+++ b/core/interaction-api/src/main/java/ru/yandex/practicum/dto/user/UserDto.java
@@ -1,8 +1,11 @@
-package ru.yandex.practicum.user.dto;
+package ru.yandex.practicum.dto.user;
public record UserDto(
+
Long id,
+
String name,
+
String email
) {
}
diff --git a/core/main-service/src/main/java/ru/yandex/practicum/user/dto/UserShortDto.java b/core/interaction-api/src/main/java/ru/yandex/practicum/dto/user/UserShortDto.java
similarity index 64%
rename from core/main-service/src/main/java/ru/yandex/practicum/user/dto/UserShortDto.java
rename to core/interaction-api/src/main/java/ru/yandex/practicum/dto/user/UserShortDto.java
index 525a4d7..f11b7b7 100644
--- a/core/main-service/src/main/java/ru/yandex/practicum/user/dto/UserShortDto.java
+++ b/core/interaction-api/src/main/java/ru/yandex/practicum/dto/user/UserShortDto.java
@@ -1,7 +1,9 @@
-package ru.yandex.practicum.user.dto;
+package ru.yandex.practicum.dto.user;
public record UserShortDto(
+
Long id,
+
String name
) {
}
diff --git a/core/interaction-api/src/main/java/ru/yandex/practicum/enums/CommentStatus.java b/core/interaction-api/src/main/java/ru/yandex/practicum/enums/CommentStatus.java
new file mode 100644
index 0000000..7ea38bd
--- /dev/null
+++ b/core/interaction-api/src/main/java/ru/yandex/practicum/enums/CommentStatus.java
@@ -0,0 +1,7 @@
+package ru.yandex.practicum.enums;
+
+public enum CommentStatus {
+ PENDING,
+ PUBLISHED,
+ REJECTED
+}
diff --git a/core/main-service/src/main/java/ru/yandex/practicum/event/model/EventState.java b/core/interaction-api/src/main/java/ru/yandex/practicum/enums/EventState.java
similarity index 62%
rename from core/main-service/src/main/java/ru/yandex/practicum/event/model/EventState.java
rename to core/interaction-api/src/main/java/ru/yandex/practicum/enums/EventState.java
index ddcae09..01d53b8 100644
--- a/core/main-service/src/main/java/ru/yandex/practicum/event/model/EventState.java
+++ b/core/interaction-api/src/main/java/ru/yandex/practicum/enums/EventState.java
@@ -1,4 +1,4 @@
-package ru.yandex.practicum.event.model;
+package ru.yandex.practicum.enums;
public enum EventState {
PENDING,
diff --git a/core/main-service/src/main/java/ru/yandex/practicum/request/model/RequestStatus.java b/core/interaction-api/src/main/java/ru/yandex/practicum/enums/RequestStatus.java
similarity index 66%
rename from core/main-service/src/main/java/ru/yandex/practicum/request/model/RequestStatus.java
rename to core/interaction-api/src/main/java/ru/yandex/practicum/enums/RequestStatus.java
index d25345a..a9e26da 100644
--- a/core/main-service/src/main/java/ru/yandex/practicum/request/model/RequestStatus.java
+++ b/core/interaction-api/src/main/java/ru/yandex/practicum/enums/RequestStatus.java
@@ -1,4 +1,4 @@
-package ru.yandex.practicum.request.model;
+package ru.yandex.practicum.enums;
public enum RequestStatus {
PENDING,
diff --git a/core/main-service/src/main/java/ru/yandex/practicum/event/model/SortState.java b/core/interaction-api/src/main/java/ru/yandex/practicum/enums/SortState.java
similarity index 56%
rename from core/main-service/src/main/java/ru/yandex/practicum/event/model/SortState.java
rename to core/interaction-api/src/main/java/ru/yandex/practicum/enums/SortState.java
index 8a35d2d..1e028df 100644
--- a/core/main-service/src/main/java/ru/yandex/practicum/event/model/SortState.java
+++ b/core/interaction-api/src/main/java/ru/yandex/practicum/enums/SortState.java
@@ -1,4 +1,4 @@
-package ru.yandex.practicum.event.model;
+package ru.yandex.practicum.enums;
public enum SortState {
EVENT_DATE,
diff --git a/core/main-service/src/main/java/ru/yandex/practicum/event/model/StateActionAdmin.java b/core/interaction-api/src/main/java/ru/yandex/practicum/enums/StateActionAdmin.java
similarity index 63%
rename from core/main-service/src/main/java/ru/yandex/practicum/event/model/StateActionAdmin.java
rename to core/interaction-api/src/main/java/ru/yandex/practicum/enums/StateActionAdmin.java
index 27a800c..3bf500f 100644
--- a/core/main-service/src/main/java/ru/yandex/practicum/event/model/StateActionAdmin.java
+++ b/core/interaction-api/src/main/java/ru/yandex/practicum/enums/StateActionAdmin.java
@@ -1,4 +1,4 @@
-package ru.yandex.practicum.event.model;
+package ru.yandex.practicum.enums;
public enum StateActionAdmin {
PUBLISH_EVENT,
diff --git a/core/main-service/src/main/java/ru/yandex/practicum/event/model/StateActionUser.java b/core/interaction-api/src/main/java/ru/yandex/practicum/enums/StateActionUser.java
similarity index 63%
rename from core/main-service/src/main/java/ru/yandex/practicum/event/model/StateActionUser.java
rename to core/interaction-api/src/main/java/ru/yandex/practicum/enums/StateActionUser.java
index 0cc9766..ee790e0 100644
--- a/core/main-service/src/main/java/ru/yandex/practicum/event/model/StateActionUser.java
+++ b/core/interaction-api/src/main/java/ru/yandex/practicum/enums/StateActionUser.java
@@ -1,4 +1,4 @@
-package ru.yandex.practicum.event.model;
+package ru.yandex.practicum.enums;
public enum StateActionUser {
SEND_TO_REVIEW,
diff --git a/core/main-service/src/main/java/ru/yandex/practicum/exception/BadRequestException.java b/core/interaction-api/src/main/java/ru/yandex/practicum/exception/BadRequestException.java
similarity index 100%
rename from core/main-service/src/main/java/ru/yandex/practicum/exception/BadRequestException.java
rename to core/interaction-api/src/main/java/ru/yandex/practicum/exception/BadRequestException.java
diff --git a/core/main-service/src/main/java/ru/yandex/practicum/exception/ConflictException.java b/core/interaction-api/src/main/java/ru/yandex/practicum/exception/ConflictException.java
similarity index 100%
rename from core/main-service/src/main/java/ru/yandex/practicum/exception/ConflictException.java
rename to core/interaction-api/src/main/java/ru/yandex/practicum/exception/ConflictException.java
diff --git a/core/main-service/src/main/java/ru/yandex/practicum/exception/ErrorResponse.java b/core/interaction-api/src/main/java/ru/yandex/practicum/exception/ErrorResponse.java
similarity index 97%
rename from core/main-service/src/main/java/ru/yandex/practicum/exception/ErrorResponse.java
rename to core/interaction-api/src/main/java/ru/yandex/practicum/exception/ErrorResponse.java
index e110861..8147162 100644
--- a/core/main-service/src/main/java/ru/yandex/practicum/exception/ErrorResponse.java
+++ b/core/interaction-api/src/main/java/ru/yandex/practicum/exception/ErrorResponse.java
@@ -1,10 +1,15 @@
package ru.yandex.practicum.exception;
public record ErrorResponse(
+
String path,
+
String httpMethod,
+
int statusCode,
+
String error,
+
String message
) {
}
diff --git a/core/main-service/src/main/java/ru/yandex/practicum/exception/ForbiddenException.java b/core/interaction-api/src/main/java/ru/yandex/practicum/exception/ForbiddenException.java
similarity index 100%
rename from core/main-service/src/main/java/ru/yandex/practicum/exception/ForbiddenException.java
rename to core/interaction-api/src/main/java/ru/yandex/practicum/exception/ForbiddenException.java
diff --git a/core/main-service/src/main/java/ru/yandex/practicum/exception/NotFoundException.java b/core/interaction-api/src/main/java/ru/yandex/practicum/exception/NotFoundException.java
similarity index 100%
rename from core/main-service/src/main/java/ru/yandex/practicum/exception/NotFoundException.java
rename to core/interaction-api/src/main/java/ru/yandex/practicum/exception/NotFoundException.java
diff --git a/core/interaction-api/src/main/java/ru/yandex/practicum/exception/ServiceUnavailableException.java b/core/interaction-api/src/main/java/ru/yandex/practicum/exception/ServiceUnavailableException.java
new file mode 100644
index 0000000..f19164a
--- /dev/null
+++ b/core/interaction-api/src/main/java/ru/yandex/practicum/exception/ServiceUnavailableException.java
@@ -0,0 +1,7 @@
+package ru.yandex.practicum.exception;
+
+public class ServiceUnavailableException extends RuntimeException {
+ public ServiceUnavailableException(String message) {
+ super(message);
+ }
+}
diff --git a/core/main-service/src/main/java/ru/yandex/practicum/exception/ValidationException.java b/core/interaction-api/src/main/java/ru/yandex/practicum/exception/ValidationException.java
similarity index 100%
rename from core/main-service/src/main/java/ru/yandex/practicum/exception/ValidationException.java
rename to core/interaction-api/src/main/java/ru/yandex/practicum/exception/ValidationException.java
diff --git a/core/main-service/Dockerfile b/core/main-service/Dockerfile
deleted file mode 100644
index 0ff1817..0000000
--- a/core/main-service/Dockerfile
+++ /dev/null
@@ -1,5 +0,0 @@
-FROM eclipse-temurin:21-jre-jammy
-VOLUME /tmp
-ARG JAR_FILE=target/*.jar
-COPY ${JAR_FILE} app.jar
-ENTRYPOINT ["sh", "-c", "java ${JAVA_OPTS} -jar /app.jar"]
\ No newline at end of file
diff --git a/core/main-service/src/main/java/ru/yandex/practicum/category/service/CategoryService.java b/core/main-service/src/main/java/ru/yandex/practicum/category/service/CategoryService.java
deleted file mode 100644
index 5e398ca..0000000
--- a/core/main-service/src/main/java/ru/yandex/practicum/category/service/CategoryService.java
+++ /dev/null
@@ -1,22 +0,0 @@
-package ru.yandex.practicum.category.service;
-
-import org.springframework.data.domain.Pageable;
-import ru.yandex.practicum.category.dto.CategoryDto;
-import ru.yandex.practicum.category.dto.NewCategoryDto;
-import ru.yandex.practicum.category.model.Category;
-
-import java.util.List;
-
-public interface CategoryService {
- CategoryDto createCategory(NewCategoryDto newCategoryDto);
-
- void deleteCategory(Long categoryId);
-
- CategoryDto updateCategory(Long categoryId, NewCategoryDto newCategoryDto);
-
- List getCategories(Pageable pageable);
-
- CategoryDto getCategoryById(Long categoryId);
-
- Category getCategoryByIdOrThrow(Long categoryId);
-}
diff --git a/core/main-service/src/main/java/ru/yandex/practicum/comment/controller/AdminCommentController.java b/core/main-service/src/main/java/ru/yandex/practicum/comment/controller/AdminCommentController.java
deleted file mode 100644
index cd5a919..0000000
--- a/core/main-service/src/main/java/ru/yandex/practicum/comment/controller/AdminCommentController.java
+++ /dev/null
@@ -1,25 +0,0 @@
-package ru.yandex.practicum.comment.controller;
-
-import jakarta.validation.constraints.Positive;
-import lombok.RequiredArgsConstructor;
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.http.HttpStatus;
-import org.springframework.validation.annotation.Validated;
-import org.springframework.web.bind.annotation.*;
-import ru.yandex.practicum.comment.service.CommentService;
-
-@Slf4j
-@Validated
-@RestController
-@RequestMapping("/admin/comments")
-@RequiredArgsConstructor
-public class AdminCommentController {
- private final CommentService commentService;
-
- @DeleteMapping("/{commentId}")
- @ResponseStatus(HttpStatus.NO_CONTENT)
- public void deleteCommentAdmin(@PathVariable @Positive Long commentId) {
- log.debug("Controller: deleteCommentAdmin commentId={}", commentId);
- commentService.deleteCommentAdmin(commentId);
- }
-}
diff --git a/core/main-service/src/main/java/ru/yandex/practicum/comment/controller/PrivateCommentController.java b/core/main-service/src/main/java/ru/yandex/practicum/comment/controller/PrivateCommentController.java
deleted file mode 100644
index 8e68f7a..0000000
--- a/core/main-service/src/main/java/ru/yandex/practicum/comment/controller/PrivateCommentController.java
+++ /dev/null
@@ -1,65 +0,0 @@
-package ru.yandex.practicum.comment.controller;
-
-import jakarta.validation.Valid;
-import jakarta.validation.constraints.Positive;
-import jakarta.validation.constraints.PositiveOrZero;
-import lombok.RequiredArgsConstructor;
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.data.domain.PageRequest;
-import org.springframework.http.HttpStatus;
-import org.springframework.validation.annotation.Validated;
-import org.springframework.web.bind.annotation.*;
-import ru.yandex.practicum.comment.dto.CommentDto;
-import ru.yandex.practicum.comment.dto.NewCommentDto;
-import ru.yandex.practicum.comment.dto.UpdateCommentDto;
-import ru.yandex.practicum.comment.service.CommentService;
-
-import java.util.List;
-
-@Slf4j
-@Validated
-@RestController
-@RequestMapping("/users/{userId}/comments")
-@RequiredArgsConstructor
-public class PrivateCommentController {
- private final CommentService commentService;
-
- @PostMapping("/{eventId}")
- @ResponseStatus(HttpStatus.CREATED)
- public CommentDto createComment(@PathVariable @Positive Long userId,
- @PathVariable @Positive Long eventId,
- @RequestBody @Valid NewCommentDto newCommentDto
- ) {
- log.debug("Controller: createComment userId={}, eventId={}, data={}", userId, eventId, newCommentDto);
- return commentService.createComment(userId, eventId, newCommentDto);
- }
-
- @PatchMapping("/{eventId}/{commentId}")
- public CommentDto updateComment(@PathVariable @Positive Long userId,
- @PathVariable @Positive Long eventId,
- @PathVariable @Positive Long commentId,
- @RequestBody @Valid UpdateCommentDto updateCommentDto
- ) {
- log.debug("Controller: updateComment userId={}, eventId={}, commentId={}, data={}", userId, eventId, commentId,
- updateCommentDto);
- return commentService.updateComment(userId, eventId, commentId, updateCommentDto);
- }
-
- @DeleteMapping("/{commentId}")
- @ResponseStatus(HttpStatus.NO_CONTENT)
- public void deleteComment(@PathVariable @Positive Long userId,
- @PathVariable @Positive Long commentId
- ) {
- log.debug("Controller: deleteComment userId={}, commentId={}", userId, commentId);
- commentService.deleteComment(userId, commentId);
- }
-
- @GetMapping
- public List getCommentsForUser(@PathVariable @Positive Long userId,
- @RequestParam(defaultValue = "0") @PositiveOrZero Integer from,
- @RequestParam(defaultValue = "10") @Positive Integer size
- ) {
- log.debug("Controller: getCommentsForUser userId={}, from={}, size={}", userId, from, size);
- return commentService.getCommentsForUser(userId, PageRequest.of(from / size, size));
- }
-}
diff --git a/core/main-service/src/main/java/ru/yandex/practicum/comment/controller/PublicCommentController.java b/core/main-service/src/main/java/ru/yandex/practicum/comment/controller/PublicCommentController.java
deleted file mode 100644
index 9561fba..0000000
--- a/core/main-service/src/main/java/ru/yandex/practicum/comment/controller/PublicCommentController.java
+++ /dev/null
@@ -1,31 +0,0 @@
-package ru.yandex.practicum.comment.controller;
-
-import jakarta.validation.constraints.Positive;
-import jakarta.validation.constraints.PositiveOrZero;
-import lombok.RequiredArgsConstructor;
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.data.domain.PageRequest;
-import org.springframework.validation.annotation.Validated;
-import org.springframework.web.bind.annotation.*;
-import ru.yandex.practicum.comment.dto.CommentDto;
-import ru.yandex.practicum.comment.service.CommentService;
-
-import java.util.List;
-
-@Slf4j
-@Validated
-@RestController
-@RequestMapping("/comments")
-@RequiredArgsConstructor
-public class PublicCommentController {
- private final CommentService commentService;
-
- @GetMapping("/event/{eventId}")
- public List getCommentsForEvent(@PathVariable @Positive Long eventId,
- @RequestParam(defaultValue = "0") @PositiveOrZero Integer from,
- @RequestParam(defaultValue = "10") @Positive Integer size
- ) {
- log.debug("Controller: getCommentsForEvent eventId={}, from={}, size={}", eventId, from, size);
- return commentService.getCommentsForEvent(eventId, PageRequest.of(from / size, size));
- }
-}
diff --git a/core/main-service/src/main/java/ru/yandex/practicum/comment/dto/CommentDto.java b/core/main-service/src/main/java/ru/yandex/practicum/comment/dto/CommentDto.java
deleted file mode 100644
index 4e8b862..0000000
--- a/core/main-service/src/main/java/ru/yandex/practicum/comment/dto/CommentDto.java
+++ /dev/null
@@ -1,21 +0,0 @@
-package ru.yandex.practicum.comment.dto;
-
-import com.fasterxml.jackson.annotation.JsonFormat;
-
-import java.time.LocalDateTime;
-
-import static ru.yandex.practicum.constants.DateTimeConstants.DATE_TIME_PATTERN;
-
-public record CommentDto(
- Long id,
-
- String text,
-
- Long userId,
-
- Long eventId,
-
- @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = DATE_TIME_PATTERN)
- LocalDateTime createdDate
-) {
-}
diff --git a/core/main-service/src/main/java/ru/yandex/practicum/comment/mapper/CommentMapper.java b/core/main-service/src/main/java/ru/yandex/practicum/comment/mapper/CommentMapper.java
deleted file mode 100644
index 56a943a..0000000
--- a/core/main-service/src/main/java/ru/yandex/practicum/comment/mapper/CommentMapper.java
+++ /dev/null
@@ -1,26 +0,0 @@
-package ru.yandex.practicum.comment.mapper;
-
-import org.mapstruct.*;
-import ru.yandex.practicum.comment.dto.CommentDto;
-import ru.yandex.practicum.comment.dto.NewCommentDto;
-import ru.yandex.practicum.comment.dto.UpdateCommentDto;
-import ru.yandex.practicum.comment.model.Comment;
-import ru.yandex.practicum.event.model.Event;
-import ru.yandex.practicum.user.model.User;
-
-@Mapper(componentModel = "spring")
-public interface CommentMapper {
- @Mapping(target = "id", ignore = true)
- @Mapping(target = "createdDate", ignore = true)
- Comment toComment(NewCommentDto newCommentDto, User user, Event event);
-
- @Mapping(target = "userId", source = "user.id")
- @Mapping(target = "eventId", source = "event.id")
- CommentDto toDto(Comment comment);
-
- @Mapping(target = "id", ignore = true)
- @Mapping(target = "user", ignore = true)
- @Mapping(target = "event", ignore = true)
- @Mapping(target = "createdDate", ignore = true)
- void updateCommentFromDto(UpdateCommentDto dto, @MappingTarget Comment comment);
-}
diff --git a/core/main-service/src/main/java/ru/yandex/practicum/comment/model/Comment.java b/core/main-service/src/main/java/ru/yandex/practicum/comment/model/Comment.java
deleted file mode 100644
index e3ee4d7..0000000
--- a/core/main-service/src/main/java/ru/yandex/practicum/comment/model/Comment.java
+++ /dev/null
@@ -1,38 +0,0 @@
-package ru.yandex.practicum.comment.model;
-
-import jakarta.persistence.*;
-import lombok.EqualsAndHashCode;
-import lombok.Getter;
-import lombok.Setter;
-import org.hibernate.annotations.CreationTimestamp;
-import ru.yandex.practicum.event.model.Event;
-import ru.yandex.practicum.user.model.User;
-
-import java.time.LocalDateTime;
-
-@Entity
-@Table(name = "comments")
-@Getter
-@Setter
-@EqualsAndHashCode(onlyExplicitlyIncluded = true)
-public class Comment {
- @Id
- @GeneratedValue(strategy = GenerationType.IDENTITY)
- @EqualsAndHashCode.Include
- private Long id;
-
- @Column(nullable = false, length = 5000)
- private String text;
-
- @ManyToOne(fetch = FetchType.LAZY)
- @JoinColumn(name = "user_id", nullable = false)
- private User user;
-
- @ManyToOne(fetch = FetchType.LAZY)
- @JoinColumn(name = "event_id", nullable = false)
- private Event event;
-
- @Column(name = "created_date", nullable = false)
- @CreationTimestamp
- private LocalDateTime createdDate;
-}
diff --git a/core/main-service/src/main/java/ru/yandex/practicum/comment/repository/CommentRepository.java b/core/main-service/src/main/java/ru/yandex/practicum/comment/repository/CommentRepository.java
deleted file mode 100644
index 8b8cadd..0000000
--- a/core/main-service/src/main/java/ru/yandex/practicum/comment/repository/CommentRepository.java
+++ /dev/null
@@ -1,47 +0,0 @@
-package ru.yandex.practicum.comment.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.yandex.practicum.comment.model.Comment;
-
-import java.util.List;
-import java.util.Optional;
-
-public interface CommentRepository extends JpaRepository {
-
- @Query("""
- SELECT c FROM Comment c
- LEFT JOIN FETCH c.user
- LEFT JOIN FETCH c.event
- WHERE c.id = :id AND c.user.id = :userId AND c.event.id = :eventId"""
- )
- Optional findByIdAndUserIdAndEventId(@Param("id") Long id, @Param("userId") Long userId, @Param("eventId") Long eventId);
-
- @Query("""
- SELECT c FROM Comment c
- LEFT JOIN FETCH c.user
- LEFT JOIN FETCH c.event
- WHERE c.id = :id AND c.user.id = :userId"""
- )
- Optional findByIdAndUserId(@Param("id") Long id, @Param("userId") Long userId);
-
- @Query("""
- SELECT c FROM Comment c
- LEFT JOIN FETCH c.user
- LEFT JOIN FETCH c.event
- WHERE c.event.id = :eventId
- ORDER BY c.createdDate DESC"""
- )
- List findByEventId(@Param("eventId") Long eventId, Pageable pageable);
-
- @Query("""
- SELECT c FROM Comment c
- LEFT JOIN FETCH c.user
- LEFT JOIN FETCH c.event
- WHERE c.user.id = :userId
- ORDER BY c.createdDate DESC"""
- )
- List findByUserId(@Param("userId") Long userId, Pageable pageable);
-}
diff --git a/core/main-service/src/main/java/ru/yandex/practicum/comment/service/CommentService.java b/core/main-service/src/main/java/ru/yandex/practicum/comment/service/CommentService.java
deleted file mode 100644
index 10468b1..0000000
--- a/core/main-service/src/main/java/ru/yandex/practicum/comment/service/CommentService.java
+++ /dev/null
@@ -1,22 +0,0 @@
-package ru.yandex.practicum.comment.service;
-
-import org.springframework.data.domain.Pageable;
-import ru.yandex.practicum.comment.dto.CommentDto;
-import ru.yandex.practicum.comment.dto.NewCommentDto;
-import ru.yandex.practicum.comment.dto.UpdateCommentDto;
-
-import java.util.List;
-
-public interface CommentService {
- CommentDto createComment(Long userId, Long eventId, NewCommentDto newCommentDto);
-
- CommentDto updateComment(Long userId, Long eventId, Long commentId, UpdateCommentDto updateCommentDto);
-
- void deleteComment(Long userId, Long commentId);
-
- void deleteCommentAdmin(Long commentId);
-
- List getCommentsForEvent(Long eventId, Pageable pageable);
-
- List getCommentsForUser(Long userId, Pageable pageable);
-}
diff --git a/core/main-service/src/main/java/ru/yandex/practicum/comment/service/CommentServiceImpl.java b/core/main-service/src/main/java/ru/yandex/practicum/comment/service/CommentServiceImpl.java
deleted file mode 100644
index 7fa5eff..0000000
--- a/core/main-service/src/main/java/ru/yandex/practicum/comment/service/CommentServiceImpl.java
+++ /dev/null
@@ -1,106 +0,0 @@
-package ru.yandex.practicum.comment.service;
-
-import lombok.RequiredArgsConstructor;
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.data.domain.Pageable;
-import org.springframework.stereotype.Service;
-import org.springframework.transaction.annotation.Transactional;
-import ru.yandex.practicum.comment.dto.CommentDto;
-import ru.yandex.practicum.comment.dto.NewCommentDto;
-import ru.yandex.practicum.comment.dto.UpdateCommentDto;
-import ru.yandex.practicum.comment.mapper.CommentMapper;
-import ru.yandex.practicum.comment.model.Comment;
-import ru.yandex.practicum.comment.repository.CommentRepository;
-import ru.yandex.practicum.event.model.Event;
-import ru.yandex.practicum.event.model.EventState;
-import ru.yandex.practicum.event.service.EventService;
-import ru.yandex.practicum.exception.ConflictException;
-import ru.yandex.practicum.exception.NotFoundException;
-import ru.yandex.practicum.user.model.User;
-import ru.yandex.practicum.user.service.UserService;
-
-import java.util.List;
-
-@Slf4j
-@Service
-@Transactional(readOnly = true)
-@RequiredArgsConstructor
-public class CommentServiceImpl implements CommentService {
- private final CommentRepository commentRepository;
- private final EventService eventService;
- private final UserService userService;
- private final CommentMapper commentMapper;
-
- @Override
- @Transactional
- public CommentDto createComment(Long userId, Long eventId, NewCommentDto newCommentDto) {
- User user = userService.getUserByIdOrThrow(userId);
- Event event = eventService.getEventOrThrow(eventId);
-
- if (EventState.PUBLISHED != event.getState())
- throw new ConflictException("Нельзя комментировать неопубликованное событие");
-
- Comment comment = commentMapper.toComment(newCommentDto, user, event);
-
- log.info("Создан новый комментарий: authorId={}, eventId={}, newCommentDto={}", userId, eventId, newCommentDto);
- return commentMapper.toDto(commentRepository.save(comment));
- }
-
- @Override
- @Transactional
- public CommentDto updateComment(Long userId, Long eventId, Long commentId, UpdateCommentDto updateCommentDto) {
- Comment comment = commentRepository.findByIdAndUserIdAndEventId(commentId, userId, eventId)
- .orElseThrow(() -> new NotFoundException("Комментарий с id=" + commentId
- + " от пользователя с id=" + userId
- + " к событию с id=" + eventId + " не найден"));
-
- commentMapper.updateCommentFromDto(updateCommentDto, comment);
-
- log.info("Комментарий обновлен: commentId={}, userId={}, eventId={}, updateCommentDto={}",
- commentId, userId, eventId, updateCommentDto);
- return commentMapper.toDto(commentRepository.save(comment));
- }
-
- @Override
- @Transactional
- public void deleteComment(Long userId, Long commentId) {
- commentRepository.findByIdAndUserId(commentId, userId)
- .orElseThrow(() -> new NotFoundException("Комментарий с id=" + commentId
- + " от пользователя с id=" + userId + " не найден"));
-
- log.info("Комментарий удален: commentId={}, userId={}", commentId, userId);
- commentRepository.deleteById(commentId);
- }
-
- @Override
- @Transactional
- public void deleteCommentAdmin(Long commentId) {
- commentRepository.findById(commentId)
- .orElseThrow(() -> new NotFoundException("Комментарий с id=" + commentId + " не найден"));
-
- log.info("Комментарий удален администратором: commentId={}", commentId);
- commentRepository.deleteById(commentId);
- }
-
- @Override
- public List getCommentsForEvent(Long eventId, Pageable pageable) {
- eventService.getEventOrThrow(eventId);
-
- log.info("Получен список комментариев для события: eventId={}", eventId);
- return commentRepository.findByEventId(eventId, pageable)
- .stream()
- .map(commentMapper::toDto)
- .toList();
- }
-
- @Override
- public List getCommentsForUser(Long userId, Pageable pageable) {
- userService.getUserByIdOrThrow(userId);
-
- log.info("Получен список комментариев для пользователя: userId={}", userId);
- return commentRepository.findByUserId(userId, pageable)
- .stream()
- .map(commentMapper::toDto)
- .toList();
- }
-}
diff --git a/core/main-service/src/main/java/ru/yandex/practicum/compilation/mapper/CompilationMapper.java b/core/main-service/src/main/java/ru/yandex/practicum/compilation/mapper/CompilationMapper.java
deleted file mode 100644
index 64b6e42..0000000
--- a/core/main-service/src/main/java/ru/yandex/practicum/compilation/mapper/CompilationMapper.java
+++ /dev/null
@@ -1,24 +0,0 @@
-package ru.yandex.practicum.compilation.mapper;
-
-import org.mapstruct.*;
-import ru.yandex.practicum.compilation.dto.CompilationDto;
-import ru.yandex.practicum.compilation.dto.NewCompilationDto;
-import ru.yandex.practicum.compilation.dto.UpdateCompilationRequest;
-import ru.yandex.practicum.compilation.model.Compilation;
-import ru.yandex.practicum.event.mapper.EventMapper;
-
-@Mapper(componentModel = "spring", uses = EventMapper.class)
-public interface CompilationMapper {
-
- @Mapping(target = "id", ignore = true)
- @Mapping(target = "events", ignore = true)
- Compilation toEntity(NewCompilationDto request);
-
- @Mapping(target = "events", qualifiedByName = "toEventShortWithoutStats")
- CompilationDto toDto(Compilation compilation);
-
- @Mapping(target = "id", ignore = true)
- @Mapping(target = "events", ignore = true)
- @BeanMapping(nullValuePropertyMappingStrategy = NullValuePropertyMappingStrategy.IGNORE)
- void updateCompilationFromRequest(UpdateCompilationRequest request, @MappingTarget Compilation compilation);
-}
diff --git a/core/main-service/src/main/java/ru/yandex/practicum/compilation/repository/CompilationRepository.java b/core/main-service/src/main/java/ru/yandex/practicum/compilation/repository/CompilationRepository.java
deleted file mode 100644
index ef90d2c..0000000
--- a/core/main-service/src/main/java/ru/yandex/practicum/compilation/repository/CompilationRepository.java
+++ /dev/null
@@ -1,37 +0,0 @@
-package ru.yandex.practicum.compilation.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.yandex.practicum.compilation.model.Compilation;
-
-import java.util.List;
-import java.util.Optional;
-
-public interface CompilationRepository extends JpaRepository {
-
- @Query("""
- SELECT c FROM Compilation c
- LEFT JOIN FETCH c.events e
- LEFT JOIN FETCH e.category
- LEFT JOIN FETCH e.initiator
- WHERE c.id = :id""")
- Optional findByIdWithEvents(@Param("id") Long id);
-
- boolean existsByTitle(String title);
-
- @Query("""
- SELECT c.id FROM Compilation c
- WHERE (:pinned IS NULL OR c.pinned = :pinned)
- ORDER BY c.id ASC""")
- List findIdsByPinned(@Param("pinned") Boolean pinned, Pageable pageable);
-
- @Query("""
- SELECT DISTINCT c FROM Compilation c
- LEFT JOIN FETCH c.events e
- LEFT JOIN FETCH e.category
- LEFT JOIN FETCH e.initiator
- WHERE c.id IN :ids""")
- List findAllByIdInWithEvents(@Param("ids") List ids);
-}
diff --git a/core/main-service/src/main/java/ru/yandex/practicum/event/dto/EventFullDto.java b/core/main-service/src/main/java/ru/yandex/practicum/event/dto/EventFullDto.java
deleted file mode 100644
index a7331a5..0000000
--- a/core/main-service/src/main/java/ru/yandex/practicum/event/dto/EventFullDto.java
+++ /dev/null
@@ -1,48 +0,0 @@
-package ru.yandex.practicum.event.dto;
-
-import com.fasterxml.jackson.annotation.JsonFormat;
-import ru.yandex.practicum.category.dto.CategoryDto;
-import ru.yandex.practicum.event.model.EventState;
-import ru.yandex.practicum.user.dto.UserShortDto;
-
-import java.time.LocalDateTime;
-
-import static ru.yandex.practicum.constants.DateTimeConstants.DATE_TIME_PATTERN;
-
-public record EventFullDto(
- Long id,
-
- String annotation,
-
- CategoryDto category,
-
- Long confirmedRequests,
-
- @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = DATE_TIME_PATTERN)
- LocalDateTime createdOn,
-
- String description,
-
- @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = DATE_TIME_PATTERN)
- LocalDateTime eventDate,
-
- UserShortDto initiator,
-
- LocationDto location,
-
- Boolean paid,
-
- Integer participantLimit,
-
- @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = DATE_TIME_PATTERN)
- LocalDateTime publishedOn,
-
- Boolean requestModeration,
-
- EventState state,
-
- String title,
-
- Long views
-) {
-}
diff --git a/core/main-service/src/main/java/ru/yandex/practicum/event/dto/EventShortDto.java b/core/main-service/src/main/java/ru/yandex/practicum/event/dto/EventShortDto.java
deleted file mode 100644
index c70ff6f..0000000
--- a/core/main-service/src/main/java/ru/yandex/practicum/event/dto/EventShortDto.java
+++ /dev/null
@@ -1,31 +0,0 @@
-package ru.yandex.practicum.event.dto;
-
-import com.fasterxml.jackson.annotation.JsonFormat;
-import ru.yandex.practicum.category.dto.CategoryDto;
-import ru.yandex.practicum.user.dto.UserShortDto;
-
-import java.time.LocalDateTime;
-
-import static ru.yandex.practicum.constants.DateTimeConstants.DATE_TIME_PATTERN;
-
-public record EventShortDto(
- Long id,
-
- String annotation,
-
- CategoryDto category,
-
- Long confirmedRequests,
-
- @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = DATE_TIME_PATTERN)
- LocalDateTime eventDate,
-
- UserShortDto initiator,
-
- boolean paid,
-
- String title,
-
- Long views
-) {
-}
diff --git a/core/main-service/src/main/java/ru/yandex/practicum/event/mapper/LocationMapper.java b/core/main-service/src/main/java/ru/yandex/practicum/event/mapper/LocationMapper.java
deleted file mode 100644
index d0297fd..0000000
--- a/core/main-service/src/main/java/ru/yandex/practicum/event/mapper/LocationMapper.java
+++ /dev/null
@@ -1,12 +0,0 @@
-package ru.yandex.practicum.event.mapper;
-
-import org.mapstruct.Mapper;
-import ru.yandex.practicum.event.dto.LocationDto;
-import ru.yandex.practicum.event.model.EventLocation;
-
-@Mapper(componentModel = "spring")
-public interface LocationMapper {
- EventLocation toEventLocation(LocationDto dto);
-
- LocationDto toDto(EventLocation entity);
-}
diff --git a/core/main-service/src/main/java/ru/yandex/practicum/request/dto/ParticipationRequestDto.java b/core/main-service/src/main/java/ru/yandex/practicum/request/dto/ParticipationRequestDto.java
deleted file mode 100644
index b9b4264..0000000
--- a/core/main-service/src/main/java/ru/yandex/practicum/request/dto/ParticipationRequestDto.java
+++ /dev/null
@@ -1,22 +0,0 @@
-package ru.yandex.practicum.request.dto;
-
-import com.fasterxml.jackson.annotation.JsonFormat;
-import ru.yandex.practicum.request.model.RequestStatus;
-
-import java.time.LocalDateTime;
-
-import static ru.yandex.practicum.constants.DateTimeConstants.DATE_TIME_PATTERN;
-
-public record ParticipationRequestDto(
- Long id,
-
- @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = DATE_TIME_PATTERN)
- LocalDateTime created,
-
- Long event,
-
- Long requester,
-
- RequestStatus status
-) {
-}
diff --git a/core/main-service/src/main/java/ru/yandex/practicum/request/mapper/RequestMapper.java b/core/main-service/src/main/java/ru/yandex/practicum/request/mapper/RequestMapper.java
deleted file mode 100644
index 68ae2fe..0000000
--- a/core/main-service/src/main/java/ru/yandex/practicum/request/mapper/RequestMapper.java
+++ /dev/null
@@ -1,29 +0,0 @@
-package ru.yandex.practicum.request.mapper;
-
-import org.mapstruct.Mapper;
-import org.mapstruct.Mapping;
-import ru.yandex.practicum.event.model.Event;
-import ru.yandex.practicum.request.dto.EventRequestStatusUpdateResult;
-import ru.yandex.practicum.request.dto.ParticipationRequestDto;
-import ru.yandex.practicum.request.model.Request;
-import ru.yandex.practicum.request.model.RequestStatus;
-import ru.yandex.practicum.user.model.User;
-
-import java.util.List;
-
-@Mapper(componentModel = "spring")
-public interface RequestMapper {
-
- @Mapping(target = "id", ignore = true)
- @Mapping(target = "created", ignore = true)
- Request toEntity(Event event, User requester, RequestStatus status);
-
- @Mapping(source = "event.id", target = "event")
- @Mapping(source = "requester.id", target = "requester")
- ParticipationRequestDto toDto(Request request);
-
- EventRequestStatusUpdateResult toEventRequestStatusUpdateResultDto(
- List confirmedRequests,
- List rejectedRequests
- );
-}
\ No newline at end of file
diff --git a/core/main-service/src/main/java/ru/yandex/practicum/request/repository/RequestRepository.java b/core/main-service/src/main/java/ru/yandex/practicum/request/repository/RequestRepository.java
deleted file mode 100644
index b450636..0000000
--- a/core/main-service/src/main/java/ru/yandex/practicum/request/repository/RequestRepository.java
+++ /dev/null
@@ -1,56 +0,0 @@
-package ru.yandex.practicum.request.repository;
-
-import org.springframework.data.jpa.repository.JpaRepository;
-import org.springframework.data.jpa.repository.Query;
-import org.springframework.data.repository.query.Param;
-import ru.yandex.practicum.event.dto.EventWithCountConfirmedRequests;
-import ru.yandex.practicum.request.dto.ParticipationRequestDto;
-import ru.yandex.practicum.request.model.Request;
-import ru.yandex.practicum.request.model.RequestStatus;
-
-import java.util.List;
-
-public interface RequestRepository extends JpaRepository {
-
- @Query("""
- SELECT NEW ru.yandex.practicum.event.dto.EventWithCountConfirmedRequests(r.event.id, COUNT(r))
- FROM Request r
- WHERE r.event.id IN :eventIds AND r.status = ru.yandex.practicum.request.model.RequestStatus.CONFIRMED
- GROUP BY r.event.id"""
- )
- List findCountConfirmedRequestsByEventIds(@Param("eventIds") List eventIds);
-
- @Query("""
- SELECT r FROM Request r
- LEFT JOIN FETCH r.event
- LEFT JOIN FETCH r.requester
- WHERE r.event.id = :eventId"""
- )
- List findAllParticipationRequestByEventId(@Param("eventId") Long eventId);
-
- @Query("""
- SELECT r FROM Request r
- LEFT JOIN FETCH r.event
- LEFT JOIN FETCH r.requester
- WHERE r.id IN :requestIds"""
- )
- List findAllRequestById(@Param("requestIds") List requestIds);
-
- @Query("""
- SELECT NEW ru.yandex.practicum.request.dto.ParticipationRequestDto(
- r.id,
- r.created,
- r.event.id,
- r.requester.id,
- r.status)
- FROM Request r
- WHERE r.requester.id = :userId"""
- )
- List findAllRequestsByUserId(@Param("userId") Long userId);
-
- boolean existsByEventIdAndRequesterId(Long eventId, Long userId);
-
- int countByEventIdAndStatus(Long id, RequestStatus requestStatus);
-
- List findAllByEventIdAndStatus(Long eventId, RequestStatus requestStatus);
-}
diff --git a/core/main-service/src/main/java/ru/yandex/practicum/user/model/User.java b/core/main-service/src/main/java/ru/yandex/practicum/user/model/User.java
deleted file mode 100644
index 50270d1..0000000
--- a/core/main-service/src/main/java/ru/yandex/practicum/user/model/User.java
+++ /dev/null
@@ -1,26 +0,0 @@
-package ru.yandex.practicum.user.model;
-
-import jakarta.persistence.*;
-import lombok.EqualsAndHashCode;
-import lombok.Getter;
-import lombok.Setter;
-import lombok.ToString;
-
-@Entity
-@Table(name = "users")
-@Getter
-@Setter
-@ToString
-@EqualsAndHashCode(onlyExplicitlyIncluded = true)
-public class User {
- @Id
- @GeneratedValue(strategy = GenerationType.IDENTITY)
- @EqualsAndHashCode.Include
- private Long id;
-
- @Column(nullable = false)
- private String name;
-
- @Column(nullable = false, unique = true)
- private String email;
-}
diff --git a/core/main-service/src/main/java/ru/yandex/practicum/user/service/UserService.java b/core/main-service/src/main/java/ru/yandex/practicum/user/service/UserService.java
deleted file mode 100644
index ad636a1..0000000
--- a/core/main-service/src/main/java/ru/yandex/practicum/user/service/UserService.java
+++ /dev/null
@@ -1,20 +0,0 @@
-package ru.yandex.practicum.user.service;
-
-import org.springframework.data.domain.Pageable;
-import ru.yandex.practicum.user.dto.NewUserRequest;
-import ru.yandex.practicum.user.dto.UserDto;
-import ru.yandex.practicum.user.model.User;
-
-import java.util.List;
-
-public interface UserService {
- UserDto createUser(NewUserRequest userRequest);
-
- List getUsers(List ids, Pageable pageable);
-
- void deleteUser(Long userId);
-
- User getUserById(Long userId);
-
- User getUserByIdOrThrow(Long userId);
-}
diff --git a/core/main-service/src/main/resources/application.yaml b/core/main-service/src/main/resources/application.yaml
deleted file mode 100644
index 9574515..0000000
--- a/core/main-service/src/main/resources/application.yaml
+++ /dev/null
@@ -1,21 +0,0 @@
-spring:
- application:
- name: main-service
- config:
- import: "configserver:"
- cloud:
- config:
- discovery:
- enabled: true
- service-id: config-server
- fail-fast: true
-
-server:
- port: 0
-
-eureka:
- client:
- serviceUrl:
- defaultZone: http://localhost:8761/eureka/
- instance:
- prefer-ip-address: true
\ No newline at end of file
diff --git a/core/main-service/src/main/resources/schema.sql b/core/main-service/src/main/resources/schema.sql
deleted file mode 100644
index 59365c2..0000000
--- a/core/main-service/src/main/resources/schema.sql
+++ /dev/null
@@ -1,59 +0,0 @@
-create TABLE IF NOT EXISTS categories (
- id BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
- name VARCHAR(50) NOT NULL UNIQUE
-);
-
-create TABLE IF NOT EXISTS users (
- id BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
- name VARCHAR(255) NOT NULL,
- email VARCHAR(255) NOT NULL UNIQUE
-);
-
-create TABLE IF NOT EXISTS events (
- id BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
- title VARCHAR(120) NOT NULL,
- annotation VARCHAR(2000) NOT NULL,
- description VARCHAR(7000) NOT NULL,
- category_id BIGINT REFERENCES categories(id),
- initiator_id BIGINT REFERENCES users (id),
- created_on TIMESTAMP WITHOUT TIME ZONE NOT NULL,
- event_date TIMESTAMP WITHOUT TIME ZONE NOT NULL,
- published_on TIMESTAMP WITHOUT TIME ZONE,
- paid BOOLEAN NOT NULL,
- participant_limit INTEGER NOT NULL,
- request_moderation BOOLEAN NOT NULL,
- state VARCHAR(20) NOT NULL,
- lat FLOAT,
- lon FLOAT
-);
-
-create TABLE IF NOT EXISTS requests (
- id BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
- event_id BIGINT REFERENCES events(id),
- requester_id BIGINT REFERENCES users(id),
- created TIMESTAMP WITHOUT TIME ZONE,
- status VARCHAR(255)
-);
-
-create TABLE IF NOT EXISTS compilations (
- id BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
- title VARCHAR(50) NOT NULL,
- pinned BOOLEAN NOT NULL
-);
-
-create TABLE IF NOT EXISTS compilation_events (
- compilation_id BIGINT NOT NULL REFERENCES compilations (id),
- event_id BIGINT NOT NULL REFERENCES events (id),
- CONSTRAINT pk_compilation_events PRIMARY KEY (compilation_id, event_id)
-);
-
-create TABLE IF NOT EXISTS comments (
- id BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
- text TEXT NOT NULL,
- user_id BIGINT NOT NULL REFERENCES users (id),
- event_id BIGINT NOT NULL REFERENCES events (id),
- created_date TIMESTAMP WITHOUT TIME ZONE NOT NULL
-);
-
-CREATE INDEX IF NOT EXISTS idx_comments_event_id ON comments(event_id);
-CREATE INDEX IF NOT EXISTS idx_comments_user_id ON comments(user_id);
\ No newline at end of file
diff --git a/core/pom.xml b/core/pom.xml
index 18aa957..2b14877 100644
--- a/core/pom.xml
+++ b/core/pom.xml
@@ -14,7 +14,11 @@
pom
- main-service
+ interaction-api
+ request-service
+ user-service
+ comment-service
+ event-service
diff --git a/core/request-service/pom.xml b/core/request-service/pom.xml
new file mode 100644
index 0000000..5e27657
--- /dev/null
+++ b/core/request-service/pom.xml
@@ -0,0 +1,153 @@
+
+
+ 4.0.0
+
+ ru.yandex.practicum
+ core
+ 0.0.1-SNAPSHOT
+
+
+ request-service
+
+
+ 21
+ 21
+ UTF-8
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+
+
+
+ org.springframework.boot
+ spring-boot-starter-validation
+
+
+
+ org.springframework.boot
+ spring-boot-starter-actuator
+
+
+
+ org.springframework.boot
+ spring-boot-starter-data-jpa
+
+
+
+ org.springframework.boot
+ spring-boot-starter-aop
+
+
+
+ ru.yandex.practicum
+ interaction-api
+ ${project.version}
+
+
+
+ ru.yandex.practicum
+ stats-client
+ ${project.version}
+
+
+
+ ru.yandex.practicum
+ stats-dto
+ ${project.version}
+
+
+
+ org.projectlombok
+ lombok
+ provided
+
+
+
+ org.postgresql
+ postgresql
+
+
+
+ org.springframework.cloud
+ spring-cloud-starter-config
+
+
+
+ org.springframework.cloud
+ spring-cloud-starter-netflix-eureka-client
+
+
+
+ org.springframework.cloud
+ spring-cloud-starter-openfeign
+
+
+
+ org.springframework.retry
+ spring-retry
+ 2.0.5
+
+
+
+ io.github.openfeign
+ feign-okhttp
+
+
+
+ org.mapstruct
+ mapstruct
+ ${mapstruct.version}
+
+
+
+ com.h2database
+ h2
+ runtime
+
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+
+
+
+ org.projectlombok
+ lombok
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+ 3.11.0
+
+ 21
+ 21
+
+
+ org.projectlombok
+ lombok
+ ${lombok.version}
+
+
+ org.mapstruct
+ mapstruct-processor
+ ${mapstruct.version}
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/core/request-service/src/main/java/ru/yandex/practicum/RequestServiceApp.java b/core/request-service/src/main/java/ru/yandex/practicum/RequestServiceApp.java
new file mode 100644
index 0000000..9ac7c7e
--- /dev/null
+++ b/core/request-service/src/main/java/ru/yandex/practicum/RequestServiceApp.java
@@ -0,0 +1,15 @@
+package ru.yandex.practicum;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
+import org.springframework.cloud.openfeign.EnableFeignClients;
+
+@SpringBootApplication
+@EnableFeignClients
+@EnableDiscoveryClient
+public class RequestServiceApp {
+ public static void main(String[] args) {
+ SpringApplication.run(RequestServiceApp.class, args);
+ }
+}
diff --git a/core/request-service/src/main/java/ru/yandex/practicum/controller/InternalRequestController.java b/core/request-service/src/main/java/ru/yandex/practicum/controller/InternalRequestController.java
new file mode 100644
index 0000000..49c7d68
--- /dev/null
+++ b/core/request-service/src/main/java/ru/yandex/practicum/controller/InternalRequestController.java
@@ -0,0 +1,19 @@
+package ru.yandex.practicum.controller;
+
+import lombok.RequiredArgsConstructor;
+import org.springframework.web.bind.annotation.*;
+import ru.yandex.practicum.enums.RequestStatus;
+import ru.yandex.practicum.repository.RequestRepository;
+
+@RestController
+@RequestMapping("/internal/requests")
+@RequiredArgsConstructor
+public class InternalRequestController {
+
+ private final RequestRepository requestRepository;
+
+ @GetMapping("/event/{eventId}/count/{status}")
+ public Long countByStatus(@PathVariable Long eventId, @PathVariable RequestStatus status) {
+ return requestRepository.countByEventIdAndStatus(eventId, status);
+ }
+}
diff --git a/core/request-service/src/main/java/ru/yandex/practicum/controller/PrivateEventRequestController.java b/core/request-service/src/main/java/ru/yandex/practicum/controller/PrivateEventRequestController.java
new file mode 100644
index 0000000..f4c1405
--- /dev/null
+++ b/core/request-service/src/main/java/ru/yandex/practicum/controller/PrivateEventRequestController.java
@@ -0,0 +1,42 @@
+package ru.yandex.practicum.controller;
+
+import jakarta.validation.Valid;
+import jakarta.validation.constraints.Positive;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+import ru.yandex.practicum.dto.request.*;
+import ru.yandex.practicum.service.RequestService;
+
+import java.util.List;
+
+@Slf4j
+@Validated
+@RestController
+@RequestMapping("/users/{userId}/events/{eventId}/requests")
+@RequiredArgsConstructor
+public class PrivateEventRequestController {
+ private final RequestService requestService;
+
+ @PatchMapping
+ public EventRequestStatusUpdateResult updateRequestStatus(
+ @PathVariable @Positive Long userId,
+ @PathVariable @Positive Long eventId,
+ @RequestBody @Valid EventRequestStatusUpdateRequest request) {
+
+ log.debug("Controller: updateRequestStatus userId={}, eventId={}, request={}",
+ userId, eventId, request);
+
+ return requestService.updateRequestStatus(userId, eventId, request);
+ }
+
+ @GetMapping
+ public List getEventRequests(
+ @PathVariable @Positive Long userId,
+ @PathVariable @Positive Long eventId) {
+
+ log.debug("Controller: getEventRequests userId={}, eventId={}", userId, eventId);
+ return requestService.getRequestsByEvent(userId, eventId);
+ }
+}
diff --git a/core/main-service/src/main/java/ru/yandex/practicum/request/controller/PrivateRequestController.java b/core/request-service/src/main/java/ru/yandex/practicum/controller/PrivateRequestController.java
similarity index 90%
rename from core/main-service/src/main/java/ru/yandex/practicum/request/controller/PrivateRequestController.java
rename to core/request-service/src/main/java/ru/yandex/practicum/controller/PrivateRequestController.java
index 4dede69..0531cf9 100644
--- a/core/main-service/src/main/java/ru/yandex/practicum/request/controller/PrivateRequestController.java
+++ b/core/request-service/src/main/java/ru/yandex/practicum/controller/PrivateRequestController.java
@@ -1,4 +1,4 @@
-package ru.yandex.practicum.request.controller;
+package ru.yandex.practicum.controller;
import jakarta.validation.constraints.Positive;
import lombok.RequiredArgsConstructor;
@@ -6,8 +6,8 @@
import org.springframework.http.HttpStatus;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
-import ru.yandex.practicum.request.dto.ParticipationRequestDto;
-import ru.yandex.practicum.request.service.RequestService;
+import ru.yandex.practicum.dto.request.ParticipationRequestDto;
+import ru.yandex.practicum.service.RequestService;
import java.util.List;
diff --git a/core/request-service/src/main/java/ru/yandex/practicum/handler/ErrorHandler.java b/core/request-service/src/main/java/ru/yandex/practicum/handler/ErrorHandler.java
new file mode 100644
index 0000000..6c1ca58
--- /dev/null
+++ b/core/request-service/src/main/java/ru/yandex/practicum/handler/ErrorHandler.java
@@ -0,0 +1,149 @@
+package ru.yandex.practicum.handler;
+
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.validation.ConstraintViolationException;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.context.MessageSourceResolvable;
+import org.springframework.http.HttpStatus;
+import org.springframework.web.HttpMediaTypeNotSupportedException;
+import org.springframework.web.HttpRequestMethodNotSupportedException;
+import org.springframework.web.bind.MethodArgumentNotValidException;
+import org.springframework.web.bind.ServletRequestBindingException;
+import org.springframework.web.bind.annotation.ExceptionHandler;
+import org.springframework.web.bind.annotation.ResponseStatus;
+import org.springframework.web.bind.annotation.RestControllerAdvice;
+import org.springframework.web.method.annotation.HandlerMethodValidationException;
+import org.springframework.web.servlet.NoHandlerFoundException;
+import ru.yandex.practicum.exception.*;
+
+import java.util.stream.Collectors;
+
+@Slf4j
+@RestControllerAdvice
+public class ErrorHandler {
+
+ @ExceptionHandler(NotFoundException.class)
+ @ResponseStatus(HttpStatus.NOT_FOUND)
+ public ErrorResponse handleNotFoundException(NotFoundException exception, HttpServletRequest request) {
+ return buildResponse(HttpStatus.NOT_FOUND, exception, request);
+ }
+
+ @ExceptionHandler(BadRequestException.class)
+ @ResponseStatus(HttpStatus.BAD_REQUEST)
+ public ErrorResponse handleBadRequestException(BadRequestException exception, HttpServletRequest request) {
+ return buildResponse(HttpStatus.BAD_REQUEST, exception, request);
+ }
+
+ @ExceptionHandler(ForbiddenException.class)
+ @ResponseStatus(HttpStatus.FORBIDDEN)
+ public ErrorResponse handleForbiddenException(ForbiddenException exception, HttpServletRequest request) {
+ return buildResponse(HttpStatus.FORBIDDEN, exception, request);
+ }
+
+ @ExceptionHandler(ConflictException.class)
+ @ResponseStatus(HttpStatus.CONFLICT)
+ public ErrorResponse handleConflictException(ConflictException exception, HttpServletRequest request) {
+ return buildResponse(HttpStatus.CONFLICT, exception, request);
+ }
+
+ @ExceptionHandler(ValidationException.class)
+ @ResponseStatus(HttpStatus.CONFLICT)
+ public ErrorResponse handleValidationException(ValidationException exception, HttpServletRequest request) {
+ return buildResponse(HttpStatus.CONFLICT, exception, request);
+ }
+
+ @ExceptionHandler(ConstraintViolationException.class)
+ @ResponseStatus(HttpStatus.BAD_REQUEST)
+ public ErrorResponse handleConstraintViolation(
+ ConstraintViolationException ex, HttpServletRequest request) {
+ String violations = ex.getConstraintViolations().stream()
+ .map(violation -> violation.getPropertyPath() + ": " + violation.getMessage())
+ .collect(Collectors.joining("; "));
+
+ String message = violations.isEmpty() ? "Constraint violation" : violations;
+ return buildResponse(HttpStatus.BAD_REQUEST, message, null, request);
+ }
+
+ @ExceptionHandler(MethodArgumentNotValidException.class)
+ @ResponseStatus(HttpStatus.BAD_REQUEST)
+ public ErrorResponse handleMethodArgumentNotValid(
+ MethodArgumentNotValidException ex, HttpServletRequest request) {
+ String validationErrors = ex.getBindingResult().getFieldErrors().stream()
+ .map(error -> error.getField() + ": " + error.getDefaultMessage())
+ .collect(Collectors.joining("; "));
+
+ String message = validationErrors.isEmpty() ? "Validation failed" : validationErrors;
+
+ return buildResponse(HttpStatus.BAD_REQUEST, message, null, request);
+ }
+
+ @ExceptionHandler(HandlerMethodValidationException.class)
+ @ResponseStatus(HttpStatus.BAD_REQUEST)
+ public ErrorResponse handleHandlerMethodValidation(
+ HandlerMethodValidationException ex, HttpServletRequest request) {
+ String validationErrors = ex.getAllErrors().stream()
+ .map(MessageSourceResolvable::getDefaultMessage)
+ .collect(Collectors.joining("; "));
+
+ String message = validationErrors.isEmpty() ? "Validation failed" : validationErrors;
+
+ return buildResponse(HttpStatus.BAD_REQUEST, message, null, request);
+ }
+
+ @ExceptionHandler(ServletRequestBindingException.class)
+ @ResponseStatus(HttpStatus.BAD_REQUEST)
+ public ErrorResponse handleServletRequestBindingException(
+ ServletRequestBindingException ex, HttpServletRequest request) {
+ return buildResponse(HttpStatus.BAD_REQUEST, ex.getMessage(), null, request);
+ }
+
+ @ExceptionHandler(HttpRequestMethodNotSupportedException.class)
+ @ResponseStatus(HttpStatus.METHOD_NOT_ALLOWED)
+ public ErrorResponse handleHttpRequestMethodNotSupported(
+ HttpRequestMethodNotSupportedException ex, HttpServletRequest request) {
+ return buildResponse(HttpStatus.METHOD_NOT_ALLOWED, ex.getMessage(), null, request);
+ }
+
+ @ExceptionHandler(HttpMediaTypeNotSupportedException.class)
+ @ResponseStatus(HttpStatus.UNSUPPORTED_MEDIA_TYPE)
+ public ErrorResponse handleHttpMediaTypeNotSupported(
+ HttpMediaTypeNotSupportedException ex, HttpServletRequest request) {
+ return buildResponse(HttpStatus.UNSUPPORTED_MEDIA_TYPE, ex.getMessage(), null, request);
+ }
+
+ @ExceptionHandler(NoHandlerFoundException.class)
+ @ResponseStatus(HttpStatus.NOT_FOUND)
+ public ErrorResponse handleNoHandlerFoundException(
+ NoHandlerFoundException ex, HttpServletRequest request) {
+ return buildResponse(HttpStatus.NOT_FOUND, ex.getMessage(), null, request);
+ }
+
+ @ExceptionHandler(Exception.class)
+ @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
+ public ErrorResponse handleUnexpected(Exception exception, HttpServletRequest request) {
+ return buildResponse(HttpStatus.INTERNAL_SERVER_ERROR, exception, request);
+ }
+
+ private ErrorResponse buildResponse(
+ HttpStatus httpStatus, Exception exception, HttpServletRequest request) {
+ return buildResponse(httpStatus, exception.getMessage(), exception, request);
+ }
+
+ private ErrorResponse buildResponse(
+ HttpStatus httpStatus, String message, Exception exception, HttpServletRequest request) {
+ String path = request.getRequestURI();
+ String httpMethod = request.getMethod();
+ int statusCode = httpStatus.value();
+ String error = httpStatus.getReasonPhrase();
+
+ String logMessage = String.format("Path: %s %s, '%d' %s — %s", httpMethod, path, statusCode, error, message);
+
+ if (statusCode >= 500) {
+ log.error(logMessage, exception);
+ } else {
+ log.warn(logMessage);
+ }
+
+ return new ErrorResponse(path, httpMethod, statusCode, error, message);
+ }
+}
diff --git a/core/request-service/src/main/java/ru/yandex/practicum/mapper/RequestMapper.java b/core/request-service/src/main/java/ru/yandex/practicum/mapper/RequestMapper.java
new file mode 100644
index 0000000..9f442e1
--- /dev/null
+++ b/core/request-service/src/main/java/ru/yandex/practicum/mapper/RequestMapper.java
@@ -0,0 +1,15 @@
+package ru.yandex.practicum.mapper;
+
+import org.mapstruct.Mapper;
+import ru.yandex.practicum.dto.request.ParticipationRequestDto;
+import ru.yandex.practicum.model.Request;
+
+import java.util.List;
+
+@Mapper(componentModel = "spring")
+public interface RequestMapper {
+
+ ParticipationRequestDto toDto(Request request);
+
+ List toDtoList(List requests);
+}
\ No newline at end of file
diff --git a/core/main-service/src/main/java/ru/yandex/practicum/request/model/Request.java b/core/request-service/src/main/java/ru/yandex/practicum/model/Request.java
similarity index 51%
rename from core/main-service/src/main/java/ru/yandex/practicum/request/model/Request.java
rename to core/request-service/src/main/java/ru/yandex/practicum/model/Request.java
index 1c69cf6..425081c 100644
--- a/core/main-service/src/main/java/ru/yandex/practicum/request/model/Request.java
+++ b/core/request-service/src/main/java/ru/yandex/practicum/model/Request.java
@@ -1,38 +1,42 @@
-package ru.yandex.practicum.request.model;
+package ru.yandex.practicum.model;
import jakarta.persistence.*;
-import lombok.EqualsAndHashCode;
-import lombok.Getter;
-import lombok.Setter;
+import lombok.*;
import org.hibernate.annotations.CreationTimestamp;
-import ru.yandex.practicum.event.model.Event;
-import ru.yandex.practicum.user.model.User;
+import ru.yandex.practicum.enums.RequestStatus;
import java.time.LocalDateTime;
@Entity
-@Table(name = "requests")
+@Table(name = "requests",
+ uniqueConstraints = {@UniqueConstraint(
+ columnNames = {"requester_id", "event_id"},
+ name = "uq_requester_event")}
+)
@Getter
@Setter
-@EqualsAndHashCode(onlyExplicitlyIncluded = true)
+@AllArgsConstructor
+@NoArgsConstructor
+@Builder
+@ToString
public class Request {
+
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
- @EqualsAndHashCode.Include
private Long id;
- @ManyToOne(fetch = FetchType.LAZY)
- @JoinColumn(name = "event_id")
- private Event event;
+ @Column(name = "event_id", nullable = false)
+ private Long eventId;
- @ManyToOne(fetch = FetchType.LAZY)
- @JoinColumn(name = "requester_id")
- private User requester;
+ @Column(name = "requester_id", nullable = false)
+ private Long requesterId;
@CreationTimestamp
+ @Column(nullable = false, updatable = false)
private LocalDateTime created;
@Enumerated(EnumType.STRING)
+ @Column(nullable = false, length = 60)
private RequestStatus status;
public void confirmed() {
diff --git a/core/request-service/src/main/java/ru/yandex/practicum/repository/RequestRepository.java b/core/request-service/src/main/java/ru/yandex/practicum/repository/RequestRepository.java
new file mode 100644
index 0000000..fe99db6
--- /dev/null
+++ b/core/request-service/src/main/java/ru/yandex/practicum/repository/RequestRepository.java
@@ -0,0 +1,33 @@
+package ru.yandex.practicum.repository;
+
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.data.jpa.repository.Query;
+import org.springframework.data.repository.query.Param;
+import ru.yandex.practicum.enums.RequestStatus;
+import ru.yandex.practicum.model.Request;
+
+import java.util.List;
+import java.util.Optional;
+
+public interface RequestRepository extends JpaRepository {
+
+ boolean existsByRequesterIdAndEventId(Long requesterId, Long eventId);
+
+ List findByRequesterId(Long requesterId);
+
+ List findByEventId(Long eventId);
+
+ Optional findByIdAndRequesterId(Long id, Long requesterId);
+
+ long countByEventIdAndStatus(Long eventId, RequestStatus status);
+
+ List findByEventIdAndStatus(Long eventId, RequestStatus status);
+
+ List findByIdIn(List ids);
+
+ @Query("SELECT r.eventId, " +
+ "COUNT(r) " +
+ "FROM Request r " +
+ "WHERE r.eventId IN :eventIds AND r.status = 'CONFIRMED' GROUP BY r.eventId")
+ List