├── .github
└── workflows
│ ├── api-tests.yml
│ └── wait-for-it.sh
├── .gitignore
├── ER-diagram_EWM-SERVER.png
├── ER-diagram_EWM-STATS.png
├── README.md
├── checkstyle.xml
├── db
├── server.mv.db
├── server.trace.db
├── stats.mv.db
└── stats.trace.db
├── docker-compose.yml
├── ewm-main-service-spec.json
├── ewm-stats-service-spec.json
├── lombok.config
├── pom.xml
├── server
├── Dockerfile
├── pom.xml
└── src
│ ├── main
│ ├── java
│ │ └── ru
│ │ │ └── practicum
│ │ │ └── explorewithme
│ │ │ ├── ServerApp.java
│ │ │ ├── client
│ │ │ ├── BaseClient.java
│ │ │ ├── EndpointHit.java
│ │ │ └── StatsClient.java
│ │ │ ├── controller
│ │ │ ├── admin
│ │ │ │ ├── CategoryAdminController.java
│ │ │ │ ├── CommentAdminController.java
│ │ │ │ ├── CompilationAdminController.java
│ │ │ │ ├── EventAdminController.java
│ │ │ │ └── UserAdminController.java
│ │ │ ├── priv
│ │ │ │ ├── CommentPrivateController.java
│ │ │ │ ├── EventPrivateController.java
│ │ │ │ └── RequestPrivateController.java
│ │ │ └── pub
│ │ │ │ ├── CategoriesPublicController.java
│ │ │ │ ├── CommentPublicController.java
│ │ │ │ ├── CompilationPublicController.java
│ │ │ │ └── EventPublicController.java
│ │ │ ├── dto
│ │ │ ├── category
│ │ │ │ ├── CategoryCreateDto.java
│ │ │ │ └── CategoryDto.java
│ │ │ ├── comment
│ │ │ │ ├── CommentCreateDto.java
│ │ │ │ ├── CommentDto.java
│ │ │ │ └── CommentUpdateDto.java
│ │ │ ├── compilation
│ │ │ │ ├── CompilationCreateDto.java
│ │ │ │ └── CompilationDto.java
│ │ │ ├── event
│ │ │ │ ├── EventAdminUpdate.java
│ │ │ │ ├── EventCreateDto.java
│ │ │ │ ├── EventFullDto.java
│ │ │ │ ├── EventShortDto.java
│ │ │ │ ├── EventUpdateDto.java
│ │ │ │ └── LocationDto.java
│ │ │ ├── request
│ │ │ │ ├── RequestDto.java
│ │ │ │ └── RequestStatus.java
│ │ │ └── user
│ │ │ │ ├── UserCreateDto.java
│ │ │ │ ├── UserDto.java
│ │ │ │ └── UserShortDto.java
│ │ │ ├── exception
│ │ │ ├── ApiError.java
│ │ │ ├── ErrorHandler.java
│ │ │ ├── EventSortException.java
│ │ │ ├── EventStateException.java
│ │ │ ├── ForbiddenException.java
│ │ │ └── NotFoundException.java
│ │ │ ├── mapper
│ │ │ ├── CategoryMapper.java
│ │ │ ├── CommentMapper.java
│ │ │ ├── CompilationMapper.java
│ │ │ ├── EventMapper.java
│ │ │ ├── LocationMapper.java
│ │ │ ├── RequestMapper.java
│ │ │ └── UserMapper.java
│ │ │ ├── model
│ │ │ ├── category
│ │ │ │ └── Category.java
│ │ │ ├── comment
│ │ │ │ └── Comment.java
│ │ │ ├── compilation
│ │ │ │ └── Compilation.java
│ │ │ ├── event
│ │ │ │ ├── Event.java
│ │ │ │ ├── EventSort.java
│ │ │ │ ├── EventState.java
│ │ │ │ └── Location.java
│ │ │ ├── request
│ │ │ │ └── Request.java
│ │ │ └── user
│ │ │ │ └── User.java
│ │ │ ├── repository
│ │ │ ├── CategoryRepository.java
│ │ │ ├── CommentRepository.java
│ │ │ ├── CompilationRepository.java
│ │ │ ├── EventRepository.java
│ │ │ ├── RequestRepository.java
│ │ │ └── UserRepository.java
│ │ │ └── service
│ │ │ ├── admin
│ │ │ ├── CategoryAdminService.java
│ │ │ ├── CommentAdminService.java
│ │ │ ├── CompilationAdminService.java
│ │ │ ├── EventAdminService.java
│ │ │ ├── UserAdminService.java
│ │ │ └── impl
│ │ │ │ ├── CategoryAdminServiceImpl.java
│ │ │ │ ├── CommentAdminServiceImpl.java
│ │ │ │ ├── CompilationAdminServiceImpl.java
│ │ │ │ ├── EventAdminServiceImpl.java
│ │ │ │ └── UserAdminServiceImpl.java
│ │ │ ├── priv
│ │ │ ├── CommentPrivateService.java
│ │ │ ├── EventPrivateService.java
│ │ │ ├── RequestPrivateService.java
│ │ │ └── impl
│ │ │ │ ├── CommentPrivateServiceImpl.java
│ │ │ │ ├── EventPrivateServiceImpl.java
│ │ │ │ └── RequestPrivateServiceImpl.java
│ │ │ └── pub
│ │ │ ├── CategoriesPublicService.java
│ │ │ ├── CommentPublicService.java
│ │ │ ├── CompilationPublicService.java
│ │ │ ├── EventPublicService.java
│ │ │ └── impl
│ │ │ ├── CategoriesPublicServiceImpl.java
│ │ │ ├── CommentPublicServiceImpl.java
│ │ │ ├── CompilationPublicServiceImpl.java
│ │ │ └── EventPublicServiceImpl.java
│ └── resources
│ │ ├── application.properties
│ │ └── schema.sql
│ └── test
│ └── java
│ └── ru
│ └── practicum
│ └── explorewithme
│ └── comment
│ ├── CommentAdminServiceTest.java
│ ├── CommentPrivateServiceTest.java
│ └── CommentPublicServiceTest.java
└── stats
├── Dockerfile
├── pom.xml
└── src
└── main
├── java
└── ru
│ └── practicum
│ └── explorewithme
│ ├── StatsApp.java
│ ├── controller
│ └── StatsController.java
│ ├── dto
│ ├── EndpointHitDto.java
│ └── ViewStats.java
│ ├── exception
│ ├── ApiError.java
│ └── ErrorHandler.java
│ ├── mapper
│ └── StatsMapper.java
│ ├── model
│ └── EndpointHit.java
│ ├── repository
│ └── StatsRepository.java
│ └── service
│ ├── StatsService.java
│ └── StatsServiceImpl.java
└── resources
├── application.properties
└── schema.sql
/.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 | ### DB ###
8 | *.db
9 |
10 | ### STS ###
11 | .apt_generated
12 | .classpath
13 | .factorypath
14 | .project
15 | .settings
16 | .springBeans
17 | .sts4-cache
18 |
19 | ### IntelliJ IDEA ###
20 | .idea
21 | *.iws
22 | *.iml
23 | *.ipr
24 |
25 | ### NetBeans ###
26 | /nbproject/private/
27 | /nbbuild/
28 | /dist/
29 | /nbdist/
30 | /.nb-gradle/
31 | build/
32 | !**/src/main/**/build/
33 | !**/src/test/**/build/
34 |
35 | ### VS Code ###
36 | .vscode/
37 |
--------------------------------------------------------------------------------
/ER-diagram_EWM-SERVER.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Katibat/java-explore-with-me/5d7058ac5d9f135f7bbdb96e7f65d56635417c18/ER-diagram_EWM-SERVER.png
--------------------------------------------------------------------------------
/ER-diagram_EWM-STATS.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Katibat/java-explore-with-me/5d7058ac5d9f135f7bbdb96e7f65d56635417c18/ER-diagram_EWM-STATS.png
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ## The project Explore-With-Me (programming language - Java):
2 | The application project is a poster where you can offer any event from an exhibition to going
3 | to the cinema and recruit a company to participate in it.
4 | Users can offer their events for publication in the service, as well as send applications for participation in
5 | other published events, confirm or reject other people's applications for participation in user's events.
6 | The service administrator makes decisions about publishing events and pinning collections of events
7 | on the main page of the service.
8 | Each user (including unauthorized ones) can receive information about published events. As a result,
9 | the service administrator collect statistics of event views by category.
10 |
11 | ## PR request link:
12 | https://github.com/Katibat/java-explore-with-me/pull/1#issue-1402033542
13 |
14 | ## Project structure:
15 | - Main service - [Swagger file](https://github.com/Katibat/java-explore-with-me/blob/main/ewm-main-service-spec.json)
16 | - Data Base main service - [ER-diagram](./ER_diagram_EWM-SERVER.png)
17 | - Stats service - [Swagger file](https://github.com/Katibat/java-explore-with-me/blob/main/ewm-stats-service-spec.json)
18 | - Data Base stats service - [ER-diagram](./ER_diagram_EWM-STATS.png)
19 |
20 | ## Technology used:
21 | Amazon Corretto 11.0.14, Spring-Boot 2.7.2, Spring-Web 5.3.22, Lombok 1.18.24,
22 | Postgresql 14, Driver PSQL 42.5.0, Driver H2 2.1.214, Docker-compose 3.8,
23 | GSON 2.9.0, HttpClient 5.0, Hibernate 6.2.3
24 |
25 | ## Project start should using Docker Dekstop:
26 | with script
27 | - for Window:
28 | %~dp0mvnw.cmd clean package -DskipTests
29 | docker-compose up --build
30 | - for Linux / MacOS:
31 | ./mvnw clean package -DskipTests
32 | docker-compose up --build
--------------------------------------------------------------------------------
/db/server.mv.db:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Katibat/java-explore-with-me/5d7058ac5d9f135f7bbdb96e7f65d56635417c18/db/server.mv.db
--------------------------------------------------------------------------------
/db/server.trace.db:
--------------------------------------------------------------------------------
1 | 2022-10-10 12:14:32 jdbc[3]: exception
2 | java.sql.SQLClientInfoException: Client info name 'ApplicationName' not supported.
3 | at org.h2.jdbc.JdbcConnection.setClientInfo(JdbcConnection.java:1749)
4 | at com.intellij.database.remote.jdbc.impl.RemoteConnectionImpl.setClientInfo(RemoteConnectionImpl.java:470)
5 | at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
6 | at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
7 | at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
8 | at java.base/java.lang.reflect.Method.invoke(Method.java:566)
9 | at java.rmi/sun.rmi.server.UnicastServerRef.dispatch(UnicastServerRef.java:359)
10 | at java.rmi/sun.rmi.transport.Transport$1.run(Transport.java:200)
11 | at java.rmi/sun.rmi.transport.Transport$1.run(Transport.java:197)
12 | at java.base/java.security.AccessController.doPrivileged(Native Method)
13 | at java.rmi/sun.rmi.transport.Transport.serviceCall(Transport.java:196)
14 | at java.rmi/sun.rmi.transport.tcp.TCPTransport.handleMessages(TCPTransport.java:562)
15 | at java.rmi/sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(TCPTransport.java:796)
16 | at java.rmi/sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.lambda$run$0(TCPTransport.java:677)
17 | at java.base/java.security.AccessController.doPrivileged(Native Method)
18 | at java.rmi/sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(TCPTransport.java:676)
19 | at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
20 | at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
21 | at java.base/java.lang.Thread.run(Thread.java:829)
22 | 2022-10-10 12:14:44 jdbc[3]: exception
23 | java.sql.SQLClientInfoException: Client info name 'ApplicationName' not supported.
24 | at org.h2.jdbc.JdbcConnection.setClientInfo(JdbcConnection.java:1749)
25 | at com.intellij.database.remote.jdbc.impl.RemoteConnectionImpl.setClientInfo(RemoteConnectionImpl.java:470)
26 | at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
27 | at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
28 | at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
29 | at java.base/java.lang.reflect.Method.invoke(Method.java:566)
30 | at java.rmi/sun.rmi.server.UnicastServerRef.dispatch(UnicastServerRef.java:359)
31 | at java.rmi/sun.rmi.transport.Transport$1.run(Transport.java:200)
32 | at java.rmi/sun.rmi.transport.Transport$1.run(Transport.java:197)
33 | at java.base/java.security.AccessController.doPrivileged(Native Method)
34 | at java.rmi/sun.rmi.transport.Transport.serviceCall(Transport.java:196)
35 | at java.rmi/sun.rmi.transport.tcp.TCPTransport.handleMessages(TCPTransport.java:562)
36 | at java.rmi/sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(TCPTransport.java:796)
37 | at java.rmi/sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.lambda$run$0(TCPTransport.java:677)
38 | at java.base/java.security.AccessController.doPrivileged(Native Method)
39 | at java.rmi/sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(TCPTransport.java:676)
40 | at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
41 | at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
42 | at java.base/java.lang.Thread.run(Thread.java:829)
43 |
--------------------------------------------------------------------------------
/db/stats.mv.db:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Katibat/java-explore-with-me/5d7058ac5d9f135f7bbdb96e7f65d56635417c18/db/stats.mv.db
--------------------------------------------------------------------------------
/db/stats.trace.db:
--------------------------------------------------------------------------------
1 | 2022-10-10 12:12:12 jdbc[3]: exception
2 | java.sql.SQLClientInfoException: Client info name 'ApplicationName' not supported.
3 | at org.h2.jdbc.JdbcConnection.setClientInfo(JdbcConnection.java:1749)
4 | at com.intellij.database.remote.jdbc.impl.RemoteConnectionImpl.setClientInfo(RemoteConnectionImpl.java:470)
5 | at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
6 | at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
7 | at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
8 | at java.base/java.lang.reflect.Method.invoke(Method.java:566)
9 | at java.rmi/sun.rmi.server.UnicastServerRef.dispatch(UnicastServerRef.java:359)
10 | at java.rmi/sun.rmi.transport.Transport$1.run(Transport.java:200)
11 | at java.rmi/sun.rmi.transport.Transport$1.run(Transport.java:197)
12 | at java.base/java.security.AccessController.doPrivileged(Native Method)
13 | at java.rmi/sun.rmi.transport.Transport.serviceCall(Transport.java:196)
14 | at java.rmi/sun.rmi.transport.tcp.TCPTransport.handleMessages(TCPTransport.java:562)
15 | at java.rmi/sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(TCPTransport.java:796)
16 | at java.rmi/sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.lambda$run$0(TCPTransport.java:677)
17 | at java.base/java.security.AccessController.doPrivileged(Native Method)
18 | at java.rmi/sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(TCPTransport.java:676)
19 | at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
20 | at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
21 | at java.base/java.lang.Thread.run(Thread.java:829)
22 | 2022-10-10 12:12:24 jdbc[3]: exception
23 | java.sql.SQLClientInfoException: Client info name 'ApplicationName' not supported.
24 | at org.h2.jdbc.JdbcConnection.setClientInfo(JdbcConnection.java:1749)
25 | at com.intellij.database.remote.jdbc.impl.RemoteConnectionImpl.setClientInfo(RemoteConnectionImpl.java:470)
26 | at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
27 | at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
28 | at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
29 | at java.base/java.lang.reflect.Method.invoke(Method.java:566)
30 | at java.rmi/sun.rmi.server.UnicastServerRef.dispatch(UnicastServerRef.java:359)
31 | at java.rmi/sun.rmi.transport.Transport$1.run(Transport.java:200)
32 | at java.rmi/sun.rmi.transport.Transport$1.run(Transport.java:197)
33 | at java.base/java.security.AccessController.doPrivileged(Native Method)
34 | at java.rmi/sun.rmi.transport.Transport.serviceCall(Transport.java:196)
35 | at java.rmi/sun.rmi.transport.tcp.TCPTransport.handleMessages(TCPTransport.java:562)
36 | at java.rmi/sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(TCPTransport.java:796)
37 | at java.rmi/sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.lambda$run$0(TCPTransport.java:677)
38 | at java.base/java.security.AccessController.doPrivileged(Native Method)
39 | at java.rmi/sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(TCPTransport.java:676)
40 | at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
41 | at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
42 | at java.base/java.lang.Thread.run(Thread.java:829)
43 |
--------------------------------------------------------------------------------
/docker-compose.yml:
--------------------------------------------------------------------------------
1 | version: '3.8'
2 | services:
3 |
4 | stats-server:
5 | build: ./stats
6 | container_name: stats
7 | ports:
8 | - "9090:9090"
9 | depends_on:
10 | - stats-db
11 | environment:
12 | - SPRING_DATASOURCE_URL=jdbc:postgresql://stats-db:5432/stats
13 | - POSTGRES_USER=Kate
14 | - POSTGRES_PASSWORD=purrrrrr
15 |
16 | stats-db:
17 | image: postgres:14
18 | container_name: stats-db
19 | ports:
20 | - "5432:5432"
21 | environment:
22 | - POSTGRES_DB=stats
23 | - POSTGRES_USER=Kate
24 | - POSTGRES_PASSWORD=purrrrrr
25 |
26 | ewm-service:
27 | build: ./server
28 | container_name: ewm-service
29 | ports:
30 | - "8080:8080"
31 | depends_on:
32 | - ewm-db
33 | environment:
34 | - STATS_SERVER_URL=http://stats-server:9090
35 | - SPRING_DATASOURCE_URL=jdbc:postgresql://ewm-db:5432/server
36 | - POSTGRES_USER=Kate
37 | - POSTGRES_PASSWORD=purrrrrr
38 |
39 | ewm-db:
40 | image: postgres:14
41 | container_name: ewm-service-db
42 | ports:
43 | - "5433:5432"
44 | environment:
45 | - POSTGRES_DB=server
46 | - POSTGRES_USER=Kate
47 | - POSTGRES_PASSWORD=purrrrrr
--------------------------------------------------------------------------------
/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
--------------------------------------------------------------------------------
/server/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM amazoncorretto:11
2 | COPY target/*.jar app.jar
3 | ENTRYPOINT ["java","-jar","/app.jar"]
--------------------------------------------------------------------------------
/server/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 | explore-with-me
7 | ru.practicum
8 | 0.0.1-SNAPSHOT
9 |
10 | 4.0.0
11 |
12 | server
13 |
14 |
15 | 11
16 | 11
17 | UTF-8
18 |
19 |
20 |
21 |
22 | org.springframework.boot
23 | spring-boot-starter-web
24 |
25 |
26 | org.springframework.boot
27 | spring-boot-starter-data-jpa
28 |
29 |
30 | org.springframework.boot
31 | spring-boot-starter-validation
32 |
33 |
34 | org.springframework.boot
35 | spring-boot-starter-actuator
36 |
37 |
38 | org.springframework.boot
39 | spring-boot-configuration-processor
40 | true
41 |
42 |
43 | org.postgresql
44 | postgresql
45 |
46 |
47 | com.h2database
48 | h2
49 |
50 |
51 | org.projectlombok
52 | lombok
53 |
54 |
55 | org.modelmapper
56 | modelmapper
57 |
58 |
59 | org.springframework.boot
60 | spring-boot-starter-test
61 | test
62 |
63 |
64 | junit
65 | junit
66 | test
67 |
68 |
69 |
70 |
71 |
72 |
73 | org.springframework.boot
74 | spring-boot-maven-plugin
75 |
76 |
77 |
78 |
--------------------------------------------------------------------------------
/server/src/main/java/ru/practicum/explorewithme/ServerApp.java:
--------------------------------------------------------------------------------
1 | package ru.practicum.explorewithme;
2 |
3 | import org.springframework.boot.SpringApplication;
4 | import org.springframework.boot.autoconfigure.SpringBootApplication;
5 |
6 | @SpringBootApplication
7 |
8 | public class ServerApp {
9 |
10 | public static void main(String[] args) {
11 | SpringApplication.run(ServerApp.class, args);
12 | }
13 | }
--------------------------------------------------------------------------------
/server/src/main/java/ru/practicum/explorewithme/client/BaseClient.java:
--------------------------------------------------------------------------------
1 | package ru.practicum.explorewithme.client;
2 |
3 | import lombok.RequiredArgsConstructor;
4 | import org.springframework.http.*;
5 | import org.springframework.lang.Nullable;
6 | import org.springframework.web.client.*;
7 |
8 | @RequiredArgsConstructor
9 | public class BaseClient {
10 | protected final RestTemplate rest;
11 |
12 | protected ResponseEntity