diff --git a/ewm-feature-comments-spec.json b/API-comment-service-specification.json
similarity index 100%
rename from ewm-feature-comments-spec.json
rename to API-comment-service-specification.json
diff --git a/ewm-main-service-spec.json b/API-event-service-specification.json
similarity index 76%
rename from ewm-main-service-spec.json
rename to API-event-service-specification.json
index f28d141..3de2ee2 100644
--- a/ewm-main-service-spec.json
+++ b/API-event-service-specification.json
@@ -2,7 +2,7 @@
"openapi": "3.0.1",
"info": {
"description": "Documentation \"Explore With Me\" API v1.0",
- "title": "\"Explore With Me\" API сервер",
+ "title": "Explore With Me - EVENT-SERVICE API",
"version": "1.0"
},
"servers": [
@@ -36,14 +36,6 @@
"description": "Публичный API для работы с событиями",
"name": "Public: События"
},
- {
- "description": "Закрытый API для работы с запросами текущего пользователя на участие в событиях",
- "name": "Private: Запросы на участие"
- },
- {
- "description": "API для работы с пользователями",
- "name": "Admin: Пользователи"
- },
{
"description": "API для работы с подборками событий",
"name": "Admin: Подборки событий"
@@ -612,189 +604,6 @@
]
}
},
- "/admin/users": {
- "get": {
- "description": "Возвращает информацию обо всех пользователях (учитываются параметры ограничения выборки), либо о конкретных (учитываются указанные идентификаторы)\n\nВ случае, если по заданным фильтрам не найдено ни одного пользователя, возвращает пустой список",
- "operationId": "getUsers",
- "parameters": [
- {
- "description": "id пользователей",
- "in": "query",
- "name": "ids",
- "required": false,
- "schema": {
- "type": "array",
- "items": {
- "type": "integer",
- "format": "int64"
- }
- }
- },
- {
- "description": "количество элементов, которые нужно пропустить для формирования текущего набора",
- "in": "query",
- "name": "from",
- "required": false,
- "schema": {
- "minimum": 0,
- "type": "integer",
- "format": "int32",
- "default": 0
- }
- },
- {
- "description": "количество элементов в наборе",
- "in": "query",
- "name": "size",
- "required": false,
- "schema": {
- "type": "integer",
- "format": "int32",
- "default": 10
- }
- }
- ],
- "responses": {
- "200": {
- "content": {
- "application/json": {
- "schema": {
- "type": "array",
- "items": {
- "$ref": "#/components/schemas/UserDto"
- }
- }
- }
- },
- "description": "Пользователи найдены"
- },
- "400": {
- "content": {
- "application/json": {
- "example": {
- "status": "BAD_REQUEST",
- "reason": "Incorrectly made request.",
- "message": "Failed to convert value of type java.lang.String to required type int; nested exception is java.lang.NumberFormatException: For input string: ad",
- "timestamp": "2022-09-07 09:10:50"
- },
- "schema": {
- "$ref": "#/components/schemas/ApiError"
- }
- }
- },
- "description": "Запрос составлен некорректно"
- }
- },
- "summary": "Получение информации о пользователях",
- "tags": [
- "Admin: Пользователи"
- ]
- },
- "post": {
- "operationId": "registerUser",
- "requestBody": {
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/NewUserRequest"
- }
- }
- },
- "description": "Данные добавляемого пользователя",
- "required": true
- },
- "responses": {
- "201": {
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/UserDto"
- }
- }
- },
- "description": "Пользователь зарегистрирован"
- },
- "400": {
- "content": {
- "application/json": {
- "example": {
- "status": "BAD_REQUEST",
- "reason": "Incorrectly made request.",
- "message": "Field: name. Error: must not be blank. Value: null",
- "timestamp": "2022-09-07 09:10:50"
- },
- "schema": {
- "$ref": "#/components/schemas/ApiError"
- }
- }
- },
- "description": "Запрос составлен некорректно"
- },
- "409": {
- "content": {
- "application/json": {
- "example": {
- "status": "CONFLICT",
- "reason": "Integrity constraint has been violated.",
- "message": "could not execute statement; SQL [n/a]; constraint [uq_email]; nested exception is org.hibernate.exception.ConstraintViolationException: could not execute statement",
- "timestamp": "2022-09-07 09:10:50"
- },
- "schema": {
- "$ref": "#/components/schemas/ApiError"
- }
- }
- },
- "description": "Нарушение целостности данных"
- }
- },
- "summary": "Добавление нового пользователя",
- "tags": [
- "Admin: Пользователи"
- ]
- }
- },
- "/admin/users/{userId}": {
- "delete": {
- "operationId": "delete",
- "parameters": [
- {
- "description": "id пользователя",
- "in": "path",
- "name": "userId",
- "required": true,
- "schema": {
- "type": "integer",
- "format": "int64"
- }
- }
- ],
- "responses": {
- "204": {
- "description": "Пользователь удален"
- },
- "404": {
- "content": {
- "application/json": {
- "example": {
- "status": "NOT_FOUND",
- "reason": "The required object was not found.",
- "message": "User with id=555 was not found",
- "timestamp": "2022-09-07 09:10:50"
- },
- "schema": {
- "$ref": "#/components/schemas/ApiError"
- }
- }
- },
- "description": "Пользователь не найден или недоступен"
- }
- },
- "summary": "Удаление пользователя",
- "tags": [
- "Admin: Пользователи"
- ]
- }
- },
"/categories": {
"get": {
"description": "В случае, если по заданным фильтрам не найдено ни одной категории, возвращает пустой список",
@@ -1601,414 +1410,32 @@
"Private: События"
]
}
- },
- "/users/{userId}/events/{eventId}/requests": {
- "get": {
- "description": "В случае, если по заданным фильтрам не найдено ни одной заявки, возвращает пустой список",
- "operationId": "getEventParticipants",
- "parameters": [
- {
- "description": "id текущего пользователя",
- "in": "path",
- "name": "userId",
- "required": true,
- "schema": {
- "type": "integer",
- "format": "int64"
+ }
+ },
+ "components": {
+ "schemas": {
+ "ApiError": {
+ "type": "object",
+ "properties": {
+ "errors": {
+ "type": "array",
+ "description": "Список стектрейсов или описания ошибок",
+ "example": [],
+ "items": {
+ "type": "string",
+ "description": "Список стектрейсов или описания ошибок",
+ "example": "[]"
}
},
- {
- "description": "id события",
- "in": "path",
- "name": "eventId",
- "required": true,
- "schema": {
- "type": "integer",
- "format": "int64"
- }
- }
- ],
- "responses": {
- "200": {
- "content": {
- "application/json": {
- "schema": {
- "type": "array",
- "items": {
- "$ref": "#/components/schemas/ParticipationRequestDto"
- }
- }
- }
- },
- "description": "Найдены запросы на участие"
+ "message": {
+ "type": "string",
+ "description": "Сообщение об ошибке",
+ "example": "Only pending or canceled events can be changed"
},
- "400": {
- "content": {
- "application/json": {
- "example": {
- "status": "BAD_REQUEST",
- "reason": "Incorrectly made request.",
- "message": "Failed to convert value of type java.lang.String to required type int; nested exception is java.lang.NumberFormatException: For input string: ad",
- "timestamp": "2022-09-07 09:10:50"
- },
- "schema": {
- "$ref": "#/components/schemas/ApiError"
- }
- }
- },
- "description": "Запрос составлен некорректно"
- }
- },
- "summary": "Получение информации о запросах на участие в событии текущего пользователя",
- "tags": [
- "Private: События"
- ]
- },
- "patch": {
- "description": "Обратите внимание:\n- если для события лимит заявок равен 0 или отключена пре-модерация заявок, то подтверждение заявок не требуется\n- нельзя подтвердить заявку, если уже достигнут лимит по заявкам на данное событие (Ожидается код ошибки 409)\n- статус можно изменить только у заявок, находящихся в состоянии ожидания (Ожидается код ошибки 409)\n- если при подтверждении данной заявки, лимит заявок для события исчерпан, то все неподтверждённые заявки необходимо отклонить",
- "operationId": "changeRequestStatus",
- "parameters": [
- {
- "description": "id текущего пользователя",
- "in": "path",
- "name": "userId",
- "required": true,
- "schema": {
- "type": "integer",
- "format": "int64"
- }
- },
- {
- "description": "id события текущего пользователя",
- "in": "path",
- "name": "eventId",
- "required": true,
- "schema": {
- "type": "integer",
- "format": "int64"
- }
- }
- ],
- "requestBody": {
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/EventRequestStatusUpdateRequest"
- }
- }
- },
- "description": "Новый статус для заявок на участие в событии текущего пользователя",
- "required": true
- },
- "responses": {
- "200": {
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/EventRequestStatusUpdateResult"
- }
- }
- },
- "description": "Статус заявок изменён"
- },
- "400": {
- "content": {
- "application/json": {
- "example": {
- "status": "BAD_REQUEST",
- "reason": "Incorrectly made request.",
- "message": "Request must have status PENDING",
- "timestamp": "2022-09-07 09:10:50"
- },
- "schema": {
- "$ref": "#/components/schemas/ApiError"
- }
- }
- },
- "description": "Запрос составлен некорректно"
- },
- "404": {
- "content": {
- "application/json": {
- "example": {
- "status": "NOT_FOUND",
- "reason": "The required object was not found.",
- "message": "Event with id=321 was not found",
- "timestamp": "2022-09-07 09:10:50"
- },
- "schema": {
- "$ref": "#/components/schemas/ApiError"
- }
- }
- },
- "description": "Событие не найдено или недоступно"
- },
- "409": {
- "content": {
- "application/json": {
- "example": {
- "status": "CONFLICT",
- "reason": "For the requested operation the conditions are not met.",
- "message": "The participant limit has been reached",
- "timestamp": "2022-09-07 09:10:50"
- },
- "schema": {
- "$ref": "#/components/schemas/ApiError"
- }
- }
- },
- "description": "Достигнут лимит одобренных заявок"
- }
- },
- "summary": "Изменение статуса (подтверждена, отменена) заявок на участие в событии текущего пользователя",
- "tags": [
- "Private: События"
- ]
- }
- },
- "/users/{userId}/requests": {
- "get": {
- "description": "В случае, если по заданным фильтрам не найдено ни одной заявки, возвращает пустой список",
- "operationId": "getUserRequests",
- "parameters": [
- {
- "description": "id текущего пользователя",
- "in": "path",
- "name": "userId",
- "required": true,
- "schema": {
- "type": "integer",
- "format": "int64"
- }
- }
- ],
- "responses": {
- "200": {
- "content": {
- "application/json": {
- "schema": {
- "type": "array",
- "items": {
- "$ref": "#/components/schemas/ParticipationRequestDto"
- }
- }
- }
- },
- "description": "Найдены запросы на участие"
- },
- "400": {
- "content": {
- "application/json": {
- "example": {
- "status": "BAD_REQUEST",
- "reason": "Incorrectly made request.",
- "message": "Failed to convert value of type java.lang.String to required type long; nested exception is java.lang.NumberFormatException: For input string: ad",
- "timestamp": "2022-09-07 09:10:50"
- },
- "schema": {
- "$ref": "#/components/schemas/ApiError"
- }
- }
- },
- "description": "Запрос составлен некорректно"
- },
- "404": {
- "content": {
- "application/json": {
- "example": {
- "status": "NOT_FOUND",
- "reason": "The required object was not found.",
- "message": "User with id=11 was not found",
- "timestamp": "2022-09-07 09:10:50"
- },
- "schema": {
- "$ref": "#/components/schemas/ApiError"
- }
- }
- },
- "description": "Пользователь не найден"
- }
- },
- "summary": "Получение информации о заявках текущего пользователя на участие в чужих событиях",
- "tags": [
- "Private: Запросы на участие"
- ]
- },
- "post": {
- "description": "Обратите внимание:\n- нельзя добавить повторный запрос (Ожидается код ошибки 409)\n- инициатор события не может добавить запрос на участие в своём событии (Ожидается код ошибки 409)\n- нельзя участвовать в неопубликованном событии (Ожидается код ошибки 409)\n- если у события достигнут лимит запросов на участие - необходимо вернуть ошибку (Ожидается код ошибки 409)\n- если для события отключена пре-модерация запросов на участие, то запрос должен автоматически перейти в состояние подтвержденного",
- "operationId": "addParticipationRequest",
- "parameters": [
- {
- "description": "id текущего пользователя",
- "in": "path",
- "name": "userId",
- "required": true,
- "schema": {
- "type": "integer",
- "format": "int64"
- }
- },
- {
- "description": "id события",
- "in": "query",
- "name": "eventId",
- "required": true,
- "schema": {
- "type": "integer",
- "format": "int64"
- }
- }
- ],
- "responses": {
- "201": {
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/ParticipationRequestDto"
- }
- }
- },
- "description": "Заявка создана"
- },
- "400": {
- "content": {
- "application/json": {
- "example": {
- "status": "BAD_REQUEST",
- "reason": "Incorrectly made request.",
- "message": "Failed to convert value of type java.lang.String to required type long; nested exception is java.lang.NumberFormatException: For input string: ad",
- "timestamp": "2022-09-07 09:10:50"
- },
- "schema": {
- "$ref": "#/components/schemas/ApiError"
- }
- }
- },
- "description": "Запрос составлен некорректно"
- },
- "404": {
- "content": {
- "application/json": {
- "example": {
- "status": "NOT_FOUND",
- "reason": "The required object was not found.",
- "message": "Event with id=13 was not found",
- "timestamp": "2022-09-07 09:10:50"
- },
- "schema": {
- "$ref": "#/components/schemas/ApiError"
- }
- }
- },
- "description": "Событие не найдено или недоступно"
- },
- "409": {
- "content": {
- "application/json": {
- "example": {
- "status": "CONFLICT",
- "reason": "Integrity constraint has been violated.",
- "message": "could not execute statement; SQL [n/a]; constraint [uq_request]; nested exception is org.hibernate.exception.ConstraintViolationException: could not execute statement",
- "timestamp": "2022-09-07 09:10:50"
- },
- "schema": {
- "$ref": "#/components/schemas/ApiError"
- }
- }
- },
- "description": "Нарушение целостности данных"
- }
- },
- "summary": "Добавление запроса от текущего пользователя на участие в событии",
- "tags": [
- "Private: Запросы на участие"
- ]
- }
- },
- "/users/{userId}/requests/{requestId}/cancel": {
- "patch": {
- "operationId": "cancelRequest",
- "parameters": [
- {
- "description": "id текущего пользователя",
- "in": "path",
- "name": "userId",
- "required": true,
- "schema": {
- "type": "integer",
- "format": "int64"
- }
- },
- {
- "description": "id запроса на участие",
- "in": "path",
- "name": "requestId",
- "required": true,
- "schema": {
- "type": "integer",
- "format": "int64"
- }
- }
- ],
- "responses": {
- "200": {
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/ParticipationRequestDto"
- }
- }
- },
- "description": "Заявка отменена"
- },
- "404": {
- "content": {
- "application/json": {
- "example": {
- "status": "NOT_FOUND",
- "reason": "The required object was not found.",
- "message": "Request with id=2727 was not found",
- "timestamp": "2022-09-07 09:10:50"
- },
- "schema": {
- "$ref": "#/components/schemas/ApiError"
- }
- }
- },
- "description": "Запрос не найден или недоступен"
- }
- },
- "summary": "Отмена своего запроса на участие в событии",
- "tags": [
- "Private: Запросы на участие"
- ]
- }
- }
- },
- "components": {
- "schemas": {
- "ApiError": {
- "type": "object",
- "properties": {
- "errors": {
- "type": "array",
- "description": "Список стектрейсов или описания ошибок",
- "example": [],
- "items": {
- "type": "string",
- "description": "Список стектрейсов или описания ошибок",
- "example": "[]"
- }
- },
- "message": {
- "type": "string",
- "description": "Сообщение об ошибке",
- "example": "Only pending or canceled events can be changed"
- },
- "reason": {
- "type": "string",
- "description": "Общее описание причины ошибки",
- "example": "For the requested operation the conditions are not met."
+ "reason": {
+ "type": "string",
+ "description": "Общее описание причины ошибки",
+ "example": "For the requested operation the conditions are not met."
},
"status": {
"type": "string",
@@ -2286,53 +1713,6 @@
}
}
},
- "EventRequestStatusUpdateRequest": {
- "type": "object",
- "properties": {
- "requestIds": {
- "type": "array",
- "description": "Идентификаторы запросов на участие в событии текущего пользователя",
- "example": [
- 1,
- 2,
- 3
- ],
- "items": {
- "type": "integer",
- "description": "Идентификаторы запросов на участие в событии текущего пользователя",
- "format": "int64"
- }
- },
- "status": {
- "type": "string",
- "description": "Новый статус запроса на участие в событии текущего пользователя",
- "example": "CONFIRMED",
- "enum": [
- "CONFIRMED",
- "REJECTED"
- ]
- }
- },
- "description": "Изменение статуса запроса на участие в событии текущего пользователя"
- },
- "EventRequestStatusUpdateResult": {
- "type": "object",
- "properties": {
- "confirmedRequests": {
- "type": "array",
- "items": {
- "$ref": "#/components/schemas/ParticipationRequestDto"
- }
- },
- "rejectedRequests": {
- "type": "array",
- "items": {
- "$ref": "#/components/schemas/ParticipationRequestDto"
- }
- }
- },
- "description": "Результат подтверждения/отклонения заявок на участие в событии"
- },
"EventShortDto": {
"required": [
"annotation",
@@ -2590,40 +1970,6 @@
},
"description": "Данные нового пользователя"
},
- "ParticipationRequestDto": {
- "type": "object",
- "properties": {
- "created": {
- "type": "string",
- "description": "Дата и время создания заявки",
- "example": "2022-09-06T21:10:05.432"
- },
- "event": {
- "type": "integer",
- "description": "Идентификатор события",
- "format": "int64",
- "example": 1
- },
- "id": {
- "type": "integer",
- "description": "Идентификатор заявки",
- "format": "int64",
- "example": 3
- },
- "requester": {
- "type": "integer",
- "description": "Идентификатор пользователя, отправившего заявку",
- "format": "int64",
- "example": 2
- },
- "status": {
- "type": "string",
- "description": "Статус заявки",
- "example": "PENDING"
- }
- },
- "description": "Заявка на участие в событии"
- },
"UpdateCompilationRequest": {
"type": "object",
"properties": {
@@ -2833,4 +2179,4 @@
}
}
}
-}
+}
\ No newline at end of file
diff --git a/API-request-service-specification.json b/API-request-service-specification.json
new file mode 100644
index 0000000..ba9d56a
--- /dev/null
+++ b/API-request-service-specification.json
@@ -0,0 +1,599 @@
+{
+ "openapi": "3.0.1",
+ "info": {
+ "description": "Documentation \"Explore With Me\" API v1.0",
+ "title": "Explore With Me - REQUEST SERVICE API",
+ "version": "1.0"
+ },
+ "servers": [
+ {
+ "description": "Generated server url",
+ "url": "http://localhost:8080"
+ }
+ ],
+ "tags": [
+ {
+ "description": "Закрытый API для работы с событиями",
+ "name": "Private: События"
+ },
+ {
+ "description": "Закрытый API для работы с запросами на участие в событиях",
+ "name": "Private: Запросы на участие"
+ }
+ ],
+ "paths": {
+ "/users/{userId}/events/{eventId}/requests": {
+ "get": {
+ "description": "В случае, если по заданным фильтрам не найдено ни одной заявки, возвращает пустой список",
+ "operationId": "getEventParticipants",
+ "parameters": [
+ {
+ "description": "id текущего пользователя",
+ "in": "path",
+ "name": "userId",
+ "required": true,
+ "schema": {
+ "type": "integer",
+ "format": "int64"
+ }
+ },
+ {
+ "description": "id события",
+ "in": "path",
+ "name": "eventId",
+ "required": true,
+ "schema": {
+ "type": "integer",
+ "format": "int64"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/ParticipationRequestDto"
+ }
+ }
+ }
+ },
+ "description": "Найдены запросы на участие"
+ },
+ "400": {
+ "content": {
+ "application/json": {
+ "example": {
+ "status": "BAD_REQUEST",
+ "reason": "Incorrectly made request.",
+ "message": "Failed to convert value of type java.lang.String to required type int; nested exception is java.lang.NumberFormatException: For input string: ad",
+ "timestamp": "2022-09-07 09:10:50"
+ },
+ "schema": {
+ "$ref": "#/components/schemas/ApiError"
+ }
+ }
+ },
+ "description": "Запрос составлен некорректно"
+ }
+ },
+ "summary": "Получение информации о запросах на участие в событии текущего пользователя",
+ "tags": [
+ "Private: События"
+ ]
+ },
+ "patch": {
+ "description": "Обратите внимание:\n- если для события лимит заявок равен 0 или отключена пре-модерация заявок, то подтверждение заявок не требуется\n- нельзя подтвердить заявку, если уже достигнут лимит по заявкам на данное событие (Ожидается код ошибки 409)\n- статус можно изменить только у заявок, находящихся в состоянии ожидания (Ожидается код ошибки 409)\n- если при подтверждении данной заявки, лимит заявок для события исчерпан, то все неподтверждённые заявки необходимо отклонить",
+ "operationId": "changeRequestStatus",
+ "parameters": [
+ {
+ "description": "id текущего пользователя",
+ "in": "path",
+ "name": "userId",
+ "required": true,
+ "schema": {
+ "type": "integer",
+ "format": "int64"
+ }
+ },
+ {
+ "description": "id события текущего пользователя",
+ "in": "path",
+ "name": "eventId",
+ "required": true,
+ "schema": {
+ "type": "integer",
+ "format": "int64"
+ }
+ }
+ ],
+ "requestBody": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/EventRequestStatusUpdateRequest"
+ }
+ }
+ },
+ "description": "Новый статус для заявок на участие в событии текущего пользователя",
+ "required": true
+ },
+ "responses": {
+ "200": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/EventRequestStatusUpdateResult"
+ }
+ }
+ },
+ "description": "Статус заявок изменён"
+ },
+ "400": {
+ "content": {
+ "application/json": {
+ "example": {
+ "status": "BAD_REQUEST",
+ "reason": "Incorrectly made request.",
+ "message": "Request must have status PENDING",
+ "timestamp": "2022-09-07 09:10:50"
+ },
+ "schema": {
+ "$ref": "#/components/schemas/ApiError"
+ }
+ }
+ },
+ "description": "Запрос составлен некорректно"
+ },
+ "404": {
+ "content": {
+ "application/json": {
+ "example": {
+ "status": "NOT_FOUND",
+ "reason": "The required object was not found.",
+ "message": "Event with id=321 was not found",
+ "timestamp": "2022-09-07 09:10:50"
+ },
+ "schema": {
+ "$ref": "#/components/schemas/ApiError"
+ }
+ }
+ },
+ "description": "Событие не найдено или недоступно"
+ },
+ "409": {
+ "content": {
+ "application/json": {
+ "example": {
+ "status": "CONFLICT",
+ "reason": "For the requested operation the conditions are not met.",
+ "message": "The participant limit has been reached",
+ "timestamp": "2022-09-07 09:10:50"
+ },
+ "schema": {
+ "$ref": "#/components/schemas/ApiError"
+ }
+ }
+ },
+ "description": "Достигнут лимит одобренных заявок"
+ }
+ },
+ "summary": "Изменение статуса (подтверждена, отменена) заявок на участие в событии текущего пользователя",
+ "tags": [
+ "Private: События"
+ ]
+ }
+ },
+ "/users/{userId}/requests": {
+ "get": {
+ "description": "В случае, если по заданным фильтрам не найдено ни одной заявки, возвращает пустой список",
+ "operationId": "getUserRequests",
+ "parameters": [
+ {
+ "description": "id текущего пользователя",
+ "in": "path",
+ "name": "userId",
+ "required": true,
+ "schema": {
+ "type": "integer",
+ "format": "int64"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/ParticipationRequestDto"
+ }
+ }
+ }
+ },
+ "description": "Найдены запросы на участие"
+ },
+ "400": {
+ "content": {
+ "application/json": {
+ "example": {
+ "status": "BAD_REQUEST",
+ "reason": "Incorrectly made request.",
+ "message": "Failed to convert value of type java.lang.String to required type long; nested exception is java.lang.NumberFormatException: For input string: ad",
+ "timestamp": "2022-09-07 09:10:50"
+ },
+ "schema": {
+ "$ref": "#/components/schemas/ApiError"
+ }
+ }
+ },
+ "description": "Запрос составлен некорректно"
+ },
+ "404": {
+ "content": {
+ "application/json": {
+ "example": {
+ "status": "NOT_FOUND",
+ "reason": "The required object was not found.",
+ "message": "User with id=11 was not found",
+ "timestamp": "2022-09-07 09:10:50"
+ },
+ "schema": {
+ "$ref": "#/components/schemas/ApiError"
+ }
+ }
+ },
+ "description": "Пользователь не найден"
+ }
+ },
+ "summary": "Получение информации о заявках текущего пользователя на участие в чужих событиях",
+ "tags": [
+ "Private: Запросы на участие"
+ ]
+ },
+ "post": {
+ "description": "Обратите внимание:\n- нельзя добавить повторный запрос (Ожидается код ошибки 409)\n- инициатор события не может добавить запрос на участие в своём событии (Ожидается код ошибки 409)\n- нельзя участвовать в неопубликованном событии (Ожидается код ошибки 409)\n- если у события достигнут лимит запросов на участие - необходимо вернуть ошибку (Ожидается код ошибки 409)\n- если для события отключена пре-модерация запросов на участие, то запрос должен автоматически перейти в состояние подтвержденного",
+ "operationId": "addParticipationRequest",
+ "parameters": [
+ {
+ "description": "id текущего пользователя",
+ "in": "path",
+ "name": "userId",
+ "required": true,
+ "schema": {
+ "type": "integer",
+ "format": "int64"
+ }
+ },
+ {
+ "description": "id события",
+ "in": "query",
+ "name": "eventId",
+ "required": true,
+ "schema": {
+ "type": "integer",
+ "format": "int64"
+ }
+ }
+ ],
+ "responses": {
+ "201": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ParticipationRequestDto"
+ }
+ }
+ },
+ "description": "Заявка создана"
+ },
+ "400": {
+ "content": {
+ "application/json": {
+ "example": {
+ "status": "BAD_REQUEST",
+ "reason": "Incorrectly made request.",
+ "message": "Failed to convert value of type java.lang.String to required type long; nested exception is java.lang.NumberFormatException: For input string: ad",
+ "timestamp": "2022-09-07 09:10:50"
+ },
+ "schema": {
+ "$ref": "#/components/schemas/ApiError"
+ }
+ }
+ },
+ "description": "Запрос составлен некорректно"
+ },
+ "404": {
+ "content": {
+ "application/json": {
+ "example": {
+ "status": "NOT_FOUND",
+ "reason": "The required object was not found.",
+ "message": "Event with id=13 was not found",
+ "timestamp": "2022-09-07 09:10:50"
+ },
+ "schema": {
+ "$ref": "#/components/schemas/ApiError"
+ }
+ }
+ },
+ "description": "Событие не найдено или недоступно"
+ },
+ "409": {
+ "content": {
+ "application/json": {
+ "example": {
+ "status": "CONFLICT",
+ "reason": "Integrity constraint has been violated.",
+ "message": "could not execute statement; SQL [n/a]; constraint [uq_request]; nested exception is org.hibernate.exception.ConstraintViolationException: could not execute statement",
+ "timestamp": "2022-09-07 09:10:50"
+ },
+ "schema": {
+ "$ref": "#/components/schemas/ApiError"
+ }
+ }
+ },
+ "description": "Нарушение целостности данных"
+ }
+ },
+ "summary": "Добавление запроса от текущего пользователя на участие в событии",
+ "tags": [
+ "Private: Запросы на участие"
+ ]
+ }
+ },
+ "/users/{userId}/requests/{requestId}/cancel": {
+ "patch": {
+ "operationId": "cancelRequest",
+ "parameters": [
+ {
+ "description": "id текущего пользователя",
+ "in": "path",
+ "name": "userId",
+ "required": true,
+ "schema": {
+ "type": "integer",
+ "format": "int64"
+ }
+ },
+ {
+ "description": "id запроса на участие",
+ "in": "path",
+ "name": "requestId",
+ "required": true,
+ "schema": {
+ "type": "integer",
+ "format": "int64"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ParticipationRequestDto"
+ }
+ }
+ },
+ "description": "Заявка отменена"
+ },
+ "404": {
+ "content": {
+ "application/json": {
+ "example": {
+ "status": "NOT_FOUND",
+ "reason": "The required object was not found.",
+ "message": "Request with id=2727 was not found",
+ "timestamp": "2022-09-07 09:10:50"
+ },
+ "schema": {
+ "$ref": "#/components/schemas/ApiError"
+ }
+ }
+ },
+ "description": "Запрос не найден или недоступен"
+ }
+ },
+ "summary": "Отмена своего запроса на участие в событии",
+ "tags": [
+ "Private: Запросы на участие"
+ ]
+ }
+ }
+ },
+ "components": {
+ "schemas": {
+ "ApiError": {
+ "type": "object",
+ "properties": {
+ "errors": {
+ "type": "array",
+ "description": "Список стектрейсов или описания ошибок",
+ "example": [],
+ "items": {
+ "type": "string",
+ "description": "Список стектрейсов или описания ошибок",
+ "example": "[]"
+ }
+ },
+ "message": {
+ "type": "string",
+ "description": "Сообщение об ошибке",
+ "example": "Only pending or canceled events can be changed"
+ },
+ "reason": {
+ "type": "string",
+ "description": "Общее описание причины ошибки",
+ "example": "For the requested operation the conditions are not met."
+ },
+ "status": {
+ "type": "string",
+ "description": "Код статуса HTTP-ответа",
+ "example": "FORBIDDEN",
+ "enum": [
+ "100 CONTINUE",
+ "101 SWITCHING_PROTOCOLS",
+ "102 PROCESSING",
+ "103 CHECKPOINT",
+ "200 OK",
+ "201 CREATED",
+ "202 ACCEPTED",
+ "203 NON_AUTHORITATIVE_INFORMATION",
+ "204 NO_CONTENT",
+ "205 RESET_CONTENT",
+ "206 PARTIAL_CONTENT",
+ "207 MULTI_STATUS",
+ "208 ALREADY_REPORTED",
+ "226 IM_USED",
+ "300 MULTIPLE_CHOICES",
+ "301 MOVED_PERMANENTLY",
+ "302 FOUND",
+ "302 MOVED_TEMPORARILY",
+ "303 SEE_OTHER",
+ "304 NOT_MODIFIED",
+ "305 USE_PROXY",
+ "307 TEMPORARY_REDIRECT",
+ "308 PERMANENT_REDIRECT",
+ "400 BAD_REQUEST",
+ "401 UNAUTHORIZED",
+ "402 PAYMENT_REQUIRED",
+ "403 FORBIDDEN",
+ "404 NOT_FOUND",
+ "405 METHOD_NOT_ALLOWED",
+ "406 NOT_ACCEPTABLE",
+ "407 PROXY_AUTHENTICATION_REQUIRED",
+ "408 REQUEST_TIMEOUT",
+ "409 CONFLICT",
+ "410 GONE",
+ "411 LENGTH_REQUIRED",
+ "412 PRECONDITION_FAILED",
+ "413 PAYLOAD_TOO_LARGE",
+ "413 REQUEST_ENTITY_TOO_LARGE",
+ "414 URI_TOO_LONG",
+ "414 REQUEST_URI_TOO_LONG",
+ "415 UNSUPPORTED_MEDIA_TYPE",
+ "416 REQUESTED_RANGE_NOT_SATISFIABLE",
+ "417 EXPECTATION_FAILED",
+ "418 I_AM_A_TEAPOT",
+ "419 INSUFFICIENT_SPACE_ON_RESOURCE",
+ "420 METHOD_FAILURE",
+ "421 DESTINATION_LOCKED",
+ "422 UNPROCESSABLE_ENTITY",
+ "423 LOCKED",
+ "424 FAILED_DEPENDENCY",
+ "425 TOO_EARLY",
+ "426 UPGRADE_REQUIRED",
+ "428 PRECONDITION_REQUIRED",
+ "429 TOO_MANY_REQUESTS",
+ "431 REQUEST_HEADER_FIELDS_TOO_LARGE",
+ "451 UNAVAILABLE_FOR_LEGAL_REASONS",
+ "500 INTERNAL_SERVER_ERROR",
+ "501 NOT_IMPLEMENTED",
+ "502 BAD_GATEWAY",
+ "503 SERVICE_UNAVAILABLE",
+ "504 GATEWAY_TIMEOUT",
+ "505 HTTP_VERSION_NOT_SUPPORTED",
+ "506 VARIANT_ALSO_NEGOTIATES",
+ "507 INSUFFICIENT_STORAGE",
+ "508 LOOP_DETECTED",
+ "509 BANDWIDTH_LIMIT_EXCEEDED",
+ "510 NOT_EXTENDED",
+ "511 NETWORK_AUTHENTICATION_REQUIRED"
+ ]
+ },
+ "timestamp": {
+ "type": "string",
+ "description": "Дата и время когда произошла ошибка (в формате \"yyyy-MM-dd HH:mm:ss\")",
+ "example": "2022-06-09 06:27:23"
+ }
+ },
+ "description": "Сведения об ошибке"
+ },
+ "EventRequestStatusUpdateRequest": {
+ "type": "object",
+ "properties": {
+ "requestIds": {
+ "type": "array",
+ "description": "Идентификаторы запросов на участие в событии текущего пользователя",
+ "example": [
+ 1,
+ 2,
+ 3
+ ],
+ "items": {
+ "type": "integer",
+ "description": "Идентификаторы запросов на участие в событии текущего пользователя",
+ "format": "int64"
+ }
+ },
+ "status": {
+ "type": "string",
+ "description": "Новый статус запроса на участие в событии текущего пользователя",
+ "example": "CONFIRMED",
+ "enum": [
+ "CONFIRMED",
+ "REJECTED"
+ ]
+ }
+ },
+ "description": "Изменение статуса запроса на участие в событии текущего пользователя"
+ },
+ "EventRequestStatusUpdateResult": {
+ "type": "object",
+ "properties": {
+ "confirmedRequests": {
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/ParticipationRequestDto"
+ }
+ },
+ "rejectedRequests": {
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/ParticipationRequestDto"
+ }
+ }
+ },
+ "description": "Результат подтверждения/отклонения заявок на участие в событии"
+ },
+ "ParticipationRequestDto": {
+ "type": "object",
+ "properties": {
+ "created": {
+ "type": "string",
+ "description": "Дата и время создания заявки",
+ "example": "2022-09-06T21:10:05.432"
+ },
+ "event": {
+ "type": "integer",
+ "description": "Идентификатор события",
+ "format": "int64",
+ "example": 1
+ },
+ "id": {
+ "type": "integer",
+ "description": "Идентификатор заявки",
+ "format": "int64",
+ "example": 3
+ },
+ "requester": {
+ "type": "integer",
+ "description": "Идентификатор пользователя, отправившего заявку",
+ "format": "int64",
+ "example": 2
+ },
+ "status": {
+ "type": "string",
+ "description": "Статус заявки",
+ "example": "PENDING"
+ }
+ },
+ "description": "Заявка на участие в событии"
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/ewm-stats-service-spec.json b/API-stats-server-specification.json
similarity index 100%
rename from ewm-stats-service-spec.json
rename to API-stats-server-specification.json
diff --git a/API-user-service-specification.json b/API-user-service-specification.json
new file mode 100644
index 0000000..acbd611
--- /dev/null
+++ b/API-user-service-specification.json
@@ -0,0 +1,387 @@
+{
+ "openapi": "3.0.1",
+ "info": {
+ "description": "Documentation \"Explore With Me\" API v1.0",
+ "title": "Explore With Me- USER SERVICE API",
+ "version": "1.0"
+ },
+ "servers": [
+ {
+ "description": "Generated server url",
+ "url": "http://localhost:8080"
+ }
+ ],
+ "tags": [
+ {
+ "description": "API для работы с пользователями",
+ "name": "Admin: Пользователи"
+ }
+ ],
+ "paths": {
+ "/admin/users": {
+ "get": {
+ "description": "Возвращает информацию обо всех пользователях (учитываются параметры ограничения выборки), либо о конкретных (учитываются указанные идентификаторы)\n\nВ случае, если по заданным фильтрам не найдено ни одного пользователя, возвращает пустой список",
+ "operationId": "getUsers",
+ "parameters": [
+ {
+ "description": "id пользователей",
+ "in": "query",
+ "name": "ids",
+ "required": false,
+ "schema": {
+ "type": "array",
+ "items": {
+ "type": "integer",
+ "format": "int64"
+ }
+ }
+ },
+ {
+ "description": "количество элементов, которые нужно пропустить для формирования текущего набора",
+ "in": "query",
+ "name": "from",
+ "required": false,
+ "schema": {
+ "minimum": 0,
+ "type": "integer",
+ "format": "int32",
+ "default": 0
+ }
+ },
+ {
+ "description": "количество элементов в наборе",
+ "in": "query",
+ "name": "size",
+ "required": false,
+ "schema": {
+ "type": "integer",
+ "format": "int32",
+ "default": 10
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/UserDto"
+ }
+ }
+ }
+ },
+ "description": "Пользователи найдены"
+ },
+ "400": {
+ "content": {
+ "application/json": {
+ "example": {
+ "status": "BAD_REQUEST",
+ "reason": "Incorrectly made request.",
+ "message": "Failed to convert value of type java.lang.String to required type int; nested exception is java.lang.NumberFormatException: For input string: ad",
+ "timestamp": "2022-09-07 09:10:50"
+ },
+ "schema": {
+ "$ref": "#/components/schemas/ApiError"
+ }
+ }
+ },
+ "description": "Запрос составлен некорректно"
+ }
+ },
+ "summary": "Получение информации о пользователях",
+ "tags": [
+ "Admin: Пользователи"
+ ]
+ },
+ "post": {
+ "operationId": "registerUser",
+ "requestBody": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/NewUserRequest"
+ }
+ }
+ },
+ "description": "Данные добавляемого пользователя",
+ "required": true
+ },
+ "responses": {
+ "201": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/UserDto"
+ }
+ }
+ },
+ "description": "Пользователь зарегистрирован"
+ },
+ "400": {
+ "content": {
+ "application/json": {
+ "example": {
+ "status": "BAD_REQUEST",
+ "reason": "Incorrectly made request.",
+ "message": "Field: name. Error: must not be blank. Value: null",
+ "timestamp": "2022-09-07 09:10:50"
+ },
+ "schema": {
+ "$ref": "#/components/schemas/ApiError"
+ }
+ }
+ },
+ "description": "Запрос составлен некорректно"
+ },
+ "409": {
+ "content": {
+ "application/json": {
+ "example": {
+ "status": "CONFLICT",
+ "reason": "Integrity constraint has been violated.",
+ "message": "could not execute statement; SQL [n/a]; constraint [uq_email]; nested exception is org.hibernate.exception.ConstraintViolationException: could not execute statement",
+ "timestamp": "2022-09-07 09:10:50"
+ },
+ "schema": {
+ "$ref": "#/components/schemas/ApiError"
+ }
+ }
+ },
+ "description": "Нарушение целостности данных"
+ }
+ },
+ "summary": "Добавление нового пользователя",
+ "tags": [
+ "Admin: Пользователи"
+ ]
+ }
+ },
+ "/admin/users/{userId}": {
+ "delete": {
+ "operationId": "delete",
+ "parameters": [
+ {
+ "description": "id пользователя",
+ "in": "path",
+ "name": "userId",
+ "required": true,
+ "schema": {
+ "type": "integer",
+ "format": "int64"
+ }
+ }
+ ],
+ "responses": {
+ "204": {
+ "description": "Пользователь удален"
+ },
+ "404": {
+ "content": {
+ "application/json": {
+ "example": {
+ "status": "NOT_FOUND",
+ "reason": "The required object was not found.",
+ "message": "User with id=555 was not found",
+ "timestamp": "2022-09-07 09:10:50"
+ },
+ "schema": {
+ "$ref": "#/components/schemas/ApiError"
+ }
+ }
+ },
+ "description": "Пользователь не найден или недоступен"
+ }
+ },
+ "summary": "Удаление пользователя",
+ "tags": [
+ "Admin: Пользователи"
+ ]
+ }
+ }
+ },
+ "components": {
+ "schemas": {
+ "ApiError": {
+ "type": "object",
+ "properties": {
+ "errors": {
+ "type": "array",
+ "description": "Список стектрейсов или описания ошибок",
+ "example": [],
+ "items": {
+ "type": "string",
+ "description": "Список стектрейсов или описания ошибок",
+ "example": "[]"
+ }
+ },
+ "message": {
+ "type": "string",
+ "description": "Сообщение об ошибке",
+ "example": "Only pending or canceled events can be changed"
+ },
+ "reason": {
+ "type": "string",
+ "description": "Общее описание причины ошибки",
+ "example": "For the requested operation the conditions are not met."
+ },
+ "status": {
+ "type": "string",
+ "description": "Код статуса HTTP-ответа",
+ "example": "FORBIDDEN",
+ "enum": [
+ "100 CONTINUE",
+ "101 SWITCHING_PROTOCOLS",
+ "102 PROCESSING",
+ "103 CHECKPOINT",
+ "200 OK",
+ "201 CREATED",
+ "202 ACCEPTED",
+ "203 NON_AUTHORITATIVE_INFORMATION",
+ "204 NO_CONTENT",
+ "205 RESET_CONTENT",
+ "206 PARTIAL_CONTENT",
+ "207 MULTI_STATUS",
+ "208 ALREADY_REPORTED",
+ "226 IM_USED",
+ "300 MULTIPLE_CHOICES",
+ "301 MOVED_PERMANENTLY",
+ "302 FOUND",
+ "302 MOVED_TEMPORARILY",
+ "303 SEE_OTHER",
+ "304 NOT_MODIFIED",
+ "305 USE_PROXY",
+ "307 TEMPORARY_REDIRECT",
+ "308 PERMANENT_REDIRECT",
+ "400 BAD_REQUEST",
+ "401 UNAUTHORIZED",
+ "402 PAYMENT_REQUIRED",
+ "403 FORBIDDEN",
+ "404 NOT_FOUND",
+ "405 METHOD_NOT_ALLOWED",
+ "406 NOT_ACCEPTABLE",
+ "407 PROXY_AUTHENTICATION_REQUIRED",
+ "408 REQUEST_TIMEOUT",
+ "409 CONFLICT",
+ "410 GONE",
+ "411 LENGTH_REQUIRED",
+ "412 PRECONDITION_FAILED",
+ "413 PAYLOAD_TOO_LARGE",
+ "413 REQUEST_ENTITY_TOO_LARGE",
+ "414 URI_TOO_LONG",
+ "414 REQUEST_URI_TOO_LONG",
+ "415 UNSUPPORTED_MEDIA_TYPE",
+ "416 REQUESTED_RANGE_NOT_SATISFIABLE",
+ "417 EXPECTATION_FAILED",
+ "418 I_AM_A_TEAPOT",
+ "419 INSUFFICIENT_SPACE_ON_RESOURCE",
+ "420 METHOD_FAILURE",
+ "421 DESTINATION_LOCKED",
+ "422 UNPROCESSABLE_ENTITY",
+ "423 LOCKED",
+ "424 FAILED_DEPENDENCY",
+ "425 TOO_EARLY",
+ "426 UPGRADE_REQUIRED",
+ "428 PRECONDITION_REQUIRED",
+ "429 TOO_MANY_REQUESTS",
+ "431 REQUEST_HEADER_FIELDS_TOO_LARGE",
+ "451 UNAVAILABLE_FOR_LEGAL_REASONS",
+ "500 INTERNAL_SERVER_ERROR",
+ "501 NOT_IMPLEMENTED",
+ "502 BAD_GATEWAY",
+ "503 SERVICE_UNAVAILABLE",
+ "504 GATEWAY_TIMEOUT",
+ "505 HTTP_VERSION_NOT_SUPPORTED",
+ "506 VARIANT_ALSO_NEGOTIATES",
+ "507 INSUFFICIENT_STORAGE",
+ "508 LOOP_DETECTED",
+ "509 BANDWIDTH_LIMIT_EXCEEDED",
+ "510 NOT_EXTENDED",
+ "511 NETWORK_AUTHENTICATION_REQUIRED"
+ ]
+ },
+ "timestamp": {
+ "type": "string",
+ "description": "Дата и время когда произошла ошибка (в формате \"yyyy-MM-dd HH:mm:ss\")",
+ "example": "2022-06-09 06:27:23"
+ }
+ },
+ "description": "Сведения об ошибке"
+ },
+ "NewUserRequest": {
+ "required": [
+ "email",
+ "name"
+ ],
+ "type": "object",
+ "properties": {
+ "email": {
+ "maxLength": 254,
+ "minLength": 6,
+ "type": "string",
+ "description": "Почтовый адрес",
+ "example": "ivan.petrov@practicummail.ru"
+ },
+ "name": {
+ "maxLength": 250,
+ "minLength": 2,
+ "type": "string",
+ "description": "Имя",
+ "example": "Иван Петров"
+ }
+ },
+ "description": "Данные нового пользователя"
+ },
+ "UserDto": {
+ "required": [
+ "email",
+ "name"
+ ],
+ "type": "object",
+ "properties": {
+ "email": {
+ "type": "string",
+ "description": "Почтовый адрес",
+ "example": "petrov.i@practicummail.ru"
+ },
+ "id": {
+ "type": "integer",
+ "description": "Идентификатор",
+ "format": "int64",
+ "readOnly": true,
+ "example": 1
+ },
+ "name": {
+ "type": "string",
+ "description": "Имя",
+ "example": "Петров Иван"
+ }
+ },
+ "description": "Пользователь"
+ },
+ "UserShortDto": {
+ "required": [
+ "id",
+ "name"
+ ],
+ "type": "object",
+ "properties": {
+ "id": {
+ "type": "integer",
+ "description": "Идентификатор",
+ "format": "int64",
+ "example": 3
+ },
+ "name": {
+ "type": "string",
+ "description": "Имя",
+ "example": "Фёдоров Матвей"
+ }
+ },
+ "description": "Пользователь (краткая информация)"
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..ee92cce
--- /dev/null
+++ b/README.md
@@ -0,0 +1,108 @@
+# Explore With Me
+
+Explore With Me is a web application for people who want to be in touch with
+current events in their local areas.
+
+People can view the list of events, make participation requests, get approvals or rejections,
+leave comments.
+
+Event makers can start new events and manage participants lists
+
+Administrators can manage events, users, categories and make compilations of events.
+Also, they have statistics microservice to control important metrics.
+
+# Infrastructure modules (folder `/infra`)
+
+## Discovery Service
+
+The module `discovery-server` implements Service Registry - the central part of
+Service Discovery pattern.
+
+Stack:
+- String Boot
+- Spring Cloud Eureka server
+
+## Configuration Service
+
+The module `config-server` implements an External Configuration pattern as a central storage
+of configuration files for all microservices except discovery.
+
+Stack:
+- String Boot
+- Spring Cloud Config server
+
+## Gateway Service
+
+The module `gateway-server` implements an API Gateway pattern. It works as a single entry point
+for all microservices.
+
+Stack:
+- String Boot
+- Spring Cloud Gateway server
+
+# Application core modules (folder `/core`)
+
+The Microservice-based application contains 4 integrated services. They have separate databases
+(implemented as different schemas in this release). The interaction is realized through Feign-clients with circuit breaker.
+
+Stack:
+- Java
+- String Boot
+- Spring MVC (REST)
+- Spring Data JPA (Hibernate)
+- Spring Cloud Discovery and Configuration
+- OpenFeign client + Resilience4j
+- PostgreSQL
+
+## Common library
+
+The module `core-common` contains common classes and interfaces used by all core modules such as:
+- API description interfaces
+- Feign client interaction helpers
+- DTO
+- Exceptions and exception handlers
+- Validation custom annotations
+
+## User Management Service
+
+The module `user-service` provides Admin interface to manage users. It doesn't access other services
+but provides them information about users.
+
+Public API Specification: [API-user-service-specification.json](API-user-service-specification.json)
+
+Interaction API endpoints:
+- GET /admin/users/{userId}/short (returns UserShortDto to common interaction)
+- GET /admin/users/all/short (returns list of UserShortDto)
+- GET /admin/users/all/full (returns list of UserDto)
+
+## Event Management Service
+
+The module `event-service` provides Admin, Private and Public interface to operate events - the central
+entity in application. The module interacts with request-service (to get information about requests number)
+and user-service (to get extended user information)
+
+Public API Specification: [API-event-service-specification.json](API-event-service-specification.json)
+
+Interaction API endpoints:
+- GET /events/{id}/dto/interaction (returns shortened EventInteractionDto to common interaction)
+- GET /events/{id}/dto/comment (returns EventCommentDto for comment-service)
+- POST /events/dto/list/comment (returns list of EventCommentDto for comment-service)
+
+## Participation Requests Management Service
+
+The module `request-service` provides Private interface to operate participation requests. It interacts with
+event-service and user-service (to get extended info and check existence)
+
+Public API Specification: [API-request-service-specification.json](API-request-service-specification.json)
+
+Interaction API endpoints:
+- POST /requests/confirmed (returns map of confirmed requests by event ID list)
+
+## Event Comments Management Service
+
+The module `comment-service` provides Admin, Private and Public interface to operate comments to events.
+It interacts with event-service and user-service (to get extended info and check existence)
+
+Public API Specification: [API-comment-service-specification.json](API-comment-service-specification.json)
+
+
diff --git a/core/comment-service/Dockerfile b/core/comment-service/Dockerfile
new file mode 100644
index 0000000..a52e1ca
--- /dev/null
+++ b/core/comment-service/Dockerfile
@@ -0,0 +1,4 @@
+FROM amazoncorretto:21-alpine
+LABEL authors="Слава"
+COPY target/*.jar app.jar
+ENTRYPOINT ["java", "-jar", "app.jar"]
\ 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..b42ffae
--- /dev/null
+++ b/core/comment-service/pom.xml
@@ -0,0 +1,135 @@
+
+
+ 4.0.0
+
+
+ ru.practicum
+ core
+ 0.0.1-SNAPSHOT
+
+
+ comment-service
+
+
+
+
+
+
+ ru.practicum
+ core-common
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-configuration-processor
+ true
+
+
+
+ org.projectlombok
+ lombok
+
+
+
+ org.springframework.boot
+ spring-boot-starter-actuator
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+
+
+
+ org.springframework.boot
+ spring-boot-starter-validation
+
+
+
+ javax.validation
+ validation-api
+ 2.0.1.Final
+
+
+
+
+
+ org.postgresql
+ postgresql
+
+
+
+ org.springframework.boot
+ spring-boot-starter-data-jpa
+
+
+
+
+
+ org.springframework.cloud
+ spring-cloud-starter-netflix-eureka-client
+
+
+
+ org.springframework.cloud
+ spring-cloud-starter-config
+
+
+
+ org.springframework.retry
+ spring-retry
+
+
+
+
+
+ org.springframework.cloud
+ spring-cloud-starter-openfeign
+
+
+
+ org.springframework.cloud
+ spring-cloud-starter-circuitbreaker-resilience4j
+
+
+
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+
+
+
+ org.projectlombok
+ lombok
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+
+
+
+ org.projectlombok
+ lombok
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/core/comment-service/src/main/java/ru/practicum/CommentServiceApplication.java b/core/comment-service/src/main/java/ru/practicum/CommentServiceApplication.java
new file mode 100644
index 0000000..5b05018
--- /dev/null
+++ b/core/comment-service/src/main/java/ru/practicum/CommentServiceApplication.java
@@ -0,0 +1,15 @@
+package ru.practicum;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.cloud.openfeign.EnableFeignClients;
+
+@EnableFeignClients
+@SpringBootApplication
+public class CommentServiceApplication {
+
+ public static void main(String[] args) {
+ SpringApplication.run(CommentServiceApplication.class, args);
+ }
+
+}
diff --git a/core/comment-service/src/main/java/ru/practicum/client/EventClient.java b/core/comment-service/src/main/java/ru/practicum/client/EventClient.java
new file mode 100644
index 0000000..50a0caf
--- /dev/null
+++ b/core/comment-service/src/main/java/ru/practicum/client/EventClient.java
@@ -0,0 +1,8 @@
+package ru.practicum.client;
+
+import org.springframework.cloud.openfeign.FeignClient;
+import ru.practicum.api.event.EventAllApi;
+
+@FeignClient(name = "event-service")
+public interface EventClient extends EventAllApi {
+}
\ No newline at end of file
diff --git a/core/comment-service/src/main/java/ru/practicum/client/EventClientHelper.java b/core/comment-service/src/main/java/ru/practicum/client/EventClientHelper.java
new file mode 100644
index 0000000..2c7eb86
--- /dev/null
+++ b/core/comment-service/src/main/java/ru/practicum/client/EventClientHelper.java
@@ -0,0 +1,13 @@
+package ru.practicum.client;
+
+import org.springframework.stereotype.Component;
+import ru.practicum.api.event.EventAllApi;
+
+@Component
+public class EventClientHelper extends EventClientAbstractHelper {
+
+ public EventClientHelper(EventAllApi eventApiClient) {
+ super(eventApiClient);
+ }
+
+}
\ No newline at end of file
diff --git a/core/comment-service/src/main/java/ru/practicum/client/UserClient.java b/core/comment-service/src/main/java/ru/practicum/client/UserClient.java
new file mode 100644
index 0000000..50ca2b2
--- /dev/null
+++ b/core/comment-service/src/main/java/ru/practicum/client/UserClient.java
@@ -0,0 +1,8 @@
+package ru.practicum.client;
+
+import org.springframework.cloud.openfeign.FeignClient;
+import ru.practicum.api.user.UserApi;
+
+@FeignClient(name = "user-service")
+public interface UserClient extends UserApi {
+}
diff --git a/core/comment-service/src/main/java/ru/practicum/client/UserClientHelper.java b/core/comment-service/src/main/java/ru/practicum/client/UserClientHelper.java
new file mode 100644
index 0000000..41cb654
--- /dev/null
+++ b/core/comment-service/src/main/java/ru/practicum/client/UserClientHelper.java
@@ -0,0 +1,13 @@
+package ru.practicum.client;
+
+import org.springframework.stereotype.Component;
+import ru.practicum.api.user.UserApi;
+
+@Component
+public class UserClientHelper extends UserClientAbstractHelper {
+
+ public UserClientHelper(UserApi userApiClient) {
+ super(userApiClient);
+ }
+
+}
\ No newline at end of file
diff --git a/core/comment-service/src/main/java/ru/practicum/comment/controller/CommentAdminController.java b/core/comment-service/src/main/java/ru/practicum/comment/controller/CommentAdminController.java
new file mode 100644
index 0000000..f39aa50
--- /dev/null
+++ b/core/comment-service/src/main/java/ru/practicum/comment/controller/CommentAdminController.java
@@ -0,0 +1,44 @@
+package ru.practicum.comment.controller;
+
+import lombok.RequiredArgsConstructor;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.RestController;
+import ru.practicum.api.comment.CommentAdminApi;
+import ru.practicum.comment.service.CommentAdminService;
+import ru.practicum.dto.comment.CommentDto;
+
+import java.util.Collection;
+
+@RestController
+@RequiredArgsConstructor
+@Validated
+public class CommentAdminController implements CommentAdminApi {
+
+ private final CommentAdminService commentAdminService;
+
+ @Override
+ public Collection search(String text, int from, int size) {
+ return commentAdminService.search(text, from, size);
+ }
+
+ @Override
+ public Collection get(Long userId, int from, int size) {
+ return commentAdminService.findAllByUserId(userId, from, size);
+ }
+
+ @Override
+ public boolean delete(Long comId) {
+ return commentAdminService.delete(comId);
+ }
+
+ @Override
+ public CommentDto approveComment(Long comId) {
+ return commentAdminService.approveComment(comId);
+ }
+
+ @Override
+ public CommentDto rejectComment(Long comId) {
+ return commentAdminService.rejectComment(comId);
+ }
+
+}
\ No newline at end of file
diff --git a/core/comment-service/src/main/java/ru/practicum/comment/controller/CommentPrivateController.java b/core/comment-service/src/main/java/ru/practicum/comment/controller/CommentPrivateController.java
new file mode 100644
index 0000000..ad7869e
--- /dev/null
+++ b/core/comment-service/src/main/java/ru/practicum/comment/controller/CommentPrivateController.java
@@ -0,0 +1,33 @@
+package ru.practicum.comment.controller;
+
+import lombok.RequiredArgsConstructor;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.RestController;
+import ru.practicum.api.comment.CommentPrivateApi;
+import ru.practicum.comment.service.CommentPrivateService;
+import ru.practicum.dto.comment.CommentCreateDto;
+import ru.practicum.dto.comment.CommentDto;
+
+@RestController
+@Validated
+@RequiredArgsConstructor
+public class CommentPrivateController implements CommentPrivateApi {
+
+ private final CommentPrivateService service;
+
+ @Override
+ public CommentDto create(Long userId, Long eventId, CommentCreateDto commentCreateDto) {
+ return service.createComment(userId, eventId, commentCreateDto);
+ }
+
+ @Override
+ public String delete(Long userId, Long comId) {
+ return service.deleteComment(userId, comId);
+ }
+
+ @Override
+ public CommentDto patch(Long userId, Long comId, CommentCreateDto commentCreateDto) {
+ return service.patchComment(userId, comId, commentCreateDto);
+ }
+
+}
\ No newline at end of file
diff --git a/core/comment-service/src/main/java/ru/practicum/comment/controller/CommentPublicController.java b/core/comment-service/src/main/java/ru/practicum/comment/controller/CommentPublicController.java
new file mode 100644
index 0000000..ddd7475
--- /dev/null
+++ b/core/comment-service/src/main/java/ru/practicum/comment/controller/CommentPublicController.java
@@ -0,0 +1,35 @@
+package ru.practicum.comment.controller;
+
+import lombok.RequiredArgsConstructor;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.RestController;
+import ru.practicum.api.comment.CommentPublicApi;
+import ru.practicum.comment.service.CommentPublicService;
+import ru.practicum.dto.comment.CommentDto;
+import ru.practicum.dto.comment.CommentShortDto;
+
+import java.util.Collection;
+
+@RestController
+@RequiredArgsConstructor
+@Validated
+public class CommentPublicController implements CommentPublicApi {
+
+ private final CommentPublicService commentPublicService;
+
+ @Override
+ public CommentDto getById(Long comId) {
+ return commentPublicService.getComment(comId);
+ }
+
+ @Override
+ public Collection getByEventId(Long eventId, int from, int size) {
+ return commentPublicService.getCommentsByEvent(eventId, from, size);
+ }
+
+ @Override
+ public CommentDto getByEventAndCommentId(Long eventId, Long commentId) {
+ return commentPublicService.getCommentByEventAndCommentId(eventId, commentId);
+ }
+
+}
\ No newline at end of file
diff --git a/core/main-service/src/main/java/ru/practicum/comment/model/Comment.java b/core/comment-service/src/main/java/ru/practicum/comment/dal/Comment.java
similarity index 55%
rename from core/main-service/src/main/java/ru/practicum/comment/model/Comment.java
rename to core/comment-service/src/main/java/ru/practicum/comment/dal/Comment.java
index 76cdb2f..d41b053 100644
--- a/core/main-service/src/main/java/ru/practicum/comment/model/Comment.java
+++ b/core/comment-service/src/main/java/ru/practicum/comment/dal/Comment.java
@@ -1,35 +1,37 @@
-package ru.practicum.comment.model;
+package ru.practicum.comment.dal;
import jakarta.persistence.*;
import lombok.*;
-import ru.practicum.event.model.Event;
-import ru.practicum.user.model.User;
import java.time.LocalDateTime;
@Getter
@Setter
-@Builder
+@EqualsAndHashCode(onlyExplicitlyIncluded = true)
+@ToString
@Entity
-@AllArgsConstructor
+@Builder
@NoArgsConstructor
-@Table(name = "comments")
+@AllArgsConstructor
+@Table(name = "comments", indexes = {
+ @Index(name = "idx_comments_event_id", columnList = "event_id"),
+ @Index(name = "idx_comments_textual_content", columnList = "textual_content")
+})
public class Comment {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
+ @EqualsAndHashCode.Include
private Long id;
@Column(name = "textual_content", length = 1000, nullable = false)
private String text;
- @ManyToOne
- @JoinColumn(name = "author_id", nullable = false)
- private User author;
+ @Column(name = "author_id", nullable = false)
+ private Long authorId;
- @ManyToOne
- @JoinColumn(name = "event_id", nullable = false)
- private Event event;
+ @Column(name = "event_id", nullable = false)
+ private Long eventId;
@Column(name = "create_time", nullable = false)
private LocalDateTime createTime;
@@ -40,8 +42,4 @@ public class Comment {
@Column(name = "approved", nullable = false)
private Boolean approved;
- public boolean isApproved() {
- return approved;
- }
-
}
\ No newline at end of file
diff --git a/core/comment-service/src/main/java/ru/practicum/comment/dal/CommentRepository.java b/core/comment-service/src/main/java/ru/practicum/comment/dal/CommentRepository.java
new file mode 100644
index 0000000..06ffeaa
--- /dev/null
+++ b/core/comment-service/src/main/java/ru/practicum/comment/dal/CommentRepository.java
@@ -0,0 +1,20 @@
+package ru.practicum.comment.dal;
+
+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;
+
+public interface CommentRepository extends JpaRepository {
+
+ Page findAllByEventIdAndApproved(Long eventId, Boolean approved, Pageable pageable);
+
+ Page findAllByAuthorId(Long userId, Pageable pageable);
+
+ @Query("""
+ SELECT c FROM Comment as c
+ WHERE c.text ILIKE CONCAT('%', ?1, '%')
+ """)
+ Page findByText(String text, Pageable pageable);
+
+}
\ No newline at end of file
diff --git a/core/main-service/src/main/java/ru/practicum/comment/service/CommentAdminService.java b/core/comment-service/src/main/java/ru/practicum/comment/service/CommentAdminService.java
similarity index 80%
rename from core/main-service/src/main/java/ru/practicum/comment/service/CommentAdminService.java
rename to core/comment-service/src/main/java/ru/practicum/comment/service/CommentAdminService.java
index 707f1d1..2744230 100644
--- a/core/main-service/src/main/java/ru/practicum/comment/service/CommentAdminService.java
+++ b/core/comment-service/src/main/java/ru/practicum/comment/service/CommentAdminService.java
@@ -1,12 +1,12 @@
package ru.practicum.comment.service;
-import ru.practicum.comment.dto.CommentDto;
+import ru.practicum.dto.comment.CommentDto;
import java.util.List;
public interface CommentAdminService {
- void delete(Long comId);
+ boolean delete(Long comId);
List search(String text, int from, int size);
@@ -15,4 +15,5 @@ public interface CommentAdminService {
CommentDto approveComment(Long comId);
CommentDto rejectComment(Long comId);
+
}
\ No newline at end of file
diff --git a/core/comment-service/src/main/java/ru/practicum/comment/service/CommentAdminServiceImpl.java b/core/comment-service/src/main/java/ru/practicum/comment/service/CommentAdminServiceImpl.java
new file mode 100644
index 0000000..b6a2ba3
--- /dev/null
+++ b/core/comment-service/src/main/java/ru/practicum/comment/service/CommentAdminServiceImpl.java
@@ -0,0 +1,120 @@
+package ru.practicum.comment.service;
+
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.data.domain.PageRequest;
+import org.springframework.data.domain.Pageable;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.transaction.support.TransactionTemplate;
+import ru.practicum.client.EventClientHelper;
+import ru.practicum.client.UserClientHelper;
+import ru.practicum.comment.dal.Comment;
+import ru.practicum.comment.dal.CommentRepository;
+import ru.practicum.dto.comment.CommentDto;
+import ru.practicum.dto.event.EventCommentDto;
+import ru.practicum.dto.user.UserDto;
+import ru.practicum.exception.NotFoundException;
+
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+@Service
+@RequiredArgsConstructor
+@Slf4j
+public class CommentAdminServiceImpl implements CommentAdminService {
+
+ private final TransactionTemplate transactionTemplate;
+ private final CommentRepository commentRepository;
+
+ private final UserClientHelper userClientHelper;
+ private final EventClientHelper eventClientHelper;
+
+ @Override
+ @Transactional
+ public boolean delete(Long comId) {
+ if (!commentRepository.existsById(comId)) {
+ throw new NotFoundException("Not found Comment " + comId);
+ }
+ commentRepository.deleteById(comId);
+ return true;
+ }
+
+ @Override
+ public List search(String text, int from, int size) {
+ List comments = transactionTemplate.execute(status -> {
+ Pageable pageable = PageRequest.of(from / size, size);
+ return commentRepository.findByText(text, pageable).getContent();
+ });
+ if (comments == null || comments.isEmpty()) return List.of();
+
+ Set userIds = comments.stream().map(Comment::getAuthorId).collect(Collectors.toSet());
+ Map userMap = userClientHelper.retrieveUserDtoMapByUserIdList(userIds);
+
+ Set eventIds = comments.stream().map(Comment::getEventId).collect(Collectors.toSet());
+ Map eventMap = eventClientHelper.retrieveEventCommentDtoMapByUserIdList(eventIds);
+
+ return comments.stream()
+ .map(c -> CommentMapper.toCommentDto(
+ c,
+ userMap.get(c.getAuthorId()),
+ eventMap.get(c.getEventId())
+ ))
+ .toList();
+ }
+
+ @Override
+ public List findAllByUserId(Long userId, int from, int size) {
+ UserDto userDto = userClientHelper.retrieveUserDtoByUserId(userId);
+
+ List comments = transactionTemplate.execute(status -> {
+ Pageable pageable = PageRequest.of(from / size, size);
+ return commentRepository.findAllByAuthorId(userId, pageable).getContent();
+ });
+ if (comments == null || comments.isEmpty()) return List.of();
+
+ Set eventIds = comments.stream().map(Comment::getEventId).collect(Collectors.toSet());
+ Map eventMap = eventClientHelper.retrieveEventCommentDtoMapByUserIdList(eventIds);
+
+ return comments.stream()
+ .map(c -> CommentMapper.toCommentDto(
+ c,
+ userDto,
+ eventMap.get(c.getEventId())
+ ))
+ .toList();
+ }
+
+ @Override
+ public CommentDto approveComment(Long comId) {
+ Comment comment = transactionTemplate.execute(status -> {
+ Comment commentEntity = commentRepository.findById(comId)
+ .orElseThrow(() -> new NotFoundException("Not found Comment " + comId));
+ commentEntity.setApproved(true);
+ return commentRepository.save(commentEntity);
+ });
+
+ UserDto userDto = userClientHelper.retrieveUserDtoByUserId(comment.getAuthorId());
+ EventCommentDto eventCommentDto = eventClientHelper.retrieveEventCommentDtoByEventId(comment.getEventId());
+
+ return CommentMapper.toCommentDto(comment, userDto, eventCommentDto);
+ }
+
+ @Override
+ public CommentDto rejectComment(Long comId) {
+ Comment comment = transactionTemplate.execute(status -> {
+ Comment commentEntity = commentRepository.findById(comId)
+ .orElseThrow(() -> new NotFoundException("Not found Comment " + comId));
+ commentEntity.setApproved(false);
+ return commentRepository.save(commentEntity);
+ });
+
+ UserDto userDto = userClientHelper.retrieveUserDtoByUserId(comment.getAuthorId());
+ EventCommentDto eventCommentDto = eventClientHelper.retrieveEventCommentDtoByEventId(comment.getEventId());
+
+ return CommentMapper.toCommentDto(comment, userDto, eventCommentDto);
+ }
+
+}
\ No newline at end of file
diff --git a/core/comment-service/src/main/java/ru/practicum/comment/service/CommentMapper.java b/core/comment-service/src/main/java/ru/practicum/comment/service/CommentMapper.java
new file mode 100644
index 0000000..6955124
--- /dev/null
+++ b/core/comment-service/src/main/java/ru/practicum/comment/service/CommentMapper.java
@@ -0,0 +1,31 @@
+package ru.practicum.comment.service;
+
+import ru.practicum.comment.dal.Comment;
+import ru.practicum.dto.comment.CommentDto;
+import ru.practicum.dto.comment.CommentShortDto;
+import ru.practicum.dto.event.EventCommentDto;
+import ru.practicum.dto.user.UserDto;
+
+public class CommentMapper {
+
+ public static CommentDto toCommentDto(Comment comment, UserDto author, EventCommentDto eventCommentDto) {
+ return CommentDto.builder()
+ .id(comment.getId())
+ .author(author)
+ .event(eventCommentDto)
+ .createTime(comment.getCreateTime())
+ .text(comment.getText())
+ .approved(comment.getApproved())
+ .build();
+ }
+
+ public static CommentShortDto toCommentShortDto(Comment comment, UserDto author) {
+ return CommentShortDto.builder()
+ .author(author)
+ .createTime(comment.getText())
+ .id(comment.getId())
+ .text(comment.getText())
+ .build();
+ }
+
+}
\ No newline at end of file
diff --git a/core/main-service/src/main/java/ru/practicum/comment/service/CommentPrivateService.java b/core/comment-service/src/main/java/ru/practicum/comment/service/CommentPrivateService.java
similarity index 64%
rename from core/main-service/src/main/java/ru/practicum/comment/service/CommentPrivateService.java
rename to core/comment-service/src/main/java/ru/practicum/comment/service/CommentPrivateService.java
index 1bf8dbd..eea48ed 100644
--- a/core/main-service/src/main/java/ru/practicum/comment/service/CommentPrivateService.java
+++ b/core/comment-service/src/main/java/ru/practicum/comment/service/CommentPrivateService.java
@@ -1,13 +1,14 @@
package ru.practicum.comment.service;
-import ru.practicum.comment.dto.CommentCreateDto;
-import ru.practicum.comment.dto.CommentDto;
+import ru.practicum.dto.comment.CommentCreateDto;
+import ru.practicum.dto.comment.CommentDto;
public interface CommentPrivateService {
CommentDto createComment(Long userId, Long eventId, CommentCreateDto commentDto);
- void deleteComment(Long userId, Long comId);
+ String deleteComment(Long userId, Long comId);
CommentDto patchComment(Long userId, Long comId, CommentCreateDto commentCreateDto);
+
}
\ No newline at end of file
diff --git a/core/comment-service/src/main/java/ru/practicum/comment/service/CommentPrivateServiceImpl.java b/core/comment-service/src/main/java/ru/practicum/comment/service/CommentPrivateServiceImpl.java
new file mode 100644
index 0000000..68b575a
--- /dev/null
+++ b/core/comment-service/src/main/java/ru/practicum/comment/service/CommentPrivateServiceImpl.java
@@ -0,0 +1,86 @@
+package ru.practicum.comment.service;
+
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.transaction.support.TransactionTemplate;
+import ru.practicum.client.EventClientHelper;
+import ru.practicum.client.UserClientHelper;
+import ru.practicum.comment.dal.Comment;
+import ru.practicum.comment.dal.CommentRepository;
+import ru.practicum.dto.comment.CommentCreateDto;
+import ru.practicum.dto.comment.CommentDto;
+import ru.practicum.dto.event.EventCommentDto;
+import ru.practicum.dto.event.State;
+import ru.practicum.dto.user.UserDto;
+import ru.practicum.exception.ConflictException;
+import ru.practicum.exception.NotFoundException;
+
+import java.time.LocalDateTime;
+import java.util.Objects;
+
+@Service
+@RequiredArgsConstructor
+@Slf4j
+public class CommentPrivateServiceImpl implements CommentPrivateService {
+
+ private final TransactionTemplate transactionTemplate;
+ private final CommentRepository commentRepository;
+
+ private final UserClientHelper userClientHelper;
+ private final EventClientHelper eventClientHelper;
+
+ @Override
+ public CommentDto createComment(Long userId, Long eventId, CommentCreateDto commentCreateDto) {
+ UserDto userDto = userClientHelper.retrieveUserDtoByUserIdOrFall(userId);
+ EventCommentDto eventCommentDto = eventClientHelper.retrieveEventCommentDtoByEventIdOrFall(eventId);
+
+ if (!Objects.equals(eventCommentDto.getState(), State.PUBLISHED))
+ throw new ConflictException("Unable to comment unpublished Event " + eventId);
+
+ return transactionTemplate.execute(status -> {
+ Comment comment = Comment.builder()
+ .text(commentCreateDto.getText())
+ .authorId(userId)
+ .eventId(eventId)
+ .approved(true) // по умолчанию комменты видны
+ .createTime(LocalDateTime.now())
+ .build();
+ commentRepository.save(comment);
+ return CommentMapper.toCommentDto(comment, userDto, eventCommentDto);
+ });
+ }
+
+ @Override
+ @Transactional
+ public String deleteComment(Long userId, Long comId) {
+ Comment comment = commentRepository.findById(comId)
+ .orElseThrow(() -> new NotFoundException("Not found Comment " + comId));
+ if (!Objects.equals(comment.getAuthorId(), userId))
+ throw new ConflictException("Unauthorized access by user " + userId + " to comment " + comId);
+ commentRepository.deleteById(comId);
+ return "Deleted Comment " + comId;
+ }
+
+ @Override
+ public CommentDto patchComment(Long userId, Long comId, CommentCreateDto commentCreateDto) {
+ Comment comment = transactionTemplate.execute(status -> {
+ Comment commentEntity = commentRepository.findById(comId)
+ .orElseThrow(() -> new NotFoundException("Not found Comment " + comId));
+
+ if (!Objects.equals(commentEntity.getAuthorId(), userId))
+ throw new ConflictException("Unauthorized access by user " + userId + " to comment " + comId);
+
+ commentEntity.setText(commentCreateDto.getText());
+ commentEntity.setPatchTime(LocalDateTime.now());
+ return commentRepository.save(commentEntity);
+ });
+
+ UserDto userDto = userClientHelper.retrieveUserDtoByUserIdOrFall(userId);
+ EventCommentDto eventCommentDto = eventClientHelper.retrieveEventCommentDtoByEventIdOrFall(comment.getEventId());
+
+ return CommentMapper.toCommentDto(comment, userDto, eventCommentDto);
+ }
+
+}
\ No newline at end of file
diff --git a/core/main-service/src/main/java/ru/practicum/comment/service/CommentPublicService.java b/core/comment-service/src/main/java/ru/practicum/comment/service/CommentPublicService.java
similarity index 76%
rename from core/main-service/src/main/java/ru/practicum/comment/service/CommentPublicService.java
rename to core/comment-service/src/main/java/ru/practicum/comment/service/CommentPublicService.java
index 2762467..9d81b04 100644
--- a/core/main-service/src/main/java/ru/practicum/comment/service/CommentPublicService.java
+++ b/core/comment-service/src/main/java/ru/practicum/comment/service/CommentPublicService.java
@@ -1,7 +1,7 @@
package ru.practicum.comment.service;
-import ru.practicum.comment.dto.CommentDto;
-import ru.practicum.comment.dto.CommentShortDto;
+import ru.practicum.dto.comment.CommentDto;
+import ru.practicum.dto.comment.CommentShortDto;
import java.util.List;
@@ -12,4 +12,5 @@ public interface CommentPublicService {
List getCommentsByEvent(Long eventId, int from, int size);
CommentDto getCommentByEventAndCommentId(Long eventId, Long commentId);
+
}
\ No newline at end of file
diff --git a/core/comment-service/src/main/java/ru/practicum/comment/service/CommentPublicServiceImpl.java b/core/comment-service/src/main/java/ru/practicum/comment/service/CommentPublicServiceImpl.java
new file mode 100644
index 0000000..0c5a1f2
--- /dev/null
+++ b/core/comment-service/src/main/java/ru/practicum/comment/service/CommentPublicServiceImpl.java
@@ -0,0 +1,91 @@
+package ru.practicum.comment.service;
+
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.data.domain.PageRequest;
+import org.springframework.data.domain.Pageable;
+import org.springframework.data.domain.Sort;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.support.TransactionTemplate;
+import ru.practicum.client.EventClientHelper;
+import ru.practicum.client.UserClientHelper;
+import ru.practicum.comment.dal.Comment;
+import ru.practicum.comment.dal.CommentRepository;
+import ru.practicum.dto.comment.CommentDto;
+import ru.practicum.dto.comment.CommentShortDto;
+import ru.practicum.dto.event.EventCommentDto;
+import ru.practicum.dto.user.UserDto;
+import ru.practicum.exception.ForbiddenException;
+import ru.practicum.exception.NotFoundException;
+
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+@Service
+@RequiredArgsConstructor
+@Slf4j
+public class CommentPublicServiceImpl implements CommentPublicService {
+
+ private final TransactionTemplate transactionTemplate;
+ private final CommentRepository commentRepository;
+
+ private final UserClientHelper userClientHelper;
+ private final EventClientHelper eventClientHelper;
+
+ @Override
+ public CommentDto getComment(Long comId) {
+ Comment comment = transactionTemplate.execute(status -> {
+ return commentRepository.findById(comId)
+ .orElseThrow(() -> new NotFoundException("Not found Comment " + comId));
+ });
+
+ if (!Objects.equals(comment.getApproved(), true))
+ throw new ForbiddenException("Comment " + comId + "is not approved");
+
+ UserDto userDto = userClientHelper.retrieveUserDtoByUserId(comment.getAuthorId());
+ EventCommentDto eventCommentDto = eventClientHelper.retrieveEventCommentDtoByEventId(comment.getEventId());
+
+ return CommentMapper.toCommentDto(comment, userDto, eventCommentDto);
+ }
+
+ @Override
+ public List getCommentsByEvent(Long eventId, int from, int size) {
+ EventCommentDto eventCommentDto = eventClientHelper.retrieveEventCommentDtoByEventId(eventId);
+
+ List comments = transactionTemplate.execute(status -> {
+ Pageable pageable = PageRequest.of(from / size, size, Sort.by("createTime").ascending());
+ return commentRepository.findAllByEventIdAndApproved(eventId, true, pageable).getContent();
+ });
+ if (comments == null || comments.isEmpty()) return List.of();
+
+ Set userIds = comments.stream().map(Comment::getAuthorId).collect(Collectors.toSet());
+ Map userMap = userClientHelper.retrieveUserDtoMapByUserIdList(userIds);
+
+ return comments.stream()
+ .map(c -> CommentMapper.toCommentShortDto(c, userMap.get(c.getAuthorId())))
+ .toList();
+ }
+
+ @Override
+ public CommentDto getCommentByEventAndCommentId(Long eventId, Long comId) {
+ Comment comment = transactionTemplate.execute(status -> {
+ return commentRepository.findById(comId)
+ .orElseThrow(() -> new NotFoundException("Not found Comment " + comId));
+ });
+
+ if (!Objects.equals(comment.getEventId(), eventId))
+ throw new NotFoundException("Comment " + comId + " does not belong to Event " + eventId);
+
+ if (!Objects.equals(comment.getApproved(), true))
+ throw new ForbiddenException("Comment " + comId + "is not approved");
+
+ UserDto userDto = userClientHelper.retrieveUserDtoByUserId(comment.getAuthorId());
+ EventCommentDto eventCommentDto = eventClientHelper.retrieveEventCommentDtoByEventId(comment.getEventId());
+
+ return CommentMapper.toCommentDto(comment, userDto, eventCommentDto);
+ }
+
+}
\ No newline at end of file
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..931c1b1
--- /dev/null
+++ b/core/comment-service/src/main/resources/application.yaml
@@ -0,0 +1,25 @@
+spring:
+ application:
+ name: comment-service
+ config:
+ import: "configserver:"
+ cloud:
+ config:
+ discovery:
+ enabled: true
+ serviceId: config-server
+ fail-fast: true
+ retry:
+ useRandomPolicy: true
+ max-interval: 10000
+ max-attempts: 100
+
+eureka:
+ client:
+ registerWithEureka: true
+ serviceUrl:
+ defaultZone: http://localhost:8761/eureka/
+ instance:
+ instance-id: ${spring.application.name}${random.int}
+ preferIpAddress: false
+ hostname: localhost
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..0e28872
--- /dev/null
+++ b/core/comment-service/src/main/resources/schema.sql
@@ -0,0 +1 @@
+CREATE SCHEMA IF NOT EXISTS comment_service;
diff --git a/core/core-common/pom.xml b/core/core-common/pom.xml
new file mode 100644
index 0000000..09963fa
--- /dev/null
+++ b/core/core-common/pom.xml
@@ -0,0 +1,134 @@
+
+
+ 4.0.0
+
+
+ ru.practicum
+ core
+ 0.0.1-SNAPSHOT
+
+
+ core-common
+
+
+
+
+
+
+
+
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-configuration-processor
+ true
+
+
+
+ org.projectlombok
+ lombok
+
+
+
+
+
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+
+
+
+ org.springframework.boot
+ spring-boot-starter-validation
+
+
+
+ javax.validation
+ validation-api
+ 2.0.1.Final
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ org.springframework.cloud
+ spring-cloud-starter-openfeign
+
+
+
+ org.springframework.cloud
+ spring-cloud-starter-circuitbreaker-resilience4j
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+
+
+
+ org.projectlombok
+ lombok
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/core/core-common/src/main/java/ru/practicum/api/category/CategoryAdminApi.java b/core/core-common/src/main/java/ru/practicum/api/category/CategoryAdminApi.java
new file mode 100644
index 0000000..59fb0bd
--- /dev/null
+++ b/core/core-common/src/main/java/ru/practicum/api/category/CategoryAdminApi.java
@@ -0,0 +1,31 @@
+package ru.practicum.api.category;
+
+import jakarta.validation.constraints.Positive;
+import org.springframework.http.HttpStatus;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+import ru.practicum.dto.category.CategoryDto;
+import ru.practicum.validation.CreateOrUpdateValidator;
+
+public interface CategoryAdminApi {
+
+ @PostMapping("/admin/categories")
+ @ResponseStatus(HttpStatus.CREATED)
+ CategoryDto addCategory(
+ @RequestBody @Validated(CreateOrUpdateValidator.Create.class) CategoryDto requestCategory
+ );
+
+ @DeleteMapping("/admin/categories/{catId}")
+ @ResponseStatus(HttpStatus.NO_CONTENT)
+ String deleteCategories(
+ @PathVariable @Positive Long catId
+ );
+
+ @PatchMapping("/admin/categories/{catId}")
+ @ResponseStatus(HttpStatus.OK)
+ CategoryDto updateCategory(
+ @PathVariable Long catId,
+ @RequestBody @Validated(CreateOrUpdateValidator.Update.class) CategoryDto categoryDto
+ );
+
+}
\ No newline at end of file
diff --git a/core/core-common/src/main/java/ru/practicum/api/category/CategoryPublicApi.java b/core/core-common/src/main/java/ru/practicum/api/category/CategoryPublicApi.java
new file mode 100644
index 0000000..f3bb20b
--- /dev/null
+++ b/core/core-common/src/main/java/ru/practicum/api/category/CategoryPublicApi.java
@@ -0,0 +1,29 @@
+package ru.practicum.api.category;
+
+import jakarta.validation.constraints.Positive;
+import jakarta.validation.constraints.PositiveOrZero;
+import org.springframework.http.HttpStatus;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.ResponseStatus;
+import ru.practicum.dto.category.CategoryDto;
+
+import java.util.Collection;
+
+public interface CategoryPublicApi {
+
+ @GetMapping("/categories")
+ @ResponseStatus(HttpStatus.OK)
+ Collection readAllCategories(
+ @RequestParam(defaultValue = "0") @PositiveOrZero int from,
+ @RequestParam(defaultValue = "10") @Positive int size
+ );
+
+ @GetMapping("/categories/{catId}")
+ @ResponseStatus(HttpStatus.OK)
+ CategoryDto readCategoryById(
+ @PathVariable Long catId
+ );
+
+}
\ No newline at end of file
diff --git a/core/core-common/src/main/java/ru/practicum/api/comment/CommentAdminApi.java b/core/core-common/src/main/java/ru/practicum/api/comment/CommentAdminApi.java
new file mode 100644
index 0000000..9738b88
--- /dev/null
+++ b/core/core-common/src/main/java/ru/practicum/api/comment/CommentAdminApi.java
@@ -0,0 +1,47 @@
+package ru.practicum.api.comment;
+
+import jakarta.validation.constraints.NotBlank;
+import jakarta.validation.constraints.Positive;
+import org.springframework.http.HttpStatus;
+import org.springframework.web.bind.annotation.*;
+import ru.practicum.dto.comment.CommentDto;
+
+import java.util.Collection;
+
+public interface CommentAdminApi {
+
+ @GetMapping("/admin/comments/search")
+ @ResponseStatus(HttpStatus.OK)
+ Collection search(
+ @RequestParam @NotBlank String text,
+ @RequestParam(defaultValue = "0") int from,
+ @RequestParam(defaultValue = "10") int size
+ );
+
+ @GetMapping("/admin/users/{userId}/comments")
+ @ResponseStatus(HttpStatus.OK)
+ Collection get(
+ @PathVariable @Positive Long userId,
+ @RequestParam(defaultValue = "0") int from,
+ @RequestParam(defaultValue = "10") int size
+ );
+
+ @DeleteMapping("/admin/comments/{comId}")
+ @ResponseStatus(HttpStatus.NO_CONTENT)
+ boolean delete(
+ @PathVariable @Positive Long comId
+ );
+
+ @PatchMapping("/admin/comments/{comId}/approve")
+ @ResponseStatus(HttpStatus.OK)
+ CommentDto approveComment(
+ @PathVariable @Positive Long comId
+ );
+
+ @PatchMapping("/admin/comments/{comId}/reject")
+ @ResponseStatus(HttpStatus.OK)
+ CommentDto rejectComment(
+ @PathVariable @Positive Long comId
+ );
+
+}
\ No newline at end of file
diff --git a/core/core-common/src/main/java/ru/practicum/api/comment/CommentPrivateApi.java b/core/core-common/src/main/java/ru/practicum/api/comment/CommentPrivateApi.java
new file mode 100644
index 0000000..d81a03b
--- /dev/null
+++ b/core/core-common/src/main/java/ru/practicum/api/comment/CommentPrivateApi.java
@@ -0,0 +1,35 @@
+package ru.practicum.api.comment;
+
+import jakarta.validation.Valid;
+import jakarta.validation.constraints.Positive;
+import org.springframework.http.HttpStatus;
+import org.springframework.web.bind.annotation.*;
+import ru.practicum.dto.comment.CommentCreateDto;
+import ru.practicum.dto.comment.CommentDto;
+
+public interface CommentPrivateApi {
+
+ @PostMapping("/users/{userId}/events/{eventId}/comments")
+ @ResponseStatus(HttpStatus.CREATED)
+ CommentDto create(
+ @PathVariable @Positive Long userId,
+ @PathVariable @Positive Long eventId,
+ @RequestBody @Valid CommentCreateDto commentCreateDto
+ );
+
+ @DeleteMapping("/users/{userId}/comments/{comId}")
+ @ResponseStatus(HttpStatus.NO_CONTENT)
+ String delete(
+ @PathVariable @Positive Long userId,
+ @PathVariable @Positive Long comId
+ );
+
+ @PatchMapping("/users/{userId}/comments/{comId}")
+ @ResponseStatus(HttpStatus.OK)
+ CommentDto patch(
+ @PathVariable @Positive Long userId,
+ @PathVariable @Positive Long comId,
+ @RequestBody @Valid CommentCreateDto commentCreateDto
+ );
+
+}
\ No newline at end of file
diff --git a/core/core-common/src/main/java/ru/practicum/api/comment/CommentPublicApi.java b/core/core-common/src/main/java/ru/practicum/api/comment/CommentPublicApi.java
new file mode 100644
index 0000000..04a062f
--- /dev/null
+++ b/core/core-common/src/main/java/ru/practicum/api/comment/CommentPublicApi.java
@@ -0,0 +1,37 @@
+package ru.practicum.api.comment;
+
+import jakarta.validation.constraints.Positive;
+import org.springframework.http.HttpStatus;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.ResponseStatus;
+import ru.practicum.dto.comment.CommentDto;
+import ru.practicum.dto.comment.CommentShortDto;
+
+import java.util.Collection;
+
+public interface CommentPublicApi {
+
+ @GetMapping("/comments/{comId}")
+ @ResponseStatus(HttpStatus.OK)
+ CommentDto getById(
+ @PathVariable @Positive Long comId
+ );
+
+ @GetMapping("/events/{eventId}/comments")
+ @ResponseStatus(HttpStatus.OK)
+ Collection getByEventId(
+ @PathVariable @Positive Long eventId,
+ @RequestParam(defaultValue = "0") int from,
+ @RequestParam(defaultValue = "10") int size
+ );
+
+ @GetMapping("/events/{eventId}/comments/{commentId}")
+ @ResponseStatus(HttpStatus.OK)
+ CommentDto getByEventAndCommentId(
+ @PathVariable @Positive Long eventId,
+ @PathVariable @Positive Long commentId
+ );
+
+}
\ No newline at end of file
diff --git a/core/core-common/src/main/java/ru/practicum/api/compilation/CompilationAdminApi.java b/core/core-common/src/main/java/ru/practicum/api/compilation/CompilationAdminApi.java
new file mode 100644
index 0000000..6a5bc6b
--- /dev/null
+++ b/core/core-common/src/main/java/ru/practicum/api/compilation/CompilationAdminApi.java
@@ -0,0 +1,31 @@
+package ru.practicum.api.compilation;
+
+import jakarta.validation.Valid;
+import org.springframework.http.HttpStatus;
+import org.springframework.web.bind.annotation.*;
+import ru.practicum.dto.compilation.CompilationDto;
+import ru.practicum.dto.compilation.NewCompilationDto;
+import ru.practicum.dto.compilation.UpdateCompilationDto;
+
+public interface CompilationAdminApi {
+
+ @PostMapping("/admin/compilations")
+ @ResponseStatus(HttpStatus.CREATED)
+ CompilationDto postCompilations(
+ @RequestBody @Valid NewCompilationDto newCompilationDto
+ );
+
+ @DeleteMapping("/admin/compilations/{compId}")
+ @ResponseStatus(HttpStatus.NO_CONTENT)
+ String deleteCompilation(
+ @PathVariable Long compId
+ );
+
+ @PatchMapping("/admin/compilations/{compId}")
+ @ResponseStatus(HttpStatus.OK)
+ CompilationDto patchCompilation(
+ @PathVariable Long compId,
+ @RequestBody @Valid UpdateCompilationDto updateCompilationDto
+ );
+
+}
\ No newline at end of file
diff --git a/core/core-common/src/main/java/ru/practicum/api/compilation/CompilationPublicApi.java b/core/core-common/src/main/java/ru/practicum/api/compilation/CompilationPublicApi.java
new file mode 100644
index 0000000..071559d
--- /dev/null
+++ b/core/core-common/src/main/java/ru/practicum/api/compilation/CompilationPublicApi.java
@@ -0,0 +1,30 @@
+package ru.practicum.api.compilation;
+
+import jakarta.validation.constraints.Positive;
+import jakarta.validation.constraints.PositiveOrZero;
+import org.springframework.http.HttpStatus;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.ResponseStatus;
+import ru.practicum.dto.compilation.CompilationDto;
+
+import java.util.Collection;
+
+public interface CompilationPublicApi {
+
+ @GetMapping("/compilations")
+ @ResponseStatus(HttpStatus.OK)
+ Collection getCompilation(
+ @RequestParam(required = false) Boolean pinned,
+ @RequestParam(defaultValue = "0") @PositiveOrZero int from,
+ @RequestParam(defaultValue = "10") @Positive int size
+ );
+
+ @GetMapping("/compilations/{compId}")
+ @ResponseStatus(HttpStatus.OK)
+ CompilationDto getCompilationById(
+ @PathVariable Long compId
+ );
+
+}
diff --git a/core/core-common/src/main/java/ru/practicum/api/event/EventAdminApi.java b/core/core-common/src/main/java/ru/practicum/api/event/EventAdminApi.java
new file mode 100644
index 0000000..24022a1
--- /dev/null
+++ b/core/core-common/src/main/java/ru/practicum/api/event/EventAdminApi.java
@@ -0,0 +1,40 @@
+package ru.practicum.api.event;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import jakarta.validation.Valid;
+import jakarta.validation.constraints.Positive;
+import jakarta.validation.constraints.PositiveOrZero;
+import org.springframework.http.HttpStatus;
+import org.springframework.web.bind.annotation.*;
+import ru.practicum.dto.event.EventFullDto;
+import ru.practicum.dto.event.State;
+import ru.practicum.dto.event.UpdateEventDto;
+
+import java.time.LocalDateTime;
+import java.util.Collection;
+import java.util.List;
+
+public interface EventAdminApi {
+
+ // Поиск событий
+ @GetMapping("/admin/events")
+ @ResponseStatus(HttpStatus.OK)
+ Collection getAllEventsByParams(
+ @RequestParam(required = false) List users,
+ @RequestParam(required = false) List states,
+ @RequestParam(required = false) List categories,
+ @RequestParam(required = false) @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") LocalDateTime rangeStart,
+ @RequestParam(required = false) @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") LocalDateTime rangeEnd,
+ @RequestParam(defaultValue = "0") @PositiveOrZero Integer from,
+ @RequestParam(defaultValue = "10") @Positive Integer size
+ );
+
+ // Редактирование данных события и его статуса (отклонение/публикация).
+ @PatchMapping("/admin/events/{eventId}")
+ @ResponseStatus(HttpStatus.OK)
+ EventFullDto updateEventByAdmin(
+ @PathVariable Long eventId,
+ @RequestBody @Valid UpdateEventDto updateEventDto
+ );
+
+}
diff --git a/core/core-common/src/main/java/ru/practicum/api/event/EventAllApi.java b/core/core-common/src/main/java/ru/practicum/api/event/EventAllApi.java
new file mode 100644
index 0000000..dc37691
--- /dev/null
+++ b/core/core-common/src/main/java/ru/practicum/api/event/EventAllApi.java
@@ -0,0 +1,4 @@
+package ru.practicum.api.event;
+
+public interface EventAllApi extends EventPublicApi, EventPrivateApi, EventAdminApi {
+}
diff --git a/core/core-common/src/main/java/ru/practicum/api/event/EventPrivateApi.java b/core/core-common/src/main/java/ru/practicum/api/event/EventPrivateApi.java
new file mode 100644
index 0000000..8302fef
--- /dev/null
+++ b/core/core-common/src/main/java/ru/practicum/api/event/EventPrivateApi.java
@@ -0,0 +1,50 @@
+package ru.practicum.api.event;
+
+import jakarta.validation.Valid;
+import jakarta.validation.constraints.Positive;
+import org.springframework.http.HttpStatus;
+import org.springframework.web.bind.annotation.*;
+import ru.practicum.dto.event.EventFullDto;
+import ru.practicum.dto.event.EventShortDto;
+import ru.practicum.dto.event.NewEventDto;
+import ru.practicum.dto.event.UpdateEventDto;
+
+import java.util.Collection;
+
+public interface EventPrivateApi {
+
+ // Добавление нового события
+ @PostMapping("/users/{userId}/events")
+ @ResponseStatus(HttpStatus.CREATED)
+ EventFullDto addNewEventByUser(
+ @PathVariable @Positive Long userId,
+ @Valid @RequestBody NewEventDto newEventDto
+ );
+
+ // Получение событий, добавленных текущим пользователем
+ @GetMapping("/users/{userId}/events")
+ @ResponseStatus(HttpStatus.OK)
+ Collection getAllEventsByUserId(
+ @PathVariable @Positive Long userId,
+ @RequestParam(defaultValue = "0") Integer from,
+ @RequestParam(defaultValue = "10") Integer size
+ );
+
+ // Получение полной информации о событии добавленном текущим пользователем
+ @GetMapping("/users/{userId}/events/{eventId}")
+ @ResponseStatus(HttpStatus.OK)
+ EventFullDto getEventByUserIdAndEventId(
+ @PathVariable @Positive Long userId,
+ @PathVariable @Positive Long eventId
+ );
+
+ // Изменение события добавленного текущим пользователем
+ @PatchMapping("/users/{userId}/events/{eventId}")
+ @ResponseStatus(HttpStatus.OK)
+ EventFullDto updateEventByUserIdAndEventId(
+ @PathVariable @Positive Long userId,
+ @PathVariable @Positive Long eventId,
+ @Valid @RequestBody UpdateEventDto updateEventDto
+ );
+
+}
diff --git a/core/core-common/src/main/java/ru/practicum/api/event/EventPublicApi.java b/core/core-common/src/main/java/ru/practicum/api/event/EventPublicApi.java
new file mode 100644
index 0000000..7119219
--- /dev/null
+++ b/core/core-common/src/main/java/ru/practicum/api/event/EventPublicApi.java
@@ -0,0 +1,61 @@
+package ru.practicum.api.event;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.validation.constraints.Positive;
+import org.springframework.http.HttpStatus;
+import org.springframework.web.bind.annotation.*;
+import ru.practicum.dto.event.*;
+
+import java.time.LocalDateTime;
+import java.util.Collection;
+import java.util.List;
+
+public interface EventPublicApi {
+
+ // Получение событий с возможностью фильтрации
+ @GetMapping("/events")
+ @ResponseStatus(HttpStatus.OK)
+ List getAllEventsByParams(
+ @RequestParam(required = false) String text,
+ @RequestParam(required = false) List categories,
+ @RequestParam(required = false) Boolean paid,
+ @RequestParam(required = false) @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") LocalDateTime rangeStart,
+ @RequestParam(required = false) @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") LocalDateTime rangeEnd,
+ @RequestParam(defaultValue = "false") Boolean onlyAvailable,
+ @RequestParam(defaultValue = "EVENT_DATE") EventSort eventSort,
+ @RequestParam(defaultValue = "0") Integer from,
+ @RequestParam(defaultValue = "10") Integer size,
+ HttpServletRequest request
+ );
+
+ // Получение подробной информации об опубликованном событии по его идентификатору
+ @GetMapping("/events/{id}")
+ @ResponseStatus(HttpStatus.OK)
+ EventFullDto getInformationAboutEventByEventId(
+ @PathVariable @Positive Long id,
+ HttpServletRequest request
+ );
+
+ // Получение информации о событии для сервиса комментариев
+ @GetMapping("/events/{id}/dto/comment")
+ @ResponseStatus(HttpStatus.OK)
+ EventCommentDto getEventCommentDto(
+ @PathVariable @Positive Long id
+ );
+
+ // Получение информации о списке событий для сервиса комментариев
+ @PostMapping("/events/dto/list/comment")
+ @ResponseStatus(HttpStatus.OK)
+ Collection getEventCommentDtoList(
+ @RequestBody Collection ids
+ );
+
+ // Получение информации о событии для сервиса заявок
+ @GetMapping("/events/{id}/dto/interaction")
+ @ResponseStatus(HttpStatus.OK)
+ EventInteractionDto getEventInteractionDto(
+ @PathVariable @Positive Long id
+ );
+
+}
\ No newline at end of file
diff --git a/core/main-service/src/main/java/ru/practicum/request/controller/RequestController.java b/core/core-common/src/main/java/ru/practicum/api/request/RequestApi.java
similarity index 64%
rename from core/main-service/src/main/java/ru/practicum/request/controller/RequestController.java
rename to core/core-common/src/main/java/ru/practicum/api/request/RequestApi.java
index ac51204..163c60a 100644
--- a/core/main-service/src/main/java/ru/practicum/request/controller/RequestController.java
+++ b/core/core-common/src/main/java/ru/practicum/api/request/RequestApi.java
@@ -1,74 +1,69 @@
-package ru.practicum.request.controller;
+package ru.practicum.api.request;
import jakarta.validation.Valid;
import jakarta.validation.constraints.Positive;
-import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpStatus;
-import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
-import ru.practicum.request.dto.EventRequestStatusUpdateRequestDto;
-import ru.practicum.request.dto.EventRequestStatusUpdateResultDto;
-import ru.practicum.request.dto.ParticipationRequestDto;
-import ru.practicum.request.service.RequestService;
+import ru.practicum.dto.request.EventRequestStatusUpdateRequestDto;
+import ru.practicum.dto.request.EventRequestStatusUpdateResultDto;
+import ru.practicum.dto.request.ParticipationRequestDto;
import java.util.Collection;
+import java.util.Map;
-@RestController
-@RequiredArgsConstructor
-@Validated
-public class RequestController {
-
- private final RequestService requestService;
+public interface RequestApi {
// ЗАЯВКИ ТЕКУЩЕГО ПОЛЬЗОВАТЕЛЯ
// Добавление запроса от текущего пользователя на участие в событии
@PostMapping("/users/{userId}/requests")
@ResponseStatus(HttpStatus.CREATED)
- public ParticipationRequestDto addRequest(
+ ParticipationRequestDto addRequest(
@PathVariable @Positive(message = "User Id not valid") Long userId,
@RequestParam @Positive(message = "Event Id not valid") Long eventId
- ) {
- return requestService.addRequest(userId, eventId);
- }
+ );
// Отмена своего запроса на участие в событии
@PatchMapping("/users/{userId}/requests/{requestId}/cancel")
- public ParticipationRequestDto cancelRequest(
+ @ResponseStatus(HttpStatus.OK)
+ ParticipationRequestDto cancelRequest(
@PathVariable @Positive(message = "User Id not valid") Long userId,
@PathVariable @Positive(message = "Request Id not valid") Long requestId
- ) {
- return requestService.cancelRequest(userId, requestId);
- }
+ );
// Получение информации о заявках текущего пользователя на участие в чужих событиях
@GetMapping("/users/{userId}/requests")
- public Collection getRequesterRequests(
+ @ResponseStatus(HttpStatus.OK)
+ Collection getRequesterRequests(
@PathVariable @Positive(message = "User Id not valid") Long userId
- ) {
- return requestService.findRequesterRequests(userId);
- }
+ );
// ЗАЯВКИ НА КОНКРЕТНОЕ СОБЫТИЕ
// Изменение статуса (подтверждена, отменена) заявок на участие в событии текущего пользователя
@PatchMapping("/users/{userId}/events/{eventId}/requests")
- public EventRequestStatusUpdateResultDto moderateRequest(
+ @ResponseStatus(HttpStatus.OK)
+ EventRequestStatusUpdateResultDto moderateRequest(
@PathVariable @Positive(message = "User Id not valid") Long userId,
@PathVariable @Positive(message = "Event Id not valid") Long eventId,
@RequestBody @Valid EventRequestStatusUpdateRequestDto updateRequestDto
- ) {
- return requestService.moderateRequest(userId, eventId, updateRequestDto);
- }
+ );
// Получение информации о запросах на участие в событии текущего пользователя
@GetMapping("/users/{userId}/events/{eventId}/requests")
- public Collection getEventRequests(
+ @ResponseStatus(HttpStatus.OK)
+ Collection getEventRequests(
@PathVariable @Positive(message = "User Id not valid") Long userId,
@PathVariable @Positive(message = "Event Id not valid") Long eventId
- ) {
- return requestService.findEventRequests(userId, eventId);
- }
+ );
+
+ // INTERACTION API
+ // Запрос количества подтвержденных заявок по списку eventId
+ @PostMapping("/requests/confirmed")
+ @ResponseStatus(HttpStatus.OK)
+ Map getConfirmedRequestsByEventIds(
+ @RequestBody Collection eventIds
+ );
}
\ No newline at end of file
diff --git a/core/core-common/src/main/java/ru/practicum/api/user/UserApi.java b/core/core-common/src/main/java/ru/practicum/api/user/UserApi.java
new file mode 100644
index 0000000..4bdbb74
--- /dev/null
+++ b/core/core-common/src/main/java/ru/practicum/api/user/UserApi.java
@@ -0,0 +1,66 @@
+package ru.practicum.api.user;
+
+import jakarta.validation.Valid;
+import jakarta.validation.constraints.Positive;
+import org.springframework.http.HttpStatus;
+import org.springframework.web.bind.annotation.*;
+import ru.practicum.dto.user.NewUserRequestDto;
+import ru.practicum.dto.user.UserDto;
+import ru.practicum.dto.user.UserShortDto;
+
+import java.util.Collection;
+import java.util.List;
+
+public interface UserApi {
+
+ // MODIFY OPS
+
+ @PostMapping("/admin/users")
+ @ResponseStatus(HttpStatus.CREATED)
+ UserDto createUser(
+ @RequestBody @Valid NewUserRequestDto newUserRequestDto
+ );
+
+ @DeleteMapping("/admin/users/{userId}")
+ @ResponseStatus(HttpStatus.NO_CONTENT)
+ void deleteUser(
+ @PathVariable @Positive(message = "User Id not valid") Long userId
+ );
+
+ // GET + HEAD
+
+ @GetMapping("/admin/users/{userId}")
+ @ResponseStatus(HttpStatus.OK)
+ UserDto getUser(
+ @PathVariable @Positive(message = "User Id not valid") Long userId
+ );
+
+ @GetMapping("/admin/users/{userId}/short")
+ @ResponseStatus(HttpStatus.OK)
+ UserShortDto getUserShort(
+ @PathVariable @Positive(message = "User Id not valid") Long userId
+ );
+
+ // GET COLLECTION
+
+ @GetMapping("/admin/users")
+ @ResponseStatus(HttpStatus.OK)
+ Collection getUsers(
+ @RequestParam(required = false) List ids,
+ @RequestParam(defaultValue = "0") Integer from,
+ @RequestParam(defaultValue = "10") Integer size
+ );
+
+ @GetMapping("/admin/users/all/short")
+ @ResponseStatus(HttpStatus.OK)
+ Collection getUserShortDtoListByIds(
+ @RequestParam(required = false) Collection ids
+ );
+
+ @GetMapping("/admin/users/all/full")
+ @ResponseStatus(HttpStatus.OK)
+ Collection getUserDtoListByIds(
+ @RequestParam(required = false) Collection ids
+ );
+
+}
\ No newline at end of file
diff --git a/core/core-common/src/main/java/ru/practicum/client/EventClientAbstractHelper.java b/core/core-common/src/main/java/ru/practicum/client/EventClientAbstractHelper.java
new file mode 100644
index 0000000..ba6620d
--- /dev/null
+++ b/core/core-common/src/main/java/ru/practicum/client/EventClientAbstractHelper.java
@@ -0,0 +1,89 @@
+package ru.practicum.client;
+
+import feign.FeignException;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import ru.practicum.api.event.EventAllApi;
+import ru.practicum.dto.event.EventCommentDto;
+import ru.practicum.dto.event.EventInteractionDto;
+import ru.practicum.exception.NotFoundException;
+import ru.practicum.exception.ServiceInteractionException;
+
+import java.util.Collection;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+@Slf4j
+@RequiredArgsConstructor
+public abstract class EventClientAbstractHelper {
+
+ protected final EventAllApi eventApiClient;
+
+ // EventInteractionDto
+
+ public EventInteractionDto retrieveEventInteractionDtoByEventIdOrFall(Long eventId) {
+ try {
+ return eventApiClient.getEventInteractionDto(eventId);
+ } catch (RuntimeException e) {
+ if (isNotFoundCode(e)) throw new NotFoundException("Not found Event " + eventId);
+
+ log.warn("Service Interaction Error: caught " + e.getClass().getSimpleName() + " - " + e.getMessage());
+ throw new ServiceInteractionException("Unable to check Event " + eventId, "event-service is unavailable");
+ }
+ }
+
+ public EventInteractionDto retrieveEventInteractionDtoByEventId(Long eventId) {
+ try {
+ return eventApiClient.getEventInteractionDto(eventId);
+ } catch (RuntimeException e) {
+ if (isNotFoundCode(e)) throw new NotFoundException("Not found Event " + eventId);
+
+ log.warn("Service Interaction Error: caught " + e.getClass().getSimpleName() + " - " + e.getMessage());
+ return EventInteractionDto.makeDummy(eventId);
+ }
+ }
+
+ // EventCommentDto
+
+ public EventCommentDto retrieveEventCommentDtoByEventIdOrFall(Long eventId) {
+ try {
+ return eventApiClient.getEventCommentDto(eventId);
+ } catch (RuntimeException e) {
+ if (isNotFoundCode(e)) throw new NotFoundException("Not found Event " + eventId);
+
+ log.warn("Service Interaction Error: caught " + e.getClass().getSimpleName() + " - " + e.getMessage());
+ throw new ServiceInteractionException("Unable to check Event " + eventId, "event-service is unavailable");
+ }
+ }
+
+ public EventCommentDto retrieveEventCommentDtoByEventId(Long eventId) {
+ try {
+ return eventApiClient.getEventCommentDto(eventId);
+ } catch (RuntimeException e) {
+ if (isNotFoundCode(e)) throw new NotFoundException("Not found Event " + eventId);
+
+ log.warn("Service Interaction Error: caught " + e.getClass().getSimpleName() + " - " + e.getMessage());
+ return EventCommentDto.makeDummy(eventId);
+ }
+ }
+
+ public Map retrieveEventCommentDtoMapByUserIdList(Collection eventIdList) {
+ try {
+ return eventApiClient.getEventCommentDtoList(eventIdList).stream()
+ .collect(Collectors.toMap(EventCommentDto::getId, e -> e));
+ } catch (RuntimeException e) {
+ log.warn("Service Interaction Error: caught " + e.getClass().getSimpleName() + " - " + e.getMessage());
+ return eventIdList.stream()
+ .collect(Collectors.toMap(id -> id, EventCommentDto::makeDummy));
+ }
+ }
+
+ // PRIVATE METHODS
+
+ private boolean isNotFoundCode(RuntimeException e) {
+ if (e instanceof FeignException.NotFound) return true;
+ if (e.getCause() != null && e.getCause() instanceof FeignException.NotFound) return true;
+ return false;
+ }
+
+}
diff --git a/core/core-common/src/main/java/ru/practicum/client/RequestClientAbstractHelper.java b/core/core-common/src/main/java/ru/practicum/client/RequestClientAbstractHelper.java
new file mode 100644
index 0000000..d00145e
--- /dev/null
+++ b/core/core-common/src/main/java/ru/practicum/client/RequestClientAbstractHelper.java
@@ -0,0 +1,27 @@
+package ru.practicum.client;
+
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import ru.practicum.api.request.RequestApi;
+
+import java.util.Collection;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+@Slf4j
+@RequiredArgsConstructor
+public abstract class RequestClientAbstractHelper {
+
+ protected final RequestApi requestApiClient;
+
+ // Confirmed Requests Map - by EventId List
+ public Map retrieveConfirmedRequestsMapByEventIdList(Collection eventIdList) {
+ try {
+ return requestApiClient.getConfirmedRequestsByEventIds(eventIdList);
+ } catch (RuntimeException e) {
+ log.warn("Service Interaction Error: caught " + e.getClass().getSimpleName() + " - " + e.getMessage());
+ return eventIdList.stream().collect(Collectors.toMap(id -> id, id -> -1L));
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/core/core-common/src/main/java/ru/practicum/client/UserClientAbstractHelper.java b/core/core-common/src/main/java/ru/practicum/client/UserClientAbstractHelper.java
new file mode 100644
index 0000000..91bfa04
--- /dev/null
+++ b/core/core-common/src/main/java/ru/practicum/client/UserClientAbstractHelper.java
@@ -0,0 +1,100 @@
+package ru.practicum.client;
+
+import feign.FeignException;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import ru.practicum.api.user.UserApi;
+import ru.practicum.dto.user.UserDto;
+import ru.practicum.dto.user.UserShortDto;
+import ru.practicum.exception.NotFoundException;
+import ru.practicum.exception.ServiceInteractionException;
+
+import java.util.Collection;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+@Slf4j
+@RequiredArgsConstructor
+public abstract class UserClientAbstractHelper {
+
+ protected final UserApi userApiClient;
+
+ // UserShortDto
+
+ public UserShortDto retrieveUserShortDtoByUserIdOrFall(Long userId) {
+ try {
+ return userApiClient.getUserShort(userId);
+ } catch (RuntimeException e) {
+ if (isNotFoundCode(e)) throw new NotFoundException("Not found User " + userId);
+
+ log.warn("Service Interaction Error: caught " + e.getClass().getSimpleName() + " - " + e.getMessage());
+ throw new ServiceInteractionException("Unable to check User " + userId, "user-service is unavailable");
+ }
+ }
+
+ public UserShortDto retrieveUserShortDtoByUserId(Long userId) {
+ try {
+ return userApiClient.getUserShort(userId);
+ } catch (RuntimeException e) {
+ if (isNotFoundCode(e)) throw new NotFoundException("Not found User " + userId);
+
+ log.warn("Service Interaction Error: caught " + e.getClass().getSimpleName() + " - " + e.getMessage());
+ return UserShortDto.makeDummy(userId);
+ }
+ }
+
+ public Map retrieveUserShortDtoMapByUserIdList(Collection userIdList) {
+ try {
+ return userApiClient.getUserShortDtoListByIds(userIdList).stream()
+ .collect(Collectors.toMap(UserShortDto::getId, u -> u));
+ } catch (RuntimeException e) {
+ log.warn("Service Interaction Error: caught " + e.getClass().getSimpleName() + " - " + e.getMessage());
+ return userIdList.stream()
+ .collect(Collectors.toMap(id -> id, UserShortDto::makeDummy));
+ }
+ }
+
+ // UserDto
+
+ public UserDto retrieveUserDtoByUserIdOrFall(Long userId) {
+ try {
+ return userApiClient.getUser(userId);
+ } catch (RuntimeException e) {
+ if (isNotFoundCode(e)) throw new NotFoundException("Not found User " + userId);
+
+ log.warn("Service Interaction Error: caught " + e.getClass().getSimpleName() + " - " + e.getMessage());
+ throw new ServiceInteractionException("Unable to check User " + userId, "user-service is unavailable");
+ }
+ }
+
+ public UserDto retrieveUserDtoByUserId(Long userId) {
+ try {
+ return userApiClient.getUser(userId);
+ } catch (RuntimeException e) {
+ if (isNotFoundCode(e)) throw new NotFoundException("Not found User " + userId);
+
+ log.warn("Service Interaction Error: caught " + e.getClass().getSimpleName() + " - " + e.getMessage());
+ return UserDto.makeDummy(userId);
+ }
+ }
+
+ public Map retrieveUserDtoMapByUserIdList(Collection userIdList) {
+ try {
+ return userApiClient.getUserDtoListByIds(userIdList).stream()
+ .collect(Collectors.toMap(UserDto::getId, u -> u));
+ } catch (RuntimeException e) {
+ log.warn("Service Interaction Error: caught " + e.getClass().getSimpleName() + " - " + e.getMessage());
+ return userIdList.stream()
+ .collect(Collectors.toMap(id -> id, UserDto::makeDummy));
+ }
+ }
+
+ // PRIVATE METHODS
+
+ private boolean isNotFoundCode(RuntimeException e) {
+ if (e instanceof FeignException.NotFound) return true;
+ if (e.getCause() != null && e.getCause() instanceof FeignException.NotFound) return true;
+ return false;
+ }
+
+}
\ No newline at end of file
diff --git a/core/main-service/src/main/java/ru/practicum/category/dto/CategoryDto.java b/core/core-common/src/main/java/ru/practicum/dto/category/CategoryDto.java
similarity index 94%
rename from core/main-service/src/main/java/ru/practicum/category/dto/CategoryDto.java
rename to core/core-common/src/main/java/ru/practicum/dto/category/CategoryDto.java
index 7fffa9e..2ae716b 100644
--- a/core/main-service/src/main/java/ru/practicum/category/dto/CategoryDto.java
+++ b/core/core-common/src/main/java/ru/practicum/dto/category/CategoryDto.java
@@ -1,4 +1,4 @@
-package ru.practicum.category.dto;
+package ru.practicum.dto.category;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.Size;
diff --git a/core/main-service/src/main/java/ru/practicum/comment/dto/CommentCountDto.java b/core/core-common/src/main/java/ru/practicum/dto/comment/CommentCountDto.java
similarity index 88%
rename from core/main-service/src/main/java/ru/practicum/comment/dto/CommentCountDto.java
rename to core/core-common/src/main/java/ru/practicum/dto/comment/CommentCountDto.java
index fe16256..3e6f0e9 100644
--- a/core/main-service/src/main/java/ru/practicum/comment/dto/CommentCountDto.java
+++ b/core/core-common/src/main/java/ru/practicum/dto/comment/CommentCountDto.java
@@ -1,4 +1,4 @@
-package ru.practicum.comment.dto;
+package ru.practicum.dto.comment;
import lombok.AllArgsConstructor;
import lombok.Builder;
diff --git a/core/main-service/src/main/java/ru/practicum/comment/dto/CommentCreateDto.java b/core/core-common/src/main/java/ru/practicum/dto/comment/CommentCreateDto.java
similarity index 91%
rename from core/main-service/src/main/java/ru/practicum/comment/dto/CommentCreateDto.java
rename to core/core-common/src/main/java/ru/practicum/dto/comment/CommentCreateDto.java
index 4182509..c571e20 100644
--- a/core/main-service/src/main/java/ru/practicum/comment/dto/CommentCreateDto.java
+++ b/core/core-common/src/main/java/ru/practicum/dto/comment/CommentCreateDto.java
@@ -1,4 +1,4 @@
-package ru.practicum.comment.dto;
+package ru.practicum.dto.comment;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.Size;
diff --git a/core/main-service/src/main/java/ru/practicum/comment/dto/CommentDto.java b/core/core-common/src/main/java/ru/practicum/dto/comment/CommentDto.java
similarity index 83%
rename from core/main-service/src/main/java/ru/practicum/comment/dto/CommentDto.java
rename to core/core-common/src/main/java/ru/practicum/dto/comment/CommentDto.java
index 1de7f27..db161a4 100644
--- a/core/main-service/src/main/java/ru/practicum/comment/dto/CommentDto.java
+++ b/core/core-common/src/main/java/ru/practicum/dto/comment/CommentDto.java
@@ -1,12 +1,12 @@
-package ru.practicum.comment.dto;
+package ru.practicum.dto.comment;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
-import ru.practicum.event.dto.EventCommentDto;
-import ru.practicum.user.dto.UserDto;
+import ru.practicum.dto.event.EventCommentDto;
+import ru.practicum.dto.user.UserDto;
import java.time.LocalDateTime;
diff --git a/core/main-service/src/main/java/ru/practicum/comment/dto/CommentShortDto.java b/core/core-common/src/main/java/ru/practicum/dto/comment/CommentShortDto.java
similarity index 85%
rename from core/main-service/src/main/java/ru/practicum/comment/dto/CommentShortDto.java
rename to core/core-common/src/main/java/ru/practicum/dto/comment/CommentShortDto.java
index a32bd4c..75ccb9d 100644
--- a/core/main-service/src/main/java/ru/practicum/comment/dto/CommentShortDto.java
+++ b/core/core-common/src/main/java/ru/practicum/dto/comment/CommentShortDto.java
@@ -1,11 +1,11 @@
-package ru.practicum.comment.dto;
+package ru.practicum.dto.comment;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
-import ru.practicum.user.dto.UserDto;
+import ru.practicum.dto.user.UserDto;
@Data
@Builder
diff --git a/core/main-service/src/main/java/ru/practicum/compilation/dto/CompilationDto.java b/core/core-common/src/main/java/ru/practicum/dto/compilation/CompilationDto.java
similarity index 80%
rename from core/main-service/src/main/java/ru/practicum/compilation/dto/CompilationDto.java
rename to core/core-common/src/main/java/ru/practicum/dto/compilation/CompilationDto.java
index 8078f28..79bbe48 100644
--- a/core/main-service/src/main/java/ru/practicum/compilation/dto/CompilationDto.java
+++ b/core/core-common/src/main/java/ru/practicum/dto/compilation/CompilationDto.java
@@ -1,10 +1,10 @@
-package ru.practicum.compilation.dto;
+package ru.practicum.dto.compilation;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
-import ru.practicum.event.dto.EventShortDto;
+import ru.practicum.dto.event.EventShortDto;
import java.util.List;
diff --git a/core/main-service/src/main/java/ru/practicum/compilation/dto/NewCompilationDto.java b/core/core-common/src/main/java/ru/practicum/dto/compilation/NewCompilationDto.java
similarity index 93%
rename from core/main-service/src/main/java/ru/practicum/compilation/dto/NewCompilationDto.java
rename to core/core-common/src/main/java/ru/practicum/dto/compilation/NewCompilationDto.java
index 3dfbc8b..428903d 100644
--- a/core/main-service/src/main/java/ru/practicum/compilation/dto/NewCompilationDto.java
+++ b/core/core-common/src/main/java/ru/practicum/dto/compilation/NewCompilationDto.java
@@ -1,4 +1,4 @@
-package ru.practicum.compilation.dto;
+package ru.practicum.dto.compilation;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.Size;
diff --git a/core/main-service/src/main/java/ru/practicum/compilation/dto/UpdateCompilationDto.java b/core/core-common/src/main/java/ru/practicum/dto/compilation/UpdateCompilationDto.java
similarity index 94%
rename from core/main-service/src/main/java/ru/practicum/compilation/dto/UpdateCompilationDto.java
rename to core/core-common/src/main/java/ru/practicum/dto/compilation/UpdateCompilationDto.java
index b655cf2..e698cdb 100644
--- a/core/main-service/src/main/java/ru/practicum/compilation/dto/UpdateCompilationDto.java
+++ b/core/core-common/src/main/java/ru/practicum/dto/compilation/UpdateCompilationDto.java
@@ -1,4 +1,4 @@
-package ru.practicum.compilation.dto;
+package ru.practicum.dto.compilation;
import jakarta.validation.constraints.Size;
import lombok.AllArgsConstructor;
diff --git a/core/main-service/src/main/java/ru/practicum/event/dto/EventAdminParams.java b/core/core-common/src/main/java/ru/practicum/dto/event/EventAdminParams.java
similarity index 83%
rename from core/main-service/src/main/java/ru/practicum/event/dto/EventAdminParams.java
rename to core/core-common/src/main/java/ru/practicum/dto/event/EventAdminParams.java
index d09fe38..35dab99 100644
--- a/core/main-service/src/main/java/ru/practicum/event/dto/EventAdminParams.java
+++ b/core/core-common/src/main/java/ru/practicum/dto/event/EventAdminParams.java
@@ -1,4 +1,4 @@
-package ru.practicum.event.dto;
+package ru.practicum.dto.event;
import lombok.AllArgsConstructor;
import lombok.Builder;
@@ -24,8 +24,8 @@ public class EventAdminParams {
private LocalDateTime rangeEnd;
- private Long from;
+ private Integer from;
- private Long size;
+ private Integer size;
-}
\ No newline at end of file
+}
diff --git a/core/main-service/src/main/java/ru/practicum/event/dto/EventCommentDto.java b/core/core-common/src/main/java/ru/practicum/dto/event/EventCommentDto.java
similarity index 52%
rename from core/main-service/src/main/java/ru/practicum/event/dto/EventCommentDto.java
rename to core/core-common/src/main/java/ru/practicum/dto/event/EventCommentDto.java
index d8aeb73..8a4ada5 100644
--- a/core/main-service/src/main/java/ru/practicum/event/dto/EventCommentDto.java
+++ b/core/core-common/src/main/java/ru/practicum/dto/event/EventCommentDto.java
@@ -1,4 +1,4 @@
-package ru.practicum.event.dto;
+package ru.practicum.dto.event;
import lombok.AllArgsConstructor;
import lombok.Builder;
@@ -14,4 +14,13 @@ public class EventCommentDto {
private Long id;
private String title;
-}
\ No newline at end of file
+
+ private State state;
+
+ public static EventCommentDto makeDummy(Long id) {
+ EventCommentDto dto = new EventCommentDto();
+ dto.setId(id);
+ return dto;
+ }
+
+}
diff --git a/core/main-service/src/main/java/ru/practicum/event/dto/EventFullDto.java b/core/core-common/src/main/java/ru/practicum/dto/event/EventFullDto.java
similarity index 85%
rename from core/main-service/src/main/java/ru/practicum/event/dto/EventFullDto.java
rename to core/core-common/src/main/java/ru/practicum/dto/event/EventFullDto.java
index e892531..ffa1a1c 100644
--- a/core/main-service/src/main/java/ru/practicum/event/dto/EventFullDto.java
+++ b/core/core-common/src/main/java/ru/practicum/dto/event/EventFullDto.java
@@ -1,13 +1,13 @@
-package ru.practicum.event.dto;
+package ru.practicum.dto.event;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
-import ru.practicum.category.dto.CategoryDto;
-import ru.practicum.comment.dto.CommentShortDto;
-import ru.practicum.user.dto.UserShortDto;
+import ru.practicum.dto.category.CategoryDto;
+import ru.practicum.dto.comment.CommentShortDto;
+import ru.practicum.dto.user.UserShortDto;
import java.time.LocalDateTime;
import java.util.List;
@@ -47,4 +47,4 @@ public class EventFullDto {
private List comments;
-}
\ No newline at end of file
+}
diff --git a/core/core-common/src/main/java/ru/practicum/dto/event/EventInteractionDto.java b/core/core-common/src/main/java/ru/practicum/dto/event/EventInteractionDto.java
new file mode 100644
index 0000000..706ba0d
--- /dev/null
+++ b/core/core-common/src/main/java/ru/practicum/dto/event/EventInteractionDto.java
@@ -0,0 +1,54 @@
+package ru.practicum.dto.event;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.time.LocalDateTime;
+
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+@Builder
+public class EventInteractionDto {
+
+ private Long id;
+
+ private Long initiatorId;
+
+ private Long categoryId;
+
+ private String title;
+
+ private String annotation;
+
+ private String description;
+
+ private State state;
+
+ private LocationDto location;
+
+ private Long participantLimit;
+
+ private Boolean requestModeration;
+
+ private Boolean paid;
+
+ @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+ private LocalDateTime eventDate;
+
+ @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+ private LocalDateTime publishedOn;
+
+ @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+ private LocalDateTime createdOn;
+
+ public static EventInteractionDto makeDummy(Long id) {
+ EventInteractionDto dto = new EventInteractionDto();
+ dto.setId(id);
+ return dto;
+ }
+
+}
diff --git a/core/main-service/src/main/java/ru/practicum/event/dto/EventParams.java b/core/core-common/src/main/java/ru/practicum/dto/event/EventParams.java
similarity index 84%
rename from core/main-service/src/main/java/ru/practicum/event/dto/EventParams.java
rename to core/core-common/src/main/java/ru/practicum/dto/event/EventParams.java
index 411ce9c..73e141f 100644
--- a/core/main-service/src/main/java/ru/practicum/event/dto/EventParams.java
+++ b/core/core-common/src/main/java/ru/practicum/dto/event/EventParams.java
@@ -1,4 +1,4 @@
-package ru.practicum.event.dto;
+package ru.practicum.dto.event;
import lombok.AllArgsConstructor;
import lombok.Builder;
@@ -28,8 +28,8 @@ public class EventParams {
private EventSort eventSort;
- private Long from;
+ private Integer from;
- private Long size;
+ private Integer size;
-}
\ No newline at end of file
+}
diff --git a/core/main-service/src/main/java/ru/practicum/event/dto/EventRequestStatusUpdateRequest.java b/core/core-common/src/main/java/ru/practicum/dto/event/EventRequestStatusUpdateRequest.java
similarity index 82%
rename from core/main-service/src/main/java/ru/practicum/event/dto/EventRequestStatusUpdateRequest.java
rename to core/core-common/src/main/java/ru/practicum/dto/event/EventRequestStatusUpdateRequest.java
index 3fbc1a3..859a768 100644
--- a/core/main-service/src/main/java/ru/practicum/event/dto/EventRequestStatusUpdateRequest.java
+++ b/core/core-common/src/main/java/ru/practicum/dto/event/EventRequestStatusUpdateRequest.java
@@ -1,4 +1,4 @@
-package ru.practicum.event.dto;
+package ru.practicum.dto.event;
import lombok.Data;
@@ -11,4 +11,4 @@ public class EventRequestStatusUpdateRequest {
private State state;
-}
\ No newline at end of file
+}
diff --git a/core/main-service/src/main/java/ru/practicum/event/dto/EventRequestStatusUpdateResult.java b/core/core-common/src/main/java/ru/practicum/dto/event/EventRequestStatusUpdateResult.java
similarity index 70%
rename from core/main-service/src/main/java/ru/practicum/event/dto/EventRequestStatusUpdateResult.java
rename to core/core-common/src/main/java/ru/practicum/dto/event/EventRequestStatusUpdateResult.java
index 4f5c254..3be6bc9 100644
--- a/core/main-service/src/main/java/ru/practicum/event/dto/EventRequestStatusUpdateResult.java
+++ b/core/core-common/src/main/java/ru/practicum/dto/event/EventRequestStatusUpdateResult.java
@@ -1,7 +1,7 @@
-package ru.practicum.event.dto;
+package ru.practicum.dto.event;
import lombok.Data;
-import ru.practicum.request.dto.ParticipationRequestDto;
+import ru.practicum.dto.request.ParticipationRequestDto;
import java.util.List;
@@ -12,4 +12,4 @@ public class EventRequestStatusUpdateResult {
private List rejectedRequests;
-}
\ No newline at end of file
+}
diff --git a/core/main-service/src/main/java/ru/practicum/event/dto/EventShortDto.java b/core/core-common/src/main/java/ru/practicum/dto/event/EventShortDto.java
similarity index 83%
rename from core/main-service/src/main/java/ru/practicum/event/dto/EventShortDto.java
rename to core/core-common/src/main/java/ru/practicum/dto/event/EventShortDto.java
index 8b3a31a..7f3843c 100644
--- a/core/main-service/src/main/java/ru/practicum/event/dto/EventShortDto.java
+++ b/core/core-common/src/main/java/ru/practicum/dto/event/EventShortDto.java
@@ -1,12 +1,12 @@
-package ru.practicum.event.dto;
+package ru.practicum.dto.event;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
-import ru.practicum.category.dto.CategoryDto;
-import ru.practicum.user.dto.UserShortDto;
+import ru.practicum.dto.category.CategoryDto;
+import ru.practicum.dto.user.UserShortDto;
import java.time.LocalDateTime;
@@ -32,4 +32,4 @@ public class EventShortDto {
private Long confirmedRequests;
private Long views;
-}
\ No newline at end of file
+}
diff --git a/core/main-service/src/main/java/ru/practicum/event/dto/EventSort.java b/core/core-common/src/main/java/ru/practicum/dto/event/EventSort.java
similarity index 58%
rename from core/main-service/src/main/java/ru/practicum/event/dto/EventSort.java
rename to core/core-common/src/main/java/ru/practicum/dto/event/EventSort.java
index 56e6dc6..ea36265 100644
--- a/core/main-service/src/main/java/ru/practicum/event/dto/EventSort.java
+++ b/core/core-common/src/main/java/ru/practicum/dto/event/EventSort.java
@@ -1,5 +1,5 @@
-package ru.practicum.event.dto;
+package ru.practicum.dto.event;
public enum EventSort {
EVENT_DATE, VIEWS
-}
\ No newline at end of file
+}
diff --git a/core/main-service/src/main/java/ru/practicum/event/dto/LocationDto.java b/core/core-common/src/main/java/ru/practicum/dto/event/LocationDto.java
similarity index 87%
rename from core/main-service/src/main/java/ru/practicum/event/dto/LocationDto.java
rename to core/core-common/src/main/java/ru/practicum/dto/event/LocationDto.java
index 687d4ee..3b6c1b9 100644
--- a/core/main-service/src/main/java/ru/practicum/event/dto/LocationDto.java
+++ b/core/core-common/src/main/java/ru/practicum/dto/event/LocationDto.java
@@ -1,4 +1,4 @@
-package ru.practicum.event.dto;
+package ru.practicum.dto.event;
import lombok.AllArgsConstructor;
import lombok.Builder;
@@ -14,4 +14,4 @@ public class LocationDto {
private Float lat;
private Float lon;
-}
\ No newline at end of file
+}
diff --git a/core/main-service/src/main/java/ru/practicum/event/dto/NewEventDto.java b/core/core-common/src/main/java/ru/practicum/dto/event/NewEventDto.java
similarity index 95%
rename from core/main-service/src/main/java/ru/practicum/event/dto/NewEventDto.java
rename to core/core-common/src/main/java/ru/practicum/dto/event/NewEventDto.java
index 09e385d..7e43c7e 100644
--- a/core/main-service/src/main/java/ru/practicum/event/dto/NewEventDto.java
+++ b/core/core-common/src/main/java/ru/practicum/dto/event/NewEventDto.java
@@ -1,4 +1,4 @@
-package ru.practicum.event.dto;
+package ru.practicum.dto.event;
import com.fasterxml.jackson.annotation.JsonFormat;
import jakarta.validation.constraints.*;
@@ -39,4 +39,4 @@ public class NewEventDto {
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime eventDate;
-}
\ No newline at end of file
+}
diff --git a/core/main-service/src/main/java/ru/practicum/event/dto/State.java b/core/core-common/src/main/java/ru/practicum/dto/event/State.java
similarity index 61%
rename from core/main-service/src/main/java/ru/practicum/event/dto/State.java
rename to core/core-common/src/main/java/ru/practicum/dto/event/State.java
index 8d04843..976062e 100644
--- a/core/main-service/src/main/java/ru/practicum/event/dto/State.java
+++ b/core/core-common/src/main/java/ru/practicum/dto/event/State.java
@@ -1,5 +1,5 @@
-package ru.practicum.event.dto;
+package ru.practicum.dto.event;
public enum State {
PENDING, PUBLISHED, CANCELED
-}
\ No newline at end of file
+}
diff --git a/core/main-service/src/main/java/ru/practicum/event/dto/StateAction.java b/core/core-common/src/main/java/ru/practicum/dto/event/StateAction.java
similarity index 75%
rename from core/main-service/src/main/java/ru/practicum/event/dto/StateAction.java
rename to core/core-common/src/main/java/ru/practicum/dto/event/StateAction.java
index b6ee34d..c35bda8 100644
--- a/core/main-service/src/main/java/ru/practicum/event/dto/StateAction.java
+++ b/core/core-common/src/main/java/ru/practicum/dto/event/StateAction.java
@@ -1,8 +1,8 @@
-package ru.practicum.event.dto;
+package ru.practicum.dto.event;
public enum StateAction {
SEND_TO_REVIEW,
CANCEL_REVIEW,
PUBLISH_EVENT,
REJECT_EVENT
-}
\ No newline at end of file
+}
diff --git a/core/main-service/src/main/java/ru/practicum/event/dto/UpdateEventDto.java b/core/core-common/src/main/java/ru/practicum/dto/event/UpdateEventDto.java
similarity index 97%
rename from core/main-service/src/main/java/ru/practicum/event/dto/UpdateEventDto.java
rename to core/core-common/src/main/java/ru/practicum/dto/event/UpdateEventDto.java
index f73ee20..1725e05 100644
--- a/core/main-service/src/main/java/ru/practicum/event/dto/UpdateEventDto.java
+++ b/core/core-common/src/main/java/ru/practicum/dto/event/UpdateEventDto.java
@@ -1,4 +1,4 @@
-package ru.practicum.event.dto;
+package ru.practicum.dto.event;
import com.fasterxml.jackson.annotation.JsonFormat;
import jakarta.validation.constraints.Future;
@@ -48,4 +48,4 @@ public class UpdateEventDto {
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime eventDate;
-}
\ No newline at end of file
+}
diff --git a/core/main-service/src/main/java/ru/practicum/request/dto/EventRequestStatusUpdateRequestDto.java b/core/core-common/src/main/java/ru/practicum/dto/request/EventRequestStatusUpdateRequestDto.java
similarity index 79%
rename from core/main-service/src/main/java/ru/practicum/request/dto/EventRequestStatusUpdateRequestDto.java
rename to core/core-common/src/main/java/ru/practicum/dto/request/EventRequestStatusUpdateRequestDto.java
index 3b50544..4af1b9b 100644
--- a/core/main-service/src/main/java/ru/practicum/request/dto/EventRequestStatusUpdateRequestDto.java
+++ b/core/core-common/src/main/java/ru/practicum/dto/request/EventRequestStatusUpdateRequestDto.java
@@ -1,7 +1,5 @@
-package ru.practicum.request.dto;
+package ru.practicum.dto.request;
-import jakarta.persistence.EnumType;
-import jakarta.persistence.Enumerated;
import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.NotNull;
import lombok.AllArgsConstructor;
@@ -20,8 +18,7 @@ public class EventRequestStatusUpdateRequestDto {
@NotEmpty(message = "Field 'requestIds' shouldn't be empty")
private List requestIds;
- @Enumerated(EnumType.STRING)
@NotNull(message = "Field 'status' shouldn't be null")
private ParticipationRequestStatus status;
-}
\ No newline at end of file
+}
diff --git a/core/main-service/src/main/java/ru/practicum/request/dto/EventRequestStatusUpdateResultDto.java b/core/core-common/src/main/java/ru/practicum/dto/request/EventRequestStatusUpdateResultDto.java
similarity index 92%
rename from core/main-service/src/main/java/ru/practicum/request/dto/EventRequestStatusUpdateResultDto.java
rename to core/core-common/src/main/java/ru/practicum/dto/request/EventRequestStatusUpdateResultDto.java
index 4db9fc2..b678c65 100644
--- a/core/main-service/src/main/java/ru/practicum/request/dto/EventRequestStatusUpdateResultDto.java
+++ b/core/core-common/src/main/java/ru/practicum/dto/request/EventRequestStatusUpdateResultDto.java
@@ -1,4 +1,4 @@
-package ru.practicum.request.dto;
+package ru.practicum.dto.request;
import lombok.AllArgsConstructor;
import lombok.Builder;
@@ -20,4 +20,4 @@ public class EventRequestStatusUpdateResultDto {
@Builder.Default
private List rejectedRequests = new ArrayList<>();
-}
\ No newline at end of file
+}
diff --git a/core/main-service/src/main/java/ru/practicum/request/dto/ParticipationRequestDto.java b/core/core-common/src/main/java/ru/practicum/dto/request/ParticipationRequestDto.java
similarity index 93%
rename from core/main-service/src/main/java/ru/practicum/request/dto/ParticipationRequestDto.java
rename to core/core-common/src/main/java/ru/practicum/dto/request/ParticipationRequestDto.java
index 6285a26..25b8afb 100644
--- a/core/main-service/src/main/java/ru/practicum/request/dto/ParticipationRequestDto.java
+++ b/core/core-common/src/main/java/ru/practicum/dto/request/ParticipationRequestDto.java
@@ -1,4 +1,4 @@
-package ru.practicum.request.dto;
+package ru.practicum.dto.request;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.AllArgsConstructor;
@@ -25,4 +25,4 @@ public class ParticipationRequestDto {
@JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss.SSS")
private LocalDateTime created;
-}
\ No newline at end of file
+}
diff --git a/core/main-service/src/main/java/ru/practicum/request/dto/ParticipationRequestStatus.java b/core/core-common/src/main/java/ru/practicum/dto/request/ParticipationRequestStatus.java
similarity index 70%
rename from core/main-service/src/main/java/ru/practicum/request/dto/ParticipationRequestStatus.java
rename to core/core-common/src/main/java/ru/practicum/dto/request/ParticipationRequestStatus.java
index a1fcc71..e2f335e 100644
--- a/core/main-service/src/main/java/ru/practicum/request/dto/ParticipationRequestStatus.java
+++ b/core/core-common/src/main/java/ru/practicum/dto/request/ParticipationRequestStatus.java
@@ -1,7 +1,7 @@
-package ru.practicum.request.dto;
+package ru.practicum.dto.request;
public enum ParticipationRequestStatus {
PENDING, CONFIRMED, CANCELED, REJECTED
-}
\ No newline at end of file
+}
diff --git a/core/main-service/src/main/java/ru/practicum/user/dto/NewUserRequestDto.java b/core/core-common/src/main/java/ru/practicum/dto/user/NewUserRequestDto.java
similarity index 96%
rename from core/main-service/src/main/java/ru/practicum/user/dto/NewUserRequestDto.java
rename to core/core-common/src/main/java/ru/practicum/dto/user/NewUserRequestDto.java
index fb6bf52..c2fecdf 100644
--- a/core/main-service/src/main/java/ru/practicum/user/dto/NewUserRequestDto.java
+++ b/core/core-common/src/main/java/ru/practicum/dto/user/NewUserRequestDto.java
@@ -1,4 +1,4 @@
-package ru.practicum.user.dto;
+package ru.practicum.dto.user;
import jakarta.validation.constraints.Email;
import jakarta.validation.constraints.NotBlank;
diff --git a/core/main-service/src/main/java/ru/practicum/user/dto/UserDto.java b/core/core-common/src/main/java/ru/practicum/dto/user/UserDto.java
similarity index 61%
rename from core/main-service/src/main/java/ru/practicum/user/dto/UserDto.java
rename to core/core-common/src/main/java/ru/practicum/dto/user/UserDto.java
index ffd285f..88b1dd5 100644
--- a/core/main-service/src/main/java/ru/practicum/user/dto/UserDto.java
+++ b/core/core-common/src/main/java/ru/practicum/dto/user/UserDto.java
@@ -1,4 +1,4 @@
-package ru.practicum.user.dto;
+package ru.practicum.dto.user;
import lombok.AllArgsConstructor;
import lombok.Builder;
@@ -17,4 +17,10 @@ public class UserDto {
private String name;
+ public static UserDto makeDummy(Long id) {
+ UserDto dto = new UserDto();
+ dto.setId(id);
+ return dto;
+ }
+
}
diff --git a/core/main-service/src/main/java/ru/practicum/user/dto/UserShortDto.java b/core/core-common/src/main/java/ru/practicum/dto/user/UserShortDto.java
similarity index 57%
rename from core/main-service/src/main/java/ru/practicum/user/dto/UserShortDto.java
rename to core/core-common/src/main/java/ru/practicum/dto/user/UserShortDto.java
index fbb974a..33418cd 100644
--- a/core/main-service/src/main/java/ru/practicum/user/dto/UserShortDto.java
+++ b/core/core-common/src/main/java/ru/practicum/dto/user/UserShortDto.java
@@ -1,4 +1,4 @@
-package ru.practicum.user.dto;
+package ru.practicum.dto.user;
import lombok.AllArgsConstructor;
import lombok.Builder;
@@ -15,4 +15,10 @@ public class UserShortDto {
private String name;
-}
+ public static UserShortDto makeDummy(Long id) {
+ UserShortDto dto = new UserShortDto();
+ dto.setId(id);
+ return dto;
+ }
+
+}
\ No newline at end of file
diff --git a/core/main-service/src/main/java/ru/practicum/exception/ApiError.java b/core/core-common/src/main/java/ru/practicum/exception/ApiError.java
similarity index 99%
rename from core/main-service/src/main/java/ru/practicum/exception/ApiError.java
rename to core/core-common/src/main/java/ru/practicum/exception/ApiError.java
index b765a1d..3d2937a 100644
--- a/core/main-service/src/main/java/ru/practicum/exception/ApiError.java
+++ b/core/core-common/src/main/java/ru/practicum/exception/ApiError.java
@@ -33,4 +33,4 @@ public class ApiError {
@JsonDeserialize(using = LocalDateTimeDeserializer.class)
private LocalDateTime timestamp;
-}
\ No newline at end of file
+}
diff --git a/core/main-service/src/main/java/ru/practicum/exception/BadRequestException.java b/core/core-common/src/main/java/ru/practicum/exception/BadRequestException.java
similarity index 86%
rename from core/main-service/src/main/java/ru/practicum/exception/BadRequestException.java
rename to core/core-common/src/main/java/ru/practicum/exception/BadRequestException.java
index ed9e2b1..ad10664 100644
--- a/core/main-service/src/main/java/ru/practicum/exception/BadRequestException.java
+++ b/core/core-common/src/main/java/ru/practicum/exception/BadRequestException.java
@@ -1,5 +1,8 @@
package ru.practicum.exception;
+import lombok.Getter;
+
+@Getter
public class BadRequestException extends RuntimeException {
private final String reason;
@@ -14,8 +17,4 @@ public BadRequestException(String message, String reason) {
this.reason = reason;
}
- public String getReason() {
- return reason;
- }
-
}
\ No newline at end of file
diff --git a/core/main-service/src/main/java/ru/practicum/exception/ConflictException.java b/core/core-common/src/main/java/ru/practicum/exception/ConflictException.java
similarity index 86%
rename from core/main-service/src/main/java/ru/practicum/exception/ConflictException.java
rename to core/core-common/src/main/java/ru/practicum/exception/ConflictException.java
index beb9dc0..2565e60 100644
--- a/core/main-service/src/main/java/ru/practicum/exception/ConflictException.java
+++ b/core/core-common/src/main/java/ru/practicum/exception/ConflictException.java
@@ -1,5 +1,8 @@
package ru.practicum.exception;
+import lombok.Getter;
+
+@Getter
public class ConflictException extends RuntimeException {
private final String reason;
@@ -14,8 +17,4 @@ public ConflictException(String message, String reason) {
this.reason = reason;
}
- public String getReason() {
- return reason;
- }
-
}
\ No newline at end of file
diff --git a/core/main-service/src/main/java/ru/practicum/exception/ForbiddenException.java b/core/core-common/src/main/java/ru/practicum/exception/ForbiddenException.java
similarity index 87%
rename from core/main-service/src/main/java/ru/practicum/exception/ForbiddenException.java
rename to core/core-common/src/main/java/ru/practicum/exception/ForbiddenException.java
index f7b6e0f..8d9723e 100644
--- a/core/main-service/src/main/java/ru/practicum/exception/ForbiddenException.java
+++ b/core/core-common/src/main/java/ru/practicum/exception/ForbiddenException.java
@@ -1,5 +1,8 @@
package ru.practicum.exception;
+import lombok.Getter;
+
+@Getter
public class ForbiddenException extends RuntimeException {
private final String reason;
@@ -14,8 +17,4 @@ public ForbiddenException(String message, String reason) {
this.reason = reason;
}
- public String getReason() {
- return reason;
- }
-
}
\ No newline at end of file
diff --git a/core/main-service/src/main/java/ru/practicum/exception/GlobalExceptionHandler.java b/core/core-common/src/main/java/ru/practicum/exception/GlobalExceptionHandler.java
similarity index 92%
rename from core/main-service/src/main/java/ru/practicum/exception/GlobalExceptionHandler.java
rename to core/core-common/src/main/java/ru/practicum/exception/GlobalExceptionHandler.java
index c7ab630..0422855 100644
--- a/core/main-service/src/main/java/ru/practicum/exception/GlobalExceptionHandler.java
+++ b/core/core-common/src/main/java/ru/practicum/exception/GlobalExceptionHandler.java
@@ -147,21 +147,18 @@ public ResponseEntity handleNotFoundException(NotFoundException e, Htt
return new ResponseEntity<>(apiError, HttpStatus.NOT_FOUND);
}
- // OTHER UNKNOWN EXCEPTIONS ---------------------------------------------------
-
@ExceptionHandler(
- RuntimeException.class // Internal Server Error
+ ServiceInteractionException.class // custom exception
)
- public ResponseEntity handleRuntimeException(RuntimeException e, HttpServletRequest request) {
- log.debug("INTERNAL SERVER ERROR: {}", e.getMessage());
+ public ResponseEntity handleServiceInteractionException(ServiceInteractionException e, HttpServletRequest request) {
+ log.debug("SERVICE INTERACTION ERROR: {}", e.getMessage());
ApiError apiError = ApiError.builder()
- .status(HttpStatus.INTERNAL_SERVER_ERROR)
- .reason("Internal Server Error")
+ .status(HttpStatus.SERVICE_UNAVAILABLE)
+ .reason(e.getReason())
.message(e.getMessage())
.timestamp(LocalDateTime.now())
.build();
- return new ResponseEntity<>(apiError, HttpStatus.INTERNAL_SERVER_ERROR);
+ return new ResponseEntity<>(apiError, HttpStatus.SERVICE_UNAVAILABLE);
}
-
-}
\ No newline at end of file
+}
diff --git a/core/main-service/src/main/java/ru/practicum/exception/NotFoundException.java b/core/core-common/src/main/java/ru/practicum/exception/NotFoundException.java
similarity index 86%
rename from core/main-service/src/main/java/ru/practicum/exception/NotFoundException.java
rename to core/core-common/src/main/java/ru/practicum/exception/NotFoundException.java
index 57fdec0..f8f2227 100644
--- a/core/main-service/src/main/java/ru/practicum/exception/NotFoundException.java
+++ b/core/core-common/src/main/java/ru/practicum/exception/NotFoundException.java
@@ -1,5 +1,8 @@
package ru.practicum.exception;
+import lombok.Getter;
+
+@Getter
public class NotFoundException extends RuntimeException {
private final String reason;
@@ -14,8 +17,4 @@ public NotFoundException(String message, String reason) {
this.reason = reason;
}
- public String getReason() {
- return reason;
- }
-
}
\ No newline at end of file
diff --git a/core/core-common/src/main/java/ru/practicum/exception/ServiceInteractionException.java b/core/core-common/src/main/java/ru/practicum/exception/ServiceInteractionException.java
new file mode 100644
index 0000000..cb921a1
--- /dev/null
+++ b/core/core-common/src/main/java/ru/practicum/exception/ServiceInteractionException.java
@@ -0,0 +1,20 @@
+package ru.practicum.exception;
+
+import lombok.Getter;
+
+@Getter
+public class ServiceInteractionException extends RuntimeException {
+
+ private final String reason;
+
+ public ServiceInteractionException(String message) {
+ super(message);
+ this.reason = "Unable to get info from microservice";
+ }
+
+ public ServiceInteractionException(String message, String reason) {
+ super(message);
+ this.reason = reason;
+ }
+
+}
\ No newline at end of file
diff --git a/core/main-service/src/main/java/ru/practicum/serialize/LocalDateTimeDeserializer.java b/core/core-common/src/main/java/ru/practicum/serialize/LocalDateTimeDeserializer.java
similarity index 99%
rename from core/main-service/src/main/java/ru/practicum/serialize/LocalDateTimeDeserializer.java
rename to core/core-common/src/main/java/ru/practicum/serialize/LocalDateTimeDeserializer.java
index 099319d..eb9c77f 100644
--- a/core/main-service/src/main/java/ru/practicum/serialize/LocalDateTimeDeserializer.java
+++ b/core/core-common/src/main/java/ru/practicum/serialize/LocalDateTimeDeserializer.java
@@ -31,4 +31,4 @@ public LocalDateTime deserialize(JsonParser jsonParser, DeserializationContext d
return LocalDateTime.parse(date, formatter);
}
-}
\ No newline at end of file
+}
diff --git a/core/main-service/src/main/java/ru/practicum/serialize/LocalDateTimeSerializer.java b/core/core-common/src/main/java/ru/practicum/serialize/LocalDateTimeSerializer.java
similarity index 99%
rename from core/main-service/src/main/java/ru/practicum/serialize/LocalDateTimeSerializer.java
rename to core/core-common/src/main/java/ru/practicum/serialize/LocalDateTimeSerializer.java
index fd7b307..6275664 100644
--- a/core/main-service/src/main/java/ru/practicum/serialize/LocalDateTimeSerializer.java
+++ b/core/core-common/src/main/java/ru/practicum/serialize/LocalDateTimeSerializer.java
@@ -29,4 +29,4 @@ public void serialize(LocalDateTime localDateTime, JsonGenerator jsonGenerator,
jsonGenerator.writeString(localDateTime.format(formatter));
}
-}
\ No newline at end of file
+}
diff --git a/core/main-service/src/main/java/ru/practicum/validation/AtLeastOneNotNull.java b/core/core-common/src/main/java/ru/practicum/validation/AtLeastOneNotNull.java
similarity index 100%
rename from core/main-service/src/main/java/ru/practicum/validation/AtLeastOneNotNull.java
rename to core/core-common/src/main/java/ru/practicum/validation/AtLeastOneNotNull.java
diff --git a/core/main-service/src/main/java/ru/practicum/validation/AtLeastOneNotNullValidator.java b/core/core-common/src/main/java/ru/practicum/validation/AtLeastOneNotNullValidator.java
similarity index 100%
rename from core/main-service/src/main/java/ru/practicum/validation/AtLeastOneNotNullValidator.java
rename to core/core-common/src/main/java/ru/practicum/validation/AtLeastOneNotNullValidator.java
diff --git a/core/main-service/src/main/java/ru/practicum/validation/CategoryCreateValidator.java b/core/core-common/src/main/java/ru/practicum/validation/CategoryCreateValidator.java
similarity index 94%
rename from core/main-service/src/main/java/ru/practicum/validation/CategoryCreateValidator.java
rename to core/core-common/src/main/java/ru/practicum/validation/CategoryCreateValidator.java
index a68e80a..80c87b3 100644
--- a/core/main-service/src/main/java/ru/practicum/validation/CategoryCreateValidator.java
+++ b/core/core-common/src/main/java/ru/practicum/validation/CategoryCreateValidator.java
@@ -1,6 +1,6 @@
package ru.practicum.validation;
-import ru.practicum.category.dto.CategoryDto;
+import ru.practicum.dto.category.CategoryDto;
import javax.validation.Validator;
import java.util.Set;
diff --git a/core/main-service/src/main/java/ru/practicum/validation/CategoryUpdateValidator.java b/core/core-common/src/main/java/ru/practicum/validation/CategoryUpdateValidator.java
similarity index 94%
rename from core/main-service/src/main/java/ru/practicum/validation/CategoryUpdateValidator.java
rename to core/core-common/src/main/java/ru/practicum/validation/CategoryUpdateValidator.java
index aa6fdc5..654879a 100644
--- a/core/main-service/src/main/java/ru/practicum/validation/CategoryUpdateValidator.java
+++ b/core/core-common/src/main/java/ru/practicum/validation/CategoryUpdateValidator.java
@@ -1,6 +1,6 @@
package ru.practicum.validation;
-import ru.practicum.category.dto.CategoryDto;
+import ru.practicum.dto.category.CategoryDto;
import javax.validation.Validator;
import java.util.Set;
@@ -23,4 +23,4 @@ public void validate(CategoryDto categoryDto) {
throw new IllegalArgumentException("Validation errors: " + errors);
}
}
-}
\ No newline at end of file
+}
diff --git a/core/main-service/src/main/java/ru/practicum/validation/CreateOrUpdateValidator.java b/core/core-common/src/main/java/ru/practicum/validation/CreateOrUpdateValidator.java
similarity index 100%
rename from core/main-service/src/main/java/ru/practicum/validation/CreateOrUpdateValidator.java
rename to core/core-common/src/main/java/ru/practicum/validation/CreateOrUpdateValidator.java
diff --git a/core/main-service/src/main/java/ru/practicum/validation/NewCompilationCreateValidator.java b/core/core-common/src/main/java/ru/practicum/validation/NewCompilationCreateValidator.java
similarity index 94%
rename from core/main-service/src/main/java/ru/practicum/validation/NewCompilationCreateValidator.java
rename to core/core-common/src/main/java/ru/practicum/validation/NewCompilationCreateValidator.java
index 6bf46df..69996b7 100644
--- a/core/main-service/src/main/java/ru/practicum/validation/NewCompilationCreateValidator.java
+++ b/core/core-common/src/main/java/ru/practicum/validation/NewCompilationCreateValidator.java
@@ -1,6 +1,6 @@
package ru.practicum.validation;
-import ru.practicum.compilation.dto.NewCompilationDto;
+import ru.practicum.dto.compilation.NewCompilationDto;
import javax.validation.Validator;
import java.util.Set;
diff --git a/core/main-service/src/main/java/ru/practicum/validation/NewCompilationUpdateValidator.java b/core/core-common/src/main/java/ru/practicum/validation/NewCompilationUpdateValidator.java
similarity index 93%
rename from core/main-service/src/main/java/ru/practicum/validation/NewCompilationUpdateValidator.java
rename to core/core-common/src/main/java/ru/practicum/validation/NewCompilationUpdateValidator.java
index 995a4b8..27494a5 100644
--- a/core/main-service/src/main/java/ru/practicum/validation/NewCompilationUpdateValidator.java
+++ b/core/core-common/src/main/java/ru/practicum/validation/NewCompilationUpdateValidator.java
@@ -1,6 +1,6 @@
package ru.practicum.validation;
-import ru.practicum.compilation.dto.NewCompilationDto;
+import ru.practicum.dto.compilation.NewCompilationDto;
import javax.validation.Validator;
import java.util.Set;
@@ -23,4 +23,4 @@ public void validate(NewCompilationDto newCompilationDto) {
throw new IllegalArgumentException("Validation errors: " + errors);
}
}
-}
\ No newline at end of file
+}
diff --git a/core/main-service/src/main/java/ru/practicum/validation/NotBlankButNullAllowed.java b/core/core-common/src/main/java/ru/practicum/validation/NotBlankButNullAllowed.java
similarity index 99%
rename from core/main-service/src/main/java/ru/practicum/validation/NotBlankButNullAllowed.java
rename to core/core-common/src/main/java/ru/practicum/validation/NotBlankButNullAllowed.java
index 7735d40..82168f8 100644
--- a/core/main-service/src/main/java/ru/practicum/validation/NotBlankButNullAllowed.java
+++ b/core/core-common/src/main/java/ru/practicum/validation/NotBlankButNullAllowed.java
@@ -19,4 +19,4 @@
Class extends Payload>[] payload() default {};
-}
\ No newline at end of file
+}
diff --git a/core/main-service/src/main/java/ru/practicum/validation/NotBlankButNullAllowedValidator.java b/core/core-common/src/main/java/ru/practicum/validation/NotBlankButNullAllowedValidator.java
similarity index 100%
rename from core/main-service/src/main/java/ru/practicum/validation/NotBlankButNullAllowedValidator.java
rename to core/core-common/src/main/java/ru/practicum/validation/NotBlankButNullAllowedValidator.java
diff --git a/core/main-service/Dockerfile b/core/event-service/Dockerfile
similarity index 100%
rename from core/main-service/Dockerfile
rename to core/event-service/Dockerfile
diff --git a/core/event-service/pom.xml b/core/event-service/pom.xml
new file mode 100644
index 0000000..90a8780
--- /dev/null
+++ b/core/event-service/pom.xml
@@ -0,0 +1,155 @@
+
+
+ 4.0.0
+
+
+ ru.practicum
+ core
+ 0.0.1-SNAPSHOT
+
+
+ event-service
+
+
+
+
+
+
+ ru.practicum
+ stats-client
+
+
+
+ ru.practicum
+ core-common
+ 0.0.1-SNAPSHOT
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-configuration-processor
+ true
+
+
+
+ org.projectlombok
+ lombok
+
+
+
+ org.springframework.boot
+ spring-boot-starter-actuator
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+
+
+
+ org.springframework.boot
+ spring-boot-starter-validation
+
+
+
+ javax.validation
+ validation-api
+ 2.0.1.Final
+
+
+
+
+
+ org.postgresql
+ postgresql
+
+
+
+ com.h2database
+ h2
+ test
+
+
+
+ org.springframework.boot
+ spring-boot-starter-data-jpa
+
+
+
+
+
+ org.springframework.cloud
+ spring-cloud-starter-netflix-eureka-client
+
+
+
+ org.springframework.cloud
+ spring-cloud-starter-config
+
+
+
+ org.springframework.retry
+ spring-retry
+
+
+
+
+
+ org.springframework.cloud
+ spring-cloud-starter-openfeign
+
+
+
+ org.springframework.cloud
+ spring-cloud-starter-circuitbreaker-resilience4j
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-test
+ test
+
+
+
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+
+
+
+ org.projectlombok
+ lombok
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+
+
+
+ org.projectlombok
+ lombok
+
+
+
+
+
+
+
+
+
diff --git a/core/main-service/src/main/java/ru/practicum/Main.java b/core/event-service/src/main/java/ru/practicum/EventServiceApplication.java
similarity index 61%
rename from core/main-service/src/main/java/ru/practicum/Main.java
rename to core/event-service/src/main/java/ru/practicum/EventServiceApplication.java
index 52735de..901eb02 100644
--- a/core/main-service/src/main/java/ru/practicum/Main.java
+++ b/core/event-service/src/main/java/ru/practicum/EventServiceApplication.java
@@ -1,14 +1,17 @@
package ru.practicum;
-
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.scheduling.annotation.EnableScheduling;
@EnableScheduling
+@EnableFeignClients
@SpringBootApplication
-public class Main {
+public class EventServiceApplication {
+
public static void main(String[] args) {
- SpringApplication.run(Main.class, args);
+ SpringApplication.run(EventServiceApplication.class, args);
}
+
}
\ No newline at end of file
diff --git a/core/event-service/src/main/java/ru/practicum/category/controller/CategoryAdminController.java b/core/event-service/src/main/java/ru/practicum/category/controller/CategoryAdminController.java
new file mode 100644
index 0000000..9508b24
--- /dev/null
+++ b/core/event-service/src/main/java/ru/practicum/category/controller/CategoryAdminController.java
@@ -0,0 +1,32 @@
+package ru.practicum.category.controller;
+
+import lombok.RequiredArgsConstructor;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.RestController;
+import ru.practicum.api.category.CategoryAdminApi;
+import ru.practicum.category.service.CategoryAdminService;
+import ru.practicum.dto.category.CategoryDto;
+
+@RestController
+@RequiredArgsConstructor
+@Validated
+public class CategoryAdminController implements CategoryAdminApi {
+
+ private final CategoryAdminService categoryAdminService;
+
+ @Override
+ public CategoryDto addCategory(CategoryDto requestCategory) {
+ return categoryAdminService.createCategory(requestCategory);
+ }
+
+ @Override
+ public String deleteCategories(Long catId) {
+ return categoryAdminService.deleteCategory(catId);
+ }
+
+ @Override
+ public CategoryDto updateCategory(Long catId, CategoryDto categoryDto) {
+ return categoryAdminService.updateCategory(catId, categoryDto);
+ }
+
+}
diff --git a/core/event-service/src/main/java/ru/practicum/category/controller/CategoryPublicController.java b/core/event-service/src/main/java/ru/practicum/category/controller/CategoryPublicController.java
new file mode 100644
index 0000000..260b707
--- /dev/null
+++ b/core/event-service/src/main/java/ru/practicum/category/controller/CategoryPublicController.java
@@ -0,0 +1,29 @@
+package ru.practicum.category.controller;
+
+import lombok.RequiredArgsConstructor;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.RestController;
+import ru.practicum.api.category.CategoryPublicApi;
+import ru.practicum.category.service.CategoryPublicService;
+import ru.practicum.dto.category.CategoryDto;
+
+import java.util.Collection;
+
+@RestController
+@RequiredArgsConstructor
+@Validated
+public class CategoryPublicController implements CategoryPublicApi {
+
+ private final CategoryPublicService categoryPublicService;
+
+ @Override
+ public Collection readAllCategories(int from, int size) {
+ return categoryPublicService.readAllCategories(from, size);
+ }
+
+ @Override
+ public CategoryDto readCategoryById(Long catId) {
+ return categoryPublicService.readCategoryById(catId);
+ }
+
+}
\ No newline at end of file
diff --git a/core/main-service/src/main/java/ru/practicum/category/model/Category.java b/core/event-service/src/main/java/ru/practicum/category/dal/Category.java
similarity index 57%
rename from core/main-service/src/main/java/ru/practicum/category/model/Category.java
rename to core/event-service/src/main/java/ru/practicum/category/dal/Category.java
index 6e4439c..b10e5f5 100644
--- a/core/main-service/src/main/java/ru/practicum/category/model/Category.java
+++ b/core/event-service/src/main/java/ru/practicum/category/dal/Category.java
@@ -1,4 +1,4 @@
-package ru.practicum.category.model;
+package ru.practicum.category.dal;
import jakarta.persistence.*;
import jakarta.validation.constraints.NotEmpty;
@@ -7,28 +7,24 @@
@Getter
@Setter
-@Builder
+@EqualsAndHashCode(onlyExplicitlyIncluded = true)
+@ToString
@Entity
-@AllArgsConstructor
+@Builder
@NoArgsConstructor
-@Table(name = "categories")
+@AllArgsConstructor
+@Table(name = "categories", indexes = {@Index(name = "idx_categories_cat_name", columnList = "cat_name")})
public class Category {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
+ @EqualsAndHashCode.Include
@Column(name = "id")
private Long id;
- @Column(name = "cat_name")
@Size(min = 1, max = 50)
@NotEmpty
+ @Column(name = "cat_name", length = 50, nullable = false, unique = true)
private String name;
- @Override
- public String toString() {
- return "Categories{" +
- "id=" + id +
- ", name='" + name + '\'' +
- '}';
- }
}
\ No newline at end of file
diff --git a/core/main-service/src/main/java/ru/practicum/category/repository/CategoryRepository.java b/core/event-service/src/main/java/ru/practicum/category/dal/CategoryRepository.java
similarity index 67%
rename from core/main-service/src/main/java/ru/practicum/category/repository/CategoryRepository.java
rename to core/event-service/src/main/java/ru/practicum/category/dal/CategoryRepository.java
index 539b9c8..f2376dc 100644
--- a/core/main-service/src/main/java/ru/practicum/category/repository/CategoryRepository.java
+++ b/core/event-service/src/main/java/ru/practicum/category/dal/CategoryRepository.java
@@ -1,7 +1,6 @@
-package ru.practicum.category.repository;
+package ru.practicum.category.dal;
import org.springframework.data.jpa.repository.JpaRepository;
-import ru.practicum.category.model.Category;
public interface CategoryRepository extends JpaRepository {
diff --git a/core/main-service/src/main/java/ru/practicum/category/service/CategoryAdminService.java b/core/event-service/src/main/java/ru/practicum/category/service/CategoryAdminService.java
similarity index 71%
rename from core/main-service/src/main/java/ru/practicum/category/service/CategoryAdminService.java
rename to core/event-service/src/main/java/ru/practicum/category/service/CategoryAdminService.java
index e5b1c18..c8979b2 100644
--- a/core/main-service/src/main/java/ru/practicum/category/service/CategoryAdminService.java
+++ b/core/event-service/src/main/java/ru/practicum/category/service/CategoryAdminService.java
@@ -1,13 +1,13 @@
package ru.practicum.category.service;
-import ru.practicum.category.dto.CategoryDto;
+import ru.practicum.dto.category.CategoryDto;
public interface CategoryAdminService {
CategoryDto createCategory(CategoryDto requestCategory);
- void deleteCategory(Long catId);
+ String deleteCategory(Long catId);
CategoryDto updateCategory(Long catId, CategoryDto categoryDto);
-}
\ No newline at end of file
+}
diff --git a/core/main-service/src/main/java/ru/practicum/category/service/CategoryAdminServiceImpl.java b/core/event-service/src/main/java/ru/practicum/category/service/CategoryAdminServiceImpl.java
similarity index 88%
rename from core/main-service/src/main/java/ru/practicum/category/service/CategoryAdminServiceImpl.java
rename to core/event-service/src/main/java/ru/practicum/category/service/CategoryAdminServiceImpl.java
index 4a9b694..b17c2f0 100644
--- a/core/main-service/src/main/java/ru/practicum/category/service/CategoryAdminServiceImpl.java
+++ b/core/event-service/src/main/java/ru/practicum/category/service/CategoryAdminServiceImpl.java
@@ -4,25 +4,23 @@
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
-import ru.practicum.category.dto.CategoryDto;
-import ru.practicum.category.mapper.CategoryMapper;
-import ru.practicum.category.model.Category;
-import ru.practicum.category.repository.CategoryRepository;
-import ru.practicum.event.repository.EventRepository;
+import ru.practicum.category.dal.Category;
+import ru.practicum.category.dal.CategoryRepository;
+import ru.practicum.dto.category.CategoryDto;
+import ru.practicum.event.dal.EventRepository;
import ru.practicum.exception.ConflictException;
import ru.practicum.exception.NotFoundException;
@Service
@RequiredArgsConstructor
@Slf4j
-@Transactional(readOnly = false)
public class CategoryAdminServiceImpl implements CategoryAdminService {
private final CategoryRepository categoryRepository;
-
private final EventRepository eventRepository;
@Override
+ @Transactional
public CategoryDto createCategory(CategoryDto requestCategory) {
log.info("createCategories - invoked");
if (categoryRepository.existsByName(requestCategory.getName())) {
@@ -35,7 +33,8 @@ public CategoryDto createCategory(CategoryDto requestCategory) {
}
@Override
- public void deleteCategory(Long catId) {
+ @Transactional
+ public String deleteCategory(Long catId) {
log.info("deleteCategories - invoked");
if (!categoryRepository.existsById(catId)) {
log.error("Category with this id does not exist {}", catId);
@@ -46,9 +45,11 @@ public void deleteCategory(Long catId) {
}
log.info("Result: category with id - {} - deleted", catId);
categoryRepository.deleteById(catId);
+ return "Category deleted: " + catId;
}
@Override
+ @Transactional
public CategoryDto updateCategory(Long catId, CategoryDto categoryDto) {
log.info("updateCategories - invoked");
Category category = categoryRepository.findById(catId).orElseThrow(()
@@ -62,4 +63,5 @@ public CategoryDto updateCategory(Long catId, CategoryDto categoryDto) {
log.info("Result: category - {} updated", category.getName());
return CategoryMapper.toCategoryDto(category);
}
+
}
\ No newline at end of file
diff --git a/core/main-service/src/main/java/ru/practicum/category/mapper/CategoryMapper.java b/core/event-service/src/main/java/ru/practicum/category/service/CategoryMapper.java
similarity index 83%
rename from core/main-service/src/main/java/ru/practicum/category/mapper/CategoryMapper.java
rename to core/event-service/src/main/java/ru/practicum/category/service/CategoryMapper.java
index e675a57..162c84f 100644
--- a/core/main-service/src/main/java/ru/practicum/category/mapper/CategoryMapper.java
+++ b/core/event-service/src/main/java/ru/practicum/category/service/CategoryMapper.java
@@ -1,7 +1,7 @@
-package ru.practicum.category.mapper;
+package ru.practicum.category.service;
-import ru.practicum.category.dto.CategoryDto;
-import ru.practicum.category.model.Category;
+import ru.practicum.category.dal.Category;
+import ru.practicum.dto.category.CategoryDto;
import java.util.List;
import java.util.stream.Collectors;
@@ -25,4 +25,4 @@ public static List toListCategoriesDto(List list) {
return list.stream().map(CategoryMapper::toCategoryDto).collect(Collectors.toList());
}
-}
\ No newline at end of file
+}
diff --git a/core/main-service/src/main/java/ru/practicum/category/service/CategoryPublicService.java b/core/event-service/src/main/java/ru/practicum/category/service/CategoryPublicService.java
similarity index 82%
rename from core/main-service/src/main/java/ru/practicum/category/service/CategoryPublicService.java
rename to core/event-service/src/main/java/ru/practicum/category/service/CategoryPublicService.java
index de4cdd2..798d12b 100644
--- a/core/main-service/src/main/java/ru/practicum/category/service/CategoryPublicService.java
+++ b/core/event-service/src/main/java/ru/practicum/category/service/CategoryPublicService.java
@@ -1,6 +1,6 @@
package ru.practicum.category.service;
-import ru.practicum.category.dto.CategoryDto;
+import ru.practicum.dto.category.CategoryDto;
import java.util.List;
@@ -10,4 +10,4 @@ public interface CategoryPublicService {
CategoryDto readCategoryById(Long catId);
-}
\ No newline at end of file
+}
diff --git a/core/main-service/src/main/java/ru/practicum/category/service/CategoryPublicServiceImpl.java b/core/event-service/src/main/java/ru/practicum/category/service/CategoryPublicServiceImpl.java
similarity index 67%
rename from core/main-service/src/main/java/ru/practicum/category/service/CategoryPublicServiceImpl.java
rename to core/event-service/src/main/java/ru/practicum/category/service/CategoryPublicServiceImpl.java
index b5d6fe6..195ca51 100644
--- a/core/main-service/src/main/java/ru/practicum/category/service/CategoryPublicServiceImpl.java
+++ b/core/event-service/src/main/java/ru/practicum/category/service/CategoryPublicServiceImpl.java
@@ -3,38 +3,39 @@
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.Sort;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
-import ru.practicum.category.dto.CategoryDto;
-import ru.practicum.category.mapper.CategoryMapper;
-import ru.practicum.category.model.Category;
-import ru.practicum.category.repository.CategoryRepository;
+import ru.practicum.category.dal.Category;
+import ru.practicum.category.dal.CategoryRepository;
+import ru.practicum.dto.category.CategoryDto;
import ru.practicum.exception.NotFoundException;
import java.util.List;
-import static ru.practicum.util.Util.createPageRequestAsc;
-
@Service
@RequiredArgsConstructor
@Slf4j
public class CategoryPublicServiceImpl implements CategoryPublicService {
- private final CategoryRepository repository;
+ private final CategoryRepository categoryRepository;
@Override
+ @Transactional(readOnly = true)
public List readAllCategories(Integer from, Integer size) {
log.info("readAllCategories - invoked");
- Page page = repository.findAll(createPageRequestAsc(from, size));
+ Page page = categoryRepository.findAll(PageRequest.of(from, size, Sort.Direction.ASC, "id"));
List cat = page.getContent();
log.info("Result: categories size = {}", cat.size());
return CategoryMapper.toListCategoriesDto(cat);
}
@Override
+ @Transactional(readOnly = true)
public CategoryDto readCategoryById(Long catId) {
log.info("readCategoryById - invoked");
- Category category = repository.findById(catId).orElseThrow(() -> {
+ Category category = categoryRepository.findById(catId).orElseThrow(() -> {
log.error("Category with id = {} not exist", catId);
return new NotFoundException("Category not found");
});
diff --git a/core/event-service/src/main/java/ru/practicum/client/RequestClient.java b/core/event-service/src/main/java/ru/practicum/client/RequestClient.java
new file mode 100644
index 0000000..daeffd2
--- /dev/null
+++ b/core/event-service/src/main/java/ru/practicum/client/RequestClient.java
@@ -0,0 +1,8 @@
+package ru.practicum.client;
+
+import org.springframework.cloud.openfeign.FeignClient;
+import ru.practicum.api.request.RequestApi;
+
+@FeignClient(name = "request-service")
+public interface RequestClient extends RequestApi {
+}
diff --git a/core/event-service/src/main/java/ru/practicum/client/RequestClientHelper.java b/core/event-service/src/main/java/ru/practicum/client/RequestClientHelper.java
new file mode 100644
index 0000000..b001849
--- /dev/null
+++ b/core/event-service/src/main/java/ru/practicum/client/RequestClientHelper.java
@@ -0,0 +1,13 @@
+package ru.practicum.client;
+
+import org.springframework.stereotype.Component;
+import ru.practicum.api.request.RequestApi;
+
+@Component
+public class RequestClientHelper extends RequestClientAbstractHelper {
+
+ public RequestClientHelper(RequestApi requestApiClient) {
+ super(requestApiClient);
+ }
+
+}
\ No newline at end of file
diff --git a/core/event-service/src/main/java/ru/practicum/client/UserClient.java b/core/event-service/src/main/java/ru/practicum/client/UserClient.java
new file mode 100644
index 0000000..50ca2b2
--- /dev/null
+++ b/core/event-service/src/main/java/ru/practicum/client/UserClient.java
@@ -0,0 +1,8 @@
+package ru.practicum.client;
+
+import org.springframework.cloud.openfeign.FeignClient;
+import ru.practicum.api.user.UserApi;
+
+@FeignClient(name = "user-service")
+public interface UserClient extends UserApi {
+}
diff --git a/core/event-service/src/main/java/ru/practicum/client/UserClientHelper.java b/core/event-service/src/main/java/ru/practicum/client/UserClientHelper.java
new file mode 100644
index 0000000..41cb654
--- /dev/null
+++ b/core/event-service/src/main/java/ru/practicum/client/UserClientHelper.java
@@ -0,0 +1,13 @@
+package ru.practicum.client;
+
+import org.springframework.stereotype.Component;
+import ru.practicum.api.user.UserApi;
+
+@Component
+public class UserClientHelper extends UserClientAbstractHelper {
+
+ public UserClientHelper(UserApi userApiClient) {
+ super(userApiClient);
+ }
+
+}
\ No newline at end of file
diff --git a/core/event-service/src/main/java/ru/practicum/compilation/controller/CompilationAdminController.java b/core/event-service/src/main/java/ru/practicum/compilation/controller/CompilationAdminController.java
new file mode 100644
index 0000000..9360cfb
--- /dev/null
+++ b/core/event-service/src/main/java/ru/practicum/compilation/controller/CompilationAdminController.java
@@ -0,0 +1,34 @@
+package ru.practicum.compilation.controller;
+
+import lombok.RequiredArgsConstructor;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.RestController;
+import ru.practicum.api.compilation.CompilationAdminApi;
+import ru.practicum.compilation.service.CompilationAdminService;
+import ru.practicum.dto.compilation.CompilationDto;
+import ru.practicum.dto.compilation.NewCompilationDto;
+import ru.practicum.dto.compilation.UpdateCompilationDto;
+
+@RestController
+@Validated
+@RequiredArgsConstructor
+public class CompilationAdminController implements CompilationAdminApi {
+
+ private final CompilationAdminService compilationAdminService;
+
+ @Override
+ public CompilationDto postCompilations(NewCompilationDto newCompilationDto) {
+ return compilationAdminService.createCompilation(newCompilationDto);
+ }
+
+ @Override
+ public String deleteCompilation(Long compId) {
+ return compilationAdminService.deleteCompilation(compId);
+ }
+
+ @Override
+ public CompilationDto patchCompilation(Long compId, UpdateCompilationDto updateCompilationDto) {
+ return compilationAdminService.updateCompilation(compId, updateCompilationDto);
+ }
+
+}
\ No newline at end of file
diff --git a/core/event-service/src/main/java/ru/practicum/compilation/controller/CompilationPublicController.java b/core/event-service/src/main/java/ru/practicum/compilation/controller/CompilationPublicController.java
new file mode 100644
index 0000000..796aec5
--- /dev/null
+++ b/core/event-service/src/main/java/ru/practicum/compilation/controller/CompilationPublicController.java
@@ -0,0 +1,29 @@
+package ru.practicum.compilation.controller;
+
+import lombok.RequiredArgsConstructor;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.RestController;
+import ru.practicum.api.compilation.CompilationPublicApi;
+import ru.practicum.compilation.service.CompilationPublicService;
+import ru.practicum.dto.compilation.CompilationDto;
+
+import java.util.Collection;
+
+@RestController
+@Validated
+@RequiredArgsConstructor
+public class CompilationPublicController implements CompilationPublicApi {
+
+ private final CompilationPublicService compilationPublicService;
+
+ @Override
+ public Collection getCompilation(Boolean pinned, int from, int size) {
+ return compilationPublicService.readAllCompilations(pinned, from, size);
+ }
+
+ @Override
+ public CompilationDto getCompilationById(Long compId) {
+ return compilationPublicService.readCompilationById(compId);
+ }
+
+}
\ No newline at end of file
diff --git a/core/event-service/src/main/java/ru/practicum/compilation/dal/Compilation.java b/core/event-service/src/main/java/ru/practicum/compilation/dal/Compilation.java
new file mode 100644
index 0000000..e5fa0c6
--- /dev/null
+++ b/core/event-service/src/main/java/ru/practicum/compilation/dal/Compilation.java
@@ -0,0 +1,45 @@
+package ru.practicum.compilation.dal;
+
+import jakarta.persistence.*;
+import jakarta.validation.constraints.NotEmpty;
+import jakarta.validation.constraints.Size;
+import lombok.*;
+import org.hibernate.annotations.OnDelete;
+import org.hibernate.annotations.OnDeleteAction;
+import ru.practicum.event.dal.Event;
+
+import java.util.Set;
+
+@Getter
+@Setter
+@EqualsAndHashCode(onlyExplicitlyIncluded = true)
+@ToString
+@Entity
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+@Table(name = "compilations")
+public class Compilation {
+
+ @Id
+ @GeneratedValue(strategy = GenerationType.IDENTITY)
+ @EqualsAndHashCode.Include
+ @Column(name = "id")
+ private Long id;
+
+ @Column(name = "pinned", nullable = false)
+ private Boolean pinned;
+
+ @Size(min = 1, max = 50)
+ @NotEmpty
+ @Column(name = "title", length = 50, nullable = false)
+ private String title;
+
+ @ManyToMany(cascade = CascadeType.ALL)
+ @JoinTable(name = "compilations_events",
+ joinColumns = @JoinColumn(name = "compilations_id", nullable = false),
+ inverseJoinColumns = @JoinColumn(name = "events_id", nullable = false))
+ @OnDelete(action = OnDeleteAction.CASCADE)
+ private Set events;
+
+}
\ No newline at end of file
diff --git a/core/event-service/src/main/java/ru/practicum/compilation/dal/CompilationRepository.java b/core/event-service/src/main/java/ru/practicum/compilation/dal/CompilationRepository.java
new file mode 100644
index 0000000..6ac7a0f
--- /dev/null
+++ b/core/event-service/src/main/java/ru/practicum/compilation/dal/CompilationRepository.java
@@ -0,0 +1,11 @@
+package ru.practicum.compilation.dal;
+
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.Pageable;
+import org.springframework.data.jpa.repository.JpaRepository;
+
+public interface CompilationRepository extends JpaRepository {
+
+ Page findAllByPinned(Boolean pinned, Pageable pageable);
+
+}
diff --git a/core/main-service/src/main/java/ru/practicum/compilation/service/CompilationAdminService.java b/core/event-service/src/main/java/ru/practicum/compilation/service/CompilationAdminService.java
similarity index 54%
rename from core/main-service/src/main/java/ru/practicum/compilation/service/CompilationAdminService.java
rename to core/event-service/src/main/java/ru/practicum/compilation/service/CompilationAdminService.java
index ad82c21..718d71a 100644
--- a/core/main-service/src/main/java/ru/practicum/compilation/service/CompilationAdminService.java
+++ b/core/event-service/src/main/java/ru/practicum/compilation/service/CompilationAdminService.java
@@ -1,15 +1,15 @@
package ru.practicum.compilation.service;
-import ru.practicum.compilation.dto.CompilationDto;
-import ru.practicum.compilation.dto.NewCompilationDto;
-import ru.practicum.compilation.dto.UpdateCompilationDto;
+import ru.practicum.dto.compilation.CompilationDto;
+import ru.practicum.dto.compilation.NewCompilationDto;
+import ru.practicum.dto.compilation.UpdateCompilationDto;
public interface CompilationAdminService {
CompilationDto createCompilation(NewCompilationDto request);
- void deleteCompilation(Long compId);
+ String deleteCompilation(Long compId);
CompilationDto updateCompilation(Long compId, UpdateCompilationDto updateCompilationDto);
-}
\ No newline at end of file
+}
diff --git a/core/event-service/src/main/java/ru/practicum/compilation/service/CompilationAdminServiceImpl.java b/core/event-service/src/main/java/ru/practicum/compilation/service/CompilationAdminServiceImpl.java
new file mode 100644
index 0000000..7dcc985
--- /dev/null
+++ b/core/event-service/src/main/java/ru/practicum/compilation/service/CompilationAdminServiceImpl.java
@@ -0,0 +1,102 @@
+package ru.practicum.compilation.service;
+
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.transaction.support.TransactionTemplate;
+import ru.practicum.client.UserClientHelper;
+import ru.practicum.compilation.dal.Compilation;
+import ru.practicum.compilation.dal.CompilationRepository;
+import ru.practicum.dto.compilation.CompilationDto;
+import ru.practicum.dto.compilation.NewCompilationDto;
+import ru.practicum.dto.compilation.UpdateCompilationDto;
+import ru.practicum.dto.user.UserShortDto;
+import ru.practicum.event.dal.Event;
+import ru.practicum.event.dal.EventRepository;
+import ru.practicum.exception.NotFoundException;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+@Service
+@RequiredArgsConstructor
+@Slf4j
+public class CompilationAdminServiceImpl implements CompilationAdminService {
+
+ private final TransactionTemplate transactionTemplate;
+ private final CompilationRepository compilationRepository;
+ private final EventRepository eventRepository;
+
+ private final UserClientHelper userClientHelper;
+
+ @Override
+ public CompilationDto createCompilation(NewCompilationDto newCompilationDto) {
+ Set events = new HashSet<>();
+ Map userMap = new HashMap<>();
+
+ if (newCompilationDto.getPinned() == null) newCompilationDto.setPinned(false);
+
+ if (newCompilationDto.getEvents() != null && !newCompilationDto.getEvents().isEmpty()) {
+ events = transactionTemplate.execute(status -> {
+ return new HashSet<>(eventRepository.findAllById(newCompilationDto.getEvents()));
+ });
+ Set userIds = events.stream().map(Event::getInitiatorId).collect(Collectors.toSet());
+ userMap = userClientHelper.retrieveUserShortDtoMapByUserIdList(userIds);
+ }
+
+ Set eventsFinal = events;
+ Map userMapFinal = userMap;
+
+ return transactionTemplate.execute(status -> {
+ Compilation compilation = Compilation.builder()
+ .pinned(newCompilationDto.getPinned())
+ .title(newCompilationDto.getTitle())
+ .events(eventsFinal)
+ .build();
+ compilationRepository.save(compilation);
+ return CompilationMapper.toCompilationDto(compilation, userMapFinal);
+ });
+ }
+
+ @Override
+ @Transactional
+ public String deleteCompilation(Long compId) {
+ if (!compilationRepository.existsById(compId)) throw new NotFoundException("Not found Compilation " + compId);
+ compilationRepository.deleteById(compId);
+ return "Compilation deleted: " + compId;
+ }
+
+ @Override
+ public CompilationDto updateCompilation(Long compId, UpdateCompilationDto updateCompilationDto) {
+ Set userIds = transactionTemplate.execute(status -> {
+ Compilation compilation = compilationRepository.findById(compId)
+ .orElseThrow(() -> new NotFoundException("Not found Compilation " + compId));
+ return compilation.getEvents().stream().map(Event::getInitiatorId).collect(Collectors.toSet());
+ });
+
+ Map userMap = userClientHelper.retrieveUserShortDtoMapByUserIdList(userIds);
+
+ return transactionTemplate.execute(status -> {
+ Compilation compilation = compilationRepository.findById(compId)
+ .orElseThrow(() -> new NotFoundException("Not found Compilation " + compId));
+
+ if (updateCompilationDto.getTitle() != null) {
+ compilation.setTitle(updateCompilationDto.getTitle());
+ }
+ if (updateCompilationDto.getPinned() != null) {
+ compilation.setPinned(updateCompilationDto.getPinned());
+ }
+ if (updateCompilationDto.getEvents() != null && !updateCompilationDto.getEvents().isEmpty()) {
+ Set events = new HashSet<>(eventRepository.findAllById(updateCompilationDto.getEvents()));
+ compilation.setEvents(events);
+ }
+ compilationRepository.save(compilation);
+ return CompilationMapper.toCompilationDto(compilation, userMap);
+ });
+ }
+
+}
\ No newline at end of file
diff --git a/core/event-service/src/main/java/ru/practicum/compilation/service/CompilationMapper.java b/core/event-service/src/main/java/ru/practicum/compilation/service/CompilationMapper.java
new file mode 100644
index 0000000..8c961d6
--- /dev/null
+++ b/core/event-service/src/main/java/ru/practicum/compilation/service/CompilationMapper.java
@@ -0,0 +1,27 @@
+package ru.practicum.compilation.service;
+
+import ru.practicum.compilation.dal.Compilation;
+import ru.practicum.dto.compilation.CompilationDto;
+import ru.practicum.dto.event.EventShortDto;
+import ru.practicum.dto.user.UserShortDto;
+import ru.practicum.event.service.EventMapper;
+
+import java.util.List;
+import java.util.Map;
+
+public class CompilationMapper {
+
+ public static CompilationDto toCompilationDto(Compilation compilation, Map userMap) {
+ List eventShortDtoList = compilation.getEvents().stream()
+ .map(e -> EventMapper.toEventShortDto(e, userMap.get(e.getInitiatorId()), 0L, 0L))
+ .toList();
+
+ return CompilationDto.builder()
+ .id(compilation.getId())
+ .pinned(compilation.getPinned())
+ .title(compilation.getTitle())
+ .events(eventShortDtoList)
+ .build();
+ }
+
+}
\ No newline at end of file
diff --git a/core/main-service/src/main/java/ru/practicum/compilation/service/CompilationPublicService.java b/core/event-service/src/main/java/ru/practicum/compilation/service/CompilationPublicService.java
similarity index 82%
rename from core/main-service/src/main/java/ru/practicum/compilation/service/CompilationPublicService.java
rename to core/event-service/src/main/java/ru/practicum/compilation/service/CompilationPublicService.java
index ab3283e..0977bb3 100644
--- a/core/main-service/src/main/java/ru/practicum/compilation/service/CompilationPublicService.java
+++ b/core/event-service/src/main/java/ru/practicum/compilation/service/CompilationPublicService.java
@@ -1,6 +1,6 @@
package ru.practicum.compilation.service;
-import ru.practicum.compilation.dto.CompilationDto;
+import ru.practicum.dto.compilation.CompilationDto;
import java.util.List;
@@ -10,4 +10,4 @@ public interface CompilationPublicService {
List readAllCompilations(Boolean pinned, int from, int size);
-}
\ No newline at end of file
+}
diff --git a/core/event-service/src/main/java/ru/practicum/compilation/service/CompilationPublicServiceImpl.java b/core/event-service/src/main/java/ru/practicum/compilation/service/CompilationPublicServiceImpl.java
new file mode 100644
index 0000000..527e184
--- /dev/null
+++ b/core/event-service/src/main/java/ru/practicum/compilation/service/CompilationPublicServiceImpl.java
@@ -0,0 +1,73 @@
+package ru.practicum.compilation.service;
+
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.data.domain.PageRequest;
+import org.springframework.data.domain.Pageable;
+import org.springframework.data.domain.Sort;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.support.TransactionTemplate;
+import ru.practicum.client.UserClientHelper;
+import ru.practicum.compilation.dal.Compilation;
+import ru.practicum.compilation.dal.CompilationRepository;
+import ru.practicum.dto.compilation.CompilationDto;
+import ru.practicum.dto.user.UserShortDto;
+import ru.practicum.event.dal.Event;
+import ru.practicum.exception.NotFoundException;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+@Service
+@RequiredArgsConstructor
+@Slf4j
+public class CompilationPublicServiceImpl implements CompilationPublicService {
+
+ private final TransactionTemplate transactionTemplate;
+ private final CompilationRepository compilationRepository;
+
+ private final UserClientHelper userClientHelper;
+
+ @Override
+ public CompilationDto readCompilationById(Long compId) {
+ Compilation compilation = transactionTemplate.execute(status -> {
+ return compilationRepository.findById(compId)
+ .orElseThrow(() -> new NotFoundException("Compilation not found"));
+ });
+
+ Map userMap = new HashMap<>();
+ if (compilation.getEvents() != null && !compilation.getEvents().isEmpty()) {
+ Set userIds = compilation.getEvents().stream().map(Event::getInitiatorId).collect(Collectors.toSet());
+ userMap = userClientHelper.retrieveUserShortDtoMapByUserIdList(userIds);
+ }
+
+ return CompilationMapper.toCompilationDto(compilation, userMap);
+ }
+
+ @Override
+ public List readAllCompilations(Boolean pinned, int from, int size) {
+ List compilations = transactionTemplate.execute(status -> {
+ Pageable pageable = PageRequest.of(from / size, size, Sort.Direction.ASC, "id");
+ if (pinned == null) {
+ return compilationRepository.findAll(pageable).getContent();
+ } else {
+ return compilationRepository.findAllByPinned(pinned, pageable).getContent();
+ }
+ });
+ if (compilations == null || compilations.isEmpty()) return List.of();
+
+ Set userIds = compilations.stream()
+ .flatMap(c -> c.getEvents().stream())
+ .map(Event::getInitiatorId)
+ .collect(Collectors.toSet());
+ Map userMap = userClientHelper.retrieveUserShortDtoMapByUserIdList(userIds);
+
+ return compilations.stream()
+ .map(c -> CompilationMapper.toCompilationDto(c, userMap))
+ .toList();
+ }
+
+}
\ No newline at end of file
diff --git a/core/event-service/src/main/java/ru/practicum/event/controller/EventAdminController.java b/core/event-service/src/main/java/ru/practicum/event/controller/EventAdminController.java
new file mode 100644
index 0000000..2cba963
--- /dev/null
+++ b/core/event-service/src/main/java/ru/practicum/event/controller/EventAdminController.java
@@ -0,0 +1,46 @@
+package ru.practicum.event.controller;
+
+import lombok.RequiredArgsConstructor;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.RestController;
+import ru.practicum.api.event.EventAdminApi;
+import ru.practicum.dto.event.EventAdminParams;
+import ru.practicum.dto.event.EventFullDto;
+import ru.practicum.dto.event.State;
+import ru.practicum.dto.event.UpdateEventDto;
+import ru.practicum.event.service.EventAdminService;
+
+import java.time.LocalDateTime;
+import java.util.Collection;
+import java.util.List;
+
+@RestController
+@RequiredArgsConstructor
+@Validated
+public class EventAdminController implements EventAdminApi {
+
+ private final EventAdminService eventAdminService;
+
+ // Поиск событий
+ @Override
+ public Collection getAllEventsByParams(List users, List states, List categories,
+ LocalDateTime rangeStart, LocalDateTime rangeEnd, Integer from, Integer size) {
+ EventAdminParams params = EventAdminParams.builder()
+ .users(users)
+ .states(states)
+ .categories(categories)
+ .rangeStart(rangeStart)
+ .rangeEnd(rangeEnd)
+ .from(from)
+ .size(size)
+ .build();
+ return eventAdminService.getAllEventsByParams(params);
+ }
+
+ // Редактирование данных события и его статуса (отклонение/публикация).
+ @Override
+ public EventFullDto updateEventByAdmin(Long eventId, UpdateEventDto updateEventDto) {
+ return eventAdminService.updateEventByAdmin(eventId, updateEventDto);
+ }
+
+}
\ No newline at end of file
diff --git a/core/event-service/src/main/java/ru/practicum/event/controller/EventPrivateController.java b/core/event-service/src/main/java/ru/practicum/event/controller/EventPrivateController.java
new file mode 100644
index 0000000..c933d10
--- /dev/null
+++ b/core/event-service/src/main/java/ru/practicum/event/controller/EventPrivateController.java
@@ -0,0 +1,46 @@
+package ru.practicum.event.controller;
+
+import lombok.RequiredArgsConstructor;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.RestController;
+import ru.practicum.api.event.EventPrivateApi;
+import ru.practicum.dto.event.EventFullDto;
+import ru.practicum.dto.event.EventShortDto;
+import ru.practicum.dto.event.NewEventDto;
+import ru.practicum.dto.event.UpdateEventDto;
+import ru.practicum.event.service.EventPrivateService;
+
+import java.util.Collection;
+
+@RestController
+@RequiredArgsConstructor
+@Validated
+public class EventPrivateController implements EventPrivateApi {
+
+ private final EventPrivateService eventPrivateService;
+
+ // Добавление нового события
+ @Override
+ public EventFullDto addNewEventByUser(Long userId, NewEventDto newEventDto) {
+ return eventPrivateService.addEvent(userId, newEventDto);
+ }
+
+ // Получение событий, добавленных текущим пользователем
+ @Override
+ public Collection getAllEventsByUserId(Long userId, Integer from, Integer size) {
+ return eventPrivateService.getEventsByUserId(userId, from, size);
+ }
+
+ // Получение полной информации о событии добавленном текущим пользователем
+ @Override
+ public EventFullDto getEventByUserIdAndEventId(Long userId, Long eventId) {
+ return eventPrivateService.getEventByUserIdAndEventId(userId, eventId);
+ }
+
+ // Изменение события добавленного текущим пользователем
+ @Override
+ public EventFullDto updateEventByUserIdAndEventId(Long userId, Long eventId, UpdateEventDto updateEventDto) {
+ return eventPrivateService.updateEventByUserIdAndEventId(userId, eventId, updateEventDto);
+ }
+
+}
\ No newline at end of file
diff --git a/core/event-service/src/main/java/ru/practicum/event/controller/EventPublicController.java b/core/event-service/src/main/java/ru/practicum/event/controller/EventPublicController.java
new file mode 100644
index 0000000..f249745
--- /dev/null
+++ b/core/event-service/src/main/java/ru/practicum/event/controller/EventPublicController.java
@@ -0,0 +1,71 @@
+package ru.practicum.event.controller;
+
+import jakarta.servlet.http.HttpServletRequest;
+import lombok.RequiredArgsConstructor;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.RestController;
+import ru.practicum.api.event.EventPublicApi;
+import ru.practicum.dto.event.*;
+import ru.practicum.event.service.EventPublicService;
+
+import java.time.LocalDateTime;
+import java.util.Collection;
+import java.util.List;
+
+@RestController
+@RequiredArgsConstructor
+@Validated
+public class EventPublicController implements EventPublicApi {
+
+ private final EventPublicService eventPublicService;
+
+ // Получение событий с возможностью фильтрации
+ @Override
+ public List getAllEventsByParams(
+ String text,
+ List categories,
+ Boolean paid,
+ LocalDateTime rangeStart,
+ LocalDateTime rangeEnd,
+ Boolean onlyAvailable,
+ EventSort eventSort,
+ Integer from,
+ Integer size,
+ HttpServletRequest request
+ ) {
+ EventParams params = EventParams.builder()
+ .text(text)
+ .categories(categories)
+ .paid(paid)
+ .rangeStart(rangeStart)
+ .rangeEnd(rangeEnd)
+ .onlyAvailable(onlyAvailable)
+ .eventSort(eventSort)
+ .from(from)
+ .size(size)
+ .build();
+ return eventPublicService.getAllEventsByParams(params, request);
+ }
+
+ // Получение подробной информации об опубликованном событии по его идентификатору
+ @Override
+ public EventFullDto getInformationAboutEventByEventId(Long id, HttpServletRequest request) {
+ return eventPublicService.getEventById(id, request);
+ }
+
+ @Override
+ public EventCommentDto getEventCommentDto(Long id) {
+ return eventPublicService.getEventCommentDto(id);
+ }
+
+ @Override
+ public Collection getEventCommentDtoList(Collection ids) {
+ return eventPublicService.getEventCommentDtoList(ids);
+ }
+
+ @Override
+ public EventInteractionDto getEventInteractionDto(Long id) {
+ return eventPublicService.getEventInteractionDto(id);
+ }
+
+}
\ No newline at end of file
diff --git a/core/main-service/src/main/java/ru/practicum/event/model/Event.java b/core/event-service/src/main/java/ru/practicum/event/dal/Event.java
similarity index 68%
rename from core/main-service/src/main/java/ru/practicum/event/model/Event.java
rename to core/event-service/src/main/java/ru/practicum/event/dal/Event.java
index fb8ea7c..74defe2 100644
--- a/core/main-service/src/main/java/ru/practicum/event/model/Event.java
+++ b/core/event-service/src/main/java/ru/practicum/event/dal/Event.java
@@ -1,36 +1,40 @@
-package ru.practicum.event.model;
+package ru.practicum.event.dal;
import jakarta.persistence.*;
import lombok.*;
-import ru.practicum.category.model.Category;
-import ru.practicum.comment.model.Comment;
-import ru.practicum.event.dto.State;
-import ru.practicum.request.model.Request;
-import ru.practicum.user.model.User;
+import org.hibernate.annotations.OnDelete;
+import org.hibernate.annotations.OnDeleteAction;
+import ru.practicum.category.dal.Category;
+import ru.practicum.dto.event.State;
import java.time.LocalDateTime;
-import java.util.List;
@Getter
@Setter
+@EqualsAndHashCode(onlyExplicitlyIncluded = true)
+@ToString
+@Entity
@Builder
@NoArgsConstructor
@AllArgsConstructor
-@Entity
-@Table(name = "events")
+@Table(name = "events", indexes = {
+ @Index(name = "idx_events_initiator_id", columnList = "initiator_id"),
+ @Index(name = "idx_events_categories_id", columnList = "categories_id")
+})
public class Event {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
+ @EqualsAndHashCode.Include
@Column(name = "id")
private Long id;
- @ManyToOne
- @JoinColumn(name = "initiator", nullable = false)
- private User initiator;
+ @Column(name = "initiator_id", nullable = false)
+ private Long initiatorId;
@ManyToOne
@JoinColumn(name = "categories_id", nullable = false)
+ @OnDelete(action = OnDeleteAction.RESTRICT)
private Category category;
@Column(name = "title", length = 120, nullable = false)
@@ -67,10 +71,4 @@ public class Event {
@Column(name = "created_on", nullable = false)
private LocalDateTime createdOn;
- @OneToMany(mappedBy = "event", fetch = FetchType.LAZY)
- private List requests;
-
- @OneToMany(mappedBy = "event", fetch = FetchType.LAZY)
- private List comments;
-
-}
\ No newline at end of file
+}
diff --git a/core/main-service/src/main/java/ru/practicum/event/repository/EventRepository.java b/core/event-service/src/main/java/ru/practicum/event/dal/EventRepository.java
similarity index 73%
rename from core/main-service/src/main/java/ru/practicum/event/repository/EventRepository.java
rename to core/event-service/src/main/java/ru/practicum/event/dal/EventRepository.java
index 9ccec1d..c69bb3d 100644
--- a/core/main-service/src/main/java/ru/practicum/event/repository/EventRepository.java
+++ b/core/event-service/src/main/java/ru/practicum/event/dal/EventRepository.java
@@ -1,18 +1,15 @@
-package ru.practicum.event.repository;
+package ru.practicum.event.dal;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
-import ru.practicum.event.dto.State;
-import ru.practicum.event.model.Event;
+import ru.practicum.dto.event.State;
import java.util.List;
import java.util.Optional;
public interface EventRepository extends JpaRepository, JpaSpecificationExecutor {
- Optional findByIdAndInitiatorId(Long eventId, Long initiatorId);
-
List findByInitiatorId(Long initiatorId, Pageable pageable);
Optional findByIdAndState(Long id, State state);
diff --git a/core/main-service/src/main/java/ru/practicum/event/repository/JpaSpecifications.java b/core/event-service/src/main/java/ru/practicum/event/dal/JpaSpecifications.java
similarity index 70%
rename from core/main-service/src/main/java/ru/practicum/event/repository/JpaSpecifications.java
rename to core/event-service/src/main/java/ru/practicum/event/dal/JpaSpecifications.java
index 4ca46d0..866a018 100644
--- a/core/main-service/src/main/java/ru/practicum/event/repository/JpaSpecifications.java
+++ b/core/event-service/src/main/java/ru/practicum/event/dal/JpaSpecifications.java
@@ -1,14 +1,9 @@
-package ru.practicum.event.repository;
+package ru.practicum.event.dal;
-import jakarta.persistence.criteria.Join;
-import jakarta.persistence.criteria.JoinType;
import jakarta.persistence.criteria.Predicate;
import org.springframework.data.jpa.domain.Specification;
-import ru.practicum.event.dto.EventAdminParams;
-import ru.practicum.event.dto.EventParams;
-import ru.practicum.event.model.Event;
-import ru.practicum.request.dto.ParticipationRequestStatus;
-import ru.practicum.request.model.Request;
+import ru.practicum.dto.event.EventAdminParams;
+import ru.practicum.dto.event.EventParams;
import java.util.ArrayList;
import java.util.List;
@@ -20,7 +15,7 @@ public static Specification adminFilters(EventAdminParams params) {
List predicates = new ArrayList<>();
if (params.getUsers() != null && !params.getUsers().isEmpty())
- predicates.add(root.get("initiator").get("id").in(params.getUsers()));
+ predicates.add(root.get("initiatorId").in(params.getUsers()));
if (params.getStates() != null && !params.getStates().isEmpty())
predicates.add(root.get("state").in(params.getStates()));
@@ -60,19 +55,9 @@ public static Specification publicFilters(EventParams params) {
if (params.getRangeEnd() != null)
predicates.add(cb.lessThanOrEqualTo(root.get("eventDate"), params.getRangeEnd()));
- if (params.getOnlyAvailable() == true) {
- Join requestJoin = root.join("requests", JoinType.LEFT);
- requestJoin.on(cb.equal(requestJoin.get("status"), ParticipationRequestStatus.CONFIRMED));
- query.groupBy(root.get("id"));
-
- Predicate unlimitedPredicate = cb.equal(root.get("participantLimit"), 0);
- Predicate hasFreeSeatsPredicate = cb.greaterThan(root.get("participantLimit"), cb.count(requestJoin));
- query.having(cb.or(unlimitedPredicate, hasFreeSeatsPredicate));
- }
-
return cb.and(predicates.toArray(new Predicate[0]));
};
}
-}
\ No newline at end of file
+}
diff --git a/core/main-service/src/main/java/ru/practicum/event/model/Location.java b/core/event-service/src/main/java/ru/practicum/event/dal/Location.java
similarity index 76%
rename from core/main-service/src/main/java/ru/practicum/event/model/Location.java
rename to core/event-service/src/main/java/ru/practicum/event/dal/Location.java
index 44cbad3..9c52841 100644
--- a/core/main-service/src/main/java/ru/practicum/event/model/Location.java
+++ b/core/event-service/src/main/java/ru/practicum/event/dal/Location.java
@@ -1,18 +1,20 @@
-package ru.practicum.event.model;
+package ru.practicum.event.dal;
import jakarta.persistence.Embeddable;
import lombok.*;
@Getter
@Setter
-@Embeddable
+@EqualsAndHashCode
+@ToString
@Builder
-@AllArgsConstructor
@NoArgsConstructor
+@AllArgsConstructor
+@Embeddable
public class Location {
private Float lat;
private Float lon;
-}
\ No newline at end of file
+}
diff --git a/core/event-service/src/main/java/ru/practicum/event/dal/View.java b/core/event-service/src/main/java/ru/practicum/event/dal/View.java
new file mode 100644
index 0000000..4cce663
--- /dev/null
+++ b/core/event-service/src/main/java/ru/practicum/event/dal/View.java
@@ -0,0 +1,33 @@
+package ru.practicum.event.dal;
+
+import jakarta.persistence.*;
+import lombok.*;
+import org.hibernate.annotations.OnDelete;
+import org.hibernate.annotations.OnDeleteAction;
+
+@Getter
+@Setter
+@EqualsAndHashCode(onlyExplicitlyIncluded = true)
+@ToString
+@Entity
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+@Table(name = "views", indexes = {@Index(name = "idx_views_event_id", columnList = "event_id")})
+public class View {
+
+ @Id
+ @GeneratedValue(strategy = GenerationType.IDENTITY)
+ @EqualsAndHashCode.Include
+ @Column(name = "id")
+ private Long id;
+
+ @ManyToOne
+ @JoinColumn(name = "event_id", nullable = false)
+ @OnDelete(action = OnDeleteAction.RESTRICT)
+ private Event event;
+
+ @Column(name = "ip", length = 15, nullable = false)
+ private String ip;
+
+}
diff --git a/core/main-service/src/main/java/ru/practicum/event/repository/ViewRepository.java b/core/event-service/src/main/java/ru/practicum/event/dal/ViewRepository.java
similarity index 89%
rename from core/main-service/src/main/java/ru/practicum/event/repository/ViewRepository.java
rename to core/event-service/src/main/java/ru/practicum/event/dal/ViewRepository.java
index f94c538..2d2110e 100644
--- a/core/main-service/src/main/java/ru/practicum/event/repository/ViewRepository.java
+++ b/core/event-service/src/main/java/ru/practicum/event/dal/ViewRepository.java
@@ -1,9 +1,8 @@
-package ru.practicum.event.repository;
+package ru.practicum.event.dal;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
-import ru.practicum.event.model.View;
import java.util.List;
@@ -23,4 +22,4 @@ List