├── .github
└── workflows
│ ├── api-tests.yml
│ ├── dashboard-template.hbs
│ └── wait-for-it.sh
├── .gitignore
├── README.md
├── checkstyle.xml
├── common
├── pom.xml
└── src
│ └── main
│ └── java
│ └── ru
│ └── practicum
│ └── ewm
│ ├── Constants.java
│ └── dto
│ └── stats
│ ├── StatInDto.java
│ └── StatOutDto.java
├── docker-compose.yml
├── ewm-main-service-spec.json
├── ewm-stats-service-spec.json
├── lombok.config
├── main
├── Dockerfile
├── pom.xml
└── src
│ ├── main
│ ├── java
│ │ └── ru
│ │ │ └── practicum
│ │ │ └── ewm
│ │ │ ├── ErrorHandler.java
│ │ │ ├── MainAPI.java
│ │ │ ├── dto
│ │ │ ├── categories
│ │ │ │ ├── CategoryFullDto.java
│ │ │ │ └── CategoryInDto.java
│ │ │ ├── compilations
│ │ │ │ ├── CompilationInDto.java
│ │ │ │ └── CompilationOutDto.java
│ │ │ ├── events
│ │ │ │ ├── EventInDto.java
│ │ │ │ ├── EventOutDto.java
│ │ │ │ └── EventPublicOutDto.java
│ │ │ ├── locations
│ │ │ │ └── LocationDto.java
│ │ │ ├── requests
│ │ │ │ └── RequestOutDto.java
│ │ │ └── users
│ │ │ │ ├── UserDto.java
│ │ │ │ └── UserPublicDto.java
│ │ │ ├── endpoints
│ │ │ ├── admin
│ │ │ │ ├── AdminCategoriesController.java
│ │ │ │ ├── AdminCompilationsController.java
│ │ │ │ ├── AdminEventsController.java
│ │ │ │ ├── AdminStatsController.java
│ │ │ │ ├── AdminUsersController.java
│ │ │ │ └── service
│ │ │ │ │ ├── AdminCategoriesService.java
│ │ │ │ │ ├── AdminCategoriesServiceImpl.java
│ │ │ │ │ ├── AdminCompilationsService.java
│ │ │ │ │ ├── AdminCompilationsServiceImpl.java
│ │ │ │ │ ├── AdminEventsService.java
│ │ │ │ │ ├── AdminEventsServiceImpl.java
│ │ │ │ │ ├── AdminUsersService.java
│ │ │ │ │ └── AdminUsersServiceImpl.java
│ │ │ ├── pub
│ │ │ │ ├── PublicCategoriesController.java
│ │ │ │ ├── PublicCompilationsController.java
│ │ │ │ ├── PublicEventsController.java
│ │ │ │ └── service
│ │ │ │ │ ├── CategoriesService.java
│ │ │ │ │ ├── CategoriesServiceImpl.java
│ │ │ │ │ ├── CompilationsService.java
│ │ │ │ │ ├── CompilationsServiceImpl.java
│ │ │ │ │ ├── EventsService.java
│ │ │ │ │ └── EventsServiceImpl.java
│ │ │ └── user
│ │ │ │ ├── UsersEventsController.java
│ │ │ │ ├── UsersEventsRequestsController.java
│ │ │ │ ├── UsersRequestsController.java
│ │ │ │ └── service
│ │ │ │ ├── RequestNotFoundException.java
│ │ │ │ ├── RequestsService.java
│ │ │ │ ├── RequestsServiceImpl.java
│ │ │ │ ├── UsersEventsRequestsService.java
│ │ │ │ ├── UsersEventsRequestsServiceImpl.java
│ │ │ │ ├── UsersEventsService.java
│ │ │ │ └── UsersEventsServiceImpl.java
│ │ │ ├── exception
│ │ │ ├── CategoryNotFoundException.java
│ │ │ ├── CompilationNotFoundException.java
│ │ │ ├── DoubleLikeException.java
│ │ │ ├── EventClosedException.java
│ │ │ ├── EventNotFoundException.java
│ │ │ ├── LikeNotFoundException.java
│ │ │ ├── UserNotFoundException.java
│ │ │ └── UserRequestHimselfException.java
│ │ │ ├── mapper
│ │ │ ├── CategoryMapper.java
│ │ │ ├── CompilationMapper.java
│ │ │ ├── EventMapper.java
│ │ │ ├── LocationMapper.java
│ │ │ ├── RequestMapper.java
│ │ │ └── UserMapper.java
│ │ │ ├── model
│ │ │ ├── Category.java
│ │ │ ├── Compilation.java
│ │ │ ├── Event.java
│ │ │ ├── EventState.java
│ │ │ ├── Like.java
│ │ │ ├── LikeType.java
│ │ │ ├── Location.java
│ │ │ ├── Request.java
│ │ │ ├── RequestState.java
│ │ │ ├── SortType.java
│ │ │ └── User.java
│ │ │ ├── repository
│ │ │ ├── CategoriesRepository.java
│ │ │ ├── CompilationsRepository.java
│ │ │ ├── EventsRepository.java
│ │ │ ├── LikeRepository.java
│ │ │ ├── RequestsRepository.java
│ │ │ └── UsersRepository.java
│ │ │ └── utils
│ │ │ ├── AdminStatsClient.java
│ │ │ ├── BaseClient.java
│ │ │ └── Utils.java
│ └── resources
│ │ ├── application.properties
│ │ └── schema.sql
│ └── test
│ └── java
│ └── ru
│ └── practicum
│ └── ewm
│ ├── MainAPITest.java
│ ├── UtilsTest.java
│ └── model
│ └── dto
│ ├── categories
│ ├── CategoryFullDtoTest.java
│ └── CategoryInDtoTest.java
│ ├── compilations
│ ├── CompilationInDtoTest.java
│ └── CompilationOutDtoTest.java
│ ├── events
│ ├── EventInDtoTest.java
│ └── EventOutDtoTest.java
│ ├── locations
│ └── LocationDtoTest.java
│ ├── requests
│ └── RequestOutDtoTest.java
│ └── users
│ └── UserDtoTest.java
├── pom.xml
├── postman
├── ewm-like-service.json
├── ewm-main-service.json
└── ewm-stat-service.json
├── stats
├── Dockerfile
├── pom.xml
└── src
│ ├── main
│ ├── java
│ │ └── ru
│ │ │ └── practicum
│ │ │ └── ewm
│ │ │ ├── ErrorHandler.java
│ │ │ ├── StatsAPI.java
│ │ │ ├── controller
│ │ │ └── StatsController.java
│ │ │ ├── mapper
│ │ │ └── StatMapper.java
│ │ │ ├── model
│ │ │ └── Stat.java
│ │ │ ├── repository
│ │ │ └── StatsRepository.java
│ │ │ └── service
│ │ │ ├── StatsService.java
│ │ │ └── StatsServiceImpl.java
│ └── resources
│ │ ├── application.properties
│ │ └── schema.sql
│ └── test
│ └── java
│ └── ru
│ └── practicum
│ └── ewm
│ ├── StatsAPITest.java
│ ├── dto
│ └── stats
│ │ ├── StatInDtoTest.java
│ │ └── StatOutDtoTest.java
│ └── mapper
│ └── StatMapperTest.java
└── uml
├── db-ewm-image.png
├── db-ewm.puml
└── project.puml
/.github/workflows/api-tests.yml:
--------------------------------------------------------------------------------
1 | name: Explore With Me API Tests
2 |
3 | on:
4 | pull_request:
5 |
6 | jobs:
7 | build:
8 | uses: yandex-praktikum/java-explore-with-me/.github/workflows/api-tests.yml@ci
--------------------------------------------------------------------------------
/.github/workflows/wait-for-it.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | # Use this script to test if a given TCP host/port are available
3 |
4 | WAITFORIT_cmdname=${0##*/}
5 |
6 | echoerr() { if [[ $WAITFORIT_QUIET -ne 1 ]]; then echo "$@" 1>&2; fi }
7 |
8 | usage()
9 | {
10 | cat << USAGE >&2
11 | Usage:
12 | $WAITFORIT_cmdname host:port [-s] [-t timeout] [-- command args]
13 | -h HOST | --host=HOST Host or IP under test
14 | -p PORT | --port=PORT TCP port under test
15 | Alternatively, you specify the host and port as host:port
16 | -s | --strict Only execute subcommand if the test succeeds
17 | -q | --quiet Don't output any status messages
18 | -t TIMEOUT | --timeout=TIMEOUT
19 | Timeout in seconds, zero for no timeout
20 | -- COMMAND ARGS Execute command with args after the test finishes
21 | USAGE
22 | exit 1
23 | }
24 |
25 | wait_for()
26 | {
27 | if [[ $WAITFORIT_TIMEOUT -gt 0 ]]; then
28 | echoerr "$WAITFORIT_cmdname: waiting $WAITFORIT_TIMEOUT seconds for $WAITFORIT_HOST:$WAITFORIT_PORT"
29 | else
30 | echoerr "$WAITFORIT_cmdname: waiting for $WAITFORIT_HOST:$WAITFORIT_PORT without a timeout"
31 | fi
32 | WAITFORIT_start_ts=$(date +%s)
33 | while :
34 | do
35 | if [[ $WAITFORIT_ISBUSY -eq 1 ]]; then
36 | nc -z $WAITFORIT_HOST $WAITFORIT_PORT
37 | WAITFORIT_result=$?
38 | else
39 | # (echo -n > /dev/tcp/$WAITFORIT_HOST/$WAITFORIT_PORT) >/dev/null 2>&1
40 | (curl --fail --silent $WAITFORIT_HOST:$WAITFORIT_PORT/actuator/health | grep UP) >/dev/null 2>&1
41 | WAITFORIT_result=$?
42 | fi
43 | if [[ $WAITFORIT_result -eq 0 ]]; then
44 | WAITFORIT_end_ts=$(date +%s)
45 | echoerr "$WAITFORIT_cmdname: $WAITFORIT_HOST:$WAITFORIT_PORT is available after $((WAITFORIT_end_ts - WAITFORIT_start_ts)) seconds"
46 | break
47 | fi
48 | sleep 1
49 | done
50 | return $WAITFORIT_result
51 | }
52 |
53 | wait_for_wrapper()
54 | {
55 | # In order to support SIGINT during timeout: http://unix.stackexchange.com/a/57692
56 | if [[ $WAITFORIT_QUIET -eq 1 ]]; then
57 | timeout $WAITFORIT_BUSYTIMEFLAG $WAITFORIT_TIMEOUT $0 --quiet --child --host=$WAITFORIT_HOST --port=$WAITFORIT_PORT --timeout=$WAITFORIT_TIMEOUT &
58 | else
59 | timeout $WAITFORIT_BUSYTIMEFLAG $WAITFORIT_TIMEOUT $0 --child --host=$WAITFORIT_HOST --port=$WAITFORIT_PORT --timeout=$WAITFORIT_TIMEOUT &
60 | fi
61 | WAITFORIT_PID=$!
62 | trap "kill -INT -$WAITFORIT_PID" INT
63 | wait $WAITFORIT_PID
64 | WAITFORIT_RESULT=$?
65 | if [[ $WAITFORIT_RESULT -ne 0 ]]; then
66 | echoerr "$WAITFORIT_cmdname: timeout occurred after waiting $WAITFORIT_TIMEOUT seconds for $WAITFORIT_HOST:$WAITFORIT_PORT"
67 | fi
68 | return $WAITFORIT_RESULT
69 | }
70 |
71 | # process arguments
72 | while [[ $# -gt 0 ]]
73 | do
74 | case "$1" in
75 | *:* )
76 | WAITFORIT_hostport=(${1//:/ })
77 | WAITFORIT_HOST=${WAITFORIT_hostport[0]}
78 | WAITFORIT_PORT=${WAITFORIT_hostport[1]}
79 | shift 1
80 | ;;
81 | --child)
82 | WAITFORIT_CHILD=1
83 | shift 1
84 | ;;
85 | -q | --quiet)
86 | WAITFORIT_QUIET=1
87 | shift 1
88 | ;;
89 | -s | --strict)
90 | WAITFORIT_STRICT=1
91 | shift 1
92 | ;;
93 | -h)
94 | WAITFORIT_HOST="$2"
95 | if [[ $WAITFORIT_HOST == "" ]]; then break; fi
96 | shift 2
97 | ;;
98 | --host=*)
99 | WAITFORIT_HOST="${1#*=}"
100 | shift 1
101 | ;;
102 | -p)
103 | WAITFORIT_PORT="$2"
104 | if [[ $WAITFORIT_PORT == "" ]]; then break; fi
105 | shift 2
106 | ;;
107 | --port=*)
108 | WAITFORIT_PORT="${1#*=}"
109 | shift 1
110 | ;;
111 | -t)
112 | WAITFORIT_TIMEOUT="$2"
113 | if [[ $WAITFORIT_TIMEOUT == "" ]]; then break; fi
114 | shift 2
115 | ;;
116 | --timeout=*)
117 | WAITFORIT_TIMEOUT="${1#*=}"
118 | shift 1
119 | ;;
120 | --)
121 | shift
122 | WAITFORIT_CLI=("$@")
123 | break
124 | ;;
125 | --help)
126 | usage
127 | ;;
128 | *)
129 | echoerr "Unknown argument: $1"
130 | usage
131 | ;;
132 | esac
133 | done
134 |
135 | if [[ "$WAITFORIT_HOST" == "" || "$WAITFORIT_PORT" == "" ]]; then
136 | echoerr "Error: you need to provide a host and port to test."
137 | usage
138 | fi
139 |
140 | WAITFORIT_TIMEOUT=${WAITFORIT_TIMEOUT:-15}
141 | WAITFORIT_STRICT=${WAITFORIT_STRICT:-0}
142 | WAITFORIT_CHILD=${WAITFORIT_CHILD:-0}
143 | WAITFORIT_QUIET=${WAITFORIT_QUIET:-0}
144 |
145 | # Check to see if timeout is from busybox?
146 | WAITFORIT_TIMEOUT_PATH=$(type -p timeout)
147 | WAITFORIT_TIMEOUT_PATH=$(realpath $WAITFORIT_TIMEOUT_PATH 2>/dev/null || readlink -f $WAITFORIT_TIMEOUT_PATH)
148 |
149 | WAITFORIT_BUSYTIMEFLAG=""
150 | if [[ $WAITFORIT_TIMEOUT_PATH =~ "busybox" ]]; then
151 | WAITFORIT_ISBUSY=1
152 | # Check if busybox timeout uses -t flag
153 | # (recent Alpine versions don't support -t anymore)
154 | if timeout &>/dev/stdout | grep -q -e '-t '; then
155 | WAITFORIT_BUSYTIMEFLAG="-t"
156 | fi
157 | else
158 | WAITFORIT_ISBUSY=0
159 | fi
160 |
161 | if [[ $WAITFORIT_CHILD -gt 0 ]]; then
162 | wait_for
163 | WAITFORIT_RESULT=$?
164 | exit $WAITFORIT_RESULT
165 | else
166 | if [[ $WAITFORIT_TIMEOUT -gt 0 ]]; then
167 | wait_for_wrapper
168 | WAITFORIT_RESULT=$?
169 | else
170 | wait_for
171 | WAITFORIT_RESULT=$?
172 | fi
173 | fi
174 |
175 | if [[ $WAITFORIT_CLI != "" ]]; then
176 | if [[ $WAITFORIT_RESULT -ne 0 && $WAITFORIT_STRICT -eq 1 ]]; then
177 | echoerr "$WAITFORIT_cmdname: strict mode, refusing to execute subprocess"
178 | exit $WAITFORIT_RESULT
179 | fi
180 | exec "${WAITFORIT_CLI[@]}"
181 | else
182 | exit $WAITFORIT_RESULT
183 | fi
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | HELP.md
2 | target/
3 | !.mvn/wrapper/maven-wrapper.jar
4 | !**/src/main/**/target/
5 | !**/src/test/**/target/
6 |
7 | ### STS ###
8 | .apt_generated
9 | .classpath
10 | .factorypath
11 | .project
12 | .settings
13 | .springBeans
14 | .sts4-cache
15 |
16 | ### IntelliJ IDEA ###
17 | .idea
18 | *.iws
19 | *.iml
20 | *.ipr
21 |
22 | ### NetBeans ###
23 | /nbproject/private/
24 | /nbbuild/
25 | /dist/
26 | /nbdist/
27 | /.nb-gradle/
28 | build/
29 | !**/src/main/**/build/
30 | !**/src/test/**/build/
31 |
32 | ### VS Code ###
33 | .vscode/
34 | /1
35 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # _REST API для проекта "Explore With Me"_
2 |
3 | ### _Язык реализации Java_
4 |
5 | В рамках дипломного проекта разработано REST API для приложения ExploreWithMe (англ. «исследуй со мной»). Оно
6 | предоставляет
7 | возможность
8 | делиться информацией об интересных событиях и помогать найти компанию для участия в них.
9 |
10 | ### **Инструкция по развертыванию проекта:**
11 |
12 | 1. [Скачать данный репозиторий](https://github.com/bannovdaniil/java-explore-with-me)
13 | 2. mvn clean package
14 | 3. mvn install
15 | 4. docker-compose build
16 | 5. docker-compose up -d
17 | 6. основной сервис доступен по адресу: http://localhost:8080
18 | 7. сервис статистики доступен по адресу: http://localhost:9090
19 |
20 | ### _Приложение включает в себя сервисы:_
21 |
22 | - GateWay (разрабатывается отдельно)
23 | - Проверяет права пользователей
24 | - Передает запросы на остальные микросервисы в зависимости прав
25 | - Основной сервис — содержит всё необходимое для работы.
26 | - Просмотр событий без авторизации;
27 | - Возможность создания и управления категориями;
28 | - События и работа с ними - создание, модерация;
29 | - Запросы пользователей на участие в событии - запрос, подтверждение, отклонение.
30 | - Создание и управление подборками.
31 | - Добавление и удаление Лайков событиям, формирование рейтингов.
32 | - Сервис статистики — хранит количество просмотров и позволяет делать различные выборки для анализа работы приложения.
33 | - Отдельный сервис для сбора статистики;
34 |
35 | ### _Описание сервисов:_
36 |
37 | #### _Основной сервис, выделенный порт: 8080_
38 |
39 | - **Публичный** (_доступен для всех пользователей_)
40 | - API для работы с событиями
41 | - API для работы с категориями
42 | - **Приватный** (_доступен только для зарегистрированных пользователей_)
43 | - API для работы с событиями
44 | - API для работы с запросами текущего пользователя на участие в событиях
45 | - API для работы с рейтингами
46 | - **Административный** (_доступен только для администратора проекта_)
47 | - API для работы с событиями
48 | - API для работы с категориями
49 | - API для работы с пользователями
50 | - API для работы с подборками событий
51 |
52 | #### _Сервис статистики, выделенный порт: 9090_
53 |
54 | - **Административный** (_доступен только для администратора проекта_)
55 | - API для работы со статистикой посещений
56 |
57 | #### _Фича Рейтинги включена в Основной сервис_
58 |
59 | - Сортировка событий по рейтингу
60 | - Оценивать можно только Опубликованные события
61 | - Изменить рейтинг могут только пользователи с подтвержденным участием
62 | - При изменении рейтига события изменяется, рейтинг создателя события.
63 | - При публичном просмотре событий, скрыты данные создателя события.
64 | - Создатель события не может оценивать событие.
65 |
66 | _**Список эндпоинтов для фичи:_**
67 |
68 | - Поставить лайк/дизлайк:
69 | - PUT ewm-main:8080/users/{userId}/events/{eventId}/like?type={like/dislike}
70 | - Убрать лайк/дизлайк:
71 | - DELETE ewm-main:8080/users/{userId}/events/{eventId}/like?type={like/dislike}
72 |
73 | ### _Спецификация REST API swagger_
74 |
75 | - [Основной сервис](https://raw.githubusercontent.com/bannovdaniil/java-explore-with-me/develop/ewm-main-service-spec.json)
76 | - [Сервис статистики](https://raw.githubusercontent.com/bannovdaniil/java-explore-with-me/develop/ewm-stats-service-spec.json)
77 |
78 | ### _Postman тесты для сервисов:_
79 |
80 | - [Основной сервис](https://raw.githubusercontent.com/bannovdaniil/java-explore-with-me/develop/postman/ewm-main-service.json)
81 | - [Сервис статистики](https://raw.githubusercontent.com/bannovdaniil/java-explore-with-me/develop/postman/ewm-stat-service.json)
82 | - [Тест для фичи Рейтинги](https://raw.githubusercontent.com/bannovdaniil/java-explore-with-me/develop/postman/ewm-like-service.json)
83 |
84 | ### _Схема Архитектуры проекта_
85 |
86 | 
87 |
88 | ### _Схема Базы данных проекта_
89 |
90 | 
91 |
92 | 
93 |
--------------------------------------------------------------------------------
/common/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 4.0.0
6 |
7 |
8 | explore-with-me
9 | ru.practicum
10 | 0.0.1-SNAPSHOT
11 |
12 |
13 | common
14 | 0.0.1-SNAPSHOT
15 |
16 |
17 | 11
18 | 11
19 | UTF-8
20 |
21 |
22 |
23 | org.projectlombok
24 | lombok
25 | true
26 |
27 |
28 | org.springframework.boot
29 | spring-boot-starter-validation
30 |
31 |
32 | org.springframework.boot
33 | spring-boot-starter-web
34 |
35 |
36 |
37 |
--------------------------------------------------------------------------------
/common/src/main/java/ru/practicum/ewm/Constants.java:
--------------------------------------------------------------------------------
1 | package ru.practicum.ewm;
2 |
3 | import java.time.format.DateTimeFormatter;
4 |
5 | public class Constants {
6 | public static final String DATE_TIME_STRING = "yyyy-MM-dd HH:mm:ss";
7 | public static final DateTimeFormatter DATE_TIME_SPACE = DateTimeFormatter.ofPattern(DATE_TIME_STRING);
8 | public static final String PAGE_SIZE_STRING = "10";
9 | public static final int USER_TIME_HOUR_BEFORE_START = 2;
10 | public static final int ADMIN_TIME_HOUR_BEFORE_START = 1;
11 | }
--------------------------------------------------------------------------------
/common/src/main/java/ru/practicum/ewm/dto/stats/StatInDto.java:
--------------------------------------------------------------------------------
1 | package ru.practicum.ewm.dto.stats;
2 |
3 | import com.fasterxml.jackson.annotation.JsonFormat;
4 | import lombok.AllArgsConstructor;
5 | import lombok.Getter;
6 | import lombok.NoArgsConstructor;
7 | import lombok.Setter;
8 | import ru.practicum.ewm.Constants;
9 |
10 | import javax.validation.constraints.NotNull;
11 | import java.time.LocalDateTime;
12 |
13 | @Getter
14 | @Setter
15 | @AllArgsConstructor
16 | @NoArgsConstructor
17 | public class StatInDto {
18 | @NotNull
19 | private String app;
20 | @NotNull
21 | private String uri;
22 | @NotNull
23 | private String ip;
24 | @NotNull
25 | @JsonFormat(pattern = Constants.DATE_TIME_STRING)
26 | private LocalDateTime timestamp;
27 |
28 | public StatInDto(String app, String uri, String ip, String timestamp) {
29 | this.app = app;
30 | this.uri = uri;
31 | this.ip = ip;
32 | this.timestamp = LocalDateTime.parse(timestamp, Constants.DATE_TIME_SPACE);
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/common/src/main/java/ru/practicum/ewm/dto/stats/StatOutDto.java:
--------------------------------------------------------------------------------
1 | package ru.practicum.ewm.dto.stats;
2 |
3 | import lombok.AllArgsConstructor;
4 | import lombok.Getter;
5 | import lombok.Setter;
6 |
7 | @Getter
8 | @Setter
9 | @AllArgsConstructor
10 | public class StatOutDto {
11 | private String app;
12 | private String uri;
13 | private Long hits;
14 | }
15 |
--------------------------------------------------------------------------------
/docker-compose.yml:
--------------------------------------------------------------------------------
1 | version: '3.8'
2 | services:
3 | # Stats
4 | stats-server:
5 | build: ./stats
6 | container_name: stats_server
7 | restart: always
8 | ports:
9 | - "9090:9090"
10 | depends_on:
11 | stats-db:
12 | condition: service_healthy
13 | environment:
14 | - WAIT_HOSTS=stats-db:5432
15 | - SPRING_DATASOURCE_URL=jdbc:postgresql://stats-db:5432/stats
16 | - POSTGRES_USER=sa
17 | - POSTGRES_PASSWORD=password
18 |
19 | # база данных для Stats
20 | stats-db:
21 | image: postgres:14.5-alpine
22 | container_name: stats_db
23 | restart: always
24 | volumes:
25 | - /var/lib/postgresql/data/
26 | ports:
27 | - "6590:5432"
28 | # переменные окружения
29 | environment:
30 | POSTGRES_DB: stats
31 | POSTGRES_USER: sa
32 | POSTGRES_PASSWORD: password
33 | healthcheck:
34 | test: [ "CMD-SHELL", "pg_isready -U postgres" ]
35 | interval: 10s
36 | timeout: 5s
37 | retries: 5
38 | # Main
39 | ewm-service:
40 | build: ./main
41 | container_name: main_server
42 | restart: always
43 | ports:
44 | - "8080:8080"
45 | depends_on:
46 | ewm-db:
47 | condition: service_healthy
48 |
49 | environment:
50 | - WAIT_HOSTS=ewm-db:5432
51 | - SPRING_DATASOURCE_URL=jdbc:postgresql://ewm-db:5432/ewm
52 | - POSTGRES_USER=sa
53 | - POSTGRES_PASSWORD=password
54 | - STATS_SERVER_URL=http://stats-server:9090
55 |
56 | # база для MAIn
57 | ewm-db:
58 | image: postgres:14.5-alpine
59 | container_name: ewm_db
60 | restart: always
61 | volumes:
62 | - /var/lib/postgresql/data/
63 | ports:
64 | - "6580:5432"
65 | # переменные окружения
66 | environment:
67 | POSTGRES_DB: ewm
68 | POSTGRES_USER: sa
69 | POSTGRES_PASSWORD: password
70 | healthcheck:
71 | test: [ "CMD-SHELL", "pg_isready -U postgres" ]
72 | interval: 10s
73 | timeout: 5s
74 | retries: 5
75 |
--------------------------------------------------------------------------------
/ewm-stats-service-spec.json:
--------------------------------------------------------------------------------
1 | {
2 | "openapi": "3.0.1",
3 | "info": {
4 | "title": "Stat service API",
5 | "version": "v0"
6 | },
7 | "servers": [
8 | {
9 | "url": "http://localhost:9090",
10 | "description": "Generated server url"
11 | }
12 | ],
13 | "tags": [
14 | {
15 | "name": "StatsController",
16 | "description": "API для работы со статистикой посещений"
17 | }
18 | ],
19 | "paths": {
20 | "/hit": {
21 | "post": {
22 | "tags": [
23 | "StatsController"
24 | ],
25 | "summary": "Сохранение информации о том, что к эндпоинту был запрос",
26 | "description": "Сохранение информации о том, что на uri конкретного сервиса был отправлен запрос пользователем. Название сервиса, uri и ip пользователя указаны в теле запроса.",
27 | "operationId": "hit",
28 | "requestBody": {
29 | "description": "данные запроса",
30 | "content": {
31 | "application/json": {
32 | "schema": {
33 | "$ref": "#/components/schemas/EndpointHit"
34 | }
35 | }
36 | },
37 | "required": true
38 | },
39 | "responses": {
40 | "200": {
41 | "description": "Информация сохранена"
42 | }
43 | }
44 | }
45 | },
46 | "/stats": {
47 | "get": {
48 | "tags": [
49 | "StatsController"
50 | ],
51 | "summary": "Получение статистики по посещениям. Обратите внимание: значение даты и времени нужно закодировать (например используя java.net.URLEncoder.encode) ",
52 | "operationId": "getStats",
53 | "parameters": [
54 | {
55 | "name": "start",
56 | "in": "query",
57 | "description": "Дата и время начала диапазона за который нужно выгрузить статистику (в формате \"yyyy-MM-dd HH:mm:ss\")",
58 | "required": true,
59 | "schema": {
60 | "type": "string"
61 | }
62 | },
63 | {
64 | "name": "end",
65 | "in": "query",
66 | "description": "Дата и время конца диапазона за который нужно выгрузить статистику (в формате \"yyyy-MM-dd HH:mm:ss\")",
67 | "required": true,
68 | "schema": {
69 | "type": "string"
70 | }
71 | },
72 | {
73 | "name": "uris",
74 | "in": "query",
75 | "description": "Список uri для которых нужно выгрузить статистику",
76 | "required": false,
77 | "schema": {
78 | "type": "array",
79 | "items": {
80 | "type": "string"
81 | }
82 | }
83 | },
84 | {
85 | "name": "unique",
86 | "in": "query",
87 | "description": "Нужно ли учитывать только уникальные посещения (только с уникальным ip)",
88 | "required": false,
89 | "schema": {
90 | "type": "boolean",
91 | "default": false
92 | }
93 | }
94 | ],
95 | "responses": {
96 | "200": {
97 | "description": "Статистика собрана",
98 | "content": {
99 | "application/json": {
100 | "schema": {
101 | "type": "array",
102 | "items": {
103 | "$ref": "#/components/schemas/ViewStats"
104 | }
105 | }
106 | }
107 | }
108 | }
109 | }
110 | }
111 | }
112 | },
113 | "components": {
114 | "schemas": {
115 | "EndpointHit": {
116 | "type": "object",
117 | "properties": {
118 | "id": {
119 | "type": "integer",
120 | "description": "Идентификатор записи",
121 | "format": "int64"
122 | },
123 | "app": {
124 | "type": "string",
125 | "description": "Идентификатор сервиса для которого записывается информация"
126 | },
127 | "uri": {
128 | "type": "string",
129 | "description": "URI для которого был осуществлен запрос "
130 | },
131 | "ip": {
132 | "type": "string",
133 | "description": "IP-адрес пользователя, осуществившего запрос"
134 | },
135 | "timestamp": {
136 | "type": "string",
137 | "description": "Дата и время, когда был совершен запрос к эндпоинту (в формате \"yyyy-MM-dd HH:mm:ss\")",
138 | "example": "2022-09-06 11:00:23"
139 | }
140 | }
141 | },
142 | "ViewStats": {
143 | "type": "object",
144 | "properties": {
145 | "app": {
146 | "type": "string",
147 | "description": "Название сервиса"
148 | },
149 | "uri": {
150 | "type": "string",
151 | "description": "URI сервиса"
152 | },
153 | "hits": {
154 | "type": "integer",
155 | "description": "Количество просмотров",
156 | "format": "int64"
157 | }
158 | }
159 | }
160 | }
161 | }
162 | }
--------------------------------------------------------------------------------
/lombok.config:
--------------------------------------------------------------------------------
1 | config.stopBubbling = true
2 | lombok.anyconstructor.addconstructorproperties = false
3 | lombok.addLombokGeneratedAnnotation = true
4 | lombok.addSuppressWarnings = false
--------------------------------------------------------------------------------
/main/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM amazoncorretto:11-alpine-jdk
2 | COPY target/ewm-main-server*.jar ewm_main_server.jar
3 | ENTRYPOINT ["java","-jar","/ewm_main_server.jar"]
4 |
--------------------------------------------------------------------------------
/main/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 | explore-with-me
7 | ru.practicum
8 | 0.0.1-SNAPSHOT
9 |
10 | 4.0.0
11 |
12 | ewm-main-server
13 |
14 |
15 | 11
16 | 11
17 | UTF-8
18 |
19 |
20 |
21 |
22 | ru.practicum
23 | common
24 | 0.0.1-SNAPSHOT
25 |
26 |
27 | org.apache.httpcomponents
28 | httpclient
29 | 4.5.13
30 |
31 |
32 | org.springframework.boot
33 | spring-boot-starter-data-jpa
34 |
35 |
36 |
37 | org.springframework.boot
38 | spring-boot-starter-web
39 |
40 |
41 |
42 | org.springframework.boot
43 | spring-boot-starter-actuator
44 |
45 |
46 |
47 | org.postgresql
48 | postgresql
49 | 42.5.0
50 | runtime
51 |
52 |
53 |
54 | com.h2database
55 | h2
56 | runtime
57 |
58 |
59 |
60 | org.springframework.boot
61 | spring-boot-configuration-processor
62 | true
63 |
64 |
65 |
66 | org.projectlombok
67 | lombok
68 | true
69 |
70 |
71 |
72 | org.springframework.boot
73 | spring-boot-starter-test
74 | test
75 |
76 |
77 | org.springframework.boot
78 | spring-boot-test-autoconfigure
79 |
80 |
81 | org.springframework
82 | spring-test
83 |
84 |
85 | org.hamcrest
86 | hamcrest
87 |
88 |
89 | org.springframework.boot
90 | spring-boot-autoconfigure
91 |
92 |
93 |
94 |
95 |
96 |
97 | org.springframework.boot
98 | spring-boot-maven-plugin
99 |
100 |
101 |
102 |
103 |
--------------------------------------------------------------------------------
/main/src/main/java/ru/practicum/ewm/ErrorHandler.java:
--------------------------------------------------------------------------------
1 | package ru.practicum.ewm;
2 |
3 | import lombok.AllArgsConstructor;
4 | import lombok.Getter;
5 | import lombok.Setter;
6 | import lombok.ToString;
7 | import lombok.extern.slf4j.Slf4j;
8 | import org.springframework.dao.DataIntegrityViolationException;
9 | import org.springframework.http.HttpStatus;
10 | import org.springframework.web.bind.MethodArgumentNotValidException;
11 | import org.springframework.web.bind.MissingServletRequestParameterException;
12 | import org.springframework.web.bind.annotation.ExceptionHandler;
13 | import org.springframework.web.bind.annotation.ResponseStatus;
14 | import org.springframework.web.bind.annotation.RestControllerAdvice;
15 | import ru.practicum.ewm.endpoints.admin.AdminCategoriesController;
16 | import ru.practicum.ewm.endpoints.admin.AdminCompilationsController;
17 | import ru.practicum.ewm.endpoints.admin.AdminEventsController;
18 | import ru.practicum.ewm.endpoints.admin.AdminUsersController;
19 | import ru.practicum.ewm.endpoints.pub.PublicCategoriesController;
20 | import ru.practicum.ewm.endpoints.pub.PublicCompilationsController;
21 | import ru.practicum.ewm.endpoints.pub.PublicEventsController;
22 | import ru.practicum.ewm.endpoints.user.UsersEventsController;
23 | import ru.practicum.ewm.endpoints.user.UsersEventsRequestsController;
24 | import ru.practicum.ewm.endpoints.user.UsersRequestsController;
25 | import ru.practicum.ewm.endpoints.user.service.RequestNotFoundException;
26 | import ru.practicum.ewm.exception.*;
27 |
28 | import java.nio.file.AccessDeniedException;
29 | import java.security.InvalidParameterException;
30 | import java.time.LocalDateTime;
31 |
32 | @RestControllerAdvice(
33 | assignableTypes = {
34 | AdminUsersController.class,
35 | AdminCategoriesController.class,
36 | AdminCompilationsController.class,
37 | AdminEventsController.class,
38 | UsersEventsController.class,
39 | UsersRequestsController.class,
40 | UsersEventsRequestsController.class,
41 | PublicCategoriesController.class,
42 | PublicCompilationsController.class,
43 | PublicEventsController.class
44 | })
45 | @Slf4j
46 | public class ErrorHandler {
47 | private ErrorResponse errorResponse;
48 |
49 | @ExceptionHandler({
50 | CategoryNotFoundException.class,
51 | EventNotFoundException.class,
52 | UserNotFoundException.class,
53 | RequestNotFoundException.class,
54 | CompilationNotFoundException.class,
55 | LikeNotFoundException.class
56 | })
57 | @ResponseStatus(HttpStatus.NOT_FOUND)
58 | public ErrorResponse handleNotFound(final Exception e) {
59 | log.info("Error handleNotFound: {}", e.getMessage());
60 | return new ErrorResponse(e.getMessage());
61 | }
62 |
63 | @ExceptionHandler({
64 | DataIntegrityViolationException.class,
65 | MethodArgumentNotValidException.class,
66 | InvalidParameterException.class,
67 | MissingServletRequestParameterException.class
68 | })
69 | @ResponseStatus(HttpStatus.BAD_REQUEST)
70 | public ErrorMessage handleBadRequest(final Exception e) {
71 | log.info("Error handleBadRequest: {}: {}", e.getClass().getSimpleName(), e.getMessage());
72 | return new ErrorMessage(
73 | e.getClass().getSimpleName(),
74 | e.getMessage(),
75 | "",
76 | "BAD_REQUEST",
77 | Constants.DATE_TIME_SPACE.format(LocalDateTime.now()));
78 | }
79 |
80 | @ExceptionHandler({
81 | IllegalArgumentException.class,
82 | IllegalStateException.class,
83 | UserRequestHimselfException.class
84 | })
85 | @ResponseStatus(HttpStatus.BAD_REQUEST)
86 | public ErrorResponse handleArgumentBadRequest(final Exception e) {
87 | log.info("Error handleArgumentBadRequest: {}", e.getMessage());
88 | return new ErrorResponse(e.getMessage());
89 | }
90 |
91 | @ExceptionHandler({
92 | EventClosedException.class,
93 | DoubleLikeException.class
94 | })
95 | @ResponseStatus(HttpStatus.CONFLICT)
96 | public ErrorResponse handleDoubleData(final Exception e) {
97 | log.info("Error handleDoubleData: {}", e.getMessage());
98 | return new ErrorResponse(e.getMessage());
99 | }
100 |
101 | @ExceptionHandler({
102 | AccessDeniedException.class
103 | })
104 | @ResponseStatus(HttpStatus.FORBIDDEN)
105 | public ErrorResponse handleForbidden(final Exception e) {
106 | log.info("Error handleForbidden: {}", e.getMessage());
107 | return new ErrorResponse(e.getMessage());
108 | }
109 |
110 | @ExceptionHandler
111 | @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
112 | public ErrorResponse handleAllError(final Throwable e) {
113 | log.info("Error handleAllError: {}", e.getMessage());
114 | return new ErrorResponse("Произошла непредвиденная ошибка. " + e.getMessage());
115 | }
116 |
117 | private static class ErrorResponse {
118 | private final String error;
119 |
120 | public ErrorResponse(String error) {
121 | this.error = error;
122 | }
123 |
124 | public String getError() {
125 | return error;
126 | }
127 | }
128 |
129 | @AllArgsConstructor
130 | @Getter
131 | @Setter
132 | @ToString
133 | private static class ErrorMessage {
134 | private String errors;
135 | private String message;
136 | private String reason;
137 | private String status;
138 | private String timestamp;
139 | }
140 | }
141 |
--------------------------------------------------------------------------------
/main/src/main/java/ru/practicum/ewm/MainAPI.java:
--------------------------------------------------------------------------------
1 | package ru.practicum.ewm;
2 |
3 | import org.springframework.boot.SpringApplication;
4 | import org.springframework.boot.autoconfigure.SpringBootApplication;
5 |
6 | @SpringBootApplication
7 | public class MainAPI {
8 | public static final String APP_NAME = "ewm-main";
9 |
10 | public static void main(String[] args) {
11 | SpringApplication.run(MainAPI.class, args);
12 | }
13 |
14 | }
15 |
--------------------------------------------------------------------------------
/main/src/main/java/ru/practicum/ewm/dto/categories/CategoryFullDto.java:
--------------------------------------------------------------------------------
1 | package ru.practicum.ewm.dto.categories;
2 |
3 | import lombok.AllArgsConstructor;
4 | import lombok.Getter;
5 | import lombok.NoArgsConstructor;
6 | import lombok.Setter;
7 |
8 | import javax.validation.constraints.NotBlank;
9 | import javax.validation.constraints.Positive;
10 |
11 | @Getter
12 | @Setter
13 | @AllArgsConstructor
14 | @NoArgsConstructor
15 | public class CategoryFullDto {
16 | @Positive
17 | private Long id;
18 | @NotBlank
19 | private String name;
20 | }
21 |
--------------------------------------------------------------------------------
/main/src/main/java/ru/practicum/ewm/dto/categories/CategoryInDto.java:
--------------------------------------------------------------------------------
1 | package ru.practicum.ewm.dto.categories;
2 |
3 | import lombok.AllArgsConstructor;
4 | import lombok.Getter;
5 | import lombok.NoArgsConstructor;
6 | import lombok.Setter;
7 |
8 | import javax.validation.constraints.NotBlank;
9 |
10 | @Getter
11 | @Setter
12 | @NoArgsConstructor
13 | @AllArgsConstructor
14 | public class CategoryInDto {
15 | @NotBlank
16 | private String name;
17 | }
18 |
--------------------------------------------------------------------------------
/main/src/main/java/ru/practicum/ewm/dto/compilations/CompilationInDto.java:
--------------------------------------------------------------------------------
1 | package ru.practicum.ewm.dto.compilations;
2 |
3 | import lombok.AllArgsConstructor;
4 | import lombok.Getter;
5 | import lombok.NoArgsConstructor;
6 | import lombok.Setter;
7 |
8 | import javax.validation.constraints.NotBlank;
9 | import java.util.List;
10 |
11 | @Setter
12 | @Getter
13 | @AllArgsConstructor
14 | @NoArgsConstructor
15 | public class CompilationInDto {
16 | @NotBlank
17 | private String title;
18 | private List events;
19 | private Boolean pinned;
20 | }
21 |
--------------------------------------------------------------------------------
/main/src/main/java/ru/practicum/ewm/dto/compilations/CompilationOutDto.java:
--------------------------------------------------------------------------------
1 | package ru.practicum.ewm.dto.compilations;
2 |
3 | import lombok.AllArgsConstructor;
4 | import lombok.Getter;
5 | import lombok.NoArgsConstructor;
6 | import lombok.Setter;
7 | import ru.practicum.ewm.dto.events.EventOutDto;
8 |
9 | import java.util.List;
10 |
11 | @Setter
12 | @Getter
13 | @AllArgsConstructor
14 | @NoArgsConstructor
15 | public class CompilationOutDto {
16 | private Long id;
17 | private String title;
18 | private List events;
19 | private Boolean pinned;
20 | }
21 |
--------------------------------------------------------------------------------
/main/src/main/java/ru/practicum/ewm/dto/events/EventInDto.java:
--------------------------------------------------------------------------------
1 | package ru.practicum.ewm.dto.events;
2 |
3 | import com.fasterxml.jackson.annotation.JsonFormat;
4 | import lombok.AllArgsConstructor;
5 | import lombok.Getter;
6 | import lombok.NoArgsConstructor;
7 | import lombok.Setter;
8 | import ru.practicum.ewm.Constants;
9 | import ru.practicum.ewm.dto.locations.LocationDto;
10 |
11 | import javax.validation.constraints.NotBlank;
12 | import javax.validation.constraints.NotNull;
13 | import javax.validation.constraints.Positive;
14 | import javax.validation.constraints.Size;
15 | import java.time.LocalDateTime;
16 |
17 | @Getter
18 | @Setter
19 | @NoArgsConstructor
20 | @AllArgsConstructor
21 | public class EventInDto {
22 | private Long eventId;
23 | @NotBlank
24 | @Size(min = 20, max = 2000)
25 | private String annotation;
26 | @Positive
27 | private Long category;
28 | @NotBlank
29 | @Size(min = 20, max = 7000)
30 | private String description;
31 | private LocationDto location;
32 | @NotBlank
33 | @Size(min = 3, max = 120)
34 | private String title;
35 | @NotNull
36 | @JsonFormat(pattern = Constants.DATE_TIME_STRING)
37 | private LocalDateTime eventDate;
38 | private Boolean paid;
39 | @Positive
40 | private Integer participantLimit;
41 | private Boolean requestModeration;
42 |
43 | public EventInDto(String annotation, Long category, String description, LocationDto location, String title, String eventDate, Boolean paid, Integer participantLimit, Boolean requestModeration) {
44 | this.annotation = annotation;
45 | this.category = category;
46 | this.description = description;
47 | this.location = location;
48 | this.title = title;
49 | this.eventDate = LocalDateTime.parse(eventDate, Constants.DATE_TIME_SPACE);
50 | this.paid = paid;
51 | this.participantLimit = participantLimit;
52 | this.requestModeration = requestModeration;
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/main/src/main/java/ru/practicum/ewm/dto/events/EventOutDto.java:
--------------------------------------------------------------------------------
1 | package ru.practicum.ewm.dto.events;
2 |
3 | import com.fasterxml.jackson.annotation.JsonFormat;
4 | import lombok.*;
5 | import ru.practicum.ewm.Constants;
6 | import ru.practicum.ewm.dto.categories.CategoryFullDto;
7 | import ru.practicum.ewm.dto.locations.LocationDto;
8 | import ru.practicum.ewm.dto.users.UserDto;
9 | import ru.practicum.ewm.model.EventState;
10 |
11 | import java.time.LocalDateTime;
12 |
13 | @Getter
14 | @Setter
15 | @NoArgsConstructor
16 | @AllArgsConstructor
17 | @Builder
18 | public class EventOutDto {
19 | private String annotation;
20 | private CategoryFullDto category;
21 | private UserDto initiator;
22 | private LocationDto location;
23 | private String title;
24 | private Integer confirmedRequests;
25 | @JsonFormat(pattern = Constants.DATE_TIME_STRING)
26 | private LocalDateTime createdOn;
27 | private String description;
28 | @JsonFormat(pattern = Constants.DATE_TIME_STRING)
29 | private LocalDateTime eventDate;
30 | private Long id;
31 | private Boolean paid;
32 | private Integer participantLimit;
33 | @JsonFormat(pattern = Constants.DATE_TIME_STRING)
34 | private LocalDateTime publishedOn;
35 | private Boolean requestModeration;
36 | private EventState state;
37 | private Long views;
38 | private Integer rate;
39 | }
40 |
--------------------------------------------------------------------------------
/main/src/main/java/ru/practicum/ewm/dto/events/EventPublicOutDto.java:
--------------------------------------------------------------------------------
1 | package ru.practicum.ewm.dto.events;
2 |
3 | import com.fasterxml.jackson.annotation.JsonFormat;
4 | import lombok.*;
5 | import ru.practicum.ewm.Constants;
6 | import ru.practicum.ewm.dto.categories.CategoryFullDto;
7 | import ru.practicum.ewm.dto.locations.LocationDto;
8 | import ru.practicum.ewm.dto.users.UserPublicDto;
9 | import ru.practicum.ewm.model.EventState;
10 |
11 | import java.time.LocalDateTime;
12 |
13 | @Getter
14 | @Setter
15 | @NoArgsConstructor
16 | @AllArgsConstructor
17 | @Builder
18 | public class EventPublicOutDto {
19 | private String annotation;
20 | private CategoryFullDto category;
21 | private UserPublicDto initiator;
22 | private LocationDto location;
23 | private String title;
24 | private Integer confirmedRequests;
25 | @JsonFormat(pattern = Constants.DATE_TIME_STRING)
26 | private LocalDateTime createdOn;
27 | private String description;
28 | @JsonFormat(pattern = Constants.DATE_TIME_STRING)
29 | private LocalDateTime eventDate;
30 | private Long id;
31 | private Boolean paid;
32 | private Integer participantLimit;
33 | @JsonFormat(pattern = Constants.DATE_TIME_STRING)
34 | private LocalDateTime publishedOn;
35 | private Boolean requestModeration;
36 | private EventState state;
37 | private Long views;
38 | private Integer rate;
39 | }
40 |
--------------------------------------------------------------------------------
/main/src/main/java/ru/practicum/ewm/dto/locations/LocationDto.java:
--------------------------------------------------------------------------------
1 | package ru.practicum.ewm.dto.locations;
2 |
3 | import lombok.AllArgsConstructor;
4 | import lombok.Getter;
5 | import lombok.NoArgsConstructor;
6 | import lombok.Setter;
7 |
8 | @Getter
9 | @Setter
10 | @NoArgsConstructor
11 | @AllArgsConstructor
12 | public class LocationDto {
13 | private float lat;
14 | private float lon;
15 | }
16 |
--------------------------------------------------------------------------------
/main/src/main/java/ru/practicum/ewm/dto/requests/RequestOutDto.java:
--------------------------------------------------------------------------------
1 | package ru.practicum.ewm.dto.requests;
2 |
3 | import com.fasterxml.jackson.annotation.JsonFormat;
4 | import lombok.AllArgsConstructor;
5 | import lombok.Getter;
6 | import lombok.NoArgsConstructor;
7 | import lombok.Setter;
8 | import ru.practicum.ewm.Constants;
9 | import ru.practicum.ewm.model.RequestState;
10 |
11 | import javax.validation.constraints.Positive;
12 | import java.time.LocalDateTime;
13 |
14 | @Getter
15 | @Setter
16 | @NoArgsConstructor
17 | @AllArgsConstructor
18 | public class RequestOutDto {
19 | private Long id;
20 | @JsonFormat(pattern = Constants.DATE_TIME_STRING)
21 | private LocalDateTime created;
22 | @Positive
23 | private Long event;
24 | @Positive
25 | private Long requester;
26 | private RequestState status;
27 | }
28 |
--------------------------------------------------------------------------------
/main/src/main/java/ru/practicum/ewm/dto/users/UserDto.java:
--------------------------------------------------------------------------------
1 | package ru.practicum.ewm.dto.users;
2 |
3 | import lombok.AllArgsConstructor;
4 | import lombok.Getter;
5 | import lombok.NoArgsConstructor;
6 | import lombok.Setter;
7 |
8 | import javax.validation.constraints.Email;
9 |
10 | @Getter
11 | @Setter
12 | @NoArgsConstructor
13 | @AllArgsConstructor
14 | public class UserDto {
15 | private Long id;
16 | private String name;
17 | @Email
18 | private String email;
19 | private Float rate;
20 | }
21 |
--------------------------------------------------------------------------------
/main/src/main/java/ru/practicum/ewm/dto/users/UserPublicDto.java:
--------------------------------------------------------------------------------
1 | package ru.practicum.ewm.dto.users;
2 |
3 | import lombok.AllArgsConstructor;
4 | import lombok.Getter;
5 | import lombok.NoArgsConstructor;
6 | import lombok.Setter;
7 |
8 | @Getter
9 | @Setter
10 | @NoArgsConstructor
11 | @AllArgsConstructor
12 | public class UserPublicDto {
13 | private String name;
14 | }
15 |
--------------------------------------------------------------------------------
/main/src/main/java/ru/practicum/ewm/endpoints/admin/AdminCategoriesController.java:
--------------------------------------------------------------------------------
1 | package ru.practicum.ewm.endpoints.admin;
2 |
3 | import lombok.RequiredArgsConstructor;
4 | import lombok.extern.slf4j.Slf4j;
5 | import org.springframework.validation.annotation.Validated;
6 | import org.springframework.web.bind.annotation.*;
7 | import ru.practicum.ewm.dto.categories.CategoryFullDto;
8 | import ru.practicum.ewm.dto.categories.CategoryInDto;
9 | import ru.practicum.ewm.endpoints.admin.service.AdminCategoriesService;
10 | import ru.practicum.ewm.exception.CategoryNotFoundException;
11 |
12 | import javax.validation.Valid;
13 | import javax.validation.constraints.Positive;
14 | import java.nio.file.AccessDeniedException;
15 |
16 | @RestController
17 | @RequestMapping("/admin/categories")
18 | @RequiredArgsConstructor
19 | @Validated
20 | @Slf4j
21 | public class AdminCategoriesController {
22 | private final AdminCategoriesService adminCategoriesService;
23 |
24 | @PatchMapping
25 | public CategoryFullDto updateCategory(@Valid @RequestBody CategoryFullDto categoryFullDto) throws CategoryNotFoundException {
26 | log.info("Admin updateCategory: {}", categoryFullDto);
27 | return adminCategoriesService.updateCategory(categoryFullDto);
28 | }
29 |
30 | @PostMapping
31 | public CategoryFullDto addCategory(@Valid @RequestBody CategoryInDto categoryInDto) {
32 | log.info("Admin addCategory: {}", categoryInDto);
33 | return adminCategoriesService.addCategory(categoryInDto);
34 | }
35 |
36 | @DeleteMapping("{catId}")
37 | void removeCategory(@Positive @PathVariable Long catId) throws CategoryNotFoundException, AccessDeniedException {
38 | log.info("Admin removeCategory: {}", catId);
39 | adminCategoriesService.removeCategory(catId);
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/main/src/main/java/ru/practicum/ewm/endpoints/admin/AdminCompilationsController.java:
--------------------------------------------------------------------------------
1 | package ru.practicum.ewm.endpoints.admin;
2 |
3 | import lombok.RequiredArgsConstructor;
4 | import lombok.extern.slf4j.Slf4j;
5 | import org.springframework.validation.annotation.Validated;
6 | import org.springframework.web.bind.annotation.*;
7 | import ru.practicum.ewm.dto.compilations.CompilationInDto;
8 | import ru.practicum.ewm.dto.compilations.CompilationOutDto;
9 | import ru.practicum.ewm.endpoints.admin.service.AdminCompilationsService;
10 | import ru.practicum.ewm.exception.CompilationNotFoundException;
11 | import ru.practicum.ewm.exception.EventNotFoundException;
12 |
13 | import javax.validation.Valid;
14 | import javax.validation.constraints.Positive;
15 |
16 | @RestController
17 | @RequestMapping("/admin/compilations")
18 | @RequiredArgsConstructor
19 | @Validated
20 | @Slf4j
21 | public class AdminCompilationsController {
22 | private final AdminCompilationsService adminCompilationsService;
23 |
24 | @PostMapping
25 | public CompilationOutDto addCompilation(@Valid @RequestBody CompilationInDto compilationInDto) {
26 | log.info("Admin addCompilation: {}", compilationInDto);
27 | return adminCompilationsService.addCompilation(compilationInDto);
28 | }
29 |
30 | @DeleteMapping("{compId}")
31 | public void removeCompilation(@Positive @PathVariable Long compId) throws CompilationNotFoundException {
32 | log.info("Admin removeCompilation: {}", compId);
33 | adminCompilationsService.removeCompilation(compId);
34 | }
35 |
36 | @DeleteMapping("{compId}/events/{eventId}")
37 | public void removeEventFromCompilation(
38 | @Positive @PathVariable Long compId,
39 | @Positive @PathVariable Long eventId
40 | ) throws CompilationNotFoundException {
41 | log.info("Admin removeEventFromCompilation: {},{}", compId, eventId);
42 | adminCompilationsService.removeEventFromCompilation(compId, eventId);
43 | }
44 |
45 | @PatchMapping("{compId}/events/{eventId}")
46 | public CompilationOutDto addEventToCompilation(
47 | @Positive @PathVariable Long compId,
48 | @Positive @PathVariable Long eventId
49 | ) throws CompilationNotFoundException, EventNotFoundException {
50 | log.info("Admin addEventToCompilation: {},{}", compId, eventId);
51 | return adminCompilationsService.addEventToCompilation(compId, eventId);
52 | }
53 |
54 | @DeleteMapping("{compId}/pin")
55 | public void unPinCompilation(
56 | @Positive @PathVariable Long compId
57 | ) throws CompilationNotFoundException {
58 | log.info("Admin unPinCompilation: {}", compId);
59 | adminCompilationsService.unPinCompilation(compId);
60 | }
61 |
62 | @PatchMapping("{compId}/pin")
63 | public void pinCompilation(
64 | @Positive @PathVariable Long compId
65 | ) throws CompilationNotFoundException {
66 | log.info("Admin pinCompilation: {}", compId);
67 | adminCompilationsService.pinCompilation(compId);
68 | }
69 |
70 | }
71 |
--------------------------------------------------------------------------------
/main/src/main/java/ru/practicum/ewm/endpoints/admin/AdminEventsController.java:
--------------------------------------------------------------------------------
1 | package ru.practicum.ewm.endpoints.admin;
2 |
3 | import lombok.RequiredArgsConstructor;
4 | import lombok.extern.slf4j.Slf4j;
5 | import org.springframework.validation.annotation.Validated;
6 | import org.springframework.web.bind.annotation.*;
7 | import ru.practicum.ewm.Constants;
8 | import ru.practicum.ewm.dto.events.EventInDto;
9 | import ru.practicum.ewm.dto.events.EventOutDto;
10 | import ru.practicum.ewm.endpoints.admin.service.AdminEventsService;
11 | import ru.practicum.ewm.exception.CategoryNotFoundException;
12 | import ru.practicum.ewm.exception.EventClosedException;
13 | import ru.practicum.ewm.exception.EventNotFoundException;
14 | import ru.practicum.ewm.exception.UserNotFoundException;
15 |
16 | import javax.validation.Valid;
17 | import javax.validation.constraints.Positive;
18 | import javax.validation.constraints.PositiveOrZero;
19 | import java.util.List;
20 |
21 | @RestController
22 | @RequestMapping("/admin/events")
23 | @RequiredArgsConstructor
24 | @Validated
25 | @Slf4j
26 | public class AdminEventsController {
27 | private final AdminEventsService adminEventsService;
28 |
29 | @GetMapping
30 | public List findAllEvents(
31 | @RequestParam(value = "users", defaultValue = "") Long[] users,
32 | @RequestParam(value = "states", required = false) String[] states,
33 | @RequestParam(value = "categories", required = false) Long[] categories,
34 | @RequestParam(name = "rangeStart", required = false) String rangeStart,
35 | @RequestParam(name = "rangeEnd", required = false) String rangeEnd,
36 | @PositiveOrZero
37 | @RequestParam(name = "from", defaultValue = "0") Integer from,
38 | @Positive
39 | @RequestParam(name = "size", defaultValue = Constants.PAGE_SIZE_STRING) Integer size)
40 | throws UserNotFoundException, CategoryNotFoundException {
41 | log.info("Admin findAllEvents: {},{},{},{},{},{},{}",
42 | users, states, categories, rangeStart, rangeEnd, from, size);
43 | return adminEventsService.findAllEvents(users, states, categories, rangeStart, rangeEnd, from, size);
44 | }
45 |
46 | @PatchMapping("{eventId}/publish")
47 | public EventOutDto publishEvent(@Positive @PathVariable Long eventId)
48 | throws EventNotFoundException, EventClosedException {
49 | log.info("Admin publishEvent: {}", eventId);
50 | return adminEventsService.publishEvent(eventId);
51 | }
52 |
53 | @PatchMapping("{eventId}/reject")
54 | public EventOutDto rejectEvent(@Positive @PathVariable Long eventId)
55 | throws EventNotFoundException, EventClosedException {
56 | log.info("Admin Patch rejectEvent: {}", eventId);
57 | return adminEventsService.rejectEvent(eventId);
58 | }
59 |
60 | @PutMapping("{eventId}")
61 | public EventOutDto updateEvent(@Positive @PathVariable Long eventId,
62 | @Valid @RequestBody EventInDto eventInDto)
63 | throws EventNotFoundException, CategoryNotFoundException {
64 | log.info("Admin Put updateEvent: {},{}", eventId, eventInDto);
65 | return adminEventsService.updateEvent(eventId, eventInDto);
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/main/src/main/java/ru/practicum/ewm/endpoints/admin/AdminStatsController.java:
--------------------------------------------------------------------------------
1 | package ru.practicum.ewm.endpoints.admin;
2 |
3 | import lombok.RequiredArgsConstructor;
4 | import lombok.extern.slf4j.Slf4j;
5 | import org.springframework.http.ResponseEntity;
6 | import org.springframework.validation.annotation.Validated;
7 | import org.springframework.web.bind.annotation.GetMapping;
8 | import org.springframework.web.bind.annotation.RequestParam;
9 | import org.springframework.web.bind.annotation.RestController;
10 | import ru.practicum.ewm.utils.AdminStatsClient;
11 |
12 | import javax.validation.Valid;
13 | import javax.validation.constraints.NotNull;
14 | import java.util.List;
15 |
16 | @RestController
17 | @RequiredArgsConstructor
18 | @Validated
19 | @Slf4j
20 | public class AdminStatsController {
21 | private final AdminStatsClient adminStatsClient;
22 |
23 | @GetMapping("/admin/stats")
24 | public ResponseEntity