From c90ca8c4133da3262cfec7c1935e380f66255ce4 Mon Sep 17 00:00:00 2001 From: NadezhdaTA Date: Thu, 7 Aug 2025 16:34:42 +0400 Subject: [PATCH 01/35] =?UTF-8?q?=D0=9D=D0=B0=D1=81=D1=82=D1=80=D0=BE?= =?UTF-8?q?=D0=B9=D0=BA=D0=B8=20docker=20=D0=B8=20pom.xml?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docker-compose.yml | 50 +++++- evm-service/Dockerfile | 5 + evm-service/pom.xml | 157 +++++++++++++++++ .../main/java/ru/practicum/EvmServiceApp.java | 11 ++ .../src/main/resources/application.yml | 27 +++ evm-service/src/main/resources/schema.sql | 5 + pom.xml | 7 +- stat/Dockerfile | 5 + stat/pom.xml | 62 +++++++ stat/src/main/java/ru/practicum/StatApp.java | 11 ++ stat/stat-client/Dockerfile | 5 + stat/stat-client/pom.xml | 29 ++++ .../main/java/ru/practicum/StatClientApp.java | 10 ++ stat/stat-dto/Dockerfile | 5 + stat/stat-dto/pom.xml | 20 +++ .../main/java/ru/practicum/StatDtoApp.java | 11 ++ stat/stat-server/Dockerfile | 5 + stat/stat-server/pom.xml | 164 ++++++++++++++++++ .../main/java/ru/practicum/StatServerApp.java | 11 ++ .../src/main/resources/application.yml | 26 +++ .../stat-server/src/main/resources/schema.sql | 5 + 21 files changed, 628 insertions(+), 3 deletions(-) create mode 100644 evm-service/Dockerfile create mode 100644 evm-service/pom.xml create mode 100644 evm-service/src/main/java/ru/practicum/EvmServiceApp.java create mode 100644 evm-service/src/main/resources/application.yml create mode 100644 evm-service/src/main/resources/schema.sql create mode 100644 stat/Dockerfile create mode 100644 stat/pom.xml create mode 100644 stat/src/main/java/ru/practicum/StatApp.java create mode 100644 stat/stat-client/Dockerfile create mode 100644 stat/stat-client/pom.xml create mode 100644 stat/stat-client/src/main/java/ru/practicum/StatClientApp.java create mode 100644 stat/stat-dto/Dockerfile create mode 100644 stat/stat-dto/pom.xml create mode 100644 stat/stat-dto/src/main/java/ru/practicum/StatDtoApp.java create mode 100644 stat/stat-server/Dockerfile create mode 100644 stat/stat-server/pom.xml create mode 100644 stat/stat-server/src/main/java/ru/practicum/StatServerApp.java create mode 100644 stat/stat-server/src/main/resources/application.yml create mode 100644 stat/stat-server/src/main/resources/schema.sql diff --git a/docker-compose.yml b/docker-compose.yml index be96142..362289a 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,14 +1,60 @@ +name: explore-with-me + services: - stats-server: + + stat-server: + build: + context: ./stat/stat-server + image: explore-with-me-stats + container_name: explore-with-me-stats ports: - "9090:9090" + environment: + - SPRING_DATASOURCE_URL=jdbc:postgresql://stats-db:5432/stat-server + - SPRING_DATASOURCE_USERNAME=user + - SPRING_DATASOURCE_PASSWORD=12345 + depends_on: + - stat-db - stats-db: + stat-db: image: postgres:16.1 + container_name: postgres-stat + ports: + - "6542:5432" + environment: + - POSTGRES_PASSWORD:12345 + - POSTGRES_USER:user + - POSTGRES_DB:stats-server + healthcheck: + test: pg_isready -q -d $$POSTGRES_DB -U $$POSTGRES_USER + interval: 5s + timeout: 5s + retries: 10 ewm-service: + build: evm-service + image: explore-with-me-service + container_name: explore-with-me-service ports: - "8080:8080" + environment: + - SPRING_DATASOURCE_URL=jdbc:postgresql://ewm-db:5433/ewm-service + - SPRING_DATASOURCE_USERNAME=user + - SPRING_DATASOURCE_PASSWORD=12345 + depends_on: + - ewm-db ewm-db: image: postgres:16.1 + container_name: postgres-service + ports: + - "6541:5432" + environment: + - POSTGRES_PASSWORD=12345 + - POSTGRES_USER=user + - POSTGRES_DB=ewm-service + healthcheck: + test: pg_isready -q -d $$POSTGRES_DB -U $$POSTGRES_USER + interval: 5s + timeout: 5s + retries: 10 diff --git a/evm-service/Dockerfile b/evm-service/Dockerfile new file mode 100644 index 0000000..0ff1817 --- /dev/null +++ b/evm-service/Dockerfile @@ -0,0 +1,5 @@ +FROM eclipse-temurin:21-jre-jammy +VOLUME /tmp +ARG JAR_FILE=target/*.jar +COPY ${JAR_FILE} app.jar +ENTRYPOINT ["sh", "-c", "java ${JAVA_OPTS} -jar /app.jar"] \ No newline at end of file diff --git a/evm-service/pom.xml b/evm-service/pom.xml new file mode 100644 index 0000000..e5792a2 --- /dev/null +++ b/evm-service/pom.xml @@ -0,0 +1,157 @@ + + + 4.0.0 + + ru.practicum + explore-with-me + 0.0.1-SNAPSHOT + + + evm-service + + + 21 + 1.6.3 + 0.2.0 + UTF-8 + + + + + ru.practicum + stat-dto + 0.0.1-SNAPSHOT + compile + + + org.springframework.boot + spring-boot-starter-data-jpa + + + + org.springframework.boot + spring-boot-starter-web + + + + org.springframework.boot + spring-boot-starter-actuator + + + + org.postgresql + postgresql + runtime + + + + com.h2database + h2 + runtime + + + + org.springframework.boot + spring-boot-configuration-processor + true + + + + org.projectlombok + lombok + true + + + + org.springframework.boot + spring-boot-starter-test + test + + + org.mapstruct + mapstruct + 1.6.3 + + + org.projectlombok + lombok-mapstruct-binding + ${lombok-mapstruct-binding.version} + + + com.fasterxml.jackson.datatype + jackson-datatype-jsr310 + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + org.projectlombok + lombok + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.8.1 + + 1.8 + 1.8 + + + org.projectlombok + lombok + ${lombok.version} + + + org.mapstruct + mapstruct-processor + ${org.mapstruct.version} + + + org.projectlombok + lombok-mapstruct-binding + ${lombok-mapstruct-binding.version} + + + true + + + -Amapstruct.suppressGeneratorTimestamp=true + + + -Amapstruct.suppressGeneratorVersionInfoComment=true + + + -Amapstruct.verbose=true + + + + + + + + + + coverage + + + + org.jacoco + jacoco-maven-plugin + + + + + + + \ No newline at end of file diff --git a/evm-service/src/main/java/ru/practicum/EvmServiceApp.java b/evm-service/src/main/java/ru/practicum/EvmServiceApp.java new file mode 100644 index 0000000..78f5ae5 --- /dev/null +++ b/evm-service/src/main/java/ru/practicum/EvmServiceApp.java @@ -0,0 +1,11 @@ +package ru.practicum; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class EvmServiceApp { + public static void main(String[] args) { + SpringApplication.run(EvmServiceApp.class, args); + } +} \ No newline at end of file diff --git a/evm-service/src/main/resources/application.yml b/evm-service/src/main/resources/application.yml new file mode 100644 index 0000000..5791015 --- /dev/null +++ b/evm-service/src/main/resources/application.yml @@ -0,0 +1,27 @@ +server: + port: 8080 + +stat-server: + url: http://localhost:9090 + +spring: + jpa: + hibernate.ddl-auto: none + properties.hibernate.format_sql: true + + sql: + init: + mode: always + datasource: + driverClassName: org.postgresql.Driver + url: jdbc:postgresql://localhost:5432/ewm-service + username: user + password: 12345 +logging: + level: + org: + springframework: + orm.jpa: INFO + transaction: INFO + interceptor: TRACE + JpaTransactionManager: DEBUG \ No newline at end of file diff --git a/evm-service/src/main/resources/schema.sql b/evm-service/src/main/resources/schema.sql new file mode 100644 index 0000000..9f67fba --- /dev/null +++ b/evm-service/src/main/resources/schema.sql @@ -0,0 +1,5 @@ +CREATE TABLE IF NOT EXISTS users ( + user_id BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, + user_name CHARACTER VARYING(255) NOT NULL, + user_email CHARACTER VARYING(500) NOT NULL UNIQUE +); \ No newline at end of file diff --git a/pom.xml b/pom.xml index b15acb2..7137ae7 100644 --- a/pom.xml +++ b/pom.xml @@ -12,7 +12,12 @@ Explore With Me - ru.practicum + + evm-service + stat + + + ru.practicum explore-with-me 0.0.1-SNAPSHOT pom diff --git a/stat/Dockerfile b/stat/Dockerfile new file mode 100644 index 0000000..0ff1817 --- /dev/null +++ b/stat/Dockerfile @@ -0,0 +1,5 @@ +FROM eclipse-temurin:21-jre-jammy +VOLUME /tmp +ARG JAR_FILE=target/*.jar +COPY ${JAR_FILE} app.jar +ENTRYPOINT ["sh", "-c", "java ${JAVA_OPTS} -jar /app.jar"] \ No newline at end of file diff --git a/stat/pom.xml b/stat/pom.xml new file mode 100644 index 0000000..d3bf692 --- /dev/null +++ b/stat/pom.xml @@ -0,0 +1,62 @@ + + + 4.0.0 + + ru.practicum + explore-with-me + 0.0.1-SNAPSHOT + + + stat + pom + + stat-client + stat-dto + stat-server + + + + 21 + 1.6.3 + 0.2.0 + UTF-8 + + + + + org.springframework.boot + spring-boot-starter-web + + + + org.springframework.boot + spring-boot-starter-actuator + + + + org.springframework.boot + spring-boot-configuration-processor + true + + + + org.projectlombok + lombok + true + + + + org.springframework.boot + spring-boot-starter-test + test + + + com.fasterxml.jackson.datatype + jackson-datatype-jsr310 + + + + + \ No newline at end of file diff --git a/stat/src/main/java/ru/practicum/StatApp.java b/stat/src/main/java/ru/practicum/StatApp.java new file mode 100644 index 0000000..098d27b --- /dev/null +++ b/stat/src/main/java/ru/practicum/StatApp.java @@ -0,0 +1,11 @@ +package ru.practicum; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + + +public class StatApp { + public static void main(String[] args) { + + } +} \ No newline at end of file diff --git a/stat/stat-client/Dockerfile b/stat/stat-client/Dockerfile new file mode 100644 index 0000000..0ff1817 --- /dev/null +++ b/stat/stat-client/Dockerfile @@ -0,0 +1,5 @@ +FROM eclipse-temurin:21-jre-jammy +VOLUME /tmp +ARG JAR_FILE=target/*.jar +COPY ${JAR_FILE} app.jar +ENTRYPOINT ["sh", "-c", "java ${JAVA_OPTS} -jar /app.jar"] \ No newline at end of file diff --git a/stat/stat-client/pom.xml b/stat/stat-client/pom.xml new file mode 100644 index 0000000..a5fc936 --- /dev/null +++ b/stat/stat-client/pom.xml @@ -0,0 +1,29 @@ + + + 4.0.0 + + ru.practicum + stat + 0.0.1-SNAPSHOT + + + stat-client + + + 23 + 23 + UTF-8 + + + + + ru.practicum + stat-dto + 0.0.1-SNAPSHOT + compile + + + + \ No newline at end of file diff --git a/stat/stat-client/src/main/java/ru/practicum/StatClientApp.java b/stat/stat-client/src/main/java/ru/practicum/StatClientApp.java new file mode 100644 index 0000000..ebdbd02 --- /dev/null +++ b/stat/stat-client/src/main/java/ru/practicum/StatClientApp.java @@ -0,0 +1,10 @@ +package ru.practicum; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +public class StatClientApp { + public static void main(String[] args) { + + } +} \ No newline at end of file diff --git a/stat/stat-dto/Dockerfile b/stat/stat-dto/Dockerfile new file mode 100644 index 0000000..0ff1817 --- /dev/null +++ b/stat/stat-dto/Dockerfile @@ -0,0 +1,5 @@ +FROM eclipse-temurin:21-jre-jammy +VOLUME /tmp +ARG JAR_FILE=target/*.jar +COPY ${JAR_FILE} app.jar +ENTRYPOINT ["sh", "-c", "java ${JAVA_OPTS} -jar /app.jar"] \ No newline at end of file diff --git a/stat/stat-dto/pom.xml b/stat/stat-dto/pom.xml new file mode 100644 index 0000000..605b6a0 --- /dev/null +++ b/stat/stat-dto/pom.xml @@ -0,0 +1,20 @@ + + + 4.0.0 + + ru.practicum + stat + 0.0.1-SNAPSHOT + + + stat-dto + + + 23 + 23 + UTF-8 + + + \ No newline at end of file diff --git a/stat/stat-dto/src/main/java/ru/practicum/StatDtoApp.java b/stat/stat-dto/src/main/java/ru/practicum/StatDtoApp.java new file mode 100644 index 0000000..4f66dde --- /dev/null +++ b/stat/stat-dto/src/main/java/ru/practicum/StatDtoApp.java @@ -0,0 +1,11 @@ +package ru.practicum; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + + +public class StatDtoApp { + public static void main(String[] args) { + + } +} \ No newline at end of file diff --git a/stat/stat-server/Dockerfile b/stat/stat-server/Dockerfile new file mode 100644 index 0000000..0ff1817 --- /dev/null +++ b/stat/stat-server/Dockerfile @@ -0,0 +1,5 @@ +FROM eclipse-temurin:21-jre-jammy +VOLUME /tmp +ARG JAR_FILE=target/*.jar +COPY ${JAR_FILE} app.jar +ENTRYPOINT ["sh", "-c", "java ${JAVA_OPTS} -jar /app.jar"] \ No newline at end of file diff --git a/stat/stat-server/pom.xml b/stat/stat-server/pom.xml new file mode 100644 index 0000000..f07dab0 --- /dev/null +++ b/stat/stat-server/pom.xml @@ -0,0 +1,164 @@ + + + 4.0.0 + + ru.practicum + stat + 0.0.1-SNAPSHOT + + + stat-server + + + 23 + 23 + UTF-8 + + + + + ru.practicum + stat-dto + 0.0.1-SNAPSHOT + compile + + + org.springframework.boot + spring-boot-starter-data-jdbc + + + org.springframework.boot + spring-boot-starter-actuator + + + org.springframework.boot + spring-boot-starter-data-jpa + + + + org.springframework.boot + spring-boot-starter-web + + + + org.springframework.boot + spring-boot-starter-actuator + + + + org.postgresql + postgresql + runtime + + + + com.h2database + h2 + runtime + + + + org.springframework.boot + spring-boot-configuration-processor + true + + + + org.projectlombok + lombok + true + + + + org.springframework.boot + spring-boot-starter-test + test + + + org.mapstruct + mapstruct + 1.6.3 + + + org.projectlombok + lombok-mapstruct-binding + ${lombok-mapstruct-binding.version} + + + com.fasterxml.jackson.datatype + jackson-datatype-jsr310 + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + org.projectlombok + lombok + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.8.1 + + 1.8 + 1.8 + + + org.projectlombok + lombok + ${lombok.version} + + + org.mapstruct + mapstruct-processor + ${org.mapstruct.version} + + + org.projectlombok + lombok-mapstruct-binding + ${lombok-mapstruct-binding.version} + + + true + + + -Amapstruct.suppressGeneratorTimestamp=true + + + -Amapstruct.suppressGeneratorVersionInfoComment=true + + + -Amapstruct.verbose=true + + + + + + + + + + coverage + + + + org.jacoco + jacoco-maven-plugin + + + + + + + \ No newline at end of file diff --git a/stat/stat-server/src/main/java/ru/practicum/StatServerApp.java b/stat/stat-server/src/main/java/ru/practicum/StatServerApp.java new file mode 100644 index 0000000..600b780 --- /dev/null +++ b/stat/stat-server/src/main/java/ru/practicum/StatServerApp.java @@ -0,0 +1,11 @@ +package ru.practicum; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class StatServerApp { + public static void main(String[] args) { + SpringApplication.run(StatServerApp.class, args); + } +} \ No newline at end of file diff --git a/stat/stat-server/src/main/resources/application.yml b/stat/stat-server/src/main/resources/application.yml new file mode 100644 index 0000000..42ee3e4 --- /dev/null +++ b/stat/stat-server/src/main/resources/application.yml @@ -0,0 +1,26 @@ +server: + port: 9090 + +spring: + main: + allow-bean-definition-overriding: true + jpa: + hibernate: + ddl-auto: none + properties: + hibernate: + dialect: org.hibernate.dialect.PostgreSQLDialect + format_sql: true + jdbc: + lob: + non_contextual_creation: true + show-sql: true + sql: + init: + mode: always + datasource: + url: jdbc:postgresql://localhost:5432/stats-server + username: user + password: 12345 + driverClassName: org.postgresql.Driver + diff --git a/stat/stat-server/src/main/resources/schema.sql b/stat/stat-server/src/main/resources/schema.sql new file mode 100644 index 0000000..9f67fba --- /dev/null +++ b/stat/stat-server/src/main/resources/schema.sql @@ -0,0 +1,5 @@ +CREATE TABLE IF NOT EXISTS users ( + user_id BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, + user_name CHARACTER VARYING(255) NOT NULL, + user_email CHARACTER VARYING(500) NOT NULL UNIQUE +); \ No newline at end of file From 5d3a86c3570e68616175a347b727194851f6ae3e Mon Sep 17 00:00:00 2001 From: NadezhdaTA Date: Thu, 7 Aug 2025 16:39:35 +0400 Subject: [PATCH 02/35] =?UTF-8?q?=D0=9D=D0=B0=D1=81=D1=82=D1=80=D0=BE?= =?UTF-8?q?=D0=B9=D0=BA=D0=B8=20docker=20=D0=B8=20pom.xml?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docker-compose.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index 362289a..12b13d3 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -10,7 +10,7 @@ services: ports: - "9090:9090" environment: - - SPRING_DATASOURCE_URL=jdbc:postgresql://stats-db:5432/stat-server + - SPRING_DATASOURCE_URL=jdbc:postgresql://stat-db:5432/stat-server - SPRING_DATASOURCE_USERNAME=user - SPRING_DATASOURCE_PASSWORD=12345 depends_on: @@ -24,7 +24,7 @@ services: environment: - POSTGRES_PASSWORD:12345 - POSTGRES_USER:user - - POSTGRES_DB:stats-server + - POSTGRES_DB:stat-server healthcheck: test: pg_isready -q -d $$POSTGRES_DB -U $$POSTGRES_USER interval: 5s From 65c5a24c61b85fab3a188fb8cf17c8c459a2601a Mon Sep 17 00:00:00 2001 From: NadezhdaTA Date: Thu, 7 Aug 2025 16:43:24 +0400 Subject: [PATCH 03/35] =?UTF-8?q?=D0=9D=D0=B0=D1=81=D1=82=D1=80=D0=BE?= =?UTF-8?q?=D0=B9=D0=BA=D0=B8=20docker=20=D0=B8=20pom.xml?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docker-compose.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index 12b13d3..cc33c3b 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -2,7 +2,7 @@ name: explore-with-me services: - stat-server: + stats-server: build: context: ./stat/stat-server image: explore-with-me-stats @@ -16,7 +16,7 @@ services: depends_on: - stat-db - stat-db: + stats-db: image: postgres:16.1 container_name: postgres-stat ports: From 742f8b93b108f7dcea1243ff9a5984bbc3727eba Mon Sep 17 00:00:00 2001 From: NadezhdaTA Date: Thu, 7 Aug 2025 16:44:38 +0400 Subject: [PATCH 04/35] =?UTF-8?q?=D0=9D=D0=B0=D1=81=D1=82=D1=80=D0=BE?= =?UTF-8?q?=D0=B9=D0=BA=D0=B8=20docker=20=D0=B8=20pom.xml?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docker-compose.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker-compose.yml b/docker-compose.yml index cc33c3b..6ba39aa 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -14,7 +14,7 @@ services: - SPRING_DATASOURCE_USERNAME=user - SPRING_DATASOURCE_PASSWORD=12345 depends_on: - - stat-db + - stats-db stats-db: image: postgres:16.1 From ca3691bc5ed97ea2e28db3c1652e271486afb75e Mon Sep 17 00:00:00 2001 From: NadezhdaTA Date: Mon, 11 Aug 2025 17:53:21 +0400 Subject: [PATCH 05/35] =?UTF-8?q?=D0=A0=D0=B5=D0=B0=D0=BB=D0=B8=D0=B7?= =?UTF-8?q?=D0=BE=D0=B2=D0=B0=D0=BD=D1=8B=20stat-server,=20stat-dto,=20sta?= =?UTF-8?q?t-client?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- stat/pom.xml | 5 +- stat/src/main/java/ru/practicum/StatApp.java | 11 --- .../main/java/ru/practicum/BaseClient.java | 74 +++++++++++++++++++ .../main/java/ru/practicum/StatClientApp.java | 10 --- .../main/java/ru/practicum/StatsClient.java | 32 ++++++++ stat/stat-dto/pom.xml | 31 ++++++++ .../java/ru/practicum/EndpointHitDTO.java | 32 ++++++++ .../main/java/ru/practicum/StatDtoApp.java | 11 --- .../java/ru/practicum/StatsRequestDTO.java | 27 +++++++ .../main/java/ru/practicum/ViewStatsDTO.java | 19 +++++ stat/stat-server/pom.xml | 44 +++-------- .../ru/practicum/controller/ErrorHandler.java | 51 +++++++++++++ .../practicum/controller/ErrorResponse.java | 13 ++++ .../controller/StatsServerController.java | 27 +++++++ .../exceptions/NotFoundException.java | 11 +++ .../exceptions/ValidationException.java | 12 +++ .../java/ru/practicum/mapper/HitsMapper.java | 12 +++ .../ru/practicum/mapper/HitsObjectMapper.java | 23 ++++++ .../ru/practicum/mapper/ViewStatsMapper.java | 13 ++++ .../mapper/ViewStatsObjectMapper.java | 19 +++++ .../java/ru/practicum/model/EndpointHit.java | 18 +++++ .../java/ru/practicum/model/ViewStats.java | 14 ++++ .../repository/StatsServerRepoInterface.java | 13 ++++ .../repository/StatsServerRepository.java | 54 ++++++++++++++ .../practicum/service/StatsServiceImpl.java | 47 ++++++++++++ .../service/StatsServiceInterface.java | 12 +++ .../stat-server/src/main/resources/schema.sql | 12 +-- 27 files changed, 573 insertions(+), 74 deletions(-) delete mode 100644 stat/src/main/java/ru/practicum/StatApp.java create mode 100644 stat/stat-client/src/main/java/ru/practicum/BaseClient.java delete mode 100644 stat/stat-client/src/main/java/ru/practicum/StatClientApp.java create mode 100644 stat/stat-client/src/main/java/ru/practicum/StatsClient.java create mode 100644 stat/stat-dto/src/main/java/ru/practicum/EndpointHitDTO.java delete mode 100644 stat/stat-dto/src/main/java/ru/practicum/StatDtoApp.java create mode 100644 stat/stat-dto/src/main/java/ru/practicum/StatsRequestDTO.java create mode 100644 stat/stat-dto/src/main/java/ru/practicum/ViewStatsDTO.java create mode 100644 stat/stat-server/src/main/java/ru/practicum/controller/ErrorHandler.java create mode 100644 stat/stat-server/src/main/java/ru/practicum/controller/ErrorResponse.java create mode 100644 stat/stat-server/src/main/java/ru/practicum/controller/StatsServerController.java create mode 100644 stat/stat-server/src/main/java/ru/practicum/exceptions/NotFoundException.java create mode 100644 stat/stat-server/src/main/java/ru/practicum/exceptions/ValidationException.java create mode 100644 stat/stat-server/src/main/java/ru/practicum/mapper/HitsMapper.java create mode 100644 stat/stat-server/src/main/java/ru/practicum/mapper/HitsObjectMapper.java create mode 100644 stat/stat-server/src/main/java/ru/practicum/mapper/ViewStatsMapper.java create mode 100644 stat/stat-server/src/main/java/ru/practicum/mapper/ViewStatsObjectMapper.java create mode 100644 stat/stat-server/src/main/java/ru/practicum/model/EndpointHit.java create mode 100644 stat/stat-server/src/main/java/ru/practicum/model/ViewStats.java create mode 100644 stat/stat-server/src/main/java/ru/practicum/repository/StatsServerRepoInterface.java create mode 100644 stat/stat-server/src/main/java/ru/practicum/repository/StatsServerRepository.java create mode 100644 stat/stat-server/src/main/java/ru/practicum/service/StatsServiceImpl.java create mode 100644 stat/stat-server/src/main/java/ru/practicum/service/StatsServiceInterface.java diff --git a/stat/pom.xml b/stat/pom.xml index d3bf692..bb46d2d 100644 --- a/stat/pom.xml +++ b/stat/pom.xml @@ -52,10 +52,7 @@ spring-boot-starter-test test - - com.fasterxml.jackson.datatype - jackson-datatype-jsr310 - + diff --git a/stat/src/main/java/ru/practicum/StatApp.java b/stat/src/main/java/ru/practicum/StatApp.java deleted file mode 100644 index 098d27b..0000000 --- a/stat/src/main/java/ru/practicum/StatApp.java +++ /dev/null @@ -1,11 +0,0 @@ -package ru.practicum; - -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; - - -public class StatApp { - public static void main(String[] args) { - - } -} \ No newline at end of file diff --git a/stat/stat-client/src/main/java/ru/practicum/BaseClient.java b/stat/stat-client/src/main/java/ru/practicum/BaseClient.java new file mode 100644 index 0000000..fe10b07 --- /dev/null +++ b/stat/stat-client/src/main/java/ru/practicum/BaseClient.java @@ -0,0 +1,74 @@ +package ru.practicum; + +import io.micrometer.common.lang.Nullable; +import org.springframework.http.*; +import org.springframework.web.client.HttpStatusCodeException; +import org.springframework.web.client.RestClient; +import org.springframework.web.util.UriComponentsBuilder; + +import java.util.List; +import java.util.Map; + +public class BaseClient { + protected final RestClient restClient; + + public BaseClient(RestClient restClient) { + this.restClient = restClient; + } + + protected ResponseEntity get(String path, Object object) { + return makeAndSendRequest(HttpMethod.GET, path, null, object); + } + + protected ResponseEntity post(String path, Object body) { + return makeAndSendRequest(HttpMethod.POST, path, null, body); + } + + private ResponseEntity makeAndSendRequest(HttpMethod method, String path, + @Nullable Map parameters, + @Nullable T body) { + try { + RestClient.RequestBodySpec requestSpec = restClient.method(method) + .uri(uriBuilder -> { + UriComponentsBuilder builder = UriComponentsBuilder.fromPath(path); + if (parameters != null) { + parameters.forEach(builder::queryParam); + } + return builder.build().toUri(); + }) + .headers(headers -> { + headers.setAll(defaultHeaders().toSingleValueMap()); + }); + + if (body != null) { + requestSpec.body(body); + } + + ResponseEntity responseEntity = requestSpec.retrieve() + .toEntity(Object.class); + + return prepareResponse(responseEntity); + } catch (HttpStatusCodeException e) { + return ResponseEntity.status(e.getStatusCode()) + .body(e.getResponseBodyAsByteArray()); + } + } + + private HttpHeaders defaultHeaders() { + HttpHeaders headers = new HttpHeaders(); + headers.setContentType(MediaType.APPLICATION_JSON); + headers.setAccept(List.of(MediaType.APPLICATION_JSON)); + return headers; + } + + private static ResponseEntity prepareResponse(ResponseEntity response) { + if (response.getStatusCode().is2xxSuccessful()) { + return response; + } + ResponseEntity.BodyBuilder responseBuilder = ResponseEntity.status(response.getStatusCode()); + if (response.hasBody()) { + return responseBuilder.body(response.getBody()); + } + return responseBuilder.build(); + } +} \ No newline at end of file diff --git a/stat/stat-client/src/main/java/ru/practicum/StatClientApp.java b/stat/stat-client/src/main/java/ru/practicum/StatClientApp.java deleted file mode 100644 index ebdbd02..0000000 --- a/stat/stat-client/src/main/java/ru/practicum/StatClientApp.java +++ /dev/null @@ -1,10 +0,0 @@ -package ru.practicum; - -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; - -public class StatClientApp { - public static void main(String[] args) { - - } -} \ No newline at end of file diff --git a/stat/stat-client/src/main/java/ru/practicum/StatsClient.java b/stat/stat-client/src/main/java/ru/practicum/StatsClient.java new file mode 100644 index 0000000..9243b5e --- /dev/null +++ b/stat/stat-client/src/main/java/ru/practicum/StatsClient.java @@ -0,0 +1,32 @@ +package ru.practicum; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.http.ResponseEntity; +import org.springframework.http.client.HttpComponentsClientHttpRequestFactory; +import org.springframework.web.client.RestClient; + +public class StatsClient extends BaseClient{ + String appName; + + public StatsClient(@Value("${stat-server.url}") String serverUrl, + @Value("${appName}") String appName) { + super(RestClient.create(serverUrl)); + this.appName = appName; + } + + private static RestClient createRestClient(String serverUrl) { + return RestClient.builder() + .baseUrl(serverUrl) + .requestFactory(new HttpComponentsClientHttpRequestFactory()) + .build(); + } + + public ResponseEntity createHit(EndpointHitDTO hitDTO) { + return post("/hits", hitDTO); + } + + public ResponseEntity viewStats(StatsRequestDTO statsRequestDTO) { + return get("/stats", statsRequestDTO); + } + +} diff --git a/stat/stat-dto/pom.xml b/stat/stat-dto/pom.xml index 605b6a0..0b6f802 100644 --- a/stat/stat-dto/pom.xml +++ b/stat/stat-dto/pom.xml @@ -17,4 +17,35 @@ UTF-8 + + + + org.springframework.boot + spring-boot-starter-validation + + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.13.0 + + 21 + 21 + + + org.projectlombok + lombok + 1.18.30 + + + + + + + + \ No newline at end of file diff --git a/stat/stat-dto/src/main/java/ru/practicum/EndpointHitDTO.java b/stat/stat-dto/src/main/java/ru/practicum/EndpointHitDTO.java new file mode 100644 index 0000000..547133c --- /dev/null +++ b/stat/stat-dto/src/main/java/ru/practicum/EndpointHitDTO.java @@ -0,0 +1,32 @@ +package ru.practicum; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.constraints.NotBlank; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.time.LocalDateTime; + +@Data +@AllArgsConstructor +@NoArgsConstructor +public class EndpointHitDTO { + + @NotBlank + @JsonProperty("app") + private String app; + + @NotBlank + @JsonProperty("uri") + private String uri; + + @NotBlank + @JsonProperty("ip") + private String ip; + + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @JsonProperty("timestamp") + private LocalDateTime timestamp; +} diff --git a/stat/stat-dto/src/main/java/ru/practicum/StatDtoApp.java b/stat/stat-dto/src/main/java/ru/practicum/StatDtoApp.java deleted file mode 100644 index 4f66dde..0000000 --- a/stat/stat-dto/src/main/java/ru/practicum/StatDtoApp.java +++ /dev/null @@ -1,11 +0,0 @@ -package ru.practicum; - -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; - - -public class StatDtoApp { - public static void main(String[] args) { - - } -} \ No newline at end of file diff --git a/stat/stat-dto/src/main/java/ru/practicum/StatsRequestDTO.java b/stat/stat-dto/src/main/java/ru/practicum/StatsRequestDTO.java new file mode 100644 index 0000000..0e58266 --- /dev/null +++ b/stat/stat-dto/src/main/java/ru/practicum/StatsRequestDTO.java @@ -0,0 +1,27 @@ +package ru.practicum; + +import jakarta.validation.constraints.NotNull; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.springframework.format.annotation.DateTimeFormat; + +import java.time.LocalDateTime; +import java.util.List; + +@Data +@NoArgsConstructor +@AllArgsConstructor +public class StatsRequestDTO { + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @NotNull(message = "Start date is required") + LocalDateTime start; + + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @NotNull(message = "End date is required") + LocalDateTime end; + + List uris; + Boolean unique; + +} diff --git a/stat/stat-dto/src/main/java/ru/practicum/ViewStatsDTO.java b/stat/stat-dto/src/main/java/ru/practicum/ViewStatsDTO.java new file mode 100644 index 0000000..3c5b787 --- /dev/null +++ b/stat/stat-dto/src/main/java/ru/practicum/ViewStatsDTO.java @@ -0,0 +1,19 @@ +package ru.practicum; + +import jakarta.validation.constraints.NotBlank; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@NoArgsConstructor +@AllArgsConstructor +public class ViewStatsDTO { + + @NotBlank + private String app; + + @NotBlank + private String uri; + private Integer hits; +} diff --git a/stat/stat-server/pom.xml b/stat/stat-server/pom.xml index f07dab0..6c75009 100644 --- a/stat/stat-server/pom.xml +++ b/stat/stat-server/pom.xml @@ -15,6 +15,8 @@ 23 23 UTF-8 + 1.6.3 + 0.2.0 @@ -24,27 +26,10 @@ 0.0.1-SNAPSHOT compile - - org.springframework.boot - spring-boot-starter-data-jdbc - - - org.springframework.boot - spring-boot-starter-actuator - - - org.springframework.boot - spring-boot-starter-data-jpa - org.springframework.boot - spring-boot-starter-web - - - - org.springframework.boot - spring-boot-starter-actuator + spring-boot-starter-data-jdbc @@ -60,36 +45,29 @@ - org.springframework.boot - spring-boot-configuration-processor - true - - - - org.projectlombok - lombok - true + org.mapstruct + mapstruct + 1.6.3 - - org.springframework.boot - spring-boot-starter-test - test - org.mapstruct - mapstruct + mapstruct-processor 1.6.3 + provided + org.projectlombok lombok-mapstruct-binding ${lombok-mapstruct-binding.version} + com.fasterxml.jackson.datatype jackson-datatype-jsr310 + diff --git a/stat/stat-server/src/main/java/ru/practicum/controller/ErrorHandler.java b/stat/stat-server/src/main/java/ru/practicum/controller/ErrorHandler.java new file mode 100644 index 0000000..33a30e0 --- /dev/null +++ b/stat/stat-server/src/main/java/ru/practicum/controller/ErrorHandler.java @@ -0,0 +1,51 @@ +package ru.practicum.controller; + +import lombok.extern.slf4j.Slf4j; +import org.springframework.http.HttpStatus; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.ResponseStatus; +import org.springframework.web.bind.annotation.RestControllerAdvice; +import ru.practicum.exceptions.NotFoundException; +import ru.practicum.exceptions.ValidationException; + +import java.io.PrintWriter; +import java.io.StringWriter; + +@RestControllerAdvice +@Slf4j +public class ErrorHandler { + + @ExceptionHandler + @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR) + public ErrorResponse handleException(final Exception e) { + log.error("500 {}", e.getMessage(), e); + StringWriter sw = new StringWriter(); + PrintWriter pw = new PrintWriter(sw); + e.printStackTrace(pw); + String stackTrace = sw.toString(); + return new ErrorResponse(HttpStatus.INTERNAL_SERVER_ERROR, e.getMessage(), stackTrace); + } + + @ExceptionHandler(ValidationException.class) + @ResponseStatus(HttpStatus.BAD_REQUEST) + public ErrorResponse handleValidationException(final ValidationException e) { + log.error("400 {}", e.getMessage(), e); + StringWriter sw = new StringWriter(); + PrintWriter pw = new PrintWriter(sw); + e.printStackTrace(pw); + String stackTrace = sw.toString(); + return new ErrorResponse(HttpStatus.BAD_REQUEST, e.getMessage(), stackTrace); + } + + @ExceptionHandler(NotFoundException.class) + @ResponseStatus(HttpStatus.NOT_FOUND) + public ErrorResponse handleNotFoundException(final NotFoundException e) { + log.error("404 {}", e.getMessage(), e); + StringWriter sw = new StringWriter(); + PrintWriter pw = new PrintWriter(sw); + e.printStackTrace(pw); + String stackTrace = sw.toString(); + return new ErrorResponse(HttpStatus.NOT_FOUND, e.getMessage(), stackTrace); + } + +} diff --git a/stat/stat-server/src/main/java/ru/practicum/controller/ErrorResponse.java b/stat/stat-server/src/main/java/ru/practicum/controller/ErrorResponse.java new file mode 100644 index 0000000..6fb83aa --- /dev/null +++ b/stat/stat-server/src/main/java/ru/practicum/controller/ErrorResponse.java @@ -0,0 +1,13 @@ +package ru.practicum.controller; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import org.springframework.http.HttpStatus; + +@Getter +@AllArgsConstructor +public class ErrorResponse { + private HttpStatus status; + private String message; + private String stackTrace; +} diff --git a/stat/stat-server/src/main/java/ru/practicum/controller/StatsServerController.java b/stat/stat-server/src/main/java/ru/practicum/controller/StatsServerController.java new file mode 100644 index 0000000..56f2309 --- /dev/null +++ b/stat/stat-server/src/main/java/ru/practicum/controller/StatsServerController.java @@ -0,0 +1,27 @@ +package ru.practicum.controller; + +import jakarta.validation.Valid; +import lombok.RequiredArgsConstructor; +import org.springframework.web.bind.annotation.*; +import ru.practicum.EndpointHitDTO; +import ru.practicum.StatsRequestDTO; +import ru.practicum.ViewStatsDTO; +import ru.practicum.service.StatsServiceImpl; + +import java.util.List; + +@RestController +@RequiredArgsConstructor +public class StatsServerController { + private final StatsServiceImpl statsService; + + @GetMapping("/stats") + private List viewStats(@ModelAttribute @Valid StatsRequestDTO statsRequestDTO) { + return statsService.getStats(statsRequestDTO); + } + + @PostMapping("/hit") + private void createHit(@RequestBody @Valid EndpointHitDTO hitDTO) { + statsService.createHit(hitDTO); + } +} diff --git a/stat/stat-server/src/main/java/ru/practicum/exceptions/NotFoundException.java b/stat/stat-server/src/main/java/ru/practicum/exceptions/NotFoundException.java new file mode 100644 index 0000000..48d9b83 --- /dev/null +++ b/stat/stat-server/src/main/java/ru/practicum/exceptions/NotFoundException.java @@ -0,0 +1,11 @@ +package ru.practicum.exceptions; + +public class NotFoundException extends RuntimeException { + + public NotFoundException(String message) { + super(message); + } + public NotFoundException() { + super(); + } +} diff --git a/stat/stat-server/src/main/java/ru/practicum/exceptions/ValidationException.java b/stat/stat-server/src/main/java/ru/practicum/exceptions/ValidationException.java new file mode 100644 index 0000000..3fd492f --- /dev/null +++ b/stat/stat-server/src/main/java/ru/practicum/exceptions/ValidationException.java @@ -0,0 +1,12 @@ +package ru.practicum.exceptions; + +public class ValidationException extends RuntimeException { + + public ValidationException() { + super(); + } + + public ValidationException(String message) { + super(message); + } +} diff --git a/stat/stat-server/src/main/java/ru/practicum/mapper/HitsMapper.java b/stat/stat-server/src/main/java/ru/practicum/mapper/HitsMapper.java new file mode 100644 index 0000000..b9baff5 --- /dev/null +++ b/stat/stat-server/src/main/java/ru/practicum/mapper/HitsMapper.java @@ -0,0 +1,12 @@ +package ru.practicum.mapper; + +import org.mapstruct.Mapper; +import ru.practicum.EndpointHitDTO; +import ru.practicum.model.EndpointHit; + +@Mapper(componentModel = "spring", uses = {EndpointHit.class}) +public interface HitsMapper { + + EndpointHit mapHitDTO(EndpointHitDTO endpointHitDTO); + +} diff --git a/stat/stat-server/src/main/java/ru/practicum/mapper/HitsObjectMapper.java b/stat/stat-server/src/main/java/ru/practicum/mapper/HitsObjectMapper.java new file mode 100644 index 0000000..1077ec0 --- /dev/null +++ b/stat/stat-server/src/main/java/ru/practicum/mapper/HitsObjectMapper.java @@ -0,0 +1,23 @@ +package ru.practicum.mapper; + +import org.springframework.jdbc.core.RowMapper; +import org.springframework.stereotype.Component; +import ru.practicum.model.EndpointHit; + +import java.sql.ResultSet; +import java.sql.SQLException; + +@Component +public class HitsObjectMapper implements RowMapper { + @Override + public EndpointHit mapRow(ResultSet rs, int rowNum) throws SQLException { + EndpointHit endpointHit = new EndpointHit(); + endpointHit.setApp(rs.getString("app")); + endpointHit.setId(rs.getLong("id")); + endpointHit.setIp(rs.getString("ip")); + endpointHit.setTimestamp(rs.getTimestamp("timestamp").toLocalDateTime()); + endpointHit.setUri(rs.getString("uri")); + + return endpointHit; + } +} diff --git a/stat/stat-server/src/main/java/ru/practicum/mapper/ViewStatsMapper.java b/stat/stat-server/src/main/java/ru/practicum/mapper/ViewStatsMapper.java new file mode 100644 index 0000000..aa90029 --- /dev/null +++ b/stat/stat-server/src/main/java/ru/practicum/mapper/ViewStatsMapper.java @@ -0,0 +1,13 @@ +package ru.practicum.mapper; + +import org.mapstruct.Mapper; +import org.mapstruct.MappingConstants; +import ru.practicum.ViewStatsDTO; +import ru.practicum.model.ViewStats; + +@Mapper(componentModel = MappingConstants.ComponentModel.SPRING) +public interface ViewStatsMapper { + ViewStats mapViewStatsDTO(ViewStatsDTO viewStatsDTO); + + ViewStatsDTO mapViewStats(ViewStats viewStats); +} diff --git a/stat/stat-server/src/main/java/ru/practicum/mapper/ViewStatsObjectMapper.java b/stat/stat-server/src/main/java/ru/practicum/mapper/ViewStatsObjectMapper.java new file mode 100644 index 0000000..02a1690 --- /dev/null +++ b/stat/stat-server/src/main/java/ru/practicum/mapper/ViewStatsObjectMapper.java @@ -0,0 +1,19 @@ +package ru.practicum.mapper; + +import org.springframework.jdbc.core.RowMapper; +import org.springframework.stereotype.Component; +import ru.practicum.model.ViewStats; + +import java.sql.ResultSet; +import java.sql.SQLException; + +@Component +public class ViewStatsObjectMapper implements RowMapper { + @Override + public ViewStats mapRow(ResultSet rs, int rowNum) throws SQLException { + ViewStats viewStats = new ViewStats(); + viewStats.setApp(rs.getString("app")); + viewStats.setUri(rs.getString("uri")); + return viewStats; + } +} diff --git a/stat/stat-server/src/main/java/ru/practicum/model/EndpointHit.java b/stat/stat-server/src/main/java/ru/practicum/model/EndpointHit.java new file mode 100644 index 0000000..dfaecf2 --- /dev/null +++ b/stat/stat-server/src/main/java/ru/practicum/model/EndpointHit.java @@ -0,0 +1,18 @@ +package ru.practicum.model; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.time.LocalDateTime; + +@Data +@NoArgsConstructor +@AllArgsConstructor +public class EndpointHit { + private Long id; + private String app; + private String uri; + private String ip; + private LocalDateTime timestamp; +} diff --git a/stat/stat-server/src/main/java/ru/practicum/model/ViewStats.java b/stat/stat-server/src/main/java/ru/practicum/model/ViewStats.java new file mode 100644 index 0000000..9707b8f --- /dev/null +++ b/stat/stat-server/src/main/java/ru/practicum/model/ViewStats.java @@ -0,0 +1,14 @@ +package ru.practicum.model; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@NoArgsConstructor +@AllArgsConstructor +public class ViewStats { + private String app; + private String uri; + private Integer hits; +} diff --git a/stat/stat-server/src/main/java/ru/practicum/repository/StatsServerRepoInterface.java b/stat/stat-server/src/main/java/ru/practicum/repository/StatsServerRepoInterface.java new file mode 100644 index 0000000..981e81a --- /dev/null +++ b/stat/stat-server/src/main/java/ru/practicum/repository/StatsServerRepoInterface.java @@ -0,0 +1,13 @@ +package ru.practicum.repository; + +import ru.practicum.model.EndpointHit; +import ru.practicum.model.ViewStats; + +import java.time.LocalDateTime; +import java.util.List; + +public interface StatsServerRepoInterface { + List getStats(LocalDateTime start, LocalDateTime end); + List getStatsUnique(LocalDateTime start, LocalDateTime end, List uris); + void createHit(EndpointHit hit); +} diff --git a/stat/stat-server/src/main/java/ru/practicum/repository/StatsServerRepository.java b/stat/stat-server/src/main/java/ru/practicum/repository/StatsServerRepository.java new file mode 100644 index 0000000..228d1b9 --- /dev/null +++ b/stat/stat-server/src/main/java/ru/practicum/repository/StatsServerRepository.java @@ -0,0 +1,54 @@ +package ru.practicum.repository; + +import lombok.RequiredArgsConstructor; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.stereotype.Repository; +import ru.practicum.mapper.ViewStatsObjectMapper; +import ru.practicum.model.EndpointHit; +import ru.practicum.model.ViewStats; + +import java.time.LocalDateTime; +import java.util.List; + +@Repository +@RequiredArgsConstructor +public class StatsServerRepository extends ViewStatsObjectMapper implements StatsServerRepoInterface { + + private final JdbcTemplate jdbc; + private final ViewStatsObjectMapper viewStatsMapper = new ViewStatsObjectMapper(); + + @Override + public List getStats(LocalDateTime start, LocalDateTime end) { + List viewStatsList = jdbc.query("SELECT app, uri FROM hits " + + "WHERE timestamp BETWEEN ? AND ? GROUP BY hits.app, hits.uri " + + "ORDER BY COUNT(*) DESC", new ViewStatsObjectMapper(), start, end); + + for (ViewStats viewStats : viewStatsList) { + int hits = jdbc.queryForObject("SELECT COUNT(uri) FROM hits " + + "WHERE uri = ?", Integer.class, viewStats.getUri()); + viewStats.setHits(hits); + } + return viewStatsList; + } + + @Override + public List getStatsUnique(LocalDateTime start, LocalDateTime end, List uris) { + List viewStatsList = jdbc.query("SELECT app, uri FROM hits " + + "WHERE uri = ? AND timestamp BETWEEN ? AND ? GROUP BY hits.app, hits.uri " + + "ORDER BY COUNT(*) DESC", new ViewStatsObjectMapper(), uris.getFirst(), start, end); + + for (ViewStats viewStats : viewStatsList) { + int hits = jdbc.queryForObject("SELECT COUNT(DISTINCT ip) FROM hits " + + "WHERE uri = ?", Integer.class, viewStats.getUri()); + viewStats.setHits(hits); + } + return viewStatsList; + } + + @Override + public void createHit(EndpointHit hit) { + jdbc.update("INSERT INTO hits (app, uri, ip, timestamp) VALUES (?, ?, ?, ?)", + hit.getApp(), hit.getUri(), hit.getIp(), hit.getTimestamp()); + } + +} diff --git a/stat/stat-server/src/main/java/ru/practicum/service/StatsServiceImpl.java b/stat/stat-server/src/main/java/ru/practicum/service/StatsServiceImpl.java new file mode 100644 index 0000000..b775c7d --- /dev/null +++ b/stat/stat-server/src/main/java/ru/practicum/service/StatsServiceImpl.java @@ -0,0 +1,47 @@ +package ru.practicum.service; + +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import ru.practicum.EndpointHitDTO; +import ru.practicum.StatsRequestDTO; +import ru.practicum.ViewStatsDTO; +import ru.practicum.mapper.HitsMapper; +import ru.practicum.mapper.ViewStatsMapper; +import ru.practicum.model.EndpointHit; +import ru.practicum.model.ViewStats; +import ru.practicum.repository.StatsServerRepository; + +import java.util.List; + +@Service +@RequiredArgsConstructor +public class StatsServiceImpl implements StatsServiceInterface { + private final StatsServerRepository statsService; + private final ViewStatsMapper viewStatsMapper; + private final HitsMapper hitsMapper; + + @Override + public List getStats(StatsRequestDTO statsRequestDTO) { + + List stats; + if (statsRequestDTO.getUnique() == null) { + stats = statsService.getStats(statsRequestDTO.getStart(), statsRequestDTO.getEnd()).stream() + .filter(viewStats -> statsRequestDTO.getUris().contains(viewStats.getUri())) + .toList(); + } else if (statsRequestDTO.getUnique().equals(true)) { + stats = statsService.getStatsUnique(statsRequestDTO.getStart(), statsRequestDTO.getEnd(), + statsRequestDTO.getUris()); + } else { + stats = statsService.getStats(statsRequestDTO.getStart(), statsRequestDTO.getEnd()); + } + return stats.stream() + .map(viewStatsMapper::mapViewStats) + .toList(); + } + + @Override + public void createHit(EndpointHitDTO hitDTO) { + EndpointHit hit = hitsMapper.mapHitDTO(hitDTO); + statsService.createHit(hit); + } +} diff --git a/stat/stat-server/src/main/java/ru/practicum/service/StatsServiceInterface.java b/stat/stat-server/src/main/java/ru/practicum/service/StatsServiceInterface.java new file mode 100644 index 0000000..95435cb --- /dev/null +++ b/stat/stat-server/src/main/java/ru/practicum/service/StatsServiceInterface.java @@ -0,0 +1,12 @@ +package ru.practicum.service; + +import ru.practicum.EndpointHitDTO; +import ru.practicum.StatsRequestDTO; +import ru.practicum.ViewStatsDTO; + +import java.util.List; + +public interface StatsServiceInterface { + List getStats(StatsRequestDTO statsRequestDTO); + void createHit(EndpointHitDTO hitDTO); +} diff --git a/stat/stat-server/src/main/resources/schema.sql b/stat/stat-server/src/main/resources/schema.sql index 9f67fba..ae2d69d 100644 --- a/stat/stat-server/src/main/resources/schema.sql +++ b/stat/stat-server/src/main/resources/schema.sql @@ -1,5 +1,7 @@ -CREATE TABLE IF NOT EXISTS users ( - user_id BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, - user_name CHARACTER VARYING(255) NOT NULL, - user_email CHARACTER VARYING(500) NOT NULL UNIQUE -); \ No newline at end of file +CREATE TABLE IF NOT EXISTS hits ( + id BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, + app CHARACTER VARYING(255) NOT NULL, + uri CHARACTER VARYING(100) NOT NULL, + ip CHARACTER VARYING(50) NOT NULL, + timestamp TIMESTAMP WITHOUT TIME ZONE +); From 0a02d0639e703210a92259366390e49806226238 Mon Sep 17 00:00:00 2001 From: NadezhdaTA Date: Mon, 11 Aug 2025 17:56:51 +0400 Subject: [PATCH 06/35] =?UTF-8?q?=D0=A0=D0=B5=D0=B0=D0=BB=D0=B8=D0=B7?= =?UTF-8?q?=D0=BE=D0=B2=D0=B0=D0=BD=D1=8B=20stat-server,=20stat-dto,=20sta?= =?UTF-8?q?t-client?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- stat/stat-client/src/main/java/ru/practicum/StatsClient.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stat/stat-client/src/main/java/ru/practicum/StatsClient.java b/stat/stat-client/src/main/java/ru/practicum/StatsClient.java index 9243b5e..986225e 100644 --- a/stat/stat-client/src/main/java/ru/practicum/StatsClient.java +++ b/stat/stat-client/src/main/java/ru/practicum/StatsClient.java @@ -5,7 +5,7 @@ import org.springframework.http.client.HttpComponentsClientHttpRequestFactory; import org.springframework.web.client.RestClient; -public class StatsClient extends BaseClient{ +public class StatsClient extends BaseClient { String appName; public StatsClient(@Value("${stat-server.url}") String serverUrl, From 80bcdb91ca57e4dab49cb133ddf882375df8f45f Mon Sep 17 00:00:00 2001 From: NadezhdaTA Date: Mon, 11 Aug 2025 19:28:30 +0400 Subject: [PATCH 07/35] =?UTF-8?q?=D0=A0=D0=B5=D0=B0=D0=BB=D0=B8=D0=B7?= =?UTF-8?q?=D0=BE=D0=B2=D0=B0=D0=BD=D1=8B=20stat-server,=20stat-dto,=20sta?= =?UTF-8?q?t-client?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/ru/practicum/exceptions/NotFoundException.java | 1 + .../java/ru/practicum/repository/StatsServerRepoInterface.java | 2 ++ .../main/java/ru/practicum/service/StatsServiceInterface.java | 1 + 3 files changed, 4 insertions(+) diff --git a/stat/stat-server/src/main/java/ru/practicum/exceptions/NotFoundException.java b/stat/stat-server/src/main/java/ru/practicum/exceptions/NotFoundException.java index 48d9b83..4f82b7d 100644 --- a/stat/stat-server/src/main/java/ru/practicum/exceptions/NotFoundException.java +++ b/stat/stat-server/src/main/java/ru/practicum/exceptions/NotFoundException.java @@ -5,6 +5,7 @@ public class NotFoundException extends RuntimeException { public NotFoundException(String message) { super(message); } + public NotFoundException() { super(); } diff --git a/stat/stat-server/src/main/java/ru/practicum/repository/StatsServerRepoInterface.java b/stat/stat-server/src/main/java/ru/practicum/repository/StatsServerRepoInterface.java index 981e81a..6d382d8 100644 --- a/stat/stat-server/src/main/java/ru/practicum/repository/StatsServerRepoInterface.java +++ b/stat/stat-server/src/main/java/ru/practicum/repository/StatsServerRepoInterface.java @@ -8,6 +8,8 @@ public interface StatsServerRepoInterface { List getStats(LocalDateTime start, LocalDateTime end); + List getStatsUnique(LocalDateTime start, LocalDateTime end, List uris); + void createHit(EndpointHit hit); } diff --git a/stat/stat-server/src/main/java/ru/practicum/service/StatsServiceInterface.java b/stat/stat-server/src/main/java/ru/practicum/service/StatsServiceInterface.java index 95435cb..0263295 100644 --- a/stat/stat-server/src/main/java/ru/practicum/service/StatsServiceInterface.java +++ b/stat/stat-server/src/main/java/ru/practicum/service/StatsServiceInterface.java @@ -8,5 +8,6 @@ public interface StatsServiceInterface { List getStats(StatsRequestDTO statsRequestDTO); + void createHit(EndpointHitDTO hitDTO); } From 025e9228d61db7167d362f9b84fad7319d01e345 Mon Sep 17 00:00:00 2001 From: NadezhdaTA Date: Tue, 12 Aug 2025 14:17:05 +0400 Subject: [PATCH 08/35] =?UTF-8?q?=D0=A0=D0=B5=D0=B0=D0=BB=D0=B8=D0=B7?= =?UTF-8?q?=D0=BE=D0=B2=D0=B0=D0=BD=D1=8B=20stat-server,=20stat-dto,=20sta?= =?UTF-8?q?t-client?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docker-compose.yml | 41 +++++++++++-------- evm-service/pom.xml | 12 ++++-- .../src/main/resources/application.yml | 3 +- 3 files changed, 34 insertions(+), 22 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index 6ba39aa..c83708e 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,10 +1,11 @@ -name: explore-with-me +version: '3.8' services: stats-server: build: context: ./stat/stat-server + dockerfile: Dockerfile image: explore-with-me-stats container_name: explore-with-me-stats ports: @@ -16,23 +17,10 @@ services: depends_on: - stats-db - stats-db: - image: postgres:16.1 - container_name: postgres-stat - ports: - - "6542:5432" - environment: - - POSTGRES_PASSWORD:12345 - - POSTGRES_USER:user - - POSTGRES_DB:stat-server - healthcheck: - test: pg_isready -q -d $$POSTGRES_DB -U $$POSTGRES_USER - interval: 5s - timeout: 5s - retries: 10 - ewm-service: - build: evm-service + build: + context: ./evm-service + dockerfile: Dockerfile image: explore-with-me-service container_name: explore-with-me-service ports: @@ -48,7 +36,7 @@ services: image: postgres:16.1 container_name: postgres-service ports: - - "6541:5432" + - "6542:5432" environment: - POSTGRES_PASSWORD=12345 - POSTGRES_USER=user @@ -58,3 +46,20 @@ services: interval: 5s timeout: 5s retries: 10 + + stats-db: + image: postgres:16.1 + container_name: postgres-stat + ports: + - "6541:5432" + environment: + - POSTGRES_ROOT_PASSWORD:12345 + - POSTGRES_PASSWORD:12345 + - POSTGRES_USER:user + - POSTGRES_DB:stat-server + - POSTGRES_HOST_AUTH_METHOD=trust + healthcheck: + test: pg_isready -q -d $$POSTGRES_DB -U $$POSTGRES_USER + interval: 5s + timeout: 5s + retries: 10 \ No newline at end of file diff --git a/evm-service/pom.xml b/evm-service/pom.xml index e5792a2..4cfda05 100644 --- a/evm-service/pom.xml +++ b/evm-service/pom.xml @@ -25,19 +25,25 @@ 0.0.1-SNAPSHOT compile + org.springframework.boot - spring-boot-starter-data-jpa + spring-boot-starter-web org.springframework.boot - spring-boot-starter-web + spring-boot-starter-actuator org.springframework.boot - spring-boot-starter-actuator + spring-boot-starter-data-jpa + + + + org.springframework.boot + spring-boot-starter-validation diff --git a/stat/stat-server/src/main/resources/application.yml b/stat/stat-server/src/main/resources/application.yml index 42ee3e4..103c584 100644 --- a/stat/stat-server/src/main/resources/application.yml +++ b/stat/stat-server/src/main/resources/application.yml @@ -19,8 +19,9 @@ spring: init: mode: always datasource: + driverClassName: org.postgresql.Driver url: jdbc:postgresql://localhost:5432/stats-server username: user password: 12345 - driverClassName: org.postgresql.Driver + From 79b3b8633739c7624867c6bfa6cf40747d60a3f0 Mon Sep 17 00:00:00 2001 From: NadezhdaTA Date: Tue, 12 Aug 2025 16:33:57 +0400 Subject: [PATCH 09/35] =?UTF-8?q?=D0=A0=D0=B5=D0=B0=D0=BB=D0=B8=D0=B7?= =?UTF-8?q?=D0=BE=D0=B2=D0=B0=D0=BD=D1=8B=20stat-server,=20stat-dto,=20sta?= =?UTF-8?q?t-client?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docker-compose.yml | 37 +++++++++++++++++++------------------ 1 file changed, 19 insertions(+), 18 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index c83708e..54b21fc 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -11,12 +11,29 @@ services: ports: - "9090:9090" environment: - - SPRING_DATASOURCE_URL=jdbc:postgresql://stat-db:5432/stat-server + - SPRING_DATASOURCE_URL=jdbc:postgresql://stats-db:5432/stat-server - SPRING_DATASOURCE_USERNAME=user - SPRING_DATASOURCE_PASSWORD=12345 depends_on: - stats-db + stats-db: + image: postgres:16.1 + container_name: postgres-stat + ports: + - "6541:5432" + environment: + - POSTGRES_ROOT_PASSWORD:12345 + - POSTGRES_PASSWORD:12345 + - POSTGRES_USER:user + - POSTGRES_DB:stat-server + - POSTGRES_HOST_AUTH_METHOD=trust + healthcheck: + test: pg_isready -q -d $$POSTGRES_DB -U $$POSTGRES_USER + interval: 5s + timeout: 5s + retries: 10 + ewm-service: build: context: ./evm-service @@ -26,7 +43,7 @@ services: ports: - "8080:8080" environment: - - SPRING_DATASOURCE_URL=jdbc:postgresql://ewm-db:5433/ewm-service + - SPRING_DATASOURCE_URL=jdbc:postgresql://ewm-db:5432/ewm-service - SPRING_DATASOURCE_USERNAME=user - SPRING_DATASOURCE_PASSWORD=12345 depends_on: @@ -47,19 +64,3 @@ services: timeout: 5s retries: 10 - stats-db: - image: postgres:16.1 - container_name: postgres-stat - ports: - - "6541:5432" - environment: - - POSTGRES_ROOT_PASSWORD:12345 - - POSTGRES_PASSWORD:12345 - - POSTGRES_USER:user - - POSTGRES_DB:stat-server - - POSTGRES_HOST_AUTH_METHOD=trust - healthcheck: - test: pg_isready -q -d $$POSTGRES_DB -U $$POSTGRES_USER - interval: 5s - timeout: 5s - retries: 10 \ No newline at end of file From ad715d43c418e63a36d3ddfba7e25aaaa29bac48 Mon Sep 17 00:00:00 2001 From: NadezhdaTA Date: Sat, 16 Aug 2025 12:10:36 +0400 Subject: [PATCH 10/35] =?UTF-8?q?=D0=A0=D0=B5=D0=B0=D0=BB=D0=B8=D0=B7?= =?UTF-8?q?=D0=BE=D0=B2=D0=B0=D0=BD=D1=8B=20stat-server,=20stat-dto,=20sta?= =?UTF-8?q?t-client?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docker-compose.yml | 28 ++++++++++++---------------- 1 file changed, 12 insertions(+), 16 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index 54b21fc..af38b64 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -3,19 +3,17 @@ version: '3.8' services: stats-server: - build: - context: ./stat/stat-server - dockerfile: Dockerfile - image: explore-with-me-stats - container_name: explore-with-me-stats + container_name: stats-server + image: stats-server + build: ./stat/stat-server ports: - "9090:9090" + depends_on: + - stats-db environment: - - SPRING_DATASOURCE_URL=jdbc:postgresql://stats-db:5432/stat-server + - SPRING_DATASOURCE_URL=jdbc.postgresql://stats-db:5432/stats-server - SPRING_DATASOURCE_USERNAME=user - SPRING_DATASOURCE_PASSWORD=12345 - depends_on: - - stats-db stats-db: image: postgres:16.1 @@ -23,11 +21,9 @@ services: ports: - "6541:5432" environment: - - POSTGRES_ROOT_PASSWORD:12345 - - POSTGRES_PASSWORD:12345 - - POSTGRES_USER:user - - POSTGRES_DB:stat-server - - POSTGRES_HOST_AUTH_METHOD=trust + POSTGRES_USER: user + POSTGRES_PASSWORD: 12345 + POSTGRES_DB: stats-service healthcheck: test: pg_isready -q -d $$POSTGRES_DB -U $$POSTGRES_USER interval: 5s @@ -55,9 +51,9 @@ services: ports: - "6542:5432" environment: - - POSTGRES_PASSWORD=12345 - - POSTGRES_USER=user - - POSTGRES_DB=ewm-service + POSTGRES_USER: user + POSTGRES_PASSWORD: 12345 + POSTGRES_DB: ewm-service healthcheck: test: pg_isready -q -d $$POSTGRES_DB -U $$POSTGRES_USER interval: 5s From 4437ab34491d5d1d8fd2f77a626dc79b0fa385b0 Mon Sep 17 00:00:00 2001 From: NadezhdaTA Date: Sat, 16 Aug 2025 21:03:58 +0400 Subject: [PATCH 11/35] =?UTF-8?q?=D0=A0=D0=B5=D0=B0=D0=BB=D0=B8=D0=B7?= =?UTF-8?q?=D0=BE=D0=B2=D0=B0=D0=BD=D1=8B=20stat-server,=20stat-dto,=20sta?= =?UTF-8?q?t-client?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docker-compose.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker-compose.yml b/docker-compose.yml index af38b64..b6b68dd 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -11,7 +11,7 @@ services: depends_on: - stats-db environment: - - SPRING_DATASOURCE_URL=jdbc.postgresql://stats-db:5432/stats-server + - SPRING_DATASOURCE_URL=jdbc:postgresql://stats-db:5432/stats-service - SPRING_DATASOURCE_USERNAME=user - SPRING_DATASOURCE_PASSWORD=12345 From 8f27d268a48bc0ca677dd133a12a086de8fb00b3 Mon Sep 17 00:00:00 2001 From: NadezhdaTA Date: Fri, 22 Aug 2025 19:32:43 +0400 Subject: [PATCH 12/35] =?UTF-8?q?=D0=A0=D0=B5=D0=B0=D0=BB=D0=B8=D0=B7?= =?UTF-8?q?=D0=BE=D0=B2=D0=B0=D0=BD=D0=B0=20=D1=84=D1=83=D0=BD=D0=BA=D1=86?= =?UTF-8?q?=D0=B8=D0=BE=D0=BD=D0=B0=D0=BB=D1=8C=D0=BD=D0=BE=D1=81=D1=82?= =?UTF-8?q?=D1=8C=20=D0=BF=D0=BE=20=D0=B4=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=B5=D0=BD=D0=B8=D1=8E,=20=D1=83=D0=B4=D0=B0=D0=BB=D0=B5?= =?UTF-8?q?=D0=BD=D0=B8=D1=8E=20=D0=B8=20=D0=BF=D0=BE=D0=BB=D1=83=D1=87?= =?UTF-8?q?=D0=B5=D0=BD=D0=B8=D1=8E=20=D1=81=D0=BF=D0=B8=D1=81=D0=BA=D0=B0?= =?UTF-8?q?=20=D0=BF=D0=BE=D0=BB=D1=8C=D0=B7=D0=BE=D0=B2=D0=B0=D1=82=D0=B5?= =?UTF-8?q?=D0=BB=D0=B5=D0=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- evm-service/pom.xml | 32 ++++------ .../DTO/CategoryDTO/CategoryDTO.java | 16 +++++ .../DTO/CategoryDTO/NewCategoryDTO.java | 16 +++++ .../DTO/CompilationDTO/CompilationDTO.java | 26 ++++++++ .../DTO/CompilationDTO/NewCompilationDTO.java | 21 +++++++ .../UpdateCompilationRequest.java | 19 ++++++ .../practicum/DTO/EventDTO/EventFullDTO.java | 63 +++++++++++++++++++ .../EventRequestStatusUpdateRequest.java | 17 +++++ .../EventRequestStatusUpdateResult.java | 14 +++++ .../practicum/DTO/EventDTO/EventShortDTO.java | 42 +++++++++++++ .../practicum/DTO/EventDTO/NewEventDTO.java | 46 ++++++++++++++ .../DTO/EventDTO/UpdateEventAdminRequest.java | 50 +++++++++++++++ .../DTO/EventDTO/UpdateEventUserRequest.java | 49 +++++++++++++++ .../ParticipationRequestDto.java | 19 ++++++ .../ru/practicum/Exception/ErrorHandler.java | 49 +++++++++++++++ .../ru/practicum/Exception/ErrorResponse.java | 13 ++++ .../Exception/NotFoundException.java | 11 ++++ .../Exception/ValidationException.java | 11 ++++ .../java/ru/practicum/Model/Category.java | 22 +++++++ .../java/ru/practicum/Model/Compilation.java | 24 +++++++ .../main/java/ru/practicum/Model/Event.java | 63 +++++++++++++++++++ .../java/ru/practicum/Model/Location.java | 25 ++++++++ .../main/java/ru/practicum/Model/State.java | 14 +++++ .../User/Controller/UserAdminController.java | 43 +++++++++++++ .../ru/practicum/User/DTO/NewUserRequest.java | 23 +++++++ .../java/ru/practicum/User/DTO/UserDTO.java | 21 +++++++ .../ru/practicum/User/DTO/UserShortDTO.java | 18 ++++++ .../practicum/User/DTO/UsersListRequest.java | 18 ++++++ .../ru/practicum/User/Mapper/UserMapper.java | 16 +++++ .../java/ru/practicum/User/Model/User.java | 24 +++++++ .../User/Repository/UserRepository.java | 21 +++++++ .../User/Service/UserAdminService.java | 17 +++++ .../User/Service/UserAdminServiceImpl.java | 57 +++++++++++++++++ evm-service/src/main/resources/schema.sql | 26 ++++++-- stat/pom.xml | 26 -------- stat/stat-dto/pom.xml | 27 ++++++++ .../java/ru/practicum/EndpointHitDTO.java | 4 -- stat/stat-server/pom.xml | 41 ++++++++---- 38 files changed, 977 insertions(+), 67 deletions(-) create mode 100644 evm-service/src/main/java/ru/practicum/DTO/CategoryDTO/CategoryDTO.java create mode 100644 evm-service/src/main/java/ru/practicum/DTO/CategoryDTO/NewCategoryDTO.java create mode 100644 evm-service/src/main/java/ru/practicum/DTO/CompilationDTO/CompilationDTO.java create mode 100644 evm-service/src/main/java/ru/practicum/DTO/CompilationDTO/NewCompilationDTO.java create mode 100644 evm-service/src/main/java/ru/practicum/DTO/CompilationDTO/UpdateCompilationRequest.java create mode 100644 evm-service/src/main/java/ru/practicum/DTO/EventDTO/EventFullDTO.java create mode 100644 evm-service/src/main/java/ru/practicum/DTO/EventDTO/EventRequestStatusUpdateRequest.java create mode 100644 evm-service/src/main/java/ru/practicum/DTO/EventDTO/EventRequestStatusUpdateResult.java create mode 100644 evm-service/src/main/java/ru/practicum/DTO/EventDTO/EventShortDTO.java create mode 100644 evm-service/src/main/java/ru/practicum/DTO/EventDTO/NewEventDTO.java create mode 100644 evm-service/src/main/java/ru/practicum/DTO/EventDTO/UpdateEventAdminRequest.java create mode 100644 evm-service/src/main/java/ru/practicum/DTO/EventDTO/UpdateEventUserRequest.java create mode 100644 evm-service/src/main/java/ru/practicum/DTO/ParticipationDTO/ParticipationRequestDto.java create mode 100644 evm-service/src/main/java/ru/practicum/Exception/ErrorHandler.java create mode 100644 evm-service/src/main/java/ru/practicum/Exception/ErrorResponse.java create mode 100644 evm-service/src/main/java/ru/practicum/Exception/NotFoundException.java create mode 100644 evm-service/src/main/java/ru/practicum/Exception/ValidationException.java create mode 100644 evm-service/src/main/java/ru/practicum/Model/Category.java create mode 100644 evm-service/src/main/java/ru/practicum/Model/Compilation.java create mode 100644 evm-service/src/main/java/ru/practicum/Model/Event.java create mode 100644 evm-service/src/main/java/ru/practicum/Model/Location.java create mode 100644 evm-service/src/main/java/ru/practicum/Model/State.java create mode 100644 evm-service/src/main/java/ru/practicum/User/Controller/UserAdminController.java create mode 100644 evm-service/src/main/java/ru/practicum/User/DTO/NewUserRequest.java create mode 100644 evm-service/src/main/java/ru/practicum/User/DTO/UserDTO.java create mode 100644 evm-service/src/main/java/ru/practicum/User/DTO/UserShortDTO.java create mode 100644 evm-service/src/main/java/ru/practicum/User/DTO/UsersListRequest.java create mode 100644 evm-service/src/main/java/ru/practicum/User/Mapper/UserMapper.java create mode 100644 evm-service/src/main/java/ru/practicum/User/Model/User.java create mode 100644 evm-service/src/main/java/ru/practicum/User/Repository/UserRepository.java create mode 100644 evm-service/src/main/java/ru/practicum/User/Service/UserAdminService.java create mode 100644 evm-service/src/main/java/ru/practicum/User/Service/UserAdminServiceImpl.java diff --git a/evm-service/pom.xml b/evm-service/pom.xml index 4cfda05..5039d92 100644 --- a/evm-service/pom.xml +++ b/evm-service/pom.xml @@ -12,19 +12,14 @@ evm-service - 21 + 23 + 23 1.6.3 0.2.0 UTF-8 - - ru.practicum - stat-dto - 0.0.1-SNAPSHOT - compile - org.springframework.boot @@ -89,6 +84,16 @@ com.fasterxml.jackson.datatype jackson-datatype-jsr310 + + ru.practicum + stat-dto + 0.0.1-SNAPSHOT + + + ru.practicum + stat-client + 0.0.1-SNAPSHOT + @@ -146,18 +151,5 @@ - - - coverage - - - - org.jacoco - jacoco-maven-plugin - - - - - \ No newline at end of file diff --git a/evm-service/src/main/java/ru/practicum/DTO/CategoryDTO/CategoryDTO.java b/evm-service/src/main/java/ru/practicum/DTO/CategoryDTO/CategoryDTO.java new file mode 100644 index 0000000..f1eb08d --- /dev/null +++ b/evm-service/src/main/java/ru/practicum/DTO/CategoryDTO/CategoryDTO.java @@ -0,0 +1,16 @@ +package ru.practicum.DTO.CategoryDTO; + +import jakarta.validation.constraints.NotBlank; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@NoArgsConstructor +@AllArgsConstructor +public class CategoryDTO { + private Integer id; + + @NotBlank + private String name; +} diff --git a/evm-service/src/main/java/ru/practicum/DTO/CategoryDTO/NewCategoryDTO.java b/evm-service/src/main/java/ru/practicum/DTO/CategoryDTO/NewCategoryDTO.java new file mode 100644 index 0000000..86ccf0d --- /dev/null +++ b/evm-service/src/main/java/ru/practicum/DTO/CategoryDTO/NewCategoryDTO.java @@ -0,0 +1,16 @@ +package ru.practicum.DTO.CategoryDTO; + +import jakarta.validation.constraints.NotBlank; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.hibernate.validator.constraints.Length; + +@Data +@NoArgsConstructor +@AllArgsConstructor +public class NewCategoryDTO { + @NotBlank + @Length(max = 50) + private String name; +} diff --git a/evm-service/src/main/java/ru/practicum/DTO/CompilationDTO/CompilationDTO.java b/evm-service/src/main/java/ru/practicum/DTO/CompilationDTO/CompilationDTO.java new file mode 100644 index 0000000..a54eb6d --- /dev/null +++ b/evm-service/src/main/java/ru/practicum/DTO/CompilationDTO/CompilationDTO.java @@ -0,0 +1,26 @@ +package ru.practicum.DTO.CompilationDTO; + +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import ru.practicum.DTO.EventDTO.EventShortDTO; + +import java.util.Set; + +@Data +@NoArgsConstructor +@AllArgsConstructor +public class CompilationDTO { + @NotNull + private Integer id; + + @NotNull + private Boolean pinned; + + @NotBlank + private String title; + + private Set events; +} diff --git a/evm-service/src/main/java/ru/practicum/DTO/CompilationDTO/NewCompilationDTO.java b/evm-service/src/main/java/ru/practicum/DTO/CompilationDTO/NewCompilationDTO.java new file mode 100644 index 0000000..6d04b6b --- /dev/null +++ b/evm-service/src/main/java/ru/practicum/DTO/CompilationDTO/NewCompilationDTO.java @@ -0,0 +1,21 @@ +package ru.practicum.DTO.CompilationDTO; + +import jakarta.validation.constraints.NotBlank; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.hibernate.validator.constraints.Length; + +import java.util.ArrayList; + +@Data +@NoArgsConstructor +@AllArgsConstructor +public class NewCompilationDTO { + private ArrayList events; + private Boolean pinned; + + @NotBlank + @Length(min = 1, max = 50) + private String title; +} diff --git a/evm-service/src/main/java/ru/practicum/DTO/CompilationDTO/UpdateCompilationRequest.java b/evm-service/src/main/java/ru/practicum/DTO/CompilationDTO/UpdateCompilationRequest.java new file mode 100644 index 0000000..22b40b6 --- /dev/null +++ b/evm-service/src/main/java/ru/practicum/DTO/CompilationDTO/UpdateCompilationRequest.java @@ -0,0 +1,19 @@ +package ru.practicum.DTO.CompilationDTO; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.hibernate.validator.constraints.Length; + +import java.util.ArrayList; + +@Data +@NoArgsConstructor +@AllArgsConstructor +public class UpdateCompilationRequest { + private ArrayList events; + private Boolean pinned; + + @Length(min = 1, max = 50) + private String title; +} diff --git a/evm-service/src/main/java/ru/practicum/DTO/EventDTO/EventFullDTO.java b/evm-service/src/main/java/ru/practicum/DTO/EventDTO/EventFullDTO.java new file mode 100644 index 0000000..17715a0 --- /dev/null +++ b/evm-service/src/main/java/ru/practicum/DTO/EventDTO/EventFullDTO.java @@ -0,0 +1,63 @@ +package ru.practicum.DTO.EventDTO; + +import com.fasterxml.jackson.annotation.JsonFormat; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Positive; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import ru.practicum.DTO.CategoryDTO.CategoryDTO; +import ru.practicum.User.DTO.UserShortDTO; +import ru.practicum.Model.Location; +import ru.practicum.Model.State; + +import java.time.LocalDateTime; + +@Data +@NoArgsConstructor +@AllArgsConstructor +public class EventFullDTO { + private Integer id; + + @NotBlank + private String annotation; + + @NotNull + private CategoryDTO category; + + private Integer confirmedRequests; + + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime createdOn; + + private String description; + + @NotNull + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime eventDate; + + @NotNull + private UserShortDTO initiator; + + @NotNull + private Location location; + + @NotNull + private Boolean paid; + + @Positive + private Integer participantLimit; + + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime publishedOn; + + private Boolean requestModeration; + + private State state; + + @NotBlank + private String title; + + private Integer views; +} diff --git a/evm-service/src/main/java/ru/practicum/DTO/EventDTO/EventRequestStatusUpdateRequest.java b/evm-service/src/main/java/ru/practicum/DTO/EventDTO/EventRequestStatusUpdateRequest.java new file mode 100644 index 0000000..b48246f --- /dev/null +++ b/evm-service/src/main/java/ru/practicum/DTO/EventDTO/EventRequestStatusUpdateRequest.java @@ -0,0 +1,17 @@ +package ru.practicum.DTO.EventDTO; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import ru.practicum.Model.State; + +import java.util.ArrayList; + +@Data +@NoArgsConstructor +@AllArgsConstructor +public class EventRequestStatusUpdateRequest { + private ArrayList requestIds; + private State status; + +} diff --git a/evm-service/src/main/java/ru/practicum/DTO/EventDTO/EventRequestStatusUpdateResult.java b/evm-service/src/main/java/ru/practicum/DTO/EventDTO/EventRequestStatusUpdateResult.java new file mode 100644 index 0000000..c2604f0 --- /dev/null +++ b/evm-service/src/main/java/ru/practicum/DTO/EventDTO/EventRequestStatusUpdateResult.java @@ -0,0 +1,14 @@ +package ru.practicum.DTO.EventDTO; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import ru.practicum.DTO.ParticipationDTO.ParticipationRequestDto; + +@Data +@NoArgsConstructor +@AllArgsConstructor +public class EventRequestStatusUpdateResult { + private ParticipationRequestDto confirmedRequests; + private ParticipationRequestDto rejectedRequests; +} diff --git a/evm-service/src/main/java/ru/practicum/DTO/EventDTO/EventShortDTO.java b/evm-service/src/main/java/ru/practicum/DTO/EventDTO/EventShortDTO.java new file mode 100644 index 0000000..27b021a --- /dev/null +++ b/evm-service/src/main/java/ru/practicum/DTO/EventDTO/EventShortDTO.java @@ -0,0 +1,42 @@ +package ru.practicum.DTO.EventDTO; + +import com.fasterxml.jackson.annotation.JsonFormat; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import ru.practicum.DTO.CategoryDTO.CategoryDTO; +import ru.practicum.User.DTO.UserShortDTO; + +import java.time.LocalDateTime; + +@Data +@NoArgsConstructor +@AllArgsConstructor +public class EventShortDTO { + private Integer id; + + @NotBlank + private String annotation; + + @NotNull + private CategoryDTO category; + + private Integer confirmedRequests; + + @NotNull + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime eventDate; + + @NotNull + private UserShortDTO initiator; + + @NotNull + private Boolean paid; + + @NotBlank + private String title; + + private Integer views; +} diff --git a/evm-service/src/main/java/ru/practicum/DTO/EventDTO/NewEventDTO.java b/evm-service/src/main/java/ru/practicum/DTO/EventDTO/NewEventDTO.java new file mode 100644 index 0000000..db003f2 --- /dev/null +++ b/evm-service/src/main/java/ru/practicum/DTO/EventDTO/NewEventDTO.java @@ -0,0 +1,46 @@ +package ru.practicum.DTO.EventDTO; + +import com.fasterxml.jackson.annotation.JsonFormat; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Positive; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.hibernate.validator.constraints.Length; +import ru.practicum.Model.Location; + +import java.time.LocalDateTime; + +@Data +@NoArgsConstructor +@AllArgsConstructor +public class NewEventDTO { + @NotBlank + @Length(min = 20, max = 2000) + private String annotation; + + private Integer category; + + @NotBlank + @Length(min = 20, max = 7000) + private String description; + + @NotNull + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime eventDate; + + @NotNull + private Location location; + + private Boolean paid; + + @Positive + private Integer participantLimit; + + private Boolean requestModeration; + + @NotBlank + @Length(min = 3, max = 120) + private String title; +} diff --git a/evm-service/src/main/java/ru/practicum/DTO/EventDTO/UpdateEventAdminRequest.java b/evm-service/src/main/java/ru/practicum/DTO/EventDTO/UpdateEventAdminRequest.java new file mode 100644 index 0000000..7e06b9b --- /dev/null +++ b/evm-service/src/main/java/ru/practicum/DTO/EventDTO/UpdateEventAdminRequest.java @@ -0,0 +1,50 @@ +package ru.practicum.DTO.EventDTO; + +import com.fasterxml.jackson.annotation.JsonFormat; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.hibernate.validator.constraints.Length; +import ru.practicum.DTO.CategoryDTO.CategoryDTO; +import ru.practicum.Model.Location; +import ru.practicum.Model.State; + +import java.time.LocalDateTime; + +@Data +@NoArgsConstructor +@AllArgsConstructor +public class UpdateEventAdminRequest { + + @NotBlank + @Length(min = 20, max = 2000) + private String annotation; + + @NotNull + private CategoryDTO category; + + @NotBlank + @Length(min = 20, max = 7000) + private String description; + + @NotNull + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime eventDate; + + private Location location; + + private Boolean paid; + + private Integer participantLimit; + + private Boolean requestModeration; + + private State stateAction; + + @NotBlank + @Length(min = 3, max = 120) + private String title; + +} diff --git a/evm-service/src/main/java/ru/practicum/DTO/EventDTO/UpdateEventUserRequest.java b/evm-service/src/main/java/ru/practicum/DTO/EventDTO/UpdateEventUserRequest.java new file mode 100644 index 0000000..ac29eec --- /dev/null +++ b/evm-service/src/main/java/ru/practicum/DTO/EventDTO/UpdateEventUserRequest.java @@ -0,0 +1,49 @@ +package ru.practicum.DTO.EventDTO; + +import com.fasterxml.jackson.annotation.JsonFormat; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.hibernate.validator.constraints.Length; +import ru.practicum.DTO.CategoryDTO.CategoryDTO; +import ru.practicum.Model.Location; +import ru.practicum.Model.State; + +import java.time.LocalDateTime; + +@Data +@NoArgsConstructor +@AllArgsConstructor +public class UpdateEventUserRequest { + + @NotBlank + @Length(min = 20, max = 2000) + private String annotation; + + @NotNull + private CategoryDTO category; + + @NotBlank + @Length(min = 20, max = 7000) + private String description; + + @NotNull + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime eventDate; + + private Location location; + + private Boolean paid; + + private Integer participantLimit; + + private Boolean requestModeration; + + private State stateAction; + + @NotBlank + @Length(min = 3, max = 120) + private String title; +} diff --git a/evm-service/src/main/java/ru/practicum/DTO/ParticipationDTO/ParticipationRequestDto.java b/evm-service/src/main/java/ru/practicum/DTO/ParticipationDTO/ParticipationRequestDto.java new file mode 100644 index 0000000..af4aa16 --- /dev/null +++ b/evm-service/src/main/java/ru/practicum/DTO/ParticipationDTO/ParticipationRequestDto.java @@ -0,0 +1,19 @@ +package ru.practicum.DTO.ParticipationDTO; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import ru.practicum.Model.State; + +import java.time.LocalDateTime; + +@Data +@NoArgsConstructor +@AllArgsConstructor +public class ParticipationRequestDto { + private Integer id; + private final LocalDateTime created = LocalDateTime.now(); + private Integer event; + private Integer requester; + private State status; +} diff --git a/evm-service/src/main/java/ru/practicum/Exception/ErrorHandler.java b/evm-service/src/main/java/ru/practicum/Exception/ErrorHandler.java new file mode 100644 index 0000000..f1e6124 --- /dev/null +++ b/evm-service/src/main/java/ru/practicum/Exception/ErrorHandler.java @@ -0,0 +1,49 @@ +package ru.practicum.Exception; + +import lombok.extern.slf4j.Slf4j; +import org.springframework.http.HttpStatus; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.ResponseStatus; +import org.springframework.web.bind.annotation.RestControllerAdvice; + +import java.io.PrintWriter; +import java.io.StringWriter; + +@RestControllerAdvice +@Slf4j +public class ErrorHandler { + + @ExceptionHandler + @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR) + public ErrorResponse handleException(final Exception e) { + log.error("500 {}", e.getMessage(), e); + StringWriter sw = new StringWriter(); + PrintWriter pw = new PrintWriter(sw); + e.printStackTrace(pw); + String stackTrace = sw.toString(); + return new ErrorResponse(HttpStatus.INTERNAL_SERVER_ERROR, e.getMessage(), stackTrace); + } + + @ExceptionHandler(ValidationException.class) + @ResponseStatus(HttpStatus.BAD_REQUEST) + public ErrorResponse handleValidationException(final ValidationException e) { + log.error("400 {}", e.getMessage(), e); + StringWriter sw = new StringWriter(); + PrintWriter pw = new PrintWriter(sw); + e.printStackTrace(pw); + String stackTrace = sw.toString(); + return new ErrorResponse(HttpStatus.BAD_REQUEST, e.getMessage(), stackTrace); + } + + @ExceptionHandler(NotFoundException.class) + @ResponseStatus(HttpStatus.NOT_FOUND) + public ErrorResponse handleNotFoundException(final NotFoundException e) { + log.error("404 {}", e.getMessage(), e); + StringWriter sw = new StringWriter(); + PrintWriter pw = new PrintWriter(sw); + e.printStackTrace(pw); + String stackTrace = sw.toString(); + return new ErrorResponse(HttpStatus.NOT_FOUND, e.getMessage(), stackTrace); + } + +} diff --git a/evm-service/src/main/java/ru/practicum/Exception/ErrorResponse.java b/evm-service/src/main/java/ru/practicum/Exception/ErrorResponse.java new file mode 100644 index 0000000..886d3de --- /dev/null +++ b/evm-service/src/main/java/ru/practicum/Exception/ErrorResponse.java @@ -0,0 +1,13 @@ +package ru.practicum.Exception; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import org.springframework.http.HttpStatus; + +@Getter +@AllArgsConstructor +public class ErrorResponse { + private HttpStatus status; + private String message; + private String stackTrace; +} diff --git a/evm-service/src/main/java/ru/practicum/Exception/NotFoundException.java b/evm-service/src/main/java/ru/practicum/Exception/NotFoundException.java new file mode 100644 index 0000000..982e60a --- /dev/null +++ b/evm-service/src/main/java/ru/practicum/Exception/NotFoundException.java @@ -0,0 +1,11 @@ +package ru.practicum.Exception; + +public class NotFoundException extends RuntimeException { + public NotFoundException(String message) { + super(message); + } + + public NotFoundException() { + super(); + } +} diff --git a/evm-service/src/main/java/ru/practicum/Exception/ValidationException.java b/evm-service/src/main/java/ru/practicum/Exception/ValidationException.java new file mode 100644 index 0000000..06bd106 --- /dev/null +++ b/evm-service/src/main/java/ru/practicum/Exception/ValidationException.java @@ -0,0 +1,11 @@ +package ru.practicum.Exception; + +public class ValidationException extends RuntimeException { + public ValidationException() { + super(); + } + + public ValidationException(String message) { + super(message); + } +} diff --git a/evm-service/src/main/java/ru/practicum/Model/Category.java b/evm-service/src/main/java/ru/practicum/Model/Category.java new file mode 100644 index 0000000..36cf367 --- /dev/null +++ b/evm-service/src/main/java/ru/practicum/Model/Category.java @@ -0,0 +1,22 @@ +package ru.practicum.Model; + +import jakarta.persistence.*; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@NoArgsConstructor +@AllArgsConstructor +//@Entity +//@Table(name = "categories") +public class Category { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "id") + private Integer id; + + @Column(name = "name") + private String name; +} diff --git a/evm-service/src/main/java/ru/practicum/Model/Compilation.java b/evm-service/src/main/java/ru/practicum/Model/Compilation.java new file mode 100644 index 0000000..8a188a8 --- /dev/null +++ b/evm-service/src/main/java/ru/practicum/Model/Compilation.java @@ -0,0 +1,24 @@ +package ru.practicum.Model; + +import jakarta.persistence.*; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@NoArgsConstructor +@AllArgsConstructor +//@Entity +//@Table(name = "compilations") +public class Compilation { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "id") + private Integer id; + + @Column(name = "pinned") + private Boolean pinned; + + @Column(name = "title") + private String title; +} diff --git a/evm-service/src/main/java/ru/practicum/Model/Event.java b/evm-service/src/main/java/ru/practicum/Model/Event.java new file mode 100644 index 0000000..f04aa42 --- /dev/null +++ b/evm-service/src/main/java/ru/practicum/Model/Event.java @@ -0,0 +1,63 @@ +package ru.practicum.Model; + +import jakarta.persistence.*; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import ru.practicum.User.Model.User; + +import java.time.LocalDateTime; + +@Data +@NoArgsConstructor +@AllArgsConstructor +//@Entity +//@Table(name = "events") +public class Event { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "id") + private Integer id; + + @Column(name = "annotation") + private String annotation; + + @ManyToOne(fetch = FetchType.EAGER) + private Category category; + + @Column(name = "createdOn") + private LocalDateTime createdOn; + + @Column(name = "description") + private String description; + + @Column(name = "eventDate") + private LocalDateTime eventDate; + + @OneToOne(fetch = FetchType.EAGER) + private User initiator; + + @OneToOne(fetch = FetchType.EAGER) + private Location location; + + @Column(name = "paid") + private Boolean paid; + + @Column(name = "participantLimit") + private Integer participantLimit; + + @Column(name = "publishedOn") + private LocalDateTime publishedOn; + + @Column(name = "requestModeration") + private Boolean requestModeration; + + @OneToOne(fetch = FetchType.EAGER) + private State state; + + + private String title; + + private Integer views; +} diff --git a/evm-service/src/main/java/ru/practicum/Model/Location.java b/evm-service/src/main/java/ru/practicum/Model/Location.java new file mode 100644 index 0000000..fa7cbec --- /dev/null +++ b/evm-service/src/main/java/ru/practicum/Model/Location.java @@ -0,0 +1,25 @@ +package ru.practicum.Model; + +import jakarta.persistence.*; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@Entity +@Table(name = "locations") +public class Location { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "id") + private Integer id; + + @Column(name = "lat") + private Float lat; + + @Column(name = "lon") + private Float lon; +} diff --git a/evm-service/src/main/java/ru/practicum/Model/State.java b/evm-service/src/main/java/ru/practicum/Model/State.java new file mode 100644 index 0000000..df6cb69 --- /dev/null +++ b/evm-service/src/main/java/ru/practicum/Model/State.java @@ -0,0 +1,14 @@ +package ru.practicum.Model; + + +public enum State { + PUBLISHED, + CONFIRMED, + REJECTED, + PENDING, + PUBLISH_EVENT, + REJECT_EVENT, + CANCEL_REVIEW, + SEND_TO_REVIEW + +} diff --git a/evm-service/src/main/java/ru/practicum/User/Controller/UserAdminController.java b/evm-service/src/main/java/ru/practicum/User/Controller/UserAdminController.java new file mode 100644 index 0000000..02134b5 --- /dev/null +++ b/evm-service/src/main/java/ru/practicum/User/Controller/UserAdminController.java @@ -0,0 +1,43 @@ +package ru.practicum.User.Controller; + +import jakarta.validation.Valid; +import lombok.RequiredArgsConstructor; +import org.springframework.http.HttpStatus; +import org.springframework.web.bind.annotation.*; +import ru.practicum.User.DTO.NewUserRequest; +import ru.practicum.User.DTO.UserDTO; +import ru.practicum.User.DTO.UsersListRequest; +import ru.practicum.User.Service.UserAdminServiceImpl; + +import java.util.List; + +@RestController +@RequestMapping("/admin/users") +@RequiredArgsConstructor +public class UserAdminController { + private final UserAdminServiceImpl userAdminService; + + @PostMapping + @ResponseStatus(HttpStatus.CREATED) + public UserDTO addUser(@RequestBody @Valid NewUserRequest newUser) { + return userAdminService.addUser(newUser); + } + + @GetMapping("/{userId}") + @ResponseStatus(HttpStatus.OK) + public UserDTO getUserById(@PathVariable Integer userId) { + return userAdminService.getUserById(userId); + } + + @GetMapping + @ResponseStatus(HttpStatus.OK) + public List getUsers(@ModelAttribute UsersListRequest request) { + return userAdminService.getUsers(request); + } + + @DeleteMapping("/{userId}") + @ResponseStatus(HttpStatus.NO_CONTENT) + public void deleteUser(@PathVariable Integer userId) { + userAdminService.deleteUserById(userId); + } +} diff --git a/evm-service/src/main/java/ru/practicum/User/DTO/NewUserRequest.java b/evm-service/src/main/java/ru/practicum/User/DTO/NewUserRequest.java new file mode 100644 index 0000000..54d2534 --- /dev/null +++ b/evm-service/src/main/java/ru/practicum/User/DTO/NewUserRequest.java @@ -0,0 +1,23 @@ +package ru.practicum.User.DTO; + +import jakarta.validation.constraints.Email; +import jakarta.validation.constraints.NotBlank; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.hibernate.validator.constraints.Length; + +@Data +@NoArgsConstructor +@AllArgsConstructor +public class NewUserRequest { + @Email + @NotBlank + @Length(min = 6, max = 254) + private String email; + + @NotBlank + @Length(min = 2, max = 250) + private String name; + +} diff --git a/evm-service/src/main/java/ru/practicum/User/DTO/UserDTO.java b/evm-service/src/main/java/ru/practicum/User/DTO/UserDTO.java new file mode 100644 index 0000000..552d020 --- /dev/null +++ b/evm-service/src/main/java/ru/practicum/User/DTO/UserDTO.java @@ -0,0 +1,21 @@ +package ru.practicum.User.DTO; + +import jakarta.validation.constraints.Email; +import jakarta.validation.constraints.NotBlank; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@NoArgsConstructor +@AllArgsConstructor +public class UserDTO { + private Integer id; + + @NotBlank + @Email + private String email; + + @NotBlank + private String name; +} diff --git a/evm-service/src/main/java/ru/practicum/User/DTO/UserShortDTO.java b/evm-service/src/main/java/ru/practicum/User/DTO/UserShortDTO.java new file mode 100644 index 0000000..6f8c646 --- /dev/null +++ b/evm-service/src/main/java/ru/practicum/User/DTO/UserShortDTO.java @@ -0,0 +1,18 @@ +package ru.practicum.User.DTO; + +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@NoArgsConstructor +@AllArgsConstructor +public class UserShortDTO { + @NotNull + private Integer id; + + @NotBlank + private String name; +} diff --git a/evm-service/src/main/java/ru/practicum/User/DTO/UsersListRequest.java b/evm-service/src/main/java/ru/practicum/User/DTO/UsersListRequest.java new file mode 100644 index 0000000..4c85167 --- /dev/null +++ b/evm-service/src/main/java/ru/practicum/User/DTO/UsersListRequest.java @@ -0,0 +1,18 @@ +package ru.practicum.User.DTO; + +import jakarta.validation.constraints.Positive; +import jakarta.validation.constraints.PositiveOrZero; +import lombok.Data; + +import java.util.Set; + +@Data +public class UsersListRequest { + private Set ids; + + @PositiveOrZero + private final Integer from = 0; + + @Positive + private final Integer size = 10; +} diff --git a/evm-service/src/main/java/ru/practicum/User/Mapper/UserMapper.java b/evm-service/src/main/java/ru/practicum/User/Mapper/UserMapper.java new file mode 100644 index 0000000..6ee6e70 --- /dev/null +++ b/evm-service/src/main/java/ru/practicum/User/Mapper/UserMapper.java @@ -0,0 +1,16 @@ +package ru.practicum.User.Mapper; + +import org.mapstruct.Mapper; +import ru.practicum.User.DTO.NewUserRequest; +import ru.practicum.User.DTO.UserDTO; +import ru.practicum.User.DTO.UserShortDTO; +import ru.practicum.User.Model.User; + +@Mapper(componentModel = "spring") +public interface UserMapper { + User toUser(NewUserRequest user); + + UserDTO toUserDTO(User user); + + UserShortDTO toUserShortDTO(User user); +} diff --git a/evm-service/src/main/java/ru/practicum/User/Model/User.java b/evm-service/src/main/java/ru/practicum/User/Model/User.java new file mode 100644 index 0000000..eaad6a0 --- /dev/null +++ b/evm-service/src/main/java/ru/practicum/User/Model/User.java @@ -0,0 +1,24 @@ +package ru.practicum.User.Model; + +import jakarta.persistence.*; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@Entity +@Table(name = "users") +public class User { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "id") + private Integer id; + + @Column(name = "email") + private String email; + + @Column(name = "name") + private String name; +} diff --git a/evm-service/src/main/java/ru/practicum/User/Repository/UserRepository.java b/evm-service/src/main/java/ru/practicum/User/Repository/UserRepository.java new file mode 100644 index 0000000..3306878 --- /dev/null +++ b/evm-service/src/main/java/ru/practicum/User/Repository/UserRepository.java @@ -0,0 +1,21 @@ +package ru.practicum.User.Repository; + +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.data.jpa.repository.JpaRepository; +import ru.practicum.User.Model.User; + +import java.util.Collection; +import java.util.Optional; + +public interface UserRepository extends JpaRepository { + User save(User newUser); + + void deleteUserById(Integer id); + + Optional findUserById(Integer id); + + Page findAll(Pageable pageable); + + Page findAllByIdIn(Collection ids, Pageable pageable); +} diff --git a/evm-service/src/main/java/ru/practicum/User/Service/UserAdminService.java b/evm-service/src/main/java/ru/practicum/User/Service/UserAdminService.java new file mode 100644 index 0000000..75a8beb --- /dev/null +++ b/evm-service/src/main/java/ru/practicum/User/Service/UserAdminService.java @@ -0,0 +1,17 @@ +package ru.practicum.User.Service; + +import ru.practicum.User.DTO.NewUserRequest; +import ru.practicum.User.DTO.UserDTO; +import ru.practicum.User.DTO.UsersListRequest; + +import java.util.List; + +public interface UserAdminService { + UserDTO addUser(NewUserRequest newUser); + + void deleteUserById(Integer id); + + UserDTO getUserById(Integer id); + + List getUsers(UsersListRequest request); +} diff --git a/evm-service/src/main/java/ru/practicum/User/Service/UserAdminServiceImpl.java b/evm-service/src/main/java/ru/practicum/User/Service/UserAdminServiceImpl.java new file mode 100644 index 0000000..89e04fa --- /dev/null +++ b/evm-service/src/main/java/ru/practicum/User/Service/UserAdminServiceImpl.java @@ -0,0 +1,57 @@ +package ru.practicum.User.Service; + +import lombok.RequiredArgsConstructor; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Sort; +import org.springframework.stereotype.Service; +import ru.practicum.Exception.NotFoundException; +import ru.practicum.User.DTO.NewUserRequest; +import ru.practicum.User.DTO.UserDTO; +import ru.practicum.User.DTO.UsersListRequest; +import ru.practicum.User.Mapper.UserMapper; +import ru.practicum.User.Model.User; +import ru.practicum.User.Repository.UserRepository; + +import java.util.List; + +@Service +@RequiredArgsConstructor +public class UserAdminServiceImpl implements UserAdminService { + private final UserRepository userRepository; + private final UserMapper userMapper; + + @Override + public UserDTO addUser(NewUserRequest newUser) { + return userMapper.toUserDTO(userRepository.save(userMapper.toUser(newUser))); + } + + @Override + public void deleteUserById(Integer id) { + User user = userRepository.findById(id) + .orElseThrow(() -> new NotFoundException("User with id " + id + " not found")); + + userRepository.delete(user); + } + + @Override + public UserDTO getUserById(Integer id) { + User user = userRepository.findById(id) + .orElseThrow(() -> new NotFoundException("User with id " + id + " not found")); + + return userMapper.toUserDTO(user); + } + + @Override + public List getUsers(UsersListRequest request) { + Pageable pageable = PageRequest.of(request.getFrom(), request.getSize(), Sort.by("id").ascending()); + Page users = request.getIds() == null + ? userRepository.findAll(pageable) + : userRepository.findAllByIdIn(request.getIds(), pageable); + + return users.getContent().stream() + .map(userMapper::toUserDTO) + .toList(); + } +} diff --git a/evm-service/src/main/resources/schema.sql b/evm-service/src/main/resources/schema.sql index 9f67fba..c250442 100644 --- a/evm-service/src/main/resources/schema.sql +++ b/evm-service/src/main/resources/schema.sql @@ -1,5 +1,23 @@ CREATE TABLE IF NOT EXISTS users ( - user_id BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, - user_name CHARACTER VARYING(255) NOT NULL, - user_email CHARACTER VARYING(500) NOT NULL UNIQUE -); \ No newline at end of file + id INT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, + name CHARACTER VARYING(255) NOT NULL, + email CHARACTER VARYING(500) NOT NULL UNIQUE + ); + +CREATE TABLE IF NOT EXISTS locations ( + id INT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, + lat FLOAT, + lon FLOAT +); + +CREATE TABLE IF NOT EXISTS categories ( + id INT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, + name CHARACTER VARYING(255) NOT NULL +); + +CREATE TABLE IF NOT EXISTS compilations ( + id INT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, + pinned BOOLEAN NOT NULL, + title VARCHAR NOT NULL +); + diff --git a/stat/pom.xml b/stat/pom.xml index bb46d2d..8d45d67 100644 --- a/stat/pom.xml +++ b/stat/pom.xml @@ -25,33 +25,7 @@ - - org.springframework.boot - spring-boot-starter-web - - - org.springframework.boot - spring-boot-starter-actuator - - - - org.springframework.boot - spring-boot-configuration-processor - true - - - - org.projectlombok - lombok - true - - - - org.springframework.boot - spring-boot-starter-test - test - diff --git a/stat/stat-dto/pom.xml b/stat/stat-dto/pom.xml index 0b6f802..592a310 100644 --- a/stat/stat-dto/pom.xml +++ b/stat/stat-dto/pom.xml @@ -18,6 +18,33 @@ + + org.springframework.boot + spring-boot-starter-web + + + + org.springframework.boot + spring-boot-starter-actuator + + + + org.springframework.boot + spring-boot-configuration-processor + true + + + + org.projectlombok + lombok + true + + + + org.springframework.boot + spring-boot-starter-test + test + org.springframework.boot diff --git a/stat/stat-dto/src/main/java/ru/practicum/EndpointHitDTO.java b/stat/stat-dto/src/main/java/ru/practicum/EndpointHitDTO.java index 547133c..fc6643a 100644 --- a/stat/stat-dto/src/main/java/ru/practicum/EndpointHitDTO.java +++ b/stat/stat-dto/src/main/java/ru/practicum/EndpointHitDTO.java @@ -15,18 +15,14 @@ public class EndpointHitDTO { @NotBlank - @JsonProperty("app") private String app; @NotBlank - @JsonProperty("uri") private String uri; @NotBlank - @JsonProperty("ip") private String ip; @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") - @JsonProperty("timestamp") private LocalDateTime timestamp; } diff --git a/stat/stat-server/pom.xml b/stat/stat-server/pom.xml index 6c75009..e85d47c 100644 --- a/stat/stat-server/pom.xml +++ b/stat/stat-server/pom.xml @@ -27,6 +27,34 @@ compile + + org.springframework.boot + spring-boot-starter-web + + + + org.springframework.boot + spring-boot-starter-actuator + + + + org.springframework.boot + spring-boot-configuration-processor + true + + + + org.projectlombok + lombok + true + + + + org.springframework.boot + spring-boot-starter-test + test + + org.springframework.boot spring-boot-starter-data-jdbc @@ -125,18 +153,5 @@ - - - coverage - - - - org.jacoco - jacoco-maven-plugin - - - - - \ No newline at end of file From 5ee686a2247193cc7e68a6cf90691cffc847fd47 Mon Sep 17 00:00:00 2001 From: NadezhdaTA Date: Sun, 24 Aug 2025 15:28:01 +0400 Subject: [PATCH 13/35] =?UTF-8?q?=D0=A0=D0=B5=D0=B0=D0=BB=D0=B8=D0=B7?= =?UTF-8?q?=D0=BE=D0=B2=D0=B0=D0=BD=D0=B0=20=D1=84=D1=83=D0=BD=D0=BA=D1=86?= =?UTF-8?q?=D0=B8=D0=BE=D0=BD=D0=B0=D0=BB=D1=8C=D0=BD=D0=BE=D1=81=D1=82?= =?UTF-8?q?=D1=8C=20=D0=BF=D0=BE=20=D0=B4=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=B5=D0=BD=D0=B8=D1=8E,=20=D1=83=D0=B4=D0=B0=D0=BB=D0=B5?= =?UTF-8?q?=D0=BD=D0=B8=D1=8E=20=D0=B8=20=D0=BF=D0=BE=D0=BB=D1=83=D1=87?= =?UTF-8?q?=D0=B5=D0=BD=D0=B8=D1=8E=20=D0=BA=D0=B0=D1=82=D0=B5=D0=B3=D0=BE?= =?UTF-8?q?=D1=80=D0=B8=D0=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Controller/CategoryAdminController.java | 35 +++++++++++++++ .../Controller/CategoryPublicController.java | 28 ++++++++++++ .../DTO}/CategoryDTO.java | 2 +- .../DTO}/NewCategoryDTO.java | 2 +- .../Category/Mapper/CategoryMapper.java | 15 +++++++ .../{ => Category}/Model/Category.java | 6 +-- .../Repository/CategoryRepository.java | 16 +++++++ .../Service/Admin/CategoryAdminService.java | 12 ++++++ .../Admin/CategoryAdminServiceImpl.java | 43 +++++++++++++++++++ .../Service/Public/CategoryPublicService.java | 11 +++++ .../Public/CategoryPublicServiceImpl.java | 40 +++++++++++++++++ .../practicum/DTO/EventDTO/EventFullDTO.java | 2 +- .../practicum/DTO/EventDTO/EventShortDTO.java | 2 +- .../DTO/EventDTO/UpdateEventAdminRequest.java | 2 +- .../DTO/EventDTO/UpdateEventUserRequest.java | 2 +- .../Exception/ConflictException.java | 11 +++++ .../ru/practicum/Exception/ErrorHandler.java | 22 ++++++++-- .../ru/practicum/Exception/ErrorResponse.java | 7 +++ .../main/java/ru/practicum/Model/Event.java | 1 + evm-service/src/main/resources/schema.sql | 2 +- 20 files changed, 248 insertions(+), 13 deletions(-) create mode 100644 evm-service/src/main/java/ru/practicum/Category/Controller/CategoryAdminController.java create mode 100644 evm-service/src/main/java/ru/practicum/Category/Controller/CategoryPublicController.java rename evm-service/src/main/java/ru/practicum/{DTO/CategoryDTO => Category/DTO}/CategoryDTO.java (87%) rename evm-service/src/main/java/ru/practicum/{DTO/CategoryDTO => Category/DTO}/NewCategoryDTO.java (89%) create mode 100644 evm-service/src/main/java/ru/practicum/Category/Mapper/CategoryMapper.java rename evm-service/src/main/java/ru/practicum/{ => Category}/Model/Category.java (83%) create mode 100644 evm-service/src/main/java/ru/practicum/Category/Repository/CategoryRepository.java create mode 100644 evm-service/src/main/java/ru/practicum/Category/Service/Admin/CategoryAdminService.java create mode 100644 evm-service/src/main/java/ru/practicum/Category/Service/Admin/CategoryAdminServiceImpl.java create mode 100644 evm-service/src/main/java/ru/practicum/Category/Service/Public/CategoryPublicService.java create mode 100644 evm-service/src/main/java/ru/practicum/Category/Service/Public/CategoryPublicServiceImpl.java create mode 100644 evm-service/src/main/java/ru/practicum/Exception/ConflictException.java diff --git a/evm-service/src/main/java/ru/practicum/Category/Controller/CategoryAdminController.java b/evm-service/src/main/java/ru/practicum/Category/Controller/CategoryAdminController.java new file mode 100644 index 0000000..6864f84 --- /dev/null +++ b/evm-service/src/main/java/ru/practicum/Category/Controller/CategoryAdminController.java @@ -0,0 +1,35 @@ +package ru.practicum.Category.Controller; + +import jakarta.validation.Valid; +import lombok.RequiredArgsConstructor; +import org.springframework.http.HttpStatus; +import org.springframework.web.bind.annotation.*; +import ru.practicum.Category.DTO.CategoryDTO; +import ru.practicum.Category.DTO.NewCategoryDTO; +import ru.practicum.Category.Service.Admin.CategoryAdminServiceImpl; + +@RestController +@RequestMapping("/admin/categories") +@RequiredArgsConstructor +public class CategoryAdminController { + private final CategoryAdminServiceImpl categoryService; + + @PostMapping + @ResponseStatus(HttpStatus.CREATED) + public CategoryDTO createCategory(@RequestBody @Valid NewCategoryDTO category) { + return categoryService.addCategory(category); + } + + @DeleteMapping("/{catId}") + @ResponseStatus(HttpStatus.NO_CONTENT) + public void deleteCategory(@PathVariable Integer catId) { + categoryService.deleteCategory(catId); + } + + @PatchMapping("/{catId}") + @ResponseStatus(HttpStatus.OK) + public CategoryDTO updateCategory(@PathVariable Integer catId, @RequestBody @Valid CategoryDTO category) { + return categoryService.updateCategory(catId, category); + } + +} diff --git a/evm-service/src/main/java/ru/practicum/Category/Controller/CategoryPublicController.java b/evm-service/src/main/java/ru/practicum/Category/Controller/CategoryPublicController.java new file mode 100644 index 0000000..57abb54 --- /dev/null +++ b/evm-service/src/main/java/ru/practicum/Category/Controller/CategoryPublicController.java @@ -0,0 +1,28 @@ +package ru.practicum.Category.Controller; + +import jakarta.validation.constraints.Positive; +import jakarta.validation.constraints.PositiveOrZero; +import lombok.RequiredArgsConstructor; +import org.springframework.web.bind.annotation.*; +import ru.practicum.Category.DTO.CategoryDTO; +import ru.practicum.Category.Service.Public.CategoryPublicService; + +import java.util.List; + +@RestController +@RequestMapping("/categories") +@RequiredArgsConstructor +public class CategoryPublicController { + private final CategoryPublicService categoryService; + + @GetMapping("/{catId}") + public CategoryDTO getCategory(@PathVariable Integer catId) { + return categoryService.getCategory(catId); + } + + @GetMapping + public List getCategories(@RequestParam @PositiveOrZero Integer from, + @RequestParam @Positive Integer size) { + return categoryService.getCategories(from, size); + } +} diff --git a/evm-service/src/main/java/ru/practicum/DTO/CategoryDTO/CategoryDTO.java b/evm-service/src/main/java/ru/practicum/Category/DTO/CategoryDTO.java similarity index 87% rename from evm-service/src/main/java/ru/practicum/DTO/CategoryDTO/CategoryDTO.java rename to evm-service/src/main/java/ru/practicum/Category/DTO/CategoryDTO.java index f1eb08d..92996ef 100644 --- a/evm-service/src/main/java/ru/practicum/DTO/CategoryDTO/CategoryDTO.java +++ b/evm-service/src/main/java/ru/practicum/Category/DTO/CategoryDTO.java @@ -1,4 +1,4 @@ -package ru.practicum.DTO.CategoryDTO; +package ru.practicum.Category.DTO; import jakarta.validation.constraints.NotBlank; import lombok.AllArgsConstructor; diff --git a/evm-service/src/main/java/ru/practicum/DTO/CategoryDTO/NewCategoryDTO.java b/evm-service/src/main/java/ru/practicum/Category/DTO/NewCategoryDTO.java similarity index 89% rename from evm-service/src/main/java/ru/practicum/DTO/CategoryDTO/NewCategoryDTO.java rename to evm-service/src/main/java/ru/practicum/Category/DTO/NewCategoryDTO.java index 86ccf0d..1154a12 100644 --- a/evm-service/src/main/java/ru/practicum/DTO/CategoryDTO/NewCategoryDTO.java +++ b/evm-service/src/main/java/ru/practicum/Category/DTO/NewCategoryDTO.java @@ -1,4 +1,4 @@ -package ru.practicum.DTO.CategoryDTO; +package ru.practicum.Category.DTO; import jakarta.validation.constraints.NotBlank; import lombok.AllArgsConstructor; diff --git a/evm-service/src/main/java/ru/practicum/Category/Mapper/CategoryMapper.java b/evm-service/src/main/java/ru/practicum/Category/Mapper/CategoryMapper.java new file mode 100644 index 0000000..a1d82dd --- /dev/null +++ b/evm-service/src/main/java/ru/practicum/Category/Mapper/CategoryMapper.java @@ -0,0 +1,15 @@ +package ru.practicum.Category.Mapper; + +import org.mapstruct.Mapper; +import ru.practicum.Category.DTO.CategoryDTO; +import ru.practicum.Category.DTO.NewCategoryDTO; +import ru.practicum.Category.Model.Category; + +@Mapper(componentModel = "spring") +public interface CategoryMapper { + Category toCategory(NewCategoryDTO categoryDTO); + + CategoryDTO toCategoryDTO(Category category); + + Category toCategory(CategoryDTO categoryDTO); +} diff --git a/evm-service/src/main/java/ru/practicum/Model/Category.java b/evm-service/src/main/java/ru/practicum/Category/Model/Category.java similarity index 83% rename from evm-service/src/main/java/ru/practicum/Model/Category.java rename to evm-service/src/main/java/ru/practicum/Category/Model/Category.java index 36cf367..b30954c 100644 --- a/evm-service/src/main/java/ru/practicum/Model/Category.java +++ b/evm-service/src/main/java/ru/practicum/Category/Model/Category.java @@ -1,4 +1,4 @@ -package ru.practicum.Model; +package ru.practicum.Category.Model; import jakarta.persistence.*; import lombok.AllArgsConstructor; @@ -8,8 +8,8 @@ @Data @NoArgsConstructor @AllArgsConstructor -//@Entity -//@Table(name = "categories") +@Entity +@Table(name = "categories") public class Category { @Id diff --git a/evm-service/src/main/java/ru/practicum/Category/Repository/CategoryRepository.java b/evm-service/src/main/java/ru/practicum/Category/Repository/CategoryRepository.java new file mode 100644 index 0000000..f1634f8 --- /dev/null +++ b/evm-service/src/main/java/ru/practicum/Category/Repository/CategoryRepository.java @@ -0,0 +1,16 @@ +package ru.practicum.Category.Repository; + +import org.springframework.data.jpa.repository.JpaRepository; +import ru.practicum.Category.Model.Category; + +import java.util.Optional; + +public interface CategoryRepository extends JpaRepository { + Category save(Category category); + + void deleteById(Integer id); + + Optional findById(Integer id); + + +} diff --git a/evm-service/src/main/java/ru/practicum/Category/Service/Admin/CategoryAdminService.java b/evm-service/src/main/java/ru/practicum/Category/Service/Admin/CategoryAdminService.java new file mode 100644 index 0000000..4609760 --- /dev/null +++ b/evm-service/src/main/java/ru/practicum/Category/Service/Admin/CategoryAdminService.java @@ -0,0 +1,12 @@ +package ru.practicum.Category.Service.Admin; + +import ru.practicum.Category.DTO.CategoryDTO; +import ru.practicum.Category.DTO.NewCategoryDTO; + +public interface CategoryAdminService { + CategoryDTO addCategory(NewCategoryDTO categoryDTO); + + void deleteCategory(Integer catId); + + CategoryDTO updateCategory(int id, CategoryDTO categoryDTO); +} diff --git a/evm-service/src/main/java/ru/practicum/Category/Service/Admin/CategoryAdminServiceImpl.java b/evm-service/src/main/java/ru/practicum/Category/Service/Admin/CategoryAdminServiceImpl.java new file mode 100644 index 0000000..7abede9 --- /dev/null +++ b/evm-service/src/main/java/ru/practicum/Category/Service/Admin/CategoryAdminServiceImpl.java @@ -0,0 +1,43 @@ +package ru.practicum.Category.Service.Admin; + +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import ru.practicum.Category.DTO.CategoryDTO; +import ru.practicum.Category.DTO.NewCategoryDTO; +import ru.practicum.Category.Mapper.CategoryMapper; +import ru.practicum.Category.Model.Category; +import ru.practicum.Category.Repository.CategoryRepository; +import ru.practicum.Exception.NotFoundException; + +@Service +@RequiredArgsConstructor +public class CategoryAdminServiceImpl implements CategoryAdminService { + private final CategoryMapper categoryMapper; + private final CategoryRepository repository; + + @Override + public CategoryDTO addCategory(NewCategoryDTO newCategory) { + Category category = categoryMapper.toCategory(newCategory); + return categoryMapper.toCategoryDTO(repository.save(category)); + } + + @Override + public void deleteCategory(Integer catId) { + Category category = repository.findById(catId) + .orElseThrow(() -> new NotFoundException("Category with id " + catId + " not found")); + + // Integer categoryEvents = + + repository.deleteById(catId); + } + + @Override + public CategoryDTO updateCategory(int id, CategoryDTO categoryDTO) { + Category category = repository.findById(id) + .orElseThrow(() -> new NotFoundException("Category with id " + id + " not found")); + + return categoryMapper.toCategoryDTO(repository.save(categoryMapper.toCategory(categoryDTO))); + } + + +} diff --git a/evm-service/src/main/java/ru/practicum/Category/Service/Public/CategoryPublicService.java b/evm-service/src/main/java/ru/practicum/Category/Service/Public/CategoryPublicService.java new file mode 100644 index 0000000..7d614ec --- /dev/null +++ b/evm-service/src/main/java/ru/practicum/Category/Service/Public/CategoryPublicService.java @@ -0,0 +1,11 @@ +package ru.practicum.Category.Service.Public; + +import ru.practicum.Category.DTO.CategoryDTO; + +import java.util.List; + +public interface CategoryPublicService { + CategoryDTO getCategory(Integer catId); + + List getCategories(Integer from, Integer size); +} diff --git a/evm-service/src/main/java/ru/practicum/Category/Service/Public/CategoryPublicServiceImpl.java b/evm-service/src/main/java/ru/practicum/Category/Service/Public/CategoryPublicServiceImpl.java new file mode 100644 index 0000000..fb00324 --- /dev/null +++ b/evm-service/src/main/java/ru/practicum/Category/Service/Public/CategoryPublicServiceImpl.java @@ -0,0 +1,40 @@ +package ru.practicum.Category.Service.Public; + +import lombok.RequiredArgsConstructor; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Sort; +import org.springframework.stereotype.Service; +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.Exception.NotFoundException; + +import java.util.List; + +@Service +@RequiredArgsConstructor +public class CategoryPublicServiceImpl implements CategoryPublicService { + private final CategoryRepository repository; + private final CategoryMapper categoryMapper; + + @Override + public CategoryDTO getCategory(Integer catId) { + Category category = repository.findById(catId) + .orElseThrow(() -> new NotFoundException("Category with id " + catId + " not found")); + return categoryMapper.toCategoryDTO(category); + } + + + + @Override + public List getCategories(Integer from, Integer size) { + Pageable pageable = PageRequest.of(from, size, Sort.by("id").ascending()); + Page categories = repository.findAll(pageable); + return categories.getContent().stream() + .map(categoryMapper::toCategoryDTO) + .toList(); + } +} diff --git a/evm-service/src/main/java/ru/practicum/DTO/EventDTO/EventFullDTO.java b/evm-service/src/main/java/ru/practicum/DTO/EventDTO/EventFullDTO.java index 17715a0..1fd696b 100644 --- a/evm-service/src/main/java/ru/practicum/DTO/EventDTO/EventFullDTO.java +++ b/evm-service/src/main/java/ru/practicum/DTO/EventDTO/EventFullDTO.java @@ -7,7 +7,7 @@ import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; -import ru.practicum.DTO.CategoryDTO.CategoryDTO; +import ru.practicum.Category.DTO.CategoryDTO; import ru.practicum.User.DTO.UserShortDTO; import ru.practicum.Model.Location; import ru.practicum.Model.State; diff --git a/evm-service/src/main/java/ru/practicum/DTO/EventDTO/EventShortDTO.java b/evm-service/src/main/java/ru/practicum/DTO/EventDTO/EventShortDTO.java index 27b021a..76b7778 100644 --- a/evm-service/src/main/java/ru/practicum/DTO/EventDTO/EventShortDTO.java +++ b/evm-service/src/main/java/ru/practicum/DTO/EventDTO/EventShortDTO.java @@ -6,7 +6,7 @@ import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; -import ru.practicum.DTO.CategoryDTO.CategoryDTO; +import ru.practicum.Category.DTO.CategoryDTO; import ru.practicum.User.DTO.UserShortDTO; import java.time.LocalDateTime; diff --git a/evm-service/src/main/java/ru/practicum/DTO/EventDTO/UpdateEventAdminRequest.java b/evm-service/src/main/java/ru/practicum/DTO/EventDTO/UpdateEventAdminRequest.java index 7e06b9b..fcf67bb 100644 --- a/evm-service/src/main/java/ru/practicum/DTO/EventDTO/UpdateEventAdminRequest.java +++ b/evm-service/src/main/java/ru/practicum/DTO/EventDTO/UpdateEventAdminRequest.java @@ -7,7 +7,7 @@ import lombok.Data; import lombok.NoArgsConstructor; import org.hibernate.validator.constraints.Length; -import ru.practicum.DTO.CategoryDTO.CategoryDTO; +import ru.practicum.Category.DTO.CategoryDTO; import ru.practicum.Model.Location; import ru.practicum.Model.State; diff --git a/evm-service/src/main/java/ru/practicum/DTO/EventDTO/UpdateEventUserRequest.java b/evm-service/src/main/java/ru/practicum/DTO/EventDTO/UpdateEventUserRequest.java index ac29eec..1dcf76d 100644 --- a/evm-service/src/main/java/ru/practicum/DTO/EventDTO/UpdateEventUserRequest.java +++ b/evm-service/src/main/java/ru/practicum/DTO/EventDTO/UpdateEventUserRequest.java @@ -7,7 +7,7 @@ import lombok.Data; import lombok.NoArgsConstructor; import org.hibernate.validator.constraints.Length; -import ru.practicum.DTO.CategoryDTO.CategoryDTO; +import ru.practicum.Category.DTO.CategoryDTO; import ru.practicum.Model.Location; import ru.practicum.Model.State; diff --git a/evm-service/src/main/java/ru/practicum/Exception/ConflictException.java b/evm-service/src/main/java/ru/practicum/Exception/ConflictException.java new file mode 100644 index 0000000..cd46f5b --- /dev/null +++ b/evm-service/src/main/java/ru/practicum/Exception/ConflictException.java @@ -0,0 +1,11 @@ +package ru.practicum.Exception; + +public class ConflictException extends RuntimeException { + public ConflictException(String message) { + super(message); + } + + public ConflictException() { + super(); + } +} diff --git a/evm-service/src/main/java/ru/practicum/Exception/ErrorHandler.java b/evm-service/src/main/java/ru/practicum/Exception/ErrorHandler.java index f1e6124..c95a04d 100644 --- a/evm-service/src/main/java/ru/practicum/Exception/ErrorHandler.java +++ b/evm-service/src/main/java/ru/practicum/Exception/ErrorHandler.java @@ -8,6 +8,7 @@ import java.io.PrintWriter; import java.io.StringWriter; +import java.time.LocalDateTime; @RestControllerAdvice @Slf4j @@ -21,7 +22,8 @@ public ErrorResponse handleException(final Exception e) { PrintWriter pw = new PrintWriter(sw); e.printStackTrace(pw); String stackTrace = sw.toString(); - return new ErrorResponse(HttpStatus.INTERNAL_SERVER_ERROR, e.getMessage(), stackTrace); + LocalDateTime timestamp = LocalDateTime.now(); + return new ErrorResponse(HttpStatus.INTERNAL_SERVER_ERROR, e.getMessage(), stackTrace, timestamp); } @ExceptionHandler(ValidationException.class) @@ -32,7 +34,8 @@ public ErrorResponse handleValidationException(final ValidationException e) { PrintWriter pw = new PrintWriter(sw); e.printStackTrace(pw); String stackTrace = sw.toString(); - return new ErrorResponse(HttpStatus.BAD_REQUEST, e.getMessage(), stackTrace); + LocalDateTime timestamp = LocalDateTime.now(); + return new ErrorResponse(HttpStatus.BAD_REQUEST, e.getMessage(), stackTrace, timestamp); } @ExceptionHandler(NotFoundException.class) @@ -43,7 +46,20 @@ public ErrorResponse handleNotFoundException(final NotFoundException e) { PrintWriter pw = new PrintWriter(sw); e.printStackTrace(pw); String stackTrace = sw.toString(); - return new ErrorResponse(HttpStatus.NOT_FOUND, e.getMessage(), stackTrace); + LocalDateTime timestamp = LocalDateTime.now(); + return new ErrorResponse(HttpStatus.NOT_FOUND, e.getMessage(), stackTrace, timestamp); + } + + @ExceptionHandler(ConflictException.class) + @ResponseStatus(HttpStatus.CONFLICT) + public ErrorResponse handleConflictException(final ConflictException e) { + log.error("409 {}", e.getMessage(), e); + StringWriter sw = new StringWriter(); + PrintWriter pw = new PrintWriter(sw); + e.printStackTrace(pw); + String stackTrace = sw.toString(); + LocalDateTime timestamp = LocalDateTime.now(); + return new ErrorResponse(HttpStatus.CONFLICT, e.getMessage(), stackTrace, timestamp); } } diff --git a/evm-service/src/main/java/ru/practicum/Exception/ErrorResponse.java b/evm-service/src/main/java/ru/practicum/Exception/ErrorResponse.java index 886d3de..edff969 100644 --- a/evm-service/src/main/java/ru/practicum/Exception/ErrorResponse.java +++ b/evm-service/src/main/java/ru/practicum/Exception/ErrorResponse.java @@ -1,13 +1,20 @@ package ru.practicum.Exception; +import com.fasterxml.jackson.annotation.JsonFormat; import lombok.AllArgsConstructor; import lombok.Getter; import org.springframework.http.HttpStatus; +import java.time.LocalDateTime; + @Getter @AllArgsConstructor public class ErrorResponse { private HttpStatus status; private String message; private String stackTrace; + + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime timestamp; + } diff --git a/evm-service/src/main/java/ru/practicum/Model/Event.java b/evm-service/src/main/java/ru/practicum/Model/Event.java index f04aa42..98a39dc 100644 --- a/evm-service/src/main/java/ru/practicum/Model/Event.java +++ b/evm-service/src/main/java/ru/practicum/Model/Event.java @@ -4,6 +4,7 @@ import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; +import ru.practicum.Category.Model.Category; import ru.practicum.User.Model.User; import java.time.LocalDateTime; diff --git a/evm-service/src/main/resources/schema.sql b/evm-service/src/main/resources/schema.sql index c250442..9996348 100644 --- a/evm-service/src/main/resources/schema.sql +++ b/evm-service/src/main/resources/schema.sql @@ -12,7 +12,7 @@ CREATE TABLE IF NOT EXISTS locations ( CREATE TABLE IF NOT EXISTS categories ( id INT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, - name CHARACTER VARYING(255) NOT NULL + name CHARACTER VARYING(255) NOT NULL UNIQUE ); CREATE TABLE IF NOT EXISTS compilations ( From 6ccb365587b80a0e6732f1acf4524277bb1aea4c Mon Sep 17 00:00:00 2001 From: NadezhdaTA Date: Thu, 28 Aug 2025 14:29:16 +0400 Subject: [PATCH 14/35] =?UTF-8?q?=D0=A0=D0=B5=D0=B0=D0=BB=D0=B8=D0=B7?= =?UTF-8?q?=D0=BE=D0=B2=D0=B0=D0=BD=D0=B0=20=D1=84=D1=83=D0=BD=D0=BA=D1=86?= =?UTF-8?q?=D0=B8=D0=BE=D0=BD=D0=B0=D0=BB=D1=8C=D0=BD=D0=BE=D1=81=D1=82?= =?UTF-8?q?=D1=8C=20=D0=BF=D0=BE=20=D0=B4=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=B5=D0=BD=D0=B8=D1=8E,=20=D1=83=D0=B4=D0=B0=D0=BB=D0=B5?= =?UTF-8?q?=D0=BD=D0=B8=D1=8E=20=D0=B8=20=D0=BF=D0=BE=D0=BB=D1=83=D1=87?= =?UTF-8?q?=D0=B5=D0=BD=D0=B8=D1=8E=20=D1=81=D0=BE=D0=B1=D1=8B=D1=82=D0=B8?= =?UTF-8?q?=D0=B9,=20=D0=B7=D0=B0=D0=BF=D1=80=D0=BE=D1=81=D0=BE=D0=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../CompilationDTO/CompilationDTO.java | 4 +- .../CompilationDTO/NewCompilationDTO.java | 2 +- .../UpdateCompilationRequest.java | 2 +- .../{ => Compilation}/Model/Compilation.java | 2 +- .../Controller/EventAdminController.java | 31 ++++++ .../Controller/EventPrivateController.java | 35 +++++++ .../EventDTO => Event/DTO}/EventFullDTO.java | 17 +--- .../DTO}/EventRequestStatusUpdateRequest.java | 4 +- .../DTO}/EventRequestStatusUpdateResult.java | 4 +- .../EventDTO => Event/DTO}/EventShortDTO.java | 2 +- .../practicum/Event/DTO/EventsRequestDTO.java | 28 ++++++ .../EventDTO => Event/DTO}/NewEventDTO.java | 9 +- .../DTO}/UpdateEventAdminRequest.java | 16 +-- .../DTO}/UpdateEventUserRequest.java | 16 +-- .../practicum/Event/Mapper/EventMapper.java | 21 ++++ .../ru/practicum/{ => Event}/Model/Event.java | 31 +++--- .../practicum/{ => Event}/Model/Location.java | 12 +-- .../ru/practicum/{ => Event}/Model/State.java | 5 +- .../Event/Repository/EventRepository.java | 14 +++ .../Service/Admin/EventAdminService.java | 13 +++ .../Service/Admin/EventAdminServiceImpl.java | 87 ++++++++++++++++ .../Service/Private/EventPrivateService.java | 13 +++ .../Private/EventPrivateServiceImpl.java | 98 +++++++++++++++++++ .../Controller/RequestPrivateController.java | 36 +++++++ .../Request/Mapper/RequestMapper.java | 18 ++++ .../ru/practicum/Request/Model/Request.java | 37 +++++++ .../Request/Repository/RequestRepository.java | 13 +++ .../RequestDTO}/ParticipationRequestDto.java | 9 +- .../Service/RequestPrivateService.java | 13 +++ .../Service/RequestPrivateServiceImpl.java | 78 +++++++++++++++ evm-service/src/main/resources/schema.sql | 41 +++++++- .../java/ru/practicum/EndpointHitDTO.java | 1 - 32 files changed, 627 insertions(+), 85 deletions(-) rename evm-service/src/main/java/ru/practicum/{DTO => Compilation}/CompilationDTO/CompilationDTO.java (82%) rename evm-service/src/main/java/ru/practicum/{DTO => Compilation}/CompilationDTO/NewCompilationDTO.java (89%) rename evm-service/src/main/java/ru/practicum/{DTO => Compilation}/CompilationDTO/UpdateCompilationRequest.java (88%) rename evm-service/src/main/java/ru/practicum/{ => Compilation}/Model/Compilation.java (92%) create mode 100644 evm-service/src/main/java/ru/practicum/Event/Controller/EventAdminController.java create mode 100644 evm-service/src/main/java/ru/practicum/Event/Controller/EventPrivateController.java rename evm-service/src/main/java/ru/practicum/{DTO/EventDTO => Event/DTO}/EventFullDTO.java (74%) rename evm-service/src/main/java/ru/practicum/{DTO/EventDTO => Event/DTO}/EventRequestStatusUpdateRequest.java (79%) rename evm-service/src/main/java/ru/practicum/{DTO/EventDTO => Event/DTO}/EventRequestStatusUpdateResult.java (74%) rename evm-service/src/main/java/ru/practicum/{DTO/EventDTO => Event/DTO}/EventShortDTO.java (96%) create mode 100644 evm-service/src/main/java/ru/practicum/Event/DTO/EventsRequestDTO.java rename evm-service/src/main/java/ru/practicum/{DTO/EventDTO => Event/DTO}/NewEventDTO.java (82%) rename evm-service/src/main/java/ru/practicum/{DTO/EventDTO => Event/DTO}/UpdateEventAdminRequest.java (68%) rename evm-service/src/main/java/ru/practicum/{DTO/EventDTO => Event/DTO}/UpdateEventUserRequest.java (68%) create mode 100644 evm-service/src/main/java/ru/practicum/Event/Mapper/EventMapper.java rename evm-service/src/main/java/ru/practicum/{ => Event}/Model/Event.java (67%) rename evm-service/src/main/java/ru/practicum/{ => Event}/Model/Location.java (50%) rename evm-service/src/main/java/ru/practicum/{ => Event}/Model/State.java (67%) create mode 100644 evm-service/src/main/java/ru/practicum/Event/Repository/EventRepository.java create mode 100644 evm-service/src/main/java/ru/practicum/Event/Service/Admin/EventAdminService.java create mode 100644 evm-service/src/main/java/ru/practicum/Event/Service/Admin/EventAdminServiceImpl.java create mode 100644 evm-service/src/main/java/ru/practicum/Event/Service/Private/EventPrivateService.java create mode 100644 evm-service/src/main/java/ru/practicum/Event/Service/Private/EventPrivateServiceImpl.java create mode 100644 evm-service/src/main/java/ru/practicum/Request/Controller/RequestPrivateController.java create mode 100644 evm-service/src/main/java/ru/practicum/Request/Mapper/RequestMapper.java create mode 100644 evm-service/src/main/java/ru/practicum/Request/Model/Request.java create mode 100644 evm-service/src/main/java/ru/practicum/Request/Repository/RequestRepository.java rename evm-service/src/main/java/ru/practicum/{DTO/ParticipationDTO => Request/RequestDTO}/ParticipationRequestDto.java (67%) create mode 100644 evm-service/src/main/java/ru/practicum/Request/Service/RequestPrivateService.java create mode 100644 evm-service/src/main/java/ru/practicum/Request/Service/RequestPrivateServiceImpl.java diff --git a/evm-service/src/main/java/ru/practicum/DTO/CompilationDTO/CompilationDTO.java b/evm-service/src/main/java/ru/practicum/Compilation/CompilationDTO/CompilationDTO.java similarity index 82% rename from evm-service/src/main/java/ru/practicum/DTO/CompilationDTO/CompilationDTO.java rename to evm-service/src/main/java/ru/practicum/Compilation/CompilationDTO/CompilationDTO.java index a54eb6d..062239e 100644 --- a/evm-service/src/main/java/ru/practicum/DTO/CompilationDTO/CompilationDTO.java +++ b/evm-service/src/main/java/ru/practicum/Compilation/CompilationDTO/CompilationDTO.java @@ -1,11 +1,11 @@ -package ru.practicum.DTO.CompilationDTO; +package ru.practicum.Compilation.CompilationDTO; import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotNull; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; -import ru.practicum.DTO.EventDTO.EventShortDTO; +import ru.practicum.Event.DTO.EventShortDTO; import java.util.Set; diff --git a/evm-service/src/main/java/ru/practicum/DTO/CompilationDTO/NewCompilationDTO.java b/evm-service/src/main/java/ru/practicum/Compilation/CompilationDTO/NewCompilationDTO.java similarity index 89% rename from evm-service/src/main/java/ru/practicum/DTO/CompilationDTO/NewCompilationDTO.java rename to evm-service/src/main/java/ru/practicum/Compilation/CompilationDTO/NewCompilationDTO.java index 6d04b6b..f41feae 100644 --- a/evm-service/src/main/java/ru/practicum/DTO/CompilationDTO/NewCompilationDTO.java +++ b/evm-service/src/main/java/ru/practicum/Compilation/CompilationDTO/NewCompilationDTO.java @@ -1,4 +1,4 @@ -package ru.practicum.DTO.CompilationDTO; +package ru.practicum.Compilation.CompilationDTO; import jakarta.validation.constraints.NotBlank; import lombok.AllArgsConstructor; diff --git a/evm-service/src/main/java/ru/practicum/DTO/CompilationDTO/UpdateCompilationRequest.java b/evm-service/src/main/java/ru/practicum/Compilation/CompilationDTO/UpdateCompilationRequest.java similarity index 88% rename from evm-service/src/main/java/ru/practicum/DTO/CompilationDTO/UpdateCompilationRequest.java rename to evm-service/src/main/java/ru/practicum/Compilation/CompilationDTO/UpdateCompilationRequest.java index 22b40b6..56663cd 100644 --- a/evm-service/src/main/java/ru/practicum/DTO/CompilationDTO/UpdateCompilationRequest.java +++ b/evm-service/src/main/java/ru/practicum/Compilation/CompilationDTO/UpdateCompilationRequest.java @@ -1,4 +1,4 @@ -package ru.practicum.DTO.CompilationDTO; +package ru.practicum.Compilation.CompilationDTO; import lombok.AllArgsConstructor; import lombok.Data; diff --git a/evm-service/src/main/java/ru/practicum/Model/Compilation.java b/evm-service/src/main/java/ru/practicum/Compilation/Model/Compilation.java similarity index 92% rename from evm-service/src/main/java/ru/practicum/Model/Compilation.java rename to evm-service/src/main/java/ru/practicum/Compilation/Model/Compilation.java index 8a188a8..818eb21 100644 --- a/evm-service/src/main/java/ru/practicum/Model/Compilation.java +++ b/evm-service/src/main/java/ru/practicum/Compilation/Model/Compilation.java @@ -1,4 +1,4 @@ -package ru.practicum.Model; +package ru.practicum.Compilation.Model; import jakarta.persistence.*; import lombok.AllArgsConstructor; diff --git a/evm-service/src/main/java/ru/practicum/Event/Controller/EventAdminController.java b/evm-service/src/main/java/ru/practicum/Event/Controller/EventAdminController.java new file mode 100644 index 0000000..27c3e5b --- /dev/null +++ b/evm-service/src/main/java/ru/practicum/Event/Controller/EventAdminController.java @@ -0,0 +1,31 @@ +package ru.practicum.Event.Controller; + +import lombok.RequiredArgsConstructor; +import org.springframework.http.HttpStatus; +import org.springframework.web.bind.annotation.*; +import ru.practicum.Event.DTO.EventFullDTO; +import ru.practicum.Event.DTO.EventsRequestDTO; +import ru.practicum.Event.DTO.UpdateEventAdminRequest; +import ru.practicum.Event.Service.Admin.EventAdminService; + +import java.util.List; + +@RestController +@RequestMapping("/admin/events") +@RequiredArgsConstructor +public class EventAdminController { + private final EventAdminService eventAdminService; + + @GetMapping + public List getEvents(@ModelAttribute EventsRequestDTO eventsRequestDTO) { + return null; + } + + @PatchMapping("/{eventId}") + @ResponseStatus(HttpStatus.OK) + public EventFullDTO updateEvent(@PathVariable Integer eventId, + @RequestBody UpdateEventAdminRequest request) { + return eventAdminService.updateEvent(eventId, request); + } + +} diff --git a/evm-service/src/main/java/ru/practicum/Event/Controller/EventPrivateController.java b/evm-service/src/main/java/ru/practicum/Event/Controller/EventPrivateController.java new file mode 100644 index 0000000..7836969 --- /dev/null +++ b/evm-service/src/main/java/ru/practicum/Event/Controller/EventPrivateController.java @@ -0,0 +1,35 @@ +package ru.practicum.Event.Controller; + +import jakarta.validation.Valid; +import lombok.RequiredArgsConstructor; +import org.springframework.http.HttpStatus; +import org.springframework.web.bind.annotation.*; +import ru.practicum.Event.DTO.EventFullDTO; +import ru.practicum.Event.DTO.NewEventDTO; +import ru.practicum.Event.DTO.UpdateEventUserRequest; +import ru.practicum.Event.Service.Private.EventPrivateServiceImpl; + +@RestController +@RequestMapping("/users/{userId}/events") +@RequiredArgsConstructor +public class EventPrivateController { + private final EventPrivateServiceImpl eventPrivateService; + + @PostMapping + @ResponseStatus(HttpStatus.CREATED) + public EventFullDTO addEvent(@PathVariable Integer userId, @RequestBody @Valid NewEventDTO event) { + return eventPrivateService.addEvent(userId, event); + } + + @GetMapping("/{eventId}") + public EventFullDTO getEvent(@PathVariable Integer userId, @PathVariable Integer eventId) { + return eventPrivateService.getEvent(userId, eventId); + } + + @PatchMapping("/{eventId}") + public EventFullDTO updateEvent(@PathVariable Integer userId, + @PathVariable Integer eventId, @RequestBody @Valid UpdateEventUserRequest event) { + return eventPrivateService.updateEvent(userId, eventId, event); + } + +} diff --git a/evm-service/src/main/java/ru/practicum/DTO/EventDTO/EventFullDTO.java b/evm-service/src/main/java/ru/practicum/Event/DTO/EventFullDTO.java similarity index 74% rename from evm-service/src/main/java/ru/practicum/DTO/EventDTO/EventFullDTO.java rename to evm-service/src/main/java/ru/practicum/Event/DTO/EventFullDTO.java index 1fd696b..49f5fbf 100644 --- a/evm-service/src/main/java/ru/practicum/DTO/EventDTO/EventFullDTO.java +++ b/evm-service/src/main/java/ru/practicum/Event/DTO/EventFullDTO.java @@ -1,16 +1,13 @@ -package ru.practicum.DTO.EventDTO; +package ru.practicum.Event.DTO; import com.fasterxml.jackson.annotation.JsonFormat; -import jakarta.validation.constraints.NotBlank; -import jakarta.validation.constraints.NotNull; -import jakarta.validation.constraints.Positive; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; import ru.practicum.Category.DTO.CategoryDTO; import ru.practicum.User.DTO.UserShortDTO; -import ru.practicum.Model.Location; -import ru.practicum.Model.State; +import ru.practicum.Event.Model.Location; +import ru.practicum.Event.Model.State; import java.time.LocalDateTime; @@ -20,10 +17,8 @@ public class EventFullDTO { private Integer id; - @NotBlank private String annotation; - @NotNull private CategoryDTO category; private Integer confirmedRequests; @@ -33,20 +28,15 @@ public class EventFullDTO { private String description; - @NotNull @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") private LocalDateTime eventDate; - @NotNull private UserShortDTO initiator; - @NotNull private Location location; - @NotNull private Boolean paid; - @Positive private Integer participantLimit; @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") @@ -56,7 +46,6 @@ public class EventFullDTO { private State state; - @NotBlank private String title; private Integer views; diff --git a/evm-service/src/main/java/ru/practicum/DTO/EventDTO/EventRequestStatusUpdateRequest.java b/evm-service/src/main/java/ru/practicum/Event/DTO/EventRequestStatusUpdateRequest.java similarity index 79% rename from evm-service/src/main/java/ru/practicum/DTO/EventDTO/EventRequestStatusUpdateRequest.java rename to evm-service/src/main/java/ru/practicum/Event/DTO/EventRequestStatusUpdateRequest.java index b48246f..1aab0a3 100644 --- a/evm-service/src/main/java/ru/practicum/DTO/EventDTO/EventRequestStatusUpdateRequest.java +++ b/evm-service/src/main/java/ru/practicum/Event/DTO/EventRequestStatusUpdateRequest.java @@ -1,9 +1,9 @@ -package ru.practicum.DTO.EventDTO; +package ru.practicum.Event.DTO; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; -import ru.practicum.Model.State; +import ru.practicum.Event.Model.State; import java.util.ArrayList; diff --git a/evm-service/src/main/java/ru/practicum/DTO/EventDTO/EventRequestStatusUpdateResult.java b/evm-service/src/main/java/ru/practicum/Event/DTO/EventRequestStatusUpdateResult.java similarity index 74% rename from evm-service/src/main/java/ru/practicum/DTO/EventDTO/EventRequestStatusUpdateResult.java rename to evm-service/src/main/java/ru/practicum/Event/DTO/EventRequestStatusUpdateResult.java index c2604f0..0190350 100644 --- a/evm-service/src/main/java/ru/practicum/DTO/EventDTO/EventRequestStatusUpdateResult.java +++ b/evm-service/src/main/java/ru/practicum/Event/DTO/EventRequestStatusUpdateResult.java @@ -1,9 +1,9 @@ -package ru.practicum.DTO.EventDTO; +package ru.practicum.Event.DTO; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; -import ru.practicum.DTO.ParticipationDTO.ParticipationRequestDto; +import ru.practicum.Request.RequestDTO.ParticipationRequestDto; @Data @NoArgsConstructor diff --git a/evm-service/src/main/java/ru/practicum/DTO/EventDTO/EventShortDTO.java b/evm-service/src/main/java/ru/practicum/Event/DTO/EventShortDTO.java similarity index 96% rename from evm-service/src/main/java/ru/practicum/DTO/EventDTO/EventShortDTO.java rename to evm-service/src/main/java/ru/practicum/Event/DTO/EventShortDTO.java index 76b7778..382329e 100644 --- a/evm-service/src/main/java/ru/practicum/DTO/EventDTO/EventShortDTO.java +++ b/evm-service/src/main/java/ru/practicum/Event/DTO/EventShortDTO.java @@ -1,4 +1,4 @@ -package ru.practicum.DTO.EventDTO; +package ru.practicum.Event.DTO; import com.fasterxml.jackson.annotation.JsonFormat; import jakarta.validation.constraints.NotBlank; diff --git a/evm-service/src/main/java/ru/practicum/Event/DTO/EventsRequestDTO.java b/evm-service/src/main/java/ru/practicum/Event/DTO/EventsRequestDTO.java new file mode 100644 index 0000000..22b5fbc --- /dev/null +++ b/evm-service/src/main/java/ru/practicum/Event/DTO/EventsRequestDTO.java @@ -0,0 +1,28 @@ +package ru.practicum.Event.DTO; + +import com.fasterxml.jackson.annotation.JsonFormat; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import ru.practicum.Event.Model.State; + +import java.time.LocalDateTime; +import java.util.ArrayList; + +@Data +@NoArgsConstructor +@AllArgsConstructor +public class EventsRequestDTO { + private ArrayList users; + private ArrayList states; + private ArrayList categories; + + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime rangeStart; + + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime rangeEnd; + + private Integer from; + private Integer size; +} diff --git a/evm-service/src/main/java/ru/practicum/DTO/EventDTO/NewEventDTO.java b/evm-service/src/main/java/ru/practicum/Event/DTO/NewEventDTO.java similarity index 82% rename from evm-service/src/main/java/ru/practicum/DTO/EventDTO/NewEventDTO.java rename to evm-service/src/main/java/ru/practicum/Event/DTO/NewEventDTO.java index db003f2..4649434 100644 --- a/evm-service/src/main/java/ru/practicum/DTO/EventDTO/NewEventDTO.java +++ b/evm-service/src/main/java/ru/practicum/Event/DTO/NewEventDTO.java @@ -1,6 +1,7 @@ -package ru.practicum.DTO.EventDTO; +package ru.practicum.Event.DTO; import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.annotation.JsonProperty; import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotNull; import jakarta.validation.constraints.Positive; @@ -8,7 +9,7 @@ import lombok.Data; import lombok.NoArgsConstructor; import org.hibernate.validator.constraints.Length; -import ru.practicum.Model.Location; +import ru.practicum.Event.Model.Location; import java.time.LocalDateTime; @@ -20,7 +21,9 @@ public class NewEventDTO { @Length(min = 20, max = 2000) private String annotation; - private Integer category; + @NotNull + @JsonProperty("category") + private Integer categoryId; @NotBlank @Length(min = 20, max = 7000) diff --git a/evm-service/src/main/java/ru/practicum/DTO/EventDTO/UpdateEventAdminRequest.java b/evm-service/src/main/java/ru/practicum/Event/DTO/UpdateEventAdminRequest.java similarity index 68% rename from evm-service/src/main/java/ru/practicum/DTO/EventDTO/UpdateEventAdminRequest.java rename to evm-service/src/main/java/ru/practicum/Event/DTO/UpdateEventAdminRequest.java index fcf67bb..62b9562 100644 --- a/evm-service/src/main/java/ru/practicum/DTO/EventDTO/UpdateEventAdminRequest.java +++ b/evm-service/src/main/java/ru/practicum/Event/DTO/UpdateEventAdminRequest.java @@ -1,15 +1,12 @@ -package ru.practicum.DTO.EventDTO; +package ru.practicum.Event.DTO; import com.fasterxml.jackson.annotation.JsonFormat; -import jakarta.validation.constraints.NotBlank; -import jakarta.validation.constraints.NotNull; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; import org.hibernate.validator.constraints.Length; -import ru.practicum.Category.DTO.CategoryDTO; -import ru.practicum.Model.Location; -import ru.practicum.Model.State; +import ru.practicum.Event.Model.Location; +import ru.practicum.Event.Model.State; import java.time.LocalDateTime; @@ -18,18 +15,14 @@ @AllArgsConstructor public class UpdateEventAdminRequest { - @NotBlank @Length(min = 20, max = 2000) private String annotation; - @NotNull - private CategoryDTO category; + private Integer category; - @NotBlank @Length(min = 20, max = 7000) private String description; - @NotNull @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") private LocalDateTime eventDate; @@ -43,7 +36,6 @@ public class UpdateEventAdminRequest { private State stateAction; - @NotBlank @Length(min = 3, max = 120) private String title; diff --git a/evm-service/src/main/java/ru/practicum/DTO/EventDTO/UpdateEventUserRequest.java b/evm-service/src/main/java/ru/practicum/Event/DTO/UpdateEventUserRequest.java similarity index 68% rename from evm-service/src/main/java/ru/practicum/DTO/EventDTO/UpdateEventUserRequest.java rename to evm-service/src/main/java/ru/practicum/Event/DTO/UpdateEventUserRequest.java index 1dcf76d..80b40d8 100644 --- a/evm-service/src/main/java/ru/practicum/DTO/EventDTO/UpdateEventUserRequest.java +++ b/evm-service/src/main/java/ru/practicum/Event/DTO/UpdateEventUserRequest.java @@ -1,15 +1,12 @@ -package ru.practicum.DTO.EventDTO; +package ru.practicum.Event.DTO; import com.fasterxml.jackson.annotation.JsonFormat; -import jakarta.validation.constraints.NotBlank; -import jakarta.validation.constraints.NotNull; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; import org.hibernate.validator.constraints.Length; -import ru.practicum.Category.DTO.CategoryDTO; -import ru.practicum.Model.Location; -import ru.practicum.Model.State; +import ru.practicum.Event.Model.Location; +import ru.practicum.Event.Model.State; import java.time.LocalDateTime; @@ -18,18 +15,14 @@ @AllArgsConstructor public class UpdateEventUserRequest { - @NotBlank @Length(min = 20, max = 2000) private String annotation; - @NotNull - private CategoryDTO category; + private Integer categoryId; - @NotBlank @Length(min = 20, max = 7000) private String description; - @NotNull @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") private LocalDateTime eventDate; @@ -43,7 +36,6 @@ public class UpdateEventUserRequest { private State stateAction; - @NotBlank @Length(min = 3, max = 120) private String title; } diff --git a/evm-service/src/main/java/ru/practicum/Event/Mapper/EventMapper.java b/evm-service/src/main/java/ru/practicum/Event/Mapper/EventMapper.java new file mode 100644 index 0000000..74afdec --- /dev/null +++ b/evm-service/src/main/java/ru/practicum/Event/Mapper/EventMapper.java @@ -0,0 +1,21 @@ +package ru.practicum.Event.Mapper; + +import org.mapstruct.*; +import ru.practicum.Event.DTO.EventFullDTO; +import ru.practicum.Event.DTO.EventShortDTO; +import ru.practicum.Event.DTO.NewEventDTO; +import ru.practicum.Event.DTO.UpdateEventAdminRequest; +import ru.practicum.Event.Model.Event; + +@Mapper(componentModel = "spring") +public interface EventMapper { + Event toEvent(NewEventDTO event); + + EventShortDTO toEventShortDTO(Event event); + + EventFullDTO toEventFullDTO(Event event); + + @BeanMapping(nullValuePropertyMappingStrategy = NullValuePropertyMappingStrategy.IGNORE) + @Mapping(target = "category", ignore = true) + Event toEvent(UpdateEventAdminRequest request, @MappingTarget Event event); +} diff --git a/evm-service/src/main/java/ru/practicum/Model/Event.java b/evm-service/src/main/java/ru/practicum/Event/Model/Event.java similarity index 67% rename from evm-service/src/main/java/ru/practicum/Model/Event.java rename to evm-service/src/main/java/ru/practicum/Event/Model/Event.java index 98a39dc..66bd240 100644 --- a/evm-service/src/main/java/ru/practicum/Model/Event.java +++ b/evm-service/src/main/java/ru/practicum/Event/Model/Event.java @@ -1,4 +1,4 @@ -package ru.practicum.Model; +package ru.practicum.Event.Model; import jakarta.persistence.*; import lombok.AllArgsConstructor; @@ -12,8 +12,8 @@ @Data @NoArgsConstructor @AllArgsConstructor -//@Entity -//@Table(name = "events") +@Entity +@Table(name = "events") public class Event { @Id @@ -21,44 +21,47 @@ public class Event { @Column(name = "id") private Integer id; + @Column(name = "title") + private String title; + @Column(name = "annotation") private String annotation; @ManyToOne(fetch = FetchType.EAGER) private Category category; - @Column(name = "createdOn") - private LocalDateTime createdOn; + @Column(name = "created_on") + private LocalDateTime createdOn = LocalDateTime.now(); @Column(name = "description") private String description; - @Column(name = "eventDate") + @Column(name = "event_date") private LocalDateTime eventDate; @OneToOne(fetch = FetchType.EAGER) + @JoinColumn(name = "initiator_id") private User initiator; - @OneToOne(fetch = FetchType.EAGER) + @Embedded private Location location; @Column(name = "paid") private Boolean paid; - @Column(name = "participantLimit") + @Column(name = "participant_limit") private Integer participantLimit; - @Column(name = "publishedOn") + @Column(name = "published_on") private LocalDateTime publishedOn; - @Column(name = "requestModeration") + @Column(name = "request_moderation") private Boolean requestModeration; - @OneToOne(fetch = FetchType.EAGER) + @Column(name = "state_id") + @Enumerated(EnumType.ORDINAL) private State state; - - private String title; - + @Column(name = "views") private Integer views; } diff --git a/evm-service/src/main/java/ru/practicum/Model/Location.java b/evm-service/src/main/java/ru/practicum/Event/Model/Location.java similarity index 50% rename from evm-service/src/main/java/ru/practicum/Model/Location.java rename to evm-service/src/main/java/ru/practicum/Event/Model/Location.java index fa7cbec..f97e67e 100644 --- a/evm-service/src/main/java/ru/practicum/Model/Location.java +++ b/evm-service/src/main/java/ru/practicum/Event/Model/Location.java @@ -1,4 +1,4 @@ -package ru.practicum.Model; +package ru.practicum.Event.Model; import jakarta.persistence.*; import lombok.AllArgsConstructor; @@ -8,18 +8,10 @@ @Data @NoArgsConstructor @AllArgsConstructor -@Entity -@Table(name = "locations") +@Embeddable public class Location { - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - @Column(name = "id") - private Integer id; - - @Column(name = "lat") private Float lat; - @Column(name = "lon") private Float lon; } diff --git a/evm-service/src/main/java/ru/practicum/Model/State.java b/evm-service/src/main/java/ru/practicum/Event/Model/State.java similarity index 67% rename from evm-service/src/main/java/ru/practicum/Model/State.java rename to evm-service/src/main/java/ru/practicum/Event/Model/State.java index df6cb69..33b5d70 100644 --- a/evm-service/src/main/java/ru/practicum/Model/State.java +++ b/evm-service/src/main/java/ru/practicum/Event/Model/State.java @@ -1,4 +1,4 @@ -package ru.practicum.Model; +package ru.practicum.Event.Model; public enum State { @@ -9,6 +9,7 @@ public enum State { PUBLISH_EVENT, REJECT_EVENT, CANCEL_REVIEW, - SEND_TO_REVIEW + SEND_TO_REVIEW, + CANCELED } diff --git a/evm-service/src/main/java/ru/practicum/Event/Repository/EventRepository.java b/evm-service/src/main/java/ru/practicum/Event/Repository/EventRepository.java new file mode 100644 index 0000000..9d917d7 --- /dev/null +++ b/evm-service/src/main/java/ru/practicum/Event/Repository/EventRepository.java @@ -0,0 +1,14 @@ +package ru.practicum.Event.Repository; + +import org.springframework.data.jpa.repository.JpaRepository; +import ru.practicum.Event.Model.Event; + +import java.util.List; +import java.util.Optional; + +public interface EventRepository extends JpaRepository { + Optional findEventById(Integer eventId); + + + List findEventsByInitiatorId(Integer initiator_id); +} diff --git a/evm-service/src/main/java/ru/practicum/Event/Service/Admin/EventAdminService.java b/evm-service/src/main/java/ru/practicum/Event/Service/Admin/EventAdminService.java new file mode 100644 index 0000000..15b91d4 --- /dev/null +++ b/evm-service/src/main/java/ru/practicum/Event/Service/Admin/EventAdminService.java @@ -0,0 +1,13 @@ +package ru.practicum.Event.Service.Admin; + +import ru.practicum.Event.DTO.EventFullDTO; +import ru.practicum.Event.DTO.EventsRequestDTO; +import ru.practicum.Event.DTO.UpdateEventAdminRequest; + +import java.util.List; + +public interface EventAdminService { + List getEvents(EventsRequestDTO eventsRequestDTO); + + EventFullDTO updateEvent(Integer eventId, UpdateEventAdminRequest request); +} diff --git a/evm-service/src/main/java/ru/practicum/Event/Service/Admin/EventAdminServiceImpl.java b/evm-service/src/main/java/ru/practicum/Event/Service/Admin/EventAdminServiceImpl.java new file mode 100644 index 0000000..d88773d --- /dev/null +++ b/evm-service/src/main/java/ru/practicum/Event/Service/Admin/EventAdminServiceImpl.java @@ -0,0 +1,87 @@ +package ru.practicum.Event.Service.Admin; + +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import ru.practicum.Category.Repository.CategoryRepository; +import ru.practicum.Event.DTO.EventFullDTO; +import ru.practicum.Event.DTO.EventsRequestDTO; +import ru.practicum.Event.DTO.UpdateEventAdminRequest; +import ru.practicum.Event.Mapper.EventMapper; +import ru.practicum.Event.Model.Event; +import ru.practicum.Event.Model.State; +import ru.practicum.Event.Repository.EventRepository; +import ru.practicum.Exception.ConflictException; + +import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.List; + +@Service +@RequiredArgsConstructor +public class EventAdminServiceImpl implements EventAdminService { + private final EventRepository eventRepository; + private final EventMapper eventMapper; + private final CategoryRepository categoryRepository; + + @Override + public List getEvents(EventsRequestDTO eventsRequestDTO) { + List events = new ArrayList<>(); + List users = eventsRequestDTO.getUsers(); + + for (Integer userId : users) { + List eventsForUser = eventRepository.findEventsByInitiatorId(userId); + events.addAll(eventsForUser); + } + + List states = eventsRequestDTO.getStates(); + List categoryIds = eventsRequestDTO.getCategories(); + + return events.stream() + .filter(event -> states.contains(event.getState())) + .filter(event -> categoryIds.contains(event.getCategory().getId())) + .filter(event -> event.getEventDate().isAfter(eventsRequestDTO.getRangeStart())) + .filter(event -> event.getEventDate().isBefore(eventsRequestDTO.getRangeEnd())) + .map(eventMapper::toEventFullDTO) + .toList(); + + } + + @Override + public EventFullDTO updateEvent(Integer eventId, UpdateEventAdminRequest request) { + Event event = eventRepository.findEventById(eventId) + .orElseThrow(() -> new IllegalArgumentException("Event not found")); + + if (request.getEventDate() != null) { + if (event.getEventDate().isBefore(LocalDateTime.now().plusHours(1))) { + throw new ConflictException("Event date should be 1 horse after creation date"); + } + } + + if (request.getStateAction() != null) { + switch (request.getStateAction()) { + case PUBLISH_EVENT -> { + if (event.getState().equals(State.PENDING)) { + event.setState(State.PUBLISHED); + event.setPublishedOn(LocalDateTime.now()); + eventRepository.save(event); + } else { + throw new ConflictException("Event state should be PENDING"); + } + } + + case REJECT_EVENT -> { + if (!event.getState().equals(State.PUBLISHED)) { + event.setState(State.REJECTED); + eventRepository.save(event); + } else { + throw new ConflictException("Event state should be not PUBLISHED"); + } + } + } + } + + Event updatedEvent = eventMapper.toEvent(request, event); + + return eventMapper.toEventFullDTO(eventRepository.save(updatedEvent)); + } +} diff --git a/evm-service/src/main/java/ru/practicum/Event/Service/Private/EventPrivateService.java b/evm-service/src/main/java/ru/practicum/Event/Service/Private/EventPrivateService.java new file mode 100644 index 0000000..7ea1044 --- /dev/null +++ b/evm-service/src/main/java/ru/practicum/Event/Service/Private/EventPrivateService.java @@ -0,0 +1,13 @@ +package ru.practicum.Event.Service.Private; + +import ru.practicum.Event.DTO.EventFullDTO; +import ru.practicum.Event.DTO.NewEventDTO; +import ru.practicum.Event.DTO.UpdateEventUserRequest; + +public interface EventPrivateService { + EventFullDTO addEvent(Integer userId, NewEventDTO event); + + EventFullDTO getEvent(Integer userId, Integer eventId); + + EventFullDTO updateEvent(Integer userId, Integer eventId, UpdateEventUserRequest event); +} diff --git a/evm-service/src/main/java/ru/practicum/Event/Service/Private/EventPrivateServiceImpl.java b/evm-service/src/main/java/ru/practicum/Event/Service/Private/EventPrivateServiceImpl.java new file mode 100644 index 0000000..6e528b9 --- /dev/null +++ b/evm-service/src/main/java/ru/practicum/Event/Service/Private/EventPrivateServiceImpl.java @@ -0,0 +1,98 @@ +package ru.practicum.Event.Service.Private; + +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import ru.practicum.Category.Model.Category; +import ru.practicum.Category.Repository.CategoryRepository; +import ru.practicum.Event.DTO.EventFullDTO; +import ru.practicum.Event.DTO.NewEventDTO; +import ru.practicum.Event.DTO.UpdateEventUserRequest; +import ru.practicum.Event.Mapper.EventMapper; +import ru.practicum.Event.Model.Event; +import ru.practicum.Event.Repository.EventRepository; +import ru.practicum.Exception.ConflictException; +import ru.practicum.Exception.NotFoundException; +import ru.practicum.User.Model.User; +import ru.practicum.User.Repository.UserRepository; + +import java.time.LocalDateTime; + +import static ru.practicum.Event.Model.State.*; + +@Service +@RequiredArgsConstructor +public class EventPrivateServiceImpl implements EventPrivateService { + private final EventRepository eventRepository; + private final EventMapper eventMapper; + private final UserRepository userRepository; + private final CategoryRepository categoryRepository; + + @Override + public EventFullDTO addEvent(Integer userId, NewEventDTO event) { + User user = checkUser(userId); + Category category = checkCategory(event.getCategoryId()); + + Event newEvent = eventMapper.toEvent(event); + checkDates(newEvent.getCreatedOn(), event.getEventDate()); + newEvent.setInitiator(user); + newEvent.setCategory(category); + newEvent.setState(PENDING); + return eventMapper.toEventFullDTO(eventRepository.save(newEvent)); + } + + @Override + public EventFullDTO getEvent(Integer userId, Integer eventId) { + Event event = checkEvent(eventId); + return eventMapper.toEventFullDTO(event); + } + + @Override + public EventFullDTO updateEvent(Integer userId, Integer eventId, UpdateEventUserRequest event) { + Event eventFound = checkEvent(eventId); + User user = checkUser(userId); + + if (eventFound.getState().equals(PUBLISHED)) { + throw new ConflictException("Event with id " + eventId + " could not be changed"); + } + + if (!userId.equals(eventFound.getInitiator().getId())) { + throw new ConflictException("Initiator id mismatch"); + } + + if (event.getCategoryId() != null) { + Category category = checkCategory(event.getCategoryId()); + eventFound.setCategory(category); + } + + if (event.getEventDate() != null) { + checkDates(eventFound.getCreatedOn(), event.getEventDate()); + eventFound.setEventDate(event.getEventDate()); + } + + eventFound.setState(CANCELED); + + return eventMapper.toEventFullDTO(eventRepository.save(eventFound)); + } + + private void checkDates(LocalDateTime createdOn, LocalDateTime eventDate) { + if (eventDate.isBefore(createdOn) || + eventDate.minusHours(2L).isBefore(createdOn)) { + throw new ConflictException("Event date should be 2 horse after creation date"); + } + } + + private User checkUser(Integer userId) { + return userRepository.findById(userId) + .orElseThrow(() -> new NotFoundException("User with id " + userId + " not found")); + } + + private Category checkCategory(Integer categoryId) { + return categoryRepository.findById(categoryId) + .orElseThrow(() -> new NotFoundException("Category with id " + categoryId + " not found")); + } + + private Event checkEvent(Integer eventId) { + return eventRepository.findEventById(eventId) + .orElseThrow(() -> new NotFoundException("Event with id " + eventId + " not found")); + } +} diff --git a/evm-service/src/main/java/ru/practicum/Request/Controller/RequestPrivateController.java b/evm-service/src/main/java/ru/practicum/Request/Controller/RequestPrivateController.java new file mode 100644 index 0000000..6a18b95 --- /dev/null +++ b/evm-service/src/main/java/ru/practicum/Request/Controller/RequestPrivateController.java @@ -0,0 +1,36 @@ +package ru.practicum.Request.Controller; + +import jakarta.validation.constraints.Positive; +import jakarta.validation.constraints.PositiveOrZero; +import lombok.RequiredArgsConstructor; +import org.springframework.http.HttpStatus; +import org.springframework.web.bind.annotation.*; +import ru.practicum.Request.RequestDTO.ParticipationRequestDto; +import ru.practicum.Request.Service.RequestPrivateServiceImpl; + +import java.util.List; + +@RestController +@RequestMapping("/users/{userId}/requests") +@RequiredArgsConstructor +public class RequestPrivateController { + private final RequestPrivateServiceImpl requestService; + + @PostMapping + @ResponseStatus(HttpStatus.CREATED) + public ParticipationRequestDto addRequest(@PathVariable @Positive Integer userId, + @RequestParam @PositiveOrZero Integer eventId) { + return requestService.addRequest(userId, eventId); + } + + @PatchMapping("/{requestId}/cancel") + public ParticipationRequestDto cancelRequest(@PathVariable @Positive Integer userId, + @PathVariable @Positive Integer requestId) { + return requestService.cancelRequest(userId, requestId); + } + + @GetMapping + List getRequests(@PathVariable @Positive Integer userId) { + return requestService.getRequests(userId); + } +} diff --git a/evm-service/src/main/java/ru/practicum/Request/Mapper/RequestMapper.java b/evm-service/src/main/java/ru/practicum/Request/Mapper/RequestMapper.java new file mode 100644 index 0000000..e232dad --- /dev/null +++ b/evm-service/src/main/java/ru/practicum/Request/Mapper/RequestMapper.java @@ -0,0 +1,18 @@ +package ru.practicum.Request.Mapper; + +import org.mapstruct.Mapper; +import org.mapstruct.Mapping; +import ru.practicum.Request.Model.Request; +import ru.practicum.Request.RequestDTO.ParticipationRequestDto; + +@Mapper(componentModel = "spring") +public interface RequestMapper { + + @Mapping(target = "event", source = "event.id") + @Mapping(target = "requester", source = "requester.id") + ParticipationRequestDto toParticipationRequestDto(Request request); + + @Mapping(target = "event", ignore = true) + @Mapping(target = "requester", ignore = true) + Request toRequest(ParticipationRequestDto participationRequestDto); +} diff --git a/evm-service/src/main/java/ru/practicum/Request/Model/Request.java b/evm-service/src/main/java/ru/practicum/Request/Model/Request.java new file mode 100644 index 0000000..3e5b1d5 --- /dev/null +++ b/evm-service/src/main/java/ru/practicum/Request/Model/Request.java @@ -0,0 +1,37 @@ +package ru.practicum.Request.Model; + +import jakarta.persistence.*; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import ru.practicum.Event.Model.Event; +import ru.practicum.Event.Model.State; +import ru.practicum.User.Model.User; + +import java.time.LocalDateTime; + +@Data +@AllArgsConstructor +@NoArgsConstructor +@Entity +@Table(name = "requests") +public class Request { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "id") + private Integer id; + + @Column(name = "created") + private final LocalDateTime created = LocalDateTime.now(); + + @OneToOne + private Event event; + + @OneToOne(fetch = FetchType.EAGER) + private User requester; + + @Column(name = "state_id") + @Enumerated(EnumType.ORDINAL) + private State status; +} diff --git a/evm-service/src/main/java/ru/practicum/Request/Repository/RequestRepository.java b/evm-service/src/main/java/ru/practicum/Request/Repository/RequestRepository.java new file mode 100644 index 0000000..47c0d47 --- /dev/null +++ b/evm-service/src/main/java/ru/practicum/Request/Repository/RequestRepository.java @@ -0,0 +1,13 @@ +package ru.practicum.Request.Repository; + +import org.springframework.data.jpa.repository.JpaRepository; +import ru.practicum.Request.Model.Request; + +import java.util.List; +import java.util.Optional; + +public interface RequestRepository extends JpaRepository { + Optional findRequestById(Integer requestId); + + List findRequestsByRequester_Id(Integer requesterId); +} diff --git a/evm-service/src/main/java/ru/practicum/DTO/ParticipationDTO/ParticipationRequestDto.java b/evm-service/src/main/java/ru/practicum/Request/RequestDTO/ParticipationRequestDto.java similarity index 67% rename from evm-service/src/main/java/ru/practicum/DTO/ParticipationDTO/ParticipationRequestDto.java rename to evm-service/src/main/java/ru/practicum/Request/RequestDTO/ParticipationRequestDto.java index af4aa16..1e3edc8 100644 --- a/evm-service/src/main/java/ru/practicum/DTO/ParticipationDTO/ParticipationRequestDto.java +++ b/evm-service/src/main/java/ru/practicum/Request/RequestDTO/ParticipationRequestDto.java @@ -1,9 +1,10 @@ -package ru.practicum.DTO.ParticipationDTO; +package ru.practicum.Request.RequestDTO; +import com.fasterxml.jackson.annotation.JsonFormat; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; -import ru.practicum.Model.State; +import ru.practicum.Event.Model.State; import java.time.LocalDateTime; @@ -11,8 +12,12 @@ @NoArgsConstructor @AllArgsConstructor public class ParticipationRequestDto { + private Integer id; + + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") private final LocalDateTime created = LocalDateTime.now(); + private Integer event; private Integer requester; private State status; diff --git a/evm-service/src/main/java/ru/practicum/Request/Service/RequestPrivateService.java b/evm-service/src/main/java/ru/practicum/Request/Service/RequestPrivateService.java new file mode 100644 index 0000000..29be91e --- /dev/null +++ b/evm-service/src/main/java/ru/practicum/Request/Service/RequestPrivateService.java @@ -0,0 +1,13 @@ +package ru.practicum.Request.Service; + +import ru.practicum.Request.RequestDTO.ParticipationRequestDto; + +import java.util.List; + +public interface RequestPrivateService { + ParticipationRequestDto addRequest(Integer userId, Integer eventId); + + ParticipationRequestDto cancelRequest(Integer userId, Integer requestId); + + List getRequests(Integer userId); +} diff --git a/evm-service/src/main/java/ru/practicum/Request/Service/RequestPrivateServiceImpl.java b/evm-service/src/main/java/ru/practicum/Request/Service/RequestPrivateServiceImpl.java new file mode 100644 index 0000000..11af918 --- /dev/null +++ b/evm-service/src/main/java/ru/practicum/Request/Service/RequestPrivateServiceImpl.java @@ -0,0 +1,78 @@ +package ru.practicum.Request.Service; + +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import ru.practicum.Event.Model.Event; +import ru.practicum.Event.Model.State; +import ru.practicum.Event.Repository.EventRepository; +import ru.practicum.Exception.ConflictException; +import ru.practicum.Exception.NotFoundException; +import ru.practicum.Request.Mapper.RequestMapper; +import ru.practicum.Request.Model.Request; +import ru.practicum.Request.Repository.RequestRepository; +import ru.practicum.Request.RequestDTO.ParticipationRequestDto; +import ru.practicum.User.Model.User; +import ru.practicum.User.Repository.UserRepository; + +import java.util.List; + +@Service +@RequiredArgsConstructor +public class RequestPrivateServiceImpl implements RequestPrivateService { + private final RequestRepository requestRepository; + private final EventRepository eventRepository; + private final UserRepository userRepository; + private final RequestMapper requestMapper; + + @Override + public ParticipationRequestDto addRequest(Integer userId, Integer eventId) { + Request request = new Request(); + + Event event = eventRepository.findEventById(eventId) + .orElseThrow(() -> new NotFoundException("Event not found")); + + User user = checkUser(userId); + + if (!event.getState().equals(State.PUBLISHED)) { + throw new ConflictException("Event is not published"); + } else if (event.getInitiator().getId().equals(userId)) { + throw new ConflictException("Requester and initiator could not be the same."); + } + + if (event.getRequestModeration().equals(false)) { + request.setStatus(State.CONFIRMED); + } else { + request.setStatus(State.PENDING); + } + + request.setEvent(event); + request.setRequester(user); + + return requestMapper.toParticipationRequestDto(requestRepository.save(request)); + } + + @Override + public ParticipationRequestDto cancelRequest(Integer userId, Integer requestId) { + Request request = requestRepository.findRequestById(requestId) + .orElseThrow(() -> new NotFoundException("Request with id " + requestId + " not found")); + + checkUser(userId); + + request.setStatus(State.CANCELED); + + return requestMapper.toParticipationRequestDto(requestRepository.save(request)); + } + + @Override + public List getRequests(Integer userId) { + checkUser(userId); + return requestRepository.findRequestsByRequester_Id(userId).stream() + .map(requestMapper::toParticipationRequestDto) + .toList(); + } + + private User checkUser(Integer userId) { + return userRepository.findUserById(userId) + .orElseThrow(() -> new NotFoundException("User with id " + userId + " not found")); + } +} diff --git a/evm-service/src/main/resources/schema.sql b/evm-service/src/main/resources/schema.sql index 9996348..47c6bc2 100644 --- a/evm-service/src/main/resources/schema.sql +++ b/evm-service/src/main/resources/schema.sql @@ -4,20 +4,51 @@ CREATE TABLE IF NOT EXISTS users ( email CHARACTER VARYING(500) NOT NULL UNIQUE ); -CREATE TABLE IF NOT EXISTS locations ( - id INT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, - lat FLOAT, - lon FLOAT -); CREATE TABLE IF NOT EXISTS categories ( id INT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, name CHARACTER VARYING(255) NOT NULL UNIQUE ); +CREATE TABLE IF NOT EXISTS state ( + id INT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, + name CHARACTER VARYING (50) +); + +CREATE TABLE IF NOT EXISTS events ( + id INT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, + title CHARACTER VARYING (200) NOT NULL, + annotation CHARACTER VARYING (5000) NOT NULL, + category_id INT NOT NULL, + created_on TIMESTAMP WITHOUT TIME ZONE, + description CHARACTER VARYING (5000), + event_date TIMESTAMP WITHOUT TIME ZONE NOT NULL, + initiator_id INT NOT NULL, + lat INT NOT NULL, + lon INT NOT NULL, + paid BOOLEAN NOT NULL, + participant_limit INT, + published_on TIMESTAMP WITHOUT TIME ZONE, + request_moderation BOOLEAN, + state_id INT, + views INT, + CONSTRAINT fk_events_to_categories FOREIGN KEY (category_id) REFERENCES categories (id) ON DELETE CASCADE, + CONSTRAINT fk_events_to_users FOREIGN KEY (initiator_id) REFERENCES users (id) ON DELETE CASCADE +); + CREATE TABLE IF NOT EXISTS compilations ( id INT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, pinned BOOLEAN NOT NULL, title VARCHAR NOT NULL ); +CREATE TABLE IF NOT EXISTS requests ( + id INT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, + created TIMESTAMP WITHOUT TIME ZONE, + event_id INT NOT NULL, + requester_id INT NOT NULL, + state_id INT, + CONSTRAINT fk_requests_to_events FOREIGN KEY (event_id) REFERENCES events (id) ON DELETE CASCADE, + CONSTRAINT fk_requests_to_users FOREIGN KEY (requester_id) REFERENCES users (id) ON DELETE CASCADE +); + diff --git a/stat/stat-dto/src/main/java/ru/practicum/EndpointHitDTO.java b/stat/stat-dto/src/main/java/ru/practicum/EndpointHitDTO.java index fc6643a..aa55761 100644 --- a/stat/stat-dto/src/main/java/ru/practicum/EndpointHitDTO.java +++ b/stat/stat-dto/src/main/java/ru/practicum/EndpointHitDTO.java @@ -1,7 +1,6 @@ package ru.practicum; import com.fasterxml.jackson.annotation.JsonFormat; -import com.fasterxml.jackson.annotation.JsonProperty; import jakarta.validation.constraints.NotBlank; import lombok.AllArgsConstructor; import lombok.Data; From d05a6785948cd26511af5af5c32854605d43837e Mon Sep 17 00:00:00 2001 From: NadezhdaTA Date: Fri, 29 Aug 2025 18:47:28 +0400 Subject: [PATCH 15/35] =?UTF-8?q?=D0=A0=D0=B5=D0=B0=D0=BB=D0=B8=D0=B7?= =?UTF-8?q?=D0=BE=D0=B2=D0=B0=D0=BD=D0=B0=20=D1=84=D1=83=D0=BD=D0=BA=D1=86?= =?UTF-8?q?=D0=B8=D0=BE=D0=BD=D0=B0=D0=BB=D1=8C=D0=BD=D0=BE=D1=81=D1=82?= =?UTF-8?q?=D1=8C=20=D0=BF=D0=BE=20=D0=B4=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=B5=D0=BD=D0=B8=D1=8E,=20=D1=83=D0=B4=D0=B0=D0=BB=D0=B5?= =?UTF-8?q?=D0=BD=D0=B8=D1=8E=20=D0=B8=20=D0=BF=D0=BE=D0=BB=D1=83=D1=87?= =?UTF-8?q?=D0=B5=D0=BD=D0=B8=D1=8E=20=D0=BF=D0=BE=D0=B4=D0=B1=D0=BE=D1=80?= =?UTF-8?q?=D0=BE=D0=BA,=20=D1=81=D0=BE=D0=B1=D1=8B=D1=82=D0=B8=D0=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- evm-service/pom.xml | 32 +++++++++ .../Repository/CategoryRepository.java | 3 +- .../CompilationsListRequestParams.java | 10 +++ .../CompilationAdminController.java | 35 ++++++++++ .../CompilationPublicController.java | 26 +++++++ .../Compilation/Mapper/CompilationMapper.java | 18 +++++ .../Compilation/Model/Compilation.java | 15 +++- .../Repository/CompilationRepository.java | 17 +++++ .../Admin/CompilationAdminService.java | 13 ++++ .../Admin/CompilationAdminServiceImpl.java | 65 +++++++++++++++++ .../Public/CompilationPublicService.java | 12 ++++ .../Public/CompilationPublicServiceImpl.java | 41 +++++++++++ .../Controller/EventPrivateController.java | 30 ++++++-- .../Controller/EventPublicController.java | 28 ++++++++ .../Event/DTO/EventPublicParams.java | 31 ++++++++ .../DTO/EventRequestStatusUpdateResult.java | 6 +- .../Event/Repository/EventRepository.java | 12 +++- .../Service/Admin/EventAdminServiceImpl.java | 11 ++- .../Service/Private/EventPrivateService.java | 13 +++- .../Private/EventPrivateServiceImpl.java | 70 ++++++++++++++++++- .../Service/Public/EventPublicService.java | 13 ++++ .../Public/EventPublicServiceImpl.java | 53 ++++++++++++++ .../Request/Repository/RequestRepository.java | 7 +- evm-service/src/main/resources/schema.sql | 7 ++ 24 files changed, 547 insertions(+), 21 deletions(-) create mode 100644 evm-service/src/main/java/ru/practicum/Compilation/CompilationDTO/CompilationsListRequestParams.java create mode 100644 evm-service/src/main/java/ru/practicum/Compilation/Controller/CompilationAdminController.java create mode 100644 evm-service/src/main/java/ru/practicum/Compilation/Controller/CompilationPublicController.java create mode 100644 evm-service/src/main/java/ru/practicum/Compilation/Mapper/CompilationMapper.java create mode 100644 evm-service/src/main/java/ru/practicum/Compilation/Repository/CompilationRepository.java create mode 100644 evm-service/src/main/java/ru/practicum/Compilation/Service/Admin/CompilationAdminService.java create mode 100644 evm-service/src/main/java/ru/practicum/Compilation/Service/Admin/CompilationAdminServiceImpl.java create mode 100644 evm-service/src/main/java/ru/practicum/Compilation/Service/Public/CompilationPublicService.java create mode 100644 evm-service/src/main/java/ru/practicum/Compilation/Service/Public/CompilationPublicServiceImpl.java create mode 100644 evm-service/src/main/java/ru/practicum/Event/Controller/EventPublicController.java create mode 100644 evm-service/src/main/java/ru/practicum/Event/DTO/EventPublicParams.java create mode 100644 evm-service/src/main/java/ru/practicum/Event/Service/Public/EventPublicService.java create mode 100644 evm-service/src/main/java/ru/practicum/Event/Service/Public/EventPublicServiceImpl.java diff --git a/evm-service/pom.xml b/evm-service/pom.xml index 5039d92..635531d 100644 --- a/evm-service/pom.xml +++ b/evm-service/pom.xml @@ -14,6 +14,7 @@ 23 23 + 5.0.0 1.6.3 0.2.0 UTF-8 @@ -41,6 +42,13 @@ spring-boot-starter-validation + + com.querydsl + querydsl-jpa + jakarta + 5.1.0 + + org.postgresql postgresql @@ -110,6 +118,30 @@ + + com.mysema.maven + apt-maven-plugin + 1.1.3 + + + + process + + + target/generated-sources/java + com.querydsl.apt.jpa.JPAAnnotationProcessor + + + + + + com.querydsl + querydsl-apt + jakarta + 5.1.0 + + + org.apache.maven.plugins maven-compiler-plugin diff --git a/evm-service/src/main/java/ru/practicum/Category/Repository/CategoryRepository.java b/evm-service/src/main/java/ru/practicum/Category/Repository/CategoryRepository.java index f1634f8..86f63d7 100644 --- a/evm-service/src/main/java/ru/practicum/Category/Repository/CategoryRepository.java +++ b/evm-service/src/main/java/ru/practicum/Category/Repository/CategoryRepository.java @@ -1,11 +1,12 @@ package ru.practicum.Category.Repository; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.querydsl.QuerydslPredicateExecutor; import ru.practicum.Category.Model.Category; import java.util.Optional; -public interface CategoryRepository extends JpaRepository { +public interface CategoryRepository extends JpaRepository, QuerydslPredicateExecutor { Category save(Category category); void deleteById(Integer id); diff --git a/evm-service/src/main/java/ru/practicum/Compilation/CompilationDTO/CompilationsListRequestParams.java b/evm-service/src/main/java/ru/practicum/Compilation/CompilationDTO/CompilationsListRequestParams.java new file mode 100644 index 0000000..3c42369 --- /dev/null +++ b/evm-service/src/main/java/ru/practicum/Compilation/CompilationDTO/CompilationsListRequestParams.java @@ -0,0 +1,10 @@ +package ru.practicum.Compilation.CompilationDTO; + +import lombok.Data; + +@Data +public class CompilationsListRequestParams { + private Boolean pinned; + private Integer from = 0; + private Integer size = 10; +} diff --git a/evm-service/src/main/java/ru/practicum/Compilation/Controller/CompilationAdminController.java b/evm-service/src/main/java/ru/practicum/Compilation/Controller/CompilationAdminController.java new file mode 100644 index 0000000..b835bac --- /dev/null +++ b/evm-service/src/main/java/ru/practicum/Compilation/Controller/CompilationAdminController.java @@ -0,0 +1,35 @@ +package ru.practicum.Compilation.Controller; + +import lombok.RequiredArgsConstructor; +import org.springframework.http.HttpStatus; +import org.springframework.web.bind.annotation.*; +import ru.practicum.Compilation.CompilationDTO.CompilationDTO; +import ru.practicum.Compilation.CompilationDTO.NewCompilationDTO; +import ru.practicum.Compilation.Service.Admin.CompilationAdminServiceImpl; + +@RestController +@RequestMapping("/admin/compilations") +@RequiredArgsConstructor +public class CompilationAdminController { + private final CompilationAdminServiceImpl compilationService; + + @PostMapping + @ResponseStatus(HttpStatus.CREATED) + public CompilationDTO addCompilation(@RequestBody NewCompilationDTO compilationDTO) { + return compilationService.addCompilation(compilationDTO); + + } + + @DeleteMapping("/{compId}") + @ResponseStatus(HttpStatus.NO_CONTENT) + public void deleteCompilation(@PathVariable Integer compId) { + compilationService.deleteCompilation(compId); + } + + @PatchMapping("/{compId}") + public CompilationDTO updateCompilation(@PathVariable Integer compId, + @RequestBody NewCompilationDTO compilationDTO) { + return compilationService.updateCompilation(compId, compilationDTO); + } + +} diff --git a/evm-service/src/main/java/ru/practicum/Compilation/Controller/CompilationPublicController.java b/evm-service/src/main/java/ru/practicum/Compilation/Controller/CompilationPublicController.java new file mode 100644 index 0000000..81fc643 --- /dev/null +++ b/evm-service/src/main/java/ru/practicum/Compilation/Controller/CompilationPublicController.java @@ -0,0 +1,26 @@ +package ru.practicum.Compilation.Controller; + +import lombok.RequiredArgsConstructor; +import org.springframework.web.bind.annotation.*; +import ru.practicum.Compilation.CompilationDTO.CompilationDTO; +import ru.practicum.Compilation.CompilationDTO.CompilationsListRequestParams; +import ru.practicum.Compilation.Service.Public.CompilationPublicServiceImpl; + +import java.util.List; + +@RestController +@RequestMapping("/compilations") +@RequiredArgsConstructor +public class CompilationPublicController { + private final CompilationPublicServiceImpl compilationService; + + @GetMapping("/{compId}") + public CompilationDTO getCompilation(@PathVariable Integer compId) { + return compilationService.getCompilation(compId); + } + + @GetMapping + public List getCompilations(@ModelAttribute CompilationsListRequestParams params) { + return compilationService.getCompilations(params); + } +} diff --git a/evm-service/src/main/java/ru/practicum/Compilation/Mapper/CompilationMapper.java b/evm-service/src/main/java/ru/practicum/Compilation/Mapper/CompilationMapper.java new file mode 100644 index 0000000..6020c2c --- /dev/null +++ b/evm-service/src/main/java/ru/practicum/Compilation/Mapper/CompilationMapper.java @@ -0,0 +1,18 @@ +package ru.practicum.Compilation.Mapper; + +import org.mapstruct.Mapper; +import org.mapstruct.Mapping; +import ru.practicum.Compilation.CompilationDTO.CompilationDTO; +import ru.practicum.Compilation.CompilationDTO.NewCompilationDTO; +import ru.practicum.Compilation.Model.Compilation; + +@Mapper(componentModel = "spring") +public interface CompilationMapper { + CompilationDTO toDto(Compilation compilation); + + Compilation toCompilation(CompilationDTO dto); + + @Mapping(target = "events", ignore = true) + @Mapping(target = "id", ignore = true) + Compilation toCompilation(NewCompilationDTO compilation); +} diff --git a/evm-service/src/main/java/ru/practicum/Compilation/Model/Compilation.java b/evm-service/src/main/java/ru/practicum/Compilation/Model/Compilation.java index 818eb21..221ebbe 100644 --- a/evm-service/src/main/java/ru/practicum/Compilation/Model/Compilation.java +++ b/evm-service/src/main/java/ru/practicum/Compilation/Model/Compilation.java @@ -4,18 +4,29 @@ import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; +import ru.practicum.Event.Model.Event; + +import java.util.Set; @Data @NoArgsConstructor @AllArgsConstructor -//@Entity -//@Table(name = "compilations") +@Entity +@Table(name = "compilations") public class Compilation { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name = "id") private Integer id; + @ManyToMany + @JoinTable( + name = "compilation_events", + joinColumns = @JoinColumn(name = "compilation_id"), + inverseJoinColumns = @JoinColumn(name = "event_id") + ) + private Set events; + @Column(name = "pinned") private Boolean pinned; diff --git a/evm-service/src/main/java/ru/practicum/Compilation/Repository/CompilationRepository.java b/evm-service/src/main/java/ru/practicum/Compilation/Repository/CompilationRepository.java new file mode 100644 index 0000000..8a4bc5c --- /dev/null +++ b/evm-service/src/main/java/ru/practicum/Compilation/Repository/CompilationRepository.java @@ -0,0 +1,17 @@ +package ru.practicum.Compilation.Repository; + +import org.springframework.data.domain.Page; +import org.springframework.data.jpa.repository.JpaRepository; +import ru.practicum.Compilation.Model.Compilation; + +import org.springframework.data.domain.Pageable; +import java.util.Optional; + +public interface CompilationRepository extends JpaRepository { + + Optional findCompilationById(Integer compId); + + Compilation save(Compilation compilation); + + Page findCompilationByPinned(Boolean pinned, Pageable pageable); +} diff --git a/evm-service/src/main/java/ru/practicum/Compilation/Service/Admin/CompilationAdminService.java b/evm-service/src/main/java/ru/practicum/Compilation/Service/Admin/CompilationAdminService.java new file mode 100644 index 0000000..121a78b --- /dev/null +++ b/evm-service/src/main/java/ru/practicum/Compilation/Service/Admin/CompilationAdminService.java @@ -0,0 +1,13 @@ +package ru.practicum.Compilation.Service.Admin; + +import ru.practicum.Compilation.CompilationDTO.CompilationDTO; +import ru.practicum.Compilation.CompilationDTO.NewCompilationDTO; + + +public interface CompilationAdminService { + CompilationDTO addCompilation(NewCompilationDTO compilationDTO); + + void deleteCompilation(Integer compId); + + CompilationDTO updateCompilation(Integer compId, NewCompilationDTO compilationDTO); +} diff --git a/evm-service/src/main/java/ru/practicum/Compilation/Service/Admin/CompilationAdminServiceImpl.java b/evm-service/src/main/java/ru/practicum/Compilation/Service/Admin/CompilationAdminServiceImpl.java new file mode 100644 index 0000000..445021e --- /dev/null +++ b/evm-service/src/main/java/ru/practicum/Compilation/Service/Admin/CompilationAdminServiceImpl.java @@ -0,0 +1,65 @@ +package ru.practicum.Compilation.Service.Admin; + + +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import ru.practicum.Compilation.CompilationDTO.CompilationDTO; +import ru.practicum.Compilation.CompilationDTO.NewCompilationDTO; +import ru.practicum.Compilation.Mapper.CompilationMapper; +import ru.practicum.Compilation.Model.Compilation; +import ru.practicum.Compilation.Repository.CompilationRepository; +import ru.practicum.Event.Mapper.EventMapper; +import ru.practicum.Event.Model.Event; +import ru.practicum.Event.Repository.EventRepository; +import ru.practicum.Exception.NotFoundException; + +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +@Service +@RequiredArgsConstructor +public class CompilationAdminServiceImpl implements CompilationAdminService { + private final CompilationRepository compilationRepository; + private final EventRepository eventRepository; + private final CompilationMapper compilationMapper; + private final EventMapper eventMapper; + + @Override + public CompilationDTO addCompilation(NewCompilationDTO compilationDTO) { + Compilation compilation = compilationMapper.toCompilation(compilationDTO); + + if (compilationDTO.getEvents() != null) { + Set events = setEvents(compilationDTO.getEvents()); + compilation.setEvents(events); + } + + return compilationMapper.toDto(compilationRepository.save(compilation)); + } + + @Override + public void deleteCompilation(Integer compId) { + compilationRepository.delete(checkCompilation(compId)); + } + + @Override + public CompilationDTO updateCompilation(Integer compId, NewCompilationDTO compilationDTO) { + Compilation compilation = checkCompilation(compId); + + if (compilationDTO.getEvents() != null) { + Set events = setEvents(compilationDTO.getEvents()); + compilation.setEvents(events); + } + + return compilationMapper.toDto(compilationRepository.save(compilation)); + } + + private Compilation checkCompilation(Integer compId) { + return compilationRepository.findCompilationById(compId) + .orElseThrow(() -> new NotFoundException("Compilation with id " + compId + " not found")); + } + + private Set setEvents(List eventIds) { + return new HashSet<>(eventRepository.findEventsByIdIn(eventIds)); + } +} diff --git a/evm-service/src/main/java/ru/practicum/Compilation/Service/Public/CompilationPublicService.java b/evm-service/src/main/java/ru/practicum/Compilation/Service/Public/CompilationPublicService.java new file mode 100644 index 0000000..3b76595 --- /dev/null +++ b/evm-service/src/main/java/ru/practicum/Compilation/Service/Public/CompilationPublicService.java @@ -0,0 +1,12 @@ +package ru.practicum.Compilation.Service.Public; + +import ru.practicum.Compilation.CompilationDTO.CompilationDTO; +import ru.practicum.Compilation.CompilationDTO.CompilationsListRequestParams; + +import java.util.List; + +public interface CompilationPublicService { + CompilationDTO getCompilation(Integer compId); + + List getCompilations(CompilationsListRequestParams params); +} diff --git a/evm-service/src/main/java/ru/practicum/Compilation/Service/Public/CompilationPublicServiceImpl.java b/evm-service/src/main/java/ru/practicum/Compilation/Service/Public/CompilationPublicServiceImpl.java new file mode 100644 index 0000000..e9ca966 --- /dev/null +++ b/evm-service/src/main/java/ru/practicum/Compilation/Service/Public/CompilationPublicServiceImpl.java @@ -0,0 +1,41 @@ +package ru.practicum.Compilation.Service.Public; + +import lombok.RequiredArgsConstructor; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.PageRequest; +import org.springframework.stereotype.Service; +import ru.practicum.Compilation.CompilationDTO.CompilationDTO; +import ru.practicum.Compilation.CompilationDTO.CompilationsListRequestParams; +import ru.practicum.Compilation.Mapper.CompilationMapper; +import ru.practicum.Compilation.Model.Compilation; +import ru.practicum.Compilation.Repository.CompilationRepository; +import ru.practicum.Exception.NotFoundException; + +import java.util.List; + +@Service +@RequiredArgsConstructor +public class CompilationPublicServiceImpl implements CompilationPublicService { + private final CompilationRepository compilationRepository; + private final CompilationMapper compilationMapper; + + @Override + public CompilationDTO getCompilation(Integer compId) { + return compilationMapper.toDto(checkCompilation(compId)); + } + + @Override + public List getCompilations(CompilationsListRequestParams params) { + Pageable pageable = PageRequest.of(params.getFrom(), params.getSize()); + Page compilations = compilationRepository.findCompilationByPinned(params.getPinned(), pageable); + return compilations.getContent().stream() + .map(compilationMapper::toDto) + .toList(); + } + + private Compilation checkCompilation(Integer compId) { + return compilationRepository.findCompilationById(compId) + .orElseThrow(() -> new NotFoundException("Compilation with id " + compId + " not found")); + } +} diff --git a/evm-service/src/main/java/ru/practicum/Event/Controller/EventPrivateController.java b/evm-service/src/main/java/ru/practicum/Event/Controller/EventPrivateController.java index 7836969..35df8ce 100644 --- a/evm-service/src/main/java/ru/practicum/Event/Controller/EventPrivateController.java +++ b/evm-service/src/main/java/ru/practicum/Event/Controller/EventPrivateController.java @@ -4,10 +4,11 @@ import lombok.RequiredArgsConstructor; import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.*; -import ru.practicum.Event.DTO.EventFullDTO; -import ru.practicum.Event.DTO.NewEventDTO; -import ru.practicum.Event.DTO.UpdateEventUserRequest; +import ru.practicum.Event.DTO.*; import ru.practicum.Event.Service.Private.EventPrivateServiceImpl; +import ru.practicum.Request.RequestDTO.ParticipationRequestDto; + +import java.util.List; @RestController @RequestMapping("/users/{userId}/events") @@ -21,6 +22,13 @@ public EventFullDTO addEvent(@PathVariable Integer userId, @RequestBody @Valid N return eventPrivateService.addEvent(userId, event); } + @GetMapping + public List getEvents(@PathVariable Integer userId, + @RequestParam Integer from, + @RequestParam Integer size) { + return eventPrivateService.getEvents(userId, from, size); + } + @GetMapping("/{eventId}") public EventFullDTO getEvent(@PathVariable Integer userId, @PathVariable Integer eventId) { return eventPrivateService.getEvent(userId, eventId); @@ -28,8 +36,22 @@ public EventFullDTO getEvent(@PathVariable Integer userId, @PathVariable Integer @PatchMapping("/{eventId}") public EventFullDTO updateEvent(@PathVariable Integer userId, - @PathVariable Integer eventId, @RequestBody @Valid UpdateEventUserRequest event) { + @PathVariable Integer eventId, + @RequestBody @Valid UpdateEventUserRequest event) { return eventPrivateService.updateEvent(userId, eventId, event); } + @GetMapping("/{eventId}/requests") + public List getUserRequests(@PathVariable Integer userId, + @PathVariable Integer eventId) { + return eventPrivateService.getUserRequests(userId, eventId); + } + + @PatchMapping("/{eventId}/requests") + public EventRequestStatusUpdateResult updateRequests(@RequestBody @Valid EventRequestStatusUpdateRequest request, + @PathVariable Integer userId, + @PathVariable Integer eventId) { + return eventPrivateService.updateRequests(request, userId, eventId); + } + } diff --git a/evm-service/src/main/java/ru/practicum/Event/Controller/EventPublicController.java b/evm-service/src/main/java/ru/practicum/Event/Controller/EventPublicController.java new file mode 100644 index 0000000..09cab3e --- /dev/null +++ b/evm-service/src/main/java/ru/practicum/Event/Controller/EventPublicController.java @@ -0,0 +1,28 @@ +package ru.practicum.Event.Controller; + +import lombok.RequiredArgsConstructor; +import org.springframework.web.bind.annotation.*; +import ru.practicum.Event.DTO.EventFullDTO; +import ru.practicum.Event.DTO.EventPublicParams; +import ru.practicum.Event.DTO.EventShortDTO; +import ru.practicum.Event.Service.Public.EventPublicServiceImpl; + +import java.util.List; + + +@RestController +@RequestMapping("/events") +@RequiredArgsConstructor +public class EventPublicController { + private final EventPublicServiceImpl eventPublicService; + + @GetMapping("/{id}") + public EventFullDTO findEventById(@PathVariable Integer id) { + return eventPublicService.findEventById(id); + } + + @GetMapping + public List findAllEvents(@ModelAttribute EventPublicParams params) { + return eventPublicService.findAllEvents(params); + } +} diff --git a/evm-service/src/main/java/ru/practicum/Event/DTO/EventPublicParams.java b/evm-service/src/main/java/ru/practicum/Event/DTO/EventPublicParams.java new file mode 100644 index 0000000..3d71067 --- /dev/null +++ b/evm-service/src/main/java/ru/practicum/Event/DTO/EventPublicParams.java @@ -0,0 +1,31 @@ +package ru.practicum.Event.DTO; + +import com.fasterxml.jackson.annotation.JsonFormat; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.time.LocalDateTime; +import java.util.ArrayList; + +@Data +@AllArgsConstructor +@NoArgsConstructor +public class EventPublicParams { + private String text; + public ArrayList categories; + private Boolean paid; + + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime rangeStart; + + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime rangeEnd; + + private Boolean onlyAvailable; + + private String sort; + + private Integer from; + private Integer size; +} diff --git a/evm-service/src/main/java/ru/practicum/Event/DTO/EventRequestStatusUpdateResult.java b/evm-service/src/main/java/ru/practicum/Event/DTO/EventRequestStatusUpdateResult.java index 0190350..215b2be 100644 --- a/evm-service/src/main/java/ru/practicum/Event/DTO/EventRequestStatusUpdateResult.java +++ b/evm-service/src/main/java/ru/practicum/Event/DTO/EventRequestStatusUpdateResult.java @@ -5,10 +5,12 @@ import lombok.NoArgsConstructor; import ru.practicum.Request.RequestDTO.ParticipationRequestDto; +import java.util.List; + @Data @NoArgsConstructor @AllArgsConstructor public class EventRequestStatusUpdateResult { - private ParticipationRequestDto confirmedRequests; - private ParticipationRequestDto rejectedRequests; + private List confirmedRequests; + private List rejectedRequests; } diff --git a/evm-service/src/main/java/ru/practicum/Event/Repository/EventRepository.java b/evm-service/src/main/java/ru/practicum/Event/Repository/EventRepository.java index 9d917d7..de06194 100644 --- a/evm-service/src/main/java/ru/practicum/Event/Repository/EventRepository.java +++ b/evm-service/src/main/java/ru/practicum/Event/Repository/EventRepository.java @@ -1,14 +1,20 @@ package ru.practicum.Event.Repository; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.querydsl.QuerydslPredicateExecutor; import ru.practicum.Event.Model.Event; import java.util.List; import java.util.Optional; -public interface EventRepository extends JpaRepository { +public interface EventRepository extends JpaRepository, QuerydslPredicateExecutor { Optional findEventById(Integer eventId); - List findEventsByInitiatorId(Integer initiator_id); -} + + Page getEventByInitiator_Id(Integer initiatorId, Pageable pageable); + + List findEventsByIdIn(List ids); +} \ No newline at end of file diff --git a/evm-service/src/main/java/ru/practicum/Event/Service/Admin/EventAdminServiceImpl.java b/evm-service/src/main/java/ru/practicum/Event/Service/Admin/EventAdminServiceImpl.java index d88773d..2c007f6 100644 --- a/evm-service/src/main/java/ru/practicum/Event/Service/Admin/EventAdminServiceImpl.java +++ b/evm-service/src/main/java/ru/practicum/Event/Service/Admin/EventAdminServiceImpl.java @@ -1,5 +1,6 @@ package ru.practicum.Event.Service.Admin; +import com.querydsl.core.types.dsl.BooleanExpression; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; import ru.practicum.Category.Repository.CategoryRepository; @@ -8,9 +9,12 @@ import ru.practicum.Event.DTO.UpdateEventAdminRequest; import ru.practicum.Event.Mapper.EventMapper; import ru.practicum.Event.Model.Event; +import ru.practicum.Event.Model.QEvent; import ru.practicum.Event.Model.State; import ru.practicum.Event.Repository.EventRepository; import ru.practicum.Exception.ConflictException; +import ru.practicum.User.Model.User; +import ru.practicum.User.Repository.UserRepository; import java.time.LocalDateTime; import java.util.ArrayList; @@ -22,13 +26,14 @@ public class EventAdminServiceImpl implements EventAdminService { private final EventRepository eventRepository; private final EventMapper eventMapper; private final CategoryRepository categoryRepository; + private final UserRepository userRepository; @Override public List getEvents(EventsRequestDTO eventsRequestDTO) { List events = new ArrayList<>(); - List users = eventsRequestDTO.getUsers(); + List users1 = eventsRequestDTO.getUsers(); - for (Integer userId : users) { + for (Integer userId : users1) { List eventsForUser = eventRepository.findEventsByInitiatorId(userId); events.addAll(eventsForUser); } @@ -36,6 +41,8 @@ public List getEvents(EventsRequestDTO eventsRequestDTO) { List states = eventsRequestDTO.getStates(); List categoryIds = eventsRequestDTO.getCategories(); + // BooleanExpression byPaid = QEvent.event.paid.eq(eventsRequestDTO.) + return events.stream() .filter(event -> states.contains(event.getState())) .filter(event -> categoryIds.contains(event.getCategory().getId())) diff --git a/evm-service/src/main/java/ru/practicum/Event/Service/Private/EventPrivateService.java b/evm-service/src/main/java/ru/practicum/Event/Service/Private/EventPrivateService.java index 7ea1044..5ac76da 100644 --- a/evm-service/src/main/java/ru/practicum/Event/Service/Private/EventPrivateService.java +++ b/evm-service/src/main/java/ru/practicum/Event/Service/Private/EventPrivateService.java @@ -1,8 +1,9 @@ package ru.practicum.Event.Service.Private; -import ru.practicum.Event.DTO.EventFullDTO; -import ru.practicum.Event.DTO.NewEventDTO; -import ru.practicum.Event.DTO.UpdateEventUserRequest; +import ru.practicum.Event.DTO.*; +import ru.practicum.Request.RequestDTO.ParticipationRequestDto; + +import java.util.List; public interface EventPrivateService { EventFullDTO addEvent(Integer userId, NewEventDTO event); @@ -10,4 +11,10 @@ public interface EventPrivateService { EventFullDTO getEvent(Integer userId, Integer eventId); EventFullDTO updateEvent(Integer userId, Integer eventId, UpdateEventUserRequest event); + + List getUserRequests(Integer userId, Integer eventId); + + EventRequestStatusUpdateResult updateRequests(EventRequestStatusUpdateRequest request, Integer userId, Integer eventId); + + List getEvents(Integer userId, Integer from, Integer size); } diff --git a/evm-service/src/main/java/ru/practicum/Event/Service/Private/EventPrivateServiceImpl.java b/evm-service/src/main/java/ru/practicum/Event/Service/Private/EventPrivateServiceImpl.java index 6e528b9..f490a9f 100644 --- a/evm-service/src/main/java/ru/practicum/Event/Service/Private/EventPrivateServiceImpl.java +++ b/evm-service/src/main/java/ru/practicum/Event/Service/Private/EventPrivateServiceImpl.java @@ -1,21 +1,28 @@ package ru.practicum.Event.Service.Private; import lombok.RequiredArgsConstructor; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.Pageable; import org.springframework.stereotype.Service; import ru.practicum.Category.Model.Category; import ru.practicum.Category.Repository.CategoryRepository; -import ru.practicum.Event.DTO.EventFullDTO; -import ru.practicum.Event.DTO.NewEventDTO; -import ru.practicum.Event.DTO.UpdateEventUserRequest; +import ru.practicum.Event.DTO.*; import ru.practicum.Event.Mapper.EventMapper; import ru.practicum.Event.Model.Event; import ru.practicum.Event.Repository.EventRepository; import ru.practicum.Exception.ConflictException; import ru.practicum.Exception.NotFoundException; +import ru.practicum.Request.Mapper.RequestMapper; +import ru.practicum.Request.Model.Request; +import ru.practicum.Request.Repository.RequestRepository; +import ru.practicum.Request.RequestDTO.ParticipationRequestDto; import ru.practicum.User.Model.User; import ru.practicum.User.Repository.UserRepository; import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.List; import static ru.practicum.Event.Model.State.*; @@ -26,6 +33,8 @@ public class EventPrivateServiceImpl implements EventPrivateService { private final EventMapper eventMapper; private final UserRepository userRepository; private final CategoryRepository categoryRepository; + private final RequestRepository requestRepository; + private final RequestMapper requestMapper; @Override public EventFullDTO addEvent(Integer userId, NewEventDTO event) { @@ -74,6 +83,61 @@ public EventFullDTO updateEvent(Integer userId, Integer eventId, UpdateEventUser return eventMapper.toEventFullDTO(eventRepository.save(eventFound)); } + @Override + public List getUserRequests(Integer userId, Integer eventId) { + checkUser(userId); + checkEvent(eventId); + + return requestRepository.findRequestsByEvent_IdAndEvent_Initiator_Id(eventId, userId).stream() + .map(requestMapper::toParticipationRequestDto) + .toList(); + } + + @Override + public EventRequestStatusUpdateResult updateRequests(EventRequestStatusUpdateRequest request, + Integer userId, Integer eventId) { + Event event = checkEvent(eventId); + checkUser(userId); + List requests = requestRepository.findAllById(request.getRequestIds()); + List allRequests = requestRepository.findRequestsByEvent_Id(eventId); + + List confirmedRequests = new ArrayList<>(); + List rejectedRequests = new ArrayList<>(); + + for (Request request1 : requests) { + if (event.getState().equals(PUBLISHED)) { + if (event.getParticipantLimit() != null) { + + if (allRequests.size() < event.getParticipantLimit()) { + request1.setStatus(CONFIRMED); + requestRepository.save(request1); + confirmedRequests.add(requestMapper.toParticipationRequestDto(request1)); + } else { + request1.setStatus(REJECTED); + requestRepository.save(request1); + confirmedRequests.add(requestMapper.toParticipationRequestDto(request1)); + throw new ConflictException("Participation limit exceeded"); + } + } + } else { + throw new ConflictException("Event Status should be PUBLISHED"); + } + } + + return new EventRequestStatusUpdateResult(confirmedRequests, rejectedRequests); + + } + + @Override + public List getEvents(Integer userId, Integer from, Integer size) { + checkUser(userId); + Pageable pageable = PageRequest.of(from, size); + Page events = eventRepository.getEventByInitiator_Id(userId, pageable); + return events.getContent().stream() + .map(eventMapper::toEventShortDTO) + .toList(); + } + private void checkDates(LocalDateTime createdOn, LocalDateTime eventDate) { if (eventDate.isBefore(createdOn) || eventDate.minusHours(2L).isBefore(createdOn)) { diff --git a/evm-service/src/main/java/ru/practicum/Event/Service/Public/EventPublicService.java b/evm-service/src/main/java/ru/practicum/Event/Service/Public/EventPublicService.java new file mode 100644 index 0000000..a67f3a9 --- /dev/null +++ b/evm-service/src/main/java/ru/practicum/Event/Service/Public/EventPublicService.java @@ -0,0 +1,13 @@ +package ru.practicum.Event.Service.Public; + +import ru.practicum.Event.DTO.EventFullDTO; +import ru.practicum.Event.DTO.EventPublicParams; +import ru.practicum.Event.DTO.EventShortDTO; + +import java.util.List; + +public interface EventPublicService { + EventFullDTO findEventById(Integer id); + + List findAllEvents(EventPublicParams params); +} diff --git a/evm-service/src/main/java/ru/practicum/Event/Service/Public/EventPublicServiceImpl.java b/evm-service/src/main/java/ru/practicum/Event/Service/Public/EventPublicServiceImpl.java new file mode 100644 index 0000000..c07c2b5 --- /dev/null +++ b/evm-service/src/main/java/ru/practicum/Event/Service/Public/EventPublicServiceImpl.java @@ -0,0 +1,53 @@ +package ru.practicum.Event.Service.Public; + +import com.querydsl.core.types.dsl.BooleanExpression; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import ru.practicum.Category.Model.Category; +import ru.practicum.Category.Repository.CategoryRepository; +import ru.practicum.Event.DTO.EventFullDTO; +import ru.practicum.Event.DTO.EventPublicParams; +import ru.practicum.Event.DTO.EventShortDTO; +import ru.practicum.Event.Mapper.EventMapper; +import ru.practicum.Event.Model.Event; +import ru.practicum.Event.Model.QEvent; +import ru.practicum.Event.Repository.EventRepository; +import ru.practicum.Exception.NotFoundException; +import ru.practicum.Request.Model.QRequest; +import ru.practicum.Request.Repository.RequestRepository; + +import java.util.List; + +@Service +@RequiredArgsConstructor +public class EventPublicServiceImpl implements EventPublicService { + private final EventRepository eventRepository; + private final EventMapper eventMapper; + private final CategoryRepository categoryRepository; + private final RequestRepository requestRepository; + + @Override + public EventFullDTO findEventById(Integer id) { + Event event = eventRepository.findById(id) + .orElseThrow(() -> new NotFoundException("Event with id " + id + " not found")); + return eventMapper.toEventFullDTO(event); + } + + @Override + public List findAllEvents(EventPublicParams params) { + List categories = categoryRepository.findAllById(params.getCategories()); + + + BooleanExpression byPaid = QEvent.event.paid.eq(params.getPaid()); + + /* List events = eventRepository.findAll(byPaid + .and(QEvent.event.description.contains(params.getText())) + .and(QEvent.event.eventDate.between(params.getRangeStart(), params.getRangeEnd())) + .and(QEvent.event.category.in(categories)) + .and(QEvent.event.participantLimit) + .orderedBy(params.getSort()) + .pageble(params.getFrom(), params.getSize()) + );*/ + return List.of(); + } +} diff --git a/evm-service/src/main/java/ru/practicum/Request/Repository/RequestRepository.java b/evm-service/src/main/java/ru/practicum/Request/Repository/RequestRepository.java index 47c0d47..7a887da 100644 --- a/evm-service/src/main/java/ru/practicum/Request/Repository/RequestRepository.java +++ b/evm-service/src/main/java/ru/practicum/Request/Repository/RequestRepository.java @@ -1,13 +1,18 @@ package ru.practicum.Request.Repository; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.JpaSpecificationExecutor; import ru.practicum.Request.Model.Request; import java.util.List; import java.util.Optional; -public interface RequestRepository extends JpaRepository { +public interface RequestRepository extends JpaRepository, JpaSpecificationExecutor { Optional findRequestById(Integer requestId); List findRequestsByRequester_Id(Integer requesterId); + + List findRequestsByEvent_IdAndEvent_Initiator_Id(Integer eventId, Integer eventInitiatorId); + + List findRequestsByEvent_Id(Integer eventId); } diff --git a/evm-service/src/main/resources/schema.sql b/evm-service/src/main/resources/schema.sql index 47c6bc2..995e81a 100644 --- a/evm-service/src/main/resources/schema.sql +++ b/evm-service/src/main/resources/schema.sql @@ -52,3 +52,10 @@ CREATE TABLE IF NOT EXISTS requests ( CONSTRAINT fk_requests_to_users FOREIGN KEY (requester_id) REFERENCES users (id) ON DELETE CASCADE ); +CREATE TABLE IF NOT EXISTS compilation_events ( + compilation_id INT NOT NULL, + event_id INT NOT NULL, + CONSTRAINT fk_compilation_events_to_compilations FOREIGN KEY (compilation_id) REFERENCES compilations (id) ON DELETE CASCADE, + CONSTRAINT fk_compilation_events_to_events FOREIGN KEY (event_id) REFERENCES events (id) ON DELETE CASCADE +); + From 2917476e791cf53367e0f94745224921967d2061 Mon Sep 17 00:00:00 2001 From: NadezhdaTA Date: Sun, 31 Aug 2025 19:48:31 +0400 Subject: [PATCH 16/35] =?UTF-8?q?=D0=A0=D0=B5=D0=B0=D0=BB=D0=B8=D0=B7?= =?UTF-8?q?=D0=BE=D0=B2=D0=B0=D0=BD=20=D0=B2=D1=81=D0=B5=20=D1=8D=D0=BD?= =?UTF-8?q?=D0=B4=D0=BF=D0=BE=D0=B8=D0=BD=D1=82=D1=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- evm-service/pom.xml | 32 +------ .../Controller/CategoryPublicController.java | 4 +- .../Repository/CategoryRepository.java | 3 +- .../Admin/CategoryAdminServiceImpl.java | 11 +++ .../CompilationDTO/NewCompilationDTO.java | 2 +- .../CompilationAdminController.java | 6 +- .../Admin/CompilationAdminService.java | 3 +- .../Admin/CompilationAdminServiceImpl.java | 3 +- .../Controller/EventAdminController.java | 9 +- .../Controller/EventPrivateController.java | 6 +- .../Controller/EventPublicController.java | 11 ++- .../Event/DTO/EventPublicParams.java | 19 ++-- .../practicum/Event/DTO/EventsRequestDTO.java | 28 ------ .../ru/practicum/Event/DTO/NewEventDTO.java | 13 ++- .../practicum/Event/DTO/SearchEventsDTO.java | 33 +++++++ .../Event/DTO/UpdateEventAdminRequest.java | 2 + .../Event/DTO/UpdateEventUserRequest.java | 2 + .../java/ru/practicum/Event/Model/Event.java | 5 +- .../Event/Repository/EventRepository.java | 12 ++- .../Service/Admin/EventAdminService.java | 4 +- .../Service/Admin/EventAdminServiceImpl.java | 69 ++++++++++---- .../Private/EventPrivateServiceImpl.java | 54 +++++++---- .../Service/Public/EventPublicService.java | 5 +- .../Public/EventPublicServiceImpl.java | 94 +++++++++++++++---- .../ru/practicum/Exception/ErrorHandler.java | 27 +++++- .../practicum/Exception/UniqueException.java | 10 ++ .../Controller/RequestPrivateController.java | 3 +- .../Request/Repository/RequestRepository.java | 8 +- .../Service/RequestPrivateServiceImpl.java | 14 ++- .../src/main/resources/application.yml | 5 +- evm-service/src/main/resources/schema.sql | 12 ++- .../main/java/ru/practicum/StatsClient.java | 11 ++- 32 files changed, 345 insertions(+), 175 deletions(-) delete mode 100644 evm-service/src/main/java/ru/practicum/Event/DTO/EventsRequestDTO.java create mode 100644 evm-service/src/main/java/ru/practicum/Event/DTO/SearchEventsDTO.java create mode 100644 evm-service/src/main/java/ru/practicum/Exception/UniqueException.java diff --git a/evm-service/pom.xml b/evm-service/pom.xml index 635531d..3d6ab9f 100644 --- a/evm-service/pom.xml +++ b/evm-service/pom.xml @@ -42,13 +42,6 @@ spring-boot-starter-validation - - com.querydsl - querydsl-jpa - jakarta - 5.1.0 - - org.postgresql postgresql @@ -118,30 +111,7 @@ - - com.mysema.maven - apt-maven-plugin - 1.1.3 - - - - process - - - target/generated-sources/java - com.querydsl.apt.jpa.JPAAnnotationProcessor - - - - - - com.querydsl - querydsl-apt - jakarta - 5.1.0 - - - + org.apache.maven.plugins maven-compiler-plugin diff --git a/evm-service/src/main/java/ru/practicum/Category/Controller/CategoryPublicController.java b/evm-service/src/main/java/ru/practicum/Category/Controller/CategoryPublicController.java index 57abb54..65cbea9 100644 --- a/evm-service/src/main/java/ru/practicum/Category/Controller/CategoryPublicController.java +++ b/evm-service/src/main/java/ru/practicum/Category/Controller/CategoryPublicController.java @@ -21,8 +21,8 @@ public CategoryDTO getCategory(@PathVariable Integer catId) { } @GetMapping - public List getCategories(@RequestParam @PositiveOrZero Integer from, - @RequestParam @Positive Integer size) { + public List getCategories(@RequestParam(defaultValue = "0") @PositiveOrZero Integer from, + @RequestParam(defaultValue = "10") @Positive Integer size) { return categoryService.getCategories(from, size); } } diff --git a/evm-service/src/main/java/ru/practicum/Category/Repository/CategoryRepository.java b/evm-service/src/main/java/ru/practicum/Category/Repository/CategoryRepository.java index 86f63d7..f1634f8 100644 --- a/evm-service/src/main/java/ru/practicum/Category/Repository/CategoryRepository.java +++ b/evm-service/src/main/java/ru/practicum/Category/Repository/CategoryRepository.java @@ -1,12 +1,11 @@ package ru.practicum.Category.Repository; import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.data.querydsl.QuerydslPredicateExecutor; import ru.practicum.Category.Model.Category; import java.util.Optional; -public interface CategoryRepository extends JpaRepository, QuerydslPredicateExecutor { +public interface CategoryRepository extends JpaRepository { Category save(Category category); void deleteById(Integer id); diff --git a/evm-service/src/main/java/ru/practicum/Category/Service/Admin/CategoryAdminServiceImpl.java b/evm-service/src/main/java/ru/practicum/Category/Service/Admin/CategoryAdminServiceImpl.java index 7abede9..3e55fdf 100644 --- a/evm-service/src/main/java/ru/practicum/Category/Service/Admin/CategoryAdminServiceImpl.java +++ b/evm-service/src/main/java/ru/practicum/Category/Service/Admin/CategoryAdminServiceImpl.java @@ -7,13 +7,19 @@ import ru.practicum.Category.Mapper.CategoryMapper; import ru.practicum.Category.Model.Category; import ru.practicum.Category.Repository.CategoryRepository; +import ru.practicum.Event.Model.Event; +import ru.practicum.Event.Repository.EventRepository; +import ru.practicum.Exception.ConflictException; import ru.practicum.Exception.NotFoundException; +import java.util.List; + @Service @RequiredArgsConstructor public class CategoryAdminServiceImpl implements CategoryAdminService { private final CategoryMapper categoryMapper; private final CategoryRepository repository; + private final EventRepository eventRepository; @Override public CategoryDTO addCategory(NewCategoryDTO newCategory) { @@ -26,6 +32,11 @@ public void deleteCategory(Integer catId) { Category category = repository.findById(catId) .orElseThrow(() -> new NotFoundException("Category with id " + catId + " not found")); + List events = eventRepository.findEventsByCategory_Id(catId); + if (!events.isEmpty()) { + throw new ConflictException("Category with id " + catId + " has connected events"); + } + // Integer categoryEvents = repository.deleteById(catId); diff --git a/evm-service/src/main/java/ru/practicum/Compilation/CompilationDTO/NewCompilationDTO.java b/evm-service/src/main/java/ru/practicum/Compilation/CompilationDTO/NewCompilationDTO.java index f41feae..fb7be3a 100644 --- a/evm-service/src/main/java/ru/practicum/Compilation/CompilationDTO/NewCompilationDTO.java +++ b/evm-service/src/main/java/ru/practicum/Compilation/CompilationDTO/NewCompilationDTO.java @@ -13,7 +13,7 @@ @AllArgsConstructor public class NewCompilationDTO { private ArrayList events; - private Boolean pinned; + private Boolean pinned = false; @NotBlank @Length(min = 1, max = 50) diff --git a/evm-service/src/main/java/ru/practicum/Compilation/Controller/CompilationAdminController.java b/evm-service/src/main/java/ru/practicum/Compilation/Controller/CompilationAdminController.java index b835bac..24c1cf8 100644 --- a/evm-service/src/main/java/ru/practicum/Compilation/Controller/CompilationAdminController.java +++ b/evm-service/src/main/java/ru/practicum/Compilation/Controller/CompilationAdminController.java @@ -1,10 +1,12 @@ package ru.practicum.Compilation.Controller; +import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.*; import ru.practicum.Compilation.CompilationDTO.CompilationDTO; import ru.practicum.Compilation.CompilationDTO.NewCompilationDTO; +import ru.practicum.Compilation.CompilationDTO.UpdateCompilationRequest; import ru.practicum.Compilation.Service.Admin.CompilationAdminServiceImpl; @RestController @@ -15,7 +17,7 @@ public class CompilationAdminController { @PostMapping @ResponseStatus(HttpStatus.CREATED) - public CompilationDTO addCompilation(@RequestBody NewCompilationDTO compilationDTO) { + public CompilationDTO addCompilation(@RequestBody @Valid NewCompilationDTO compilationDTO) { return compilationService.addCompilation(compilationDTO); } @@ -28,7 +30,7 @@ public void deleteCompilation(@PathVariable Integer compId) { @PatchMapping("/{compId}") public CompilationDTO updateCompilation(@PathVariable Integer compId, - @RequestBody NewCompilationDTO compilationDTO) { + @RequestBody @Valid UpdateCompilationRequest compilationDTO) { return compilationService.updateCompilation(compId, compilationDTO); } diff --git a/evm-service/src/main/java/ru/practicum/Compilation/Service/Admin/CompilationAdminService.java b/evm-service/src/main/java/ru/practicum/Compilation/Service/Admin/CompilationAdminService.java index 121a78b..71b3a9e 100644 --- a/evm-service/src/main/java/ru/practicum/Compilation/Service/Admin/CompilationAdminService.java +++ b/evm-service/src/main/java/ru/practicum/Compilation/Service/Admin/CompilationAdminService.java @@ -2,6 +2,7 @@ import ru.practicum.Compilation.CompilationDTO.CompilationDTO; import ru.practicum.Compilation.CompilationDTO.NewCompilationDTO; +import ru.practicum.Compilation.CompilationDTO.UpdateCompilationRequest; public interface CompilationAdminService { @@ -9,5 +10,5 @@ public interface CompilationAdminService { void deleteCompilation(Integer compId); - CompilationDTO updateCompilation(Integer compId, NewCompilationDTO compilationDTO); + CompilationDTO updateCompilation(Integer compId, UpdateCompilationRequest compilationDTO); } diff --git a/evm-service/src/main/java/ru/practicum/Compilation/Service/Admin/CompilationAdminServiceImpl.java b/evm-service/src/main/java/ru/practicum/Compilation/Service/Admin/CompilationAdminServiceImpl.java index 445021e..764c182 100644 --- a/evm-service/src/main/java/ru/practicum/Compilation/Service/Admin/CompilationAdminServiceImpl.java +++ b/evm-service/src/main/java/ru/practicum/Compilation/Service/Admin/CompilationAdminServiceImpl.java @@ -5,6 +5,7 @@ import org.springframework.stereotype.Service; import ru.practicum.Compilation.CompilationDTO.CompilationDTO; import ru.practicum.Compilation.CompilationDTO.NewCompilationDTO; +import ru.practicum.Compilation.CompilationDTO.UpdateCompilationRequest; import ru.practicum.Compilation.Mapper.CompilationMapper; import ru.practicum.Compilation.Model.Compilation; import ru.practicum.Compilation.Repository.CompilationRepository; @@ -43,7 +44,7 @@ public void deleteCompilation(Integer compId) { } @Override - public CompilationDTO updateCompilation(Integer compId, NewCompilationDTO compilationDTO) { + public CompilationDTO updateCompilation(Integer compId, UpdateCompilationRequest compilationDTO) { Compilation compilation = checkCompilation(compId); if (compilationDTO.getEvents() != null) { diff --git a/evm-service/src/main/java/ru/practicum/Event/Controller/EventAdminController.java b/evm-service/src/main/java/ru/practicum/Event/Controller/EventAdminController.java index 27c3e5b..24f166c 100644 --- a/evm-service/src/main/java/ru/practicum/Event/Controller/EventAdminController.java +++ b/evm-service/src/main/java/ru/practicum/Event/Controller/EventAdminController.java @@ -1,10 +1,11 @@ package ru.practicum.Event.Controller; +import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.*; import ru.practicum.Event.DTO.EventFullDTO; -import ru.practicum.Event.DTO.EventsRequestDTO; +import ru.practicum.Event.DTO.SearchEventsDTO; import ru.practicum.Event.DTO.UpdateEventAdminRequest; import ru.practicum.Event.Service.Admin.EventAdminService; @@ -17,14 +18,14 @@ public class EventAdminController { private final EventAdminService eventAdminService; @GetMapping - public List getEvents(@ModelAttribute EventsRequestDTO eventsRequestDTO) { - return null; + public List getEvents(@ModelAttribute @Valid SearchEventsDTO dto) { + return eventAdminService.getEvents(dto); } @PatchMapping("/{eventId}") @ResponseStatus(HttpStatus.OK) public EventFullDTO updateEvent(@PathVariable Integer eventId, - @RequestBody UpdateEventAdminRequest request) { + @RequestBody @Valid UpdateEventAdminRequest request) { return eventAdminService.updateEvent(eventId, request); } diff --git a/evm-service/src/main/java/ru/practicum/Event/Controller/EventPrivateController.java b/evm-service/src/main/java/ru/practicum/Event/Controller/EventPrivateController.java index 35df8ce..fb82c2c 100644 --- a/evm-service/src/main/java/ru/practicum/Event/Controller/EventPrivateController.java +++ b/evm-service/src/main/java/ru/practicum/Event/Controller/EventPrivateController.java @@ -1,6 +1,8 @@ package ru.practicum.Event.Controller; import jakarta.validation.Valid; +import jakarta.validation.constraints.Positive; +import jakarta.validation.constraints.PositiveOrZero; import lombok.RequiredArgsConstructor; import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.*; @@ -24,8 +26,8 @@ public EventFullDTO addEvent(@PathVariable Integer userId, @RequestBody @Valid N @GetMapping public List getEvents(@PathVariable Integer userId, - @RequestParam Integer from, - @RequestParam Integer size) { + @RequestParam(defaultValue = "0") @PositiveOrZero Integer from, + @RequestParam(defaultValue = "10") @Positive Integer size) { return eventPrivateService.getEvents(userId, from, size); } diff --git a/evm-service/src/main/java/ru/practicum/Event/Controller/EventPublicController.java b/evm-service/src/main/java/ru/practicum/Event/Controller/EventPublicController.java index 09cab3e..d559408 100644 --- a/evm-service/src/main/java/ru/practicum/Event/Controller/EventPublicController.java +++ b/evm-service/src/main/java/ru/practicum/Event/Controller/EventPublicController.java @@ -1,5 +1,7 @@ package ru.practicum.Event.Controller; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; import org.springframework.web.bind.annotation.*; import ru.practicum.Event.DTO.EventFullDTO; @@ -17,12 +19,13 @@ public class EventPublicController { private final EventPublicServiceImpl eventPublicService; @GetMapping("/{id}") - public EventFullDTO findEventById(@PathVariable Integer id) { - return eventPublicService.findEventById(id); + public EventFullDTO findEventById(@PathVariable Integer id, HttpServletRequest request) { + return eventPublicService.findEventById(id, request); } @GetMapping - public List findAllEvents(@ModelAttribute EventPublicParams params) { - return eventPublicService.findAllEvents(params); + public List findAllEvents(@ModelAttribute @Valid EventPublicParams params, + HttpServletRequest request) { + return eventPublicService.findAllEvents(params, request); } } diff --git a/evm-service/src/main/java/ru/practicum/Event/DTO/EventPublicParams.java b/evm-service/src/main/java/ru/practicum/Event/DTO/EventPublicParams.java index 3d71067..cf1d19b 100644 --- a/evm-service/src/main/java/ru/practicum/Event/DTO/EventPublicParams.java +++ b/evm-service/src/main/java/ru/practicum/Event/DTO/EventPublicParams.java @@ -1,9 +1,11 @@ package ru.practicum.Event.DTO; -import com.fasterxml.jackson.annotation.JsonFormat; +import jakarta.validation.constraints.Positive; +import jakarta.validation.constraints.PositiveOrZero; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; +import org.springframework.format.annotation.DateTimeFormat; import java.time.LocalDateTime; import java.util.ArrayList; @@ -16,16 +18,19 @@ public class EventPublicParams { public ArrayList categories; private Boolean paid; - @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") private LocalDateTime rangeStart; - @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") private LocalDateTime rangeEnd; - private Boolean onlyAvailable; + private Boolean onlyAvailable = false; - private String sort; + private String sort = "EVENT_DATE"; - private Integer from; - private Integer size; + @PositiveOrZero + private Integer from = 0; + + @Positive + private Integer size = 10; } diff --git a/evm-service/src/main/java/ru/practicum/Event/DTO/EventsRequestDTO.java b/evm-service/src/main/java/ru/practicum/Event/DTO/EventsRequestDTO.java deleted file mode 100644 index 22b5fbc..0000000 --- a/evm-service/src/main/java/ru/practicum/Event/DTO/EventsRequestDTO.java +++ /dev/null @@ -1,28 +0,0 @@ -package ru.practicum.Event.DTO; - -import com.fasterxml.jackson.annotation.JsonFormat; -import lombok.AllArgsConstructor; -import lombok.Data; -import lombok.NoArgsConstructor; -import ru.practicum.Event.Model.State; - -import java.time.LocalDateTime; -import java.util.ArrayList; - -@Data -@NoArgsConstructor -@AllArgsConstructor -public class EventsRequestDTO { - private ArrayList users; - private ArrayList states; - private ArrayList categories; - - @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") - private LocalDateTime rangeStart; - - @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") - private LocalDateTime rangeEnd; - - private Integer from; - private Integer size; -} diff --git a/evm-service/src/main/java/ru/practicum/Event/DTO/NewEventDTO.java b/evm-service/src/main/java/ru/practicum/Event/DTO/NewEventDTO.java index 4649434..f92438a 100644 --- a/evm-service/src/main/java/ru/practicum/Event/DTO/NewEventDTO.java +++ b/evm-service/src/main/java/ru/practicum/Event/DTO/NewEventDTO.java @@ -2,9 +2,7 @@ import com.fasterxml.jackson.annotation.JsonFormat; import com.fasterxml.jackson.annotation.JsonProperty; -import jakarta.validation.constraints.NotBlank; -import jakarta.validation.constraints.NotNull; -import jakarta.validation.constraints.Positive; +import jakarta.validation.constraints.*; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; @@ -30,18 +28,19 @@ public class NewEventDTO { private String description; @NotNull + @Future @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") private LocalDateTime eventDate; @NotNull private Location location; - private Boolean paid; + private Boolean paid = false; - @Positive - private Integer participantLimit; + @PositiveOrZero + private Integer participantLimit = 0; - private Boolean requestModeration; + private Boolean requestModeration = true; @NotBlank @Length(min = 3, max = 120) diff --git a/evm-service/src/main/java/ru/practicum/Event/DTO/SearchEventsDTO.java b/evm-service/src/main/java/ru/practicum/Event/DTO/SearchEventsDTO.java new file mode 100644 index 0000000..2f7a25f --- /dev/null +++ b/evm-service/src/main/java/ru/practicum/Event/DTO/SearchEventsDTO.java @@ -0,0 +1,33 @@ +package ru.practicum.Event.DTO; + +import jakarta.validation.constraints.Positive; +import jakarta.validation.constraints.PositiveOrZero; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.springframework.format.annotation.DateTimeFormat; +import ru.practicum.Event.Model.State; + +import java.time.LocalDateTime; +import java.util.List; + +@Data +@AllArgsConstructor +@NoArgsConstructor +public class SearchEventsDTO { + private List users; + private List states; + private List categories; + + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime rangeStart = LocalDateTime.now(); + + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime rangeEnd; + + @PositiveOrZero + private Integer from = 0; + + @Positive + private Integer size = 10; +} diff --git a/evm-service/src/main/java/ru/practicum/Event/DTO/UpdateEventAdminRequest.java b/evm-service/src/main/java/ru/practicum/Event/DTO/UpdateEventAdminRequest.java index 62b9562..823a3a6 100644 --- a/evm-service/src/main/java/ru/practicum/Event/DTO/UpdateEventAdminRequest.java +++ b/evm-service/src/main/java/ru/practicum/Event/DTO/UpdateEventAdminRequest.java @@ -1,6 +1,7 @@ package ru.practicum.Event.DTO; import com.fasterxml.jackson.annotation.JsonFormat; +import jakarta.validation.constraints.Future; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; @@ -23,6 +24,7 @@ public class UpdateEventAdminRequest { @Length(min = 20, max = 7000) private String description; + @Future @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") private LocalDateTime eventDate; diff --git a/evm-service/src/main/java/ru/practicum/Event/DTO/UpdateEventUserRequest.java b/evm-service/src/main/java/ru/practicum/Event/DTO/UpdateEventUserRequest.java index 80b40d8..37ee576 100644 --- a/evm-service/src/main/java/ru/practicum/Event/DTO/UpdateEventUserRequest.java +++ b/evm-service/src/main/java/ru/practicum/Event/DTO/UpdateEventUserRequest.java @@ -1,6 +1,7 @@ package ru.practicum.Event.DTO; import com.fasterxml.jackson.annotation.JsonFormat; +import jakarta.validation.constraints.Positive; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; @@ -30,6 +31,7 @@ public class UpdateEventUserRequest { private Boolean paid; + @Positive private Integer participantLimit; private Boolean requestModeration; diff --git a/evm-service/src/main/java/ru/practicum/Event/Model/Event.java b/evm-service/src/main/java/ru/practicum/Event/Model/Event.java index 66bd240..35f91ad 100644 --- a/evm-service/src/main/java/ru/practicum/Event/Model/Event.java +++ b/evm-service/src/main/java/ru/practicum/Event/Model/Event.java @@ -30,6 +30,9 @@ public class Event { @ManyToOne(fetch = FetchType.EAGER) private Category category; + @Column(name = "confirmed_requests") + private Integer confirmedRequests = 0; + @Column(name = "created_on") private LocalDateTime createdOn = LocalDateTime.now(); @@ -63,5 +66,5 @@ public class Event { private State state; @Column(name = "views") - private Integer views; + private Integer views = 0; } diff --git a/evm-service/src/main/java/ru/practicum/Event/Repository/EventRepository.java b/evm-service/src/main/java/ru/practicum/Event/Repository/EventRepository.java index de06194..22782e2 100644 --- a/evm-service/src/main/java/ru/practicum/Event/Repository/EventRepository.java +++ b/evm-service/src/main/java/ru/practicum/Event/Repository/EventRepository.java @@ -2,19 +2,25 @@ import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; +import org.springframework.data.jpa.domain.Specification; import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.data.querydsl.QuerydslPredicateExecutor; import ru.practicum.Event.Model.Event; +import ru.practicum.Event.Model.State; import java.util.List; import java.util.Optional; -public interface EventRepository extends JpaRepository, QuerydslPredicateExecutor { +public interface EventRepository extends JpaRepository { Optional findEventById(Integer eventId); - List findEventsByInitiatorId(Integer initiator_id); + Optional findEventsByIdAndState(Integer id, State state); Page getEventByInitiator_Id(Integer initiatorId, Pageable pageable); List findEventsByIdIn(List ids); + + List findEventsByCategory_Id(Integer categoryId); + + Page findAll(Specification spec, Pageable pageable); + } \ No newline at end of file diff --git a/evm-service/src/main/java/ru/practicum/Event/Service/Admin/EventAdminService.java b/evm-service/src/main/java/ru/practicum/Event/Service/Admin/EventAdminService.java index 15b91d4..1b4a0c9 100644 --- a/evm-service/src/main/java/ru/practicum/Event/Service/Admin/EventAdminService.java +++ b/evm-service/src/main/java/ru/practicum/Event/Service/Admin/EventAdminService.java @@ -1,13 +1,13 @@ package ru.practicum.Event.Service.Admin; import ru.practicum.Event.DTO.EventFullDTO; -import ru.practicum.Event.DTO.EventsRequestDTO; +import ru.practicum.Event.DTO.SearchEventsDTO; import ru.practicum.Event.DTO.UpdateEventAdminRequest; import java.util.List; public interface EventAdminService { - List getEvents(EventsRequestDTO eventsRequestDTO); + List getEvents(SearchEventsDTO searchEventsDTO); EventFullDTO updateEvent(Integer eventId, UpdateEventAdminRequest request); } diff --git a/evm-service/src/main/java/ru/practicum/Event/Service/Admin/EventAdminServiceImpl.java b/evm-service/src/main/java/ru/practicum/Event/Service/Admin/EventAdminServiceImpl.java index 2c007f6..880f9b5 100644 --- a/evm-service/src/main/java/ru/practicum/Event/Service/Admin/EventAdminServiceImpl.java +++ b/evm-service/src/main/java/ru/practicum/Event/Service/Admin/EventAdminServiceImpl.java @@ -1,24 +1,25 @@ package ru.practicum.Event.Service.Admin; -import com.querydsl.core.types.dsl.BooleanExpression; import lombok.RequiredArgsConstructor; +import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.Pageable; +import org.springframework.data.jpa.domain.Specification; import org.springframework.stereotype.Service; import ru.practicum.Category.Repository.CategoryRepository; import ru.practicum.Event.DTO.EventFullDTO; -import ru.practicum.Event.DTO.EventsRequestDTO; +import ru.practicum.Event.DTO.SearchEventsDTO; import ru.practicum.Event.DTO.UpdateEventAdminRequest; import ru.practicum.Event.Mapper.EventMapper; import ru.practicum.Event.Model.Event; -import ru.practicum.Event.Model.QEvent; import ru.practicum.Event.Model.State; import ru.practicum.Event.Repository.EventRepository; import ru.practicum.Exception.ConflictException; -import ru.practicum.User.Model.User; +import ru.practicum.Exception.ValidationException; import ru.practicum.User.Repository.UserRepository; import java.time.LocalDateTime; -import java.util.ArrayList; import java.util.List; +import java.util.Objects; @Service @RequiredArgsConstructor @@ -29,28 +30,21 @@ public class EventAdminServiceImpl implements EventAdminService { private final UserRepository userRepository; @Override - public List getEvents(EventsRequestDTO eventsRequestDTO) { - List events = new ArrayList<>(); - List users1 = eventsRequestDTO.getUsers(); - - for (Integer userId : users1) { - List eventsForUser = eventRepository.findEventsByInitiatorId(userId); - events.addAll(eventsForUser); + public List getEvents(SearchEventsDTO dto) { + if (dto.getRangeStart() != null || dto.getRangeEnd() != null) { + if (dto.getRangeStart().isAfter(dto.getRangeEnd())) { + throw new ValidationException("Range start is after range end"); + } } - List states = eventsRequestDTO.getStates(); - List categoryIds = eventsRequestDTO.getCategories(); + Specification spec = getEventSpecification(dto); + Pageable pageable = PageRequest.of(dto.getFrom(), dto.getSize()); - // BooleanExpression byPaid = QEvent.event.paid.eq(eventsRequestDTO.) + List events = eventRepository.findAll(spec, pageable).getContent(); return events.stream() - .filter(event -> states.contains(event.getState())) - .filter(event -> categoryIds.contains(event.getCategory().getId())) - .filter(event -> event.getEventDate().isAfter(eventsRequestDTO.getRangeStart())) - .filter(event -> event.getEventDate().isBefore(eventsRequestDTO.getRangeEnd())) .map(eventMapper::toEventFullDTO) .toList(); - } @Override @@ -91,4 +85,39 @@ public EventFullDTO updateEvent(Integer eventId, UpdateEventAdminRequest request return eventMapper.toEventFullDTO(eventRepository.save(updatedEvent)); } + + private Specification getEventSpecification(SearchEventsDTO event) { + Specification spec = Specification.where(null); + + if (Objects.nonNull(event.getUsers()) && !event.getUsers().isEmpty()) { + spec = spec.and((root, query, cb) -> root.get("initiator").get("id").in( + event.getUsers().stream().filter(Objects::nonNull).toList())); + } + + if (Objects.nonNull(event.getCategories() ) && !event.getCategories().isEmpty()) { + spec = spec.and((root, query, builder) -> + root.get("category").get("id").in(event.getCategories().stream() + .filter(Objects::nonNull) + .toList())); + } + + if (Objects.nonNull(event.getStates() ) && !event.getStates().isEmpty()) { + spec = spec.and((root, query, cb) -> + root.get("state").in(event.getStates().stream() + .filter(Objects::nonNull) + .toList())); + } + + if (Objects.nonNull(event.getRangeStart())) { + spec = spec.and((root, query, cb) -> + cb.greaterThanOrEqualTo(root.get("eventDate"), event.getRangeStart())); + } + + if (Objects.nonNull(event.getRangeEnd())) { + spec = spec.and((root, query, cb) -> + cb.lessThanOrEqualTo(root.get("eventDate"), event.getRangeEnd())); + } + + return spec; + } } diff --git a/evm-service/src/main/java/ru/practicum/Event/Service/Private/EventPrivateServiceImpl.java b/evm-service/src/main/java/ru/practicum/Event/Service/Private/EventPrivateServiceImpl.java index f490a9f..d5c52bb 100644 --- a/evm-service/src/main/java/ru/practicum/Event/Service/Private/EventPrivateServiceImpl.java +++ b/evm-service/src/main/java/ru/practicum/Event/Service/Private/EventPrivateServiceImpl.java @@ -13,6 +13,7 @@ import ru.practicum.Event.Repository.EventRepository; import ru.practicum.Exception.ConflictException; import ru.practicum.Exception.NotFoundException; +import ru.practicum.Exception.ValidationException; import ru.practicum.Request.Mapper.RequestMapper; import ru.practicum.Request.Model.Request; import ru.practicum.Request.Repository.RequestRepository; @@ -23,6 +24,7 @@ import java.time.LocalDateTime; import java.util.ArrayList; import java.util.List; +import java.util.Objects; import static ru.practicum.Event.Model.State.*; @@ -52,6 +54,7 @@ public EventFullDTO addEvent(Integer userId, NewEventDTO event) { @Override public EventFullDTO getEvent(Integer userId, Integer eventId) { Event event = checkEvent(eventId); + int confirmedRequests = requestRepository.findRequestsByEvent_IdAndStatus(eventId, CONFIRMED).size(); return eventMapper.toEventFullDTO(event); } @@ -64,6 +67,13 @@ public EventFullDTO updateEvent(Integer userId, Integer eventId, UpdateEventUser throw new ConflictException("Event with id " + eventId + " could not be changed"); } + if (event.getStateAction() != null) { + switch (event.getStateAction()) { + case CANCEL_REVIEW -> eventFound.setState(CANCELED); + case SEND_TO_REVIEW -> eventFound.setState(PENDING); + } + } + if (!userId.equals(eventFound.getInitiator().getId())) { throw new ConflictException("Initiator id mismatch"); } @@ -78,8 +88,6 @@ public EventFullDTO updateEvent(Integer userId, Integer eventId, UpdateEventUser eventFound.setEventDate(event.getEventDate()); } - eventFound.setState(CANCELED); - return eventMapper.toEventFullDTO(eventRepository.save(eventFound)); } @@ -96,36 +104,42 @@ public List getUserRequests(Integer userId, Integer eve @Override public EventRequestStatusUpdateResult updateRequests(EventRequestStatusUpdateRequest request, Integer userId, Integer eventId) { - Event event = checkEvent(eventId); checkUser(userId); + Event event = checkEvent(eventId); List requests = requestRepository.findAllById(request.getRequestIds()); - List allRequests = requestRepository.findRequestsByEvent_Id(eventId); + + if (Objects.equals(event.getParticipantLimit(), event.getConfirmedRequests())) { + throw new ConflictException("ConfirmedRequests limit exceeded"); + } List confirmedRequests = new ArrayList<>(); List rejectedRequests = new ArrayList<>(); for (Request request1 : requests) { - if (event.getState().equals(PUBLISHED)) { - if (event.getParticipantLimit() != null) { - - if (allRequests.size() < event.getParticipantLimit()) { - request1.setStatus(CONFIRMED); - requestRepository.save(request1); - confirmedRequests.add(requestMapper.toParticipationRequestDto(request1)); - } else { - request1.setStatus(REJECTED); - requestRepository.save(request1); - confirmedRequests.add(requestMapper.toParticipationRequestDto(request1)); - throw new ConflictException("Participation limit exceeded"); - } + if (!request1.getStatus().equals(PENDING)) { + throw new ConflictException("States should be PENDING"); + } + + if (request.getStatus().equals(CONFIRMED)) { + if (event.getParticipantLimit() > event.getConfirmedRequests()) { + request1.setStatus(CONFIRMED); + requestRepository.save(request1); + confirmedRequests.add(requestMapper.toParticipationRequestDto(request1)); + event.setConfirmedRequests(event.getConfirmedRequests() + 1); + eventRepository.save(event); + } else { + request1.setStatus(REJECTED); + requestRepository.save(request1); + rejectedRequests.add(requestMapper.toParticipationRequestDto(request1)); } } else { - throw new ConflictException("Event Status should be PUBLISHED"); + request1.setStatus(REJECTED); + requestRepository.save(request1); + rejectedRequests.add(requestMapper.toParticipationRequestDto(request1)); } } return new EventRequestStatusUpdateResult(confirmedRequests, rejectedRequests); - } @Override @@ -141,7 +155,7 @@ public List getEvents(Integer userId, Integer from, Integer size) private void checkDates(LocalDateTime createdOn, LocalDateTime eventDate) { if (eventDate.isBefore(createdOn) || eventDate.minusHours(2L).isBefore(createdOn)) { - throw new ConflictException("Event date should be 2 horse after creation date"); + throw new ValidationException("Event date should be 2 horse after creation date"); } } diff --git a/evm-service/src/main/java/ru/practicum/Event/Service/Public/EventPublicService.java b/evm-service/src/main/java/ru/practicum/Event/Service/Public/EventPublicService.java index a67f3a9..db38b40 100644 --- a/evm-service/src/main/java/ru/practicum/Event/Service/Public/EventPublicService.java +++ b/evm-service/src/main/java/ru/practicum/Event/Service/Public/EventPublicService.java @@ -1,5 +1,6 @@ package ru.practicum.Event.Service.Public; +import jakarta.servlet.http.HttpServletRequest; import ru.practicum.Event.DTO.EventFullDTO; import ru.practicum.Event.DTO.EventPublicParams; import ru.practicum.Event.DTO.EventShortDTO; @@ -7,7 +8,7 @@ import java.util.List; public interface EventPublicService { - EventFullDTO findEventById(Integer id); + EventFullDTO findEventById(Integer id, HttpServletRequest request); - List findAllEvents(EventPublicParams params); + List findAllEvents(EventPublicParams params, HttpServletRequest request); } diff --git a/evm-service/src/main/java/ru/practicum/Event/Service/Public/EventPublicServiceImpl.java b/evm-service/src/main/java/ru/practicum/Event/Service/Public/EventPublicServiceImpl.java index c07c2b5..43e57cd 100644 --- a/evm-service/src/main/java/ru/practicum/Event/Service/Public/EventPublicServiceImpl.java +++ b/evm-service/src/main/java/ru/practicum/Event/Service/Public/EventPublicServiceImpl.java @@ -1,22 +1,32 @@ package ru.practicum.Event.Service.Public; -import com.querydsl.core.types.dsl.BooleanExpression; +import jakarta.persistence.criteria.Root; +import jakarta.persistence.criteria.Subquery; +import jakarta.servlet.http.HttpServletRequest; import lombok.RequiredArgsConstructor; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Sort; +import org.springframework.data.jpa.domain.Specification; import org.springframework.stereotype.Service; -import ru.practicum.Category.Model.Category; import ru.practicum.Category.Repository.CategoryRepository; import ru.practicum.Event.DTO.EventFullDTO; import ru.practicum.Event.DTO.EventPublicParams; import ru.practicum.Event.DTO.EventShortDTO; import ru.practicum.Event.Mapper.EventMapper; import ru.practicum.Event.Model.Event; -import ru.practicum.Event.Model.QEvent; +import ru.practicum.Event.Model.State; import ru.practicum.Event.Repository.EventRepository; import ru.practicum.Exception.NotFoundException; -import ru.practicum.Request.Model.QRequest; +import ru.practicum.Exception.ValidationException; +import ru.practicum.Request.Model.Request; import ru.practicum.Request.Repository.RequestRepository; +import ru.practicum.StatsClient; import java.util.List; +import java.util.Objects; + @Service @RequiredArgsConstructor @@ -25,29 +35,77 @@ public class EventPublicServiceImpl implements EventPublicService { private final EventMapper eventMapper; private final CategoryRepository categoryRepository; private final RequestRepository requestRepository; + private final StatsClient statsClient; @Override - public EventFullDTO findEventById(Integer id) { - Event event = eventRepository.findById(id) + public EventFullDTO findEventById(Integer id, HttpServletRequest request) { + Event event = eventRepository.findEventsByIdAndState(id, State.PUBLISHED) .orElseThrow(() -> new NotFoundException("Event with id " + id + " not found")); + + event.setViews(event.getViews() + 1); + eventRepository.save(event); + return eventMapper.toEventFullDTO(event); } @Override - public List findAllEvents(EventPublicParams params) { - List categories = categoryRepository.findAllById(params.getCategories()); + public List findAllEvents(EventPublicParams params, HttpServletRequest request) { + if (params.getRangeStart() != null || params.getRangeEnd() != null) { + if (params.getRangeStart().isAfter(params.getRangeEnd())) { + throw new ValidationException("Range start is after range end"); + } + } + Specification spec = eventSpecification(params); + Sort sort = null; + + switch (params.getSort()) { + case "EVENT_DATE" -> sort = Sort.by(Sort.Direction.DESC, "eventDate"); + case "VIEWS" -> sort = Sort.by(Sort.Direction.ASC, "views"); + } + + Pageable pageable = PageRequest.of(params.getFrom(), params.getSize(), sort); + + Page events = eventRepository.findAll(spec, pageable); + + return events.getContent().stream() + .map(eventMapper::toEventShortDTO) + .toList(); + } + + private Specification eventSpecification(EventPublicParams params) { + Specification spec = Specification.where(null); + + if (Objects.nonNull(params.getText()) && !params.getText().isBlank()) { + String search = "%" + params.getText().toLowerCase() + "%"; + spec = spec.and((root, query, cb) -> + cb.or( + cb.like(cb.lower(root.get("annotation")), search), + cb.like(cb.lower(root.get("description")), search) + )); + } + + if (Objects.nonNull(params.getCategories() ) && !params.getCategories().isEmpty()) { + spec = spec.and((root, query, builder) -> + root.get("category").get("id").in(params.getCategories().stream().filter(Objects::nonNull).toList())); + } + + if (Objects.nonNull(params.getPaid())) { + spec = spec.and((root, query, cb) -> + cb.equal(root.get("paid"), params.getPaid())); + } + if (Objects.nonNull(params.getOnlyAvailable())) { + spec = spec.and((root, query, cb) -> { + assert query != null; + Subquery subquery = query.subquery(Long.class); + Root requestRoot = subquery.from(Request.class); + subquery.select(cb.count(requestRoot.get("id"))) + .where(cb.equal(requestRoot.get("event"), root)); - BooleanExpression byPaid = QEvent.event.paid.eq(params.getPaid()); + return cb.greaterThan(root.get("participantLimit"), subquery); + }); + } - /* List events = eventRepository.findAll(byPaid - .and(QEvent.event.description.contains(params.getText())) - .and(QEvent.event.eventDate.between(params.getRangeStart(), params.getRangeEnd())) - .and(QEvent.event.category.in(categories)) - .and(QEvent.event.participantLimit) - .orderedBy(params.getSort()) - .pageble(params.getFrom(), params.getSize()) - );*/ - return List.of(); + return spec; } } diff --git a/evm-service/src/main/java/ru/practicum/Exception/ErrorHandler.java b/evm-service/src/main/java/ru/practicum/Exception/ErrorHandler.java index c95a04d..86810f2 100644 --- a/evm-service/src/main/java/ru/practicum/Exception/ErrorHandler.java +++ b/evm-service/src/main/java/ru/practicum/Exception/ErrorHandler.java @@ -1,7 +1,9 @@ package ru.practicum.Exception; import lombok.extern.slf4j.Slf4j; +import org.springframework.dao.DataIntegrityViolationException; import org.springframework.http.HttpStatus; +import org.springframework.web.bind.MissingServletRequestParameterException; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.ResponseStatus; import org.springframework.web.bind.annotation.RestControllerAdvice; @@ -16,7 +18,7 @@ public class ErrorHandler { @ExceptionHandler @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR) - public ErrorResponse handleException(final Exception e) { + public ErrorResponse handleException(final RuntimeException e) { log.error("500 {}", e.getMessage(), e); StringWriter sw = new StringWriter(); PrintWriter pw = new PrintWriter(sw); @@ -62,4 +64,27 @@ public ErrorResponse handleConflictException(final ConflictException e) { return new ErrorResponse(HttpStatus.CONFLICT, e.getMessage(), stackTrace, timestamp); } + @ExceptionHandler(MissingServletRequestParameterException.class) + @ResponseStatus(HttpStatus.BAD_REQUEST) + public ErrorResponse handleMissingPathVariableException(final MissingServletRequestParameterException e) { + log.error("400 {}", e.getMessage(), e); + StringWriter sw = new StringWriter(); + PrintWriter pw = new PrintWriter(sw); + e.printStackTrace(pw); + String stackTrace = sw.toString(); + LocalDateTime timestamp = LocalDateTime.now(); + return new ErrorResponse(HttpStatus.BAD_REQUEST, e.getMessage(), stackTrace, timestamp); + } + + @ExceptionHandler(DataIntegrityViolationException.class) + @ResponseStatus(HttpStatus.CONFLICT) + public ErrorResponse handSQLException(final DataIntegrityViolationException e) { + log.error("409 {}", e.getMessage(), e); + StringWriter sw = new StringWriter(); + PrintWriter pw = new PrintWriter(sw); + e.printStackTrace(pw); + String stackTrace = sw.toString(); + LocalDateTime timestamp = LocalDateTime.now(); + return new ErrorResponse(HttpStatus.CONFLICT, e.getMessage(), stackTrace, timestamp); + } } diff --git a/evm-service/src/main/java/ru/practicum/Exception/UniqueException.java b/evm-service/src/main/java/ru/practicum/Exception/UniqueException.java new file mode 100644 index 0000000..d0b0b98 --- /dev/null +++ b/evm-service/src/main/java/ru/practicum/Exception/UniqueException.java @@ -0,0 +1,10 @@ +package ru.practicum.Exception; + +public class UniqueException extends RuntimeException { + public UniqueException(final String message) { + super(message); + } + public UniqueException() { + super(); + } +} diff --git a/evm-service/src/main/java/ru/practicum/Request/Controller/RequestPrivateController.java b/evm-service/src/main/java/ru/practicum/Request/Controller/RequestPrivateController.java index 6a18b95..8c25286 100644 --- a/evm-service/src/main/java/ru/practicum/Request/Controller/RequestPrivateController.java +++ b/evm-service/src/main/java/ru/practicum/Request/Controller/RequestPrivateController.java @@ -1,7 +1,6 @@ package ru.practicum.Request.Controller; import jakarta.validation.constraints.Positive; -import jakarta.validation.constraints.PositiveOrZero; import lombok.RequiredArgsConstructor; import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.*; @@ -19,7 +18,7 @@ public class RequestPrivateController { @PostMapping @ResponseStatus(HttpStatus.CREATED) public ParticipationRequestDto addRequest(@PathVariable @Positive Integer userId, - @RequestParam @PositiveOrZero Integer eventId) { + @RequestParam @Positive Integer eventId) { return requestService.addRequest(userId, eventId); } diff --git a/evm-service/src/main/java/ru/practicum/Request/Repository/RequestRepository.java b/evm-service/src/main/java/ru/practicum/Request/Repository/RequestRepository.java index 7a887da..aefc4fc 100644 --- a/evm-service/src/main/java/ru/practicum/Request/Repository/RequestRepository.java +++ b/evm-service/src/main/java/ru/practicum/Request/Repository/RequestRepository.java @@ -1,13 +1,13 @@ package ru.practicum.Request.Repository; import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.data.jpa.repository.JpaSpecificationExecutor; +import ru.practicum.Event.Model.State; import ru.practicum.Request.Model.Request; import java.util.List; import java.util.Optional; -public interface RequestRepository extends JpaRepository, JpaSpecificationExecutor { +public interface RequestRepository extends JpaRepository { Optional findRequestById(Integer requestId); List findRequestsByRequester_Id(Integer requesterId); @@ -15,4 +15,8 @@ public interface RequestRepository extends JpaRepository, JpaS List findRequestsByEvent_IdAndEvent_Initiator_Id(Integer eventId, Integer eventInitiatorId); List findRequestsByEvent_Id(Integer eventId); + + List findRequestsByEvent_IdAndStatus(Integer event_id, State status); + + Request findRequestsByEvent_IdAndRequester_Id(Integer eventId, Integer requesterId); } diff --git a/evm-service/src/main/java/ru/practicum/Request/Service/RequestPrivateServiceImpl.java b/evm-service/src/main/java/ru/practicum/Request/Service/RequestPrivateServiceImpl.java index 11af918..7cfbc06 100644 --- a/evm-service/src/main/java/ru/practicum/Request/Service/RequestPrivateServiceImpl.java +++ b/evm-service/src/main/java/ru/practicum/Request/Service/RequestPrivateServiceImpl.java @@ -33,15 +33,25 @@ public ParticipationRequestDto addRequest(Integer userId, Integer eventId) { User user = checkUser(userId); + if (requestRepository.findRequestsByEvent_IdAndRequester_Id(eventId, userId) != null) { + throw new ConflictException("Request already exists"); + } + if (!event.getState().equals(State.PUBLISHED)) { throw new ConflictException("Event is not published"); } else if (event.getInitiator().getId().equals(userId)) { throw new ConflictException("Requester and initiator could not be the same."); } - if (event.getRequestModeration().equals(false)) { + if (event.getParticipantLimit().equals(event.getConfirmedRequests()) && event.getParticipantLimit() != 0) { + throw new ConflictException("Request limit exceeded"); + } + + if (!(event.getRequestModeration()) || (event.getParticipantLimit() == 0)) { request.setStatus(State.CONFIRMED); - } else { + event.setConfirmedRequests(event.getConfirmedRequests() + 1); + eventRepository.save(event); + } else { request.setStatus(State.PENDING); } diff --git a/evm-service/src/main/resources/application.yml b/evm-service/src/main/resources/application.yml index 5791015..e2e1cd1 100644 --- a/evm-service/src/main/resources/application.yml +++ b/evm-service/src/main/resources/application.yml @@ -17,6 +17,9 @@ spring: url: jdbc:postgresql://localhost:5432/ewm-service username: user password: 12345 + application: + name: evm-service + logging: level: org: @@ -24,4 +27,4 @@ logging: orm.jpa: INFO transaction: INFO interceptor: TRACE - JpaTransactionManager: DEBUG \ No newline at end of file + JpaTransactionManager: DEBUG diff --git a/evm-service/src/main/resources/schema.sql b/evm-service/src/main/resources/schema.sql index 995e81a..d033c92 100644 --- a/evm-service/src/main/resources/schema.sql +++ b/evm-service/src/main/resources/schema.sql @@ -1,3 +1,4 @@ + CREATE TABLE IF NOT EXISTS users ( id INT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, name CHARACTER VARYING(255) NOT NULL, @@ -7,7 +8,7 @@ CREATE TABLE IF NOT EXISTS users ( CREATE TABLE IF NOT EXISTS categories ( id INT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, - name CHARACTER VARYING(255) NOT NULL UNIQUE + name CHARACTER VARYING(255) UNIQUE NOT NULL ); CREATE TABLE IF NOT EXISTS state ( @@ -18,15 +19,16 @@ CREATE TABLE IF NOT EXISTS state ( CREATE TABLE IF NOT EXISTS events ( id INT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, title CHARACTER VARYING (200) NOT NULL, - annotation CHARACTER VARYING (5000) NOT NULL, + annotation CHARACTER VARYING (2000) NOT NULL, category_id INT NOT NULL, + confirmed_requests INT, created_on TIMESTAMP WITHOUT TIME ZONE, - description CHARACTER VARYING (5000), + description CHARACTER VARYING (7000), event_date TIMESTAMP WITHOUT TIME ZONE NOT NULL, initiator_id INT NOT NULL, lat INT NOT NULL, lon INT NOT NULL, - paid BOOLEAN NOT NULL, + paid BOOLEAN, participant_limit INT, published_on TIMESTAMP WITHOUT TIME ZONE, request_moderation BOOLEAN, @@ -38,7 +40,7 @@ CREATE TABLE IF NOT EXISTS events ( CREATE TABLE IF NOT EXISTS compilations ( id INT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, - pinned BOOLEAN NOT NULL, + pinned BOOLEAN, title VARCHAR NOT NULL ); diff --git a/stat/stat-client/src/main/java/ru/practicum/StatsClient.java b/stat/stat-client/src/main/java/ru/practicum/StatsClient.java index 986225e..ea9c073 100644 --- a/stat/stat-client/src/main/java/ru/practicum/StatsClient.java +++ b/stat/stat-client/src/main/java/ru/practicum/StatsClient.java @@ -1,17 +1,20 @@ package ru.practicum; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.http.ResponseEntity; import org.springframework.http.client.HttpComponentsClientHttpRequestFactory; +import org.springframework.stereotype.Component; import org.springframework.web.client.RestClient; +@Component public class StatsClient extends BaseClient { - String appName; - public StatsClient(@Value("${stat-server.url}") String serverUrl, - @Value("${appName}") String appName) { + + @Autowired + public StatsClient(@Value("${stat-server.url}") String serverUrl) { super(RestClient.create(serverUrl)); - this.appName = appName; + } private static RestClient createRestClient(String serverUrl) { From a16f8629bde1543b750ffd9e7da2418cd682e03a Mon Sep 17 00:00:00 2001 From: NadezhdaTA Date: Wed, 3 Sep 2025 09:50:25 +0400 Subject: [PATCH 17/35] =?UTF-8?q?2=D0=BE=D0=B9=20=D1=8D=D1=82=D0=B0=D0=BF?= =?UTF-8?q?=20=D0=B4=D0=B8=D0=BF=D0=BB=D0=BE=D0=BC=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Service/Admin/EventAdminServiceImpl.java | 4 +- .../Public/EventPublicServiceImpl.java | 48 ++++++++-- ...ErrorHandler.java => EvmErrorHandler.java} | 2 +- .../practicum/Exception/UniqueException.java | 1 + .../Request/Repository/RequestRepository.java | 4 +- .../main/java/ru/practicum/BaseClient.java | 46 +++------ .../main/java/ru/practicum/StatsClient.java | 94 ++++++++++++++++--- .../java/ru/practicum/EndpointHitDTO.java | 2 + .../java/ru/practicum/StatsRequestDTO.java | 13 ++- ...rorHandler.java => StatsErrorHandler.java} | 4 +- .../controller/StatsServerController.java | 2 + .../practicum/service/StatsServiceImpl.java | 10 +- 12 files changed, 162 insertions(+), 68 deletions(-) rename evm-service/src/main/java/ru/practicum/Exception/{ErrorHandler.java => EvmErrorHandler.java} (99%) rename stat/stat-server/src/main/java/ru/practicum/controller/{ErrorHandler.java => StatsErrorHandler.java} (94%) diff --git a/evm-service/src/main/java/ru/practicum/Event/Service/Admin/EventAdminServiceImpl.java b/evm-service/src/main/java/ru/practicum/Event/Service/Admin/EventAdminServiceImpl.java index 880f9b5..ae59d68 100644 --- a/evm-service/src/main/java/ru/practicum/Event/Service/Admin/EventAdminServiceImpl.java +++ b/evm-service/src/main/java/ru/practicum/Event/Service/Admin/EventAdminServiceImpl.java @@ -94,14 +94,14 @@ private Specification getEventSpecification(SearchEventsDTO event) { event.getUsers().stream().filter(Objects::nonNull).toList())); } - if (Objects.nonNull(event.getCategories() ) && !event.getCategories().isEmpty()) { + if (Objects.nonNull(event.getCategories()) && !event.getCategories().isEmpty()) { spec = spec.and((root, query, builder) -> root.get("category").get("id").in(event.getCategories().stream() .filter(Objects::nonNull) .toList())); } - if (Objects.nonNull(event.getStates() ) && !event.getStates().isEmpty()) { + if (Objects.nonNull(event.getStates()) && !event.getStates().isEmpty()) { spec = spec.and((root, query, cb) -> root.get("state").in(event.getStates().stream() .filter(Objects::nonNull) diff --git a/evm-service/src/main/java/ru/practicum/Event/Service/Public/EventPublicServiceImpl.java b/evm-service/src/main/java/ru/practicum/Event/Service/Public/EventPublicServiceImpl.java index 43e57cd..47d50db 100644 --- a/evm-service/src/main/java/ru/practicum/Event/Service/Public/EventPublicServiceImpl.java +++ b/evm-service/src/main/java/ru/practicum/Event/Service/Public/EventPublicServiceImpl.java @@ -4,7 +4,6 @@ import jakarta.persistence.criteria.Subquery; import jakarta.servlet.http.HttpServletRequest; import lombok.RequiredArgsConstructor; -import org.springframework.data.domain.Page; import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Sort; @@ -23,10 +22,16 @@ import ru.practicum.Request.Model.Request; import ru.practicum.Request.Repository.RequestRepository; import ru.practicum.StatsClient; +import ru.practicum.ViewStatsDTO; +import java.time.LocalDateTime; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.Objects; +import static java.lang.Integer.parseInt; + @Service @RequiredArgsConstructor @@ -42,6 +47,7 @@ public EventFullDTO findEventById(Integer id, HttpServletRequest request) { Event event = eventRepository.findEventsByIdAndState(id, State.PUBLISHED) .orElseThrow(() -> new NotFoundException("Event with id " + id + " not found")); + statsClient.createHit(request, "ewm-main-service"); event.setViews(event.getViews() + 1); eventRepository.save(event); @@ -50,6 +56,8 @@ public EventFullDTO findEventById(Integer id, HttpServletRequest request) { @Override public List findAllEvents(EventPublicParams params, HttpServletRequest request) { + statsClient.createHit(request, "ewm-main-service"); + if (params.getRangeStart() != null || params.getRangeEnd() != null) { if (params.getRangeStart().isAfter(params.getRangeEnd())) { throw new ValidationException("Range start is after range end"); @@ -57,21 +65,45 @@ public List findAllEvents(EventPublicParams params, HttpServletRe } Specification spec = eventSpecification(params); Sort sort = null; - switch (params.getSort()) { case "EVENT_DATE" -> sort = Sort.by(Sort.Direction.DESC, "eventDate"); case "VIEWS" -> sort = Sort.by(Sort.Direction.ASC, "views"); } - Pageable pageable = PageRequest.of(params.getFrom(), params.getSize(), sort); - Page events = eventRepository.findAll(spec, pageable); + List events = eventRepository.findAll(spec, pageable).getContent(); - return events.getContent().stream() + Map views = getStats(events, request); + return events.stream() + .peek(event -> { + if (views.containsKey(event.getId())) { + event.setViews(views.get(event.getId())); + } + }) .map(eventMapper::toEventShortDTO) .toList(); } + private Map getStats(List events, HttpServletRequest request) { + List uris = events.stream() + .map(event -> { + return request.getRequestURI() + "/" + event.getId(); + }) + .toList(); + LocalDateTime start = LocalDateTime.now().minusMonths(6); + LocalDateTime end = LocalDateTime.now().plusMinutes(1); + List viewStatsDTOS = statsClient.viewStats(start, end, uris, true); + + Map eventViews = new HashMap<>(); + if (!viewStatsDTOS.isEmpty()) { + for (ViewStatsDTO viewStatsDTO : viewStatsDTOS) { + int eventId = parseInt(viewStatsDTO.getUri().substring("/events/".length())); + eventViews.put(eventId, viewStatsDTO.getHits()); + } + } + return eventViews; + } + private Specification eventSpecification(EventPublicParams params) { Specification spec = Specification.where(null); @@ -84,9 +116,11 @@ private Specification eventSpecification(EventPublicParams params) { )); } - if (Objects.nonNull(params.getCategories() ) && !params.getCategories().isEmpty()) { + if (Objects.nonNull(params.getCategories()) && !params.getCategories().isEmpty()) { spec = spec.and((root, query, builder) -> - root.get("category").get("id").in(params.getCategories().stream().filter(Objects::nonNull).toList())); + root.get("category").get("id").in(params.getCategories().stream() + .filter(Objects::nonNull) + .toList())); } if (Objects.nonNull(params.getPaid())) { diff --git a/evm-service/src/main/java/ru/practicum/Exception/ErrorHandler.java b/evm-service/src/main/java/ru/practicum/Exception/EvmErrorHandler.java similarity index 99% rename from evm-service/src/main/java/ru/practicum/Exception/ErrorHandler.java rename to evm-service/src/main/java/ru/practicum/Exception/EvmErrorHandler.java index 86810f2..62e99cf 100644 --- a/evm-service/src/main/java/ru/practicum/Exception/ErrorHandler.java +++ b/evm-service/src/main/java/ru/practicum/Exception/EvmErrorHandler.java @@ -14,7 +14,7 @@ @RestControllerAdvice @Slf4j -public class ErrorHandler { +public class EvmErrorHandler { @ExceptionHandler @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR) diff --git a/evm-service/src/main/java/ru/practicum/Exception/UniqueException.java b/evm-service/src/main/java/ru/practicum/Exception/UniqueException.java index d0b0b98..ca6b3a6 100644 --- a/evm-service/src/main/java/ru/practicum/Exception/UniqueException.java +++ b/evm-service/src/main/java/ru/practicum/Exception/UniqueException.java @@ -4,6 +4,7 @@ public class UniqueException extends RuntimeException { public UniqueException(final String message) { super(message); } + public UniqueException() { super(); } diff --git a/evm-service/src/main/java/ru/practicum/Request/Repository/RequestRepository.java b/evm-service/src/main/java/ru/practicum/Request/Repository/RequestRepository.java index aefc4fc..43d0400 100644 --- a/evm-service/src/main/java/ru/practicum/Request/Repository/RequestRepository.java +++ b/evm-service/src/main/java/ru/practicum/Request/Repository/RequestRepository.java @@ -14,9 +14,7 @@ public interface RequestRepository extends JpaRepository { List findRequestsByEvent_IdAndEvent_Initiator_Id(Integer eventId, Integer eventInitiatorId); - List findRequestsByEvent_Id(Integer eventId); - - List findRequestsByEvent_IdAndStatus(Integer event_id, State status); + List findRequestsByEvent_IdAndStatus(Integer eventId, State status); Request findRequestsByEvent_IdAndRequester_Id(Integer eventId, Integer requesterId); } diff --git a/stat/stat-client/src/main/java/ru/practicum/BaseClient.java b/stat/stat-client/src/main/java/ru/practicum/BaseClient.java index fe10b07..7cfa5e5 100644 --- a/stat/stat-client/src/main/java/ru/practicum/BaseClient.java +++ b/stat/stat-client/src/main/java/ru/practicum/BaseClient.java @@ -2,23 +2,19 @@ import io.micrometer.common.lang.Nullable; import org.springframework.http.*; -import org.springframework.web.client.HttpStatusCodeException; -import org.springframework.web.client.RestClient; -import org.springframework.web.util.UriComponentsBuilder; +import org.springframework.web.client.RestTemplate; import java.util.List; import java.util.Map; public class BaseClient { - protected final RestClient restClient; + protected final RestTemplate restTemplate; - public BaseClient(RestClient restClient) { - this.restClient = restClient; + public BaseClient(RestTemplate restTemplate) { + this.restTemplate = restTemplate; } - protected ResponseEntity get(String path, Object object) { - return makeAndSendRequest(HttpMethod.GET, path, null, object); - } + protected ResponseEntity post(String path, Object body) { return makeAndSendRequest(HttpMethod.POST, path, null, body); @@ -27,31 +23,15 @@ protected ResponseEntity post(String path, Object body) { private ResponseEntity makeAndSendRequest(HttpMethod method, String path, @Nullable Map parameters, @Nullable T body) { - try { - RestClient.RequestBodySpec requestSpec = restClient.method(method) - .uri(uriBuilder -> { - UriComponentsBuilder builder = UriComponentsBuilder.fromPath(path); - if (parameters != null) { - parameters.forEach(builder::queryParam); - } - return builder.build().toUri(); - }) - .headers(headers -> { - headers.setAll(defaultHeaders().toSingleValueMap()); - }); - - if (body != null) { - requestSpec.body(body); - } - - ResponseEntity responseEntity = requestSpec.retrieve() - .toEntity(Object.class); - - return prepareResponse(responseEntity); - } catch (HttpStatusCodeException e) { - return ResponseEntity.status(e.getStatusCode()) - .body(e.getResponseBodyAsByteArray()); + HttpEntity requestEntity = new HttpEntity<>(body, defaultHeaders()); + ResponseEntity statsServiceResponse; + if (parameters != null) { + statsServiceResponse = restTemplate.exchange(path, method, requestEntity, Object.class, parameters); + } else { + statsServiceResponse = restTemplate.exchange(path, method, requestEntity, Object.class); } + + return prepareResponse(statsServiceResponse); } private HttpHeaders defaultHeaders() { diff --git a/stat/stat-client/src/main/java/ru/practicum/StatsClient.java b/stat/stat-client/src/main/java/ru/practicum/StatsClient.java index ea9c073..d0f9174 100644 --- a/stat/stat-client/src/main/java/ru/practicum/StatsClient.java +++ b/stat/stat-client/src/main/java/ru/practicum/StatsClient.java @@ -1,35 +1,99 @@ package ru.practicum; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; +import io.micrometer.common.lang.Nullable; +import jakarta.servlet.http.HttpServletRequest; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; -import org.springframework.http.ResponseEntity; -import org.springframework.http.client.HttpComponentsClientHttpRequestFactory; +import org.springframework.boot.web.client.RestTemplateBuilder; +import org.springframework.http.*; import org.springframework.stereotype.Component; -import org.springframework.web.client.RestClient; +import org.springframework.web.util.UriComponentsBuilder; + +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.util.HashMap; +import java.util.List; +import java.util.Map; @Component public class StatsClient extends BaseClient { - + String serverUrl; @Autowired - public StatsClient(@Value("${stat-server.url}") String serverUrl) { - super(RestClient.create(serverUrl)); + public StatsClient(@Value("${stat-server.url:http://stat-server:9090}") String serverUrl, + RestTemplateBuilder builder) { + super(builder.build()); + this.serverUrl = serverUrl; + } + + + public ResponseEntity createHit(HttpServletRequest request, String appName) { + String uri = request.getRequestURI(); + EndpointHitDTO dto = getEndpointHitDTO(request, appName); + return post(serverUrl + "/hit", dto); } - private static RestClient createRestClient(String serverUrl) { - return RestClient.builder() - .baseUrl(serverUrl) - .requestFactory(new HttpComponentsClientHttpRequestFactory()) - .build(); + public List viewStats(LocalDateTime start, LocalDateTime end, + List uris, Boolean unique) { + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); + Map params = new HashMap<>(); + params.put("start", start.format(formatter)); + params.put("end", end.format(formatter)); + params.put("uris", uris != null ? String.join(",", uris) : ""); + params.put("unique", unique != null ? unique : false); + + ResponseEntity obj = get(serverUrl + "/stats", params); + + ObjectMapper mapper = new ObjectMapper(); + List views = null; + + if (obj.getStatusCode().is2xxSuccessful() && obj.getBody() != null) { + try { + views = mapper.readValue( + mapper.writeValueAsString(obj.getBody()), new TypeReference<>() {}); + } catch (JsonProcessingException e) { + throw new RuntimeException(e); + } + } + + return views; } - public ResponseEntity createHit(EndpointHitDTO hitDTO) { - return post("/hits", hitDTO); + private EndpointHitDTO getEndpointHitDTO(HttpServletRequest request, String appName) { + String uri = request.getRequestURI(); + String ip = request.getRemoteAddr(); + return EndpointHitDTO.builder() + .app(appName) + .uri(uri) + .ip(ip) + .timestamp(LocalDateTime.now()) + .build(); } - public ResponseEntity viewStats(StatsRequestDTO statsRequestDTO) { - return get("/stats", statsRequestDTO); + protected ResponseEntity get(String path, Map parameters) { + return makeGetRequest(HttpMethod.GET, path, parameters, null); } + private ResponseEntity makeGetRequest(HttpMethod method, String path, + @Nullable Map parameters, + @Nullable T body) { + + HttpHeaders headers = new HttpHeaders(); + headers.setContentType(MediaType.APPLICATION_JSON); + headers.setAccept(List.of(MediaType.APPLICATION_JSON)); + + UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl(path); + if (parameters != null) { + parameters.forEach(builder::queryParam); + } + + HttpEntity entity = new HttpEntity<>(body, headers); + + return restTemplate.exchange(builder.build().encode().toUri(), + method, entity, Object.class); + } } diff --git a/stat/stat-dto/src/main/java/ru/practicum/EndpointHitDTO.java b/stat/stat-dto/src/main/java/ru/practicum/EndpointHitDTO.java index aa55761..d0953f9 100644 --- a/stat/stat-dto/src/main/java/ru/practicum/EndpointHitDTO.java +++ b/stat/stat-dto/src/main/java/ru/practicum/EndpointHitDTO.java @@ -3,6 +3,7 @@ import com.fasterxml.jackson.annotation.JsonFormat; import jakarta.validation.constraints.NotBlank; import lombok.AllArgsConstructor; +import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; @@ -11,6 +12,7 @@ @Data @AllArgsConstructor @NoArgsConstructor +@Builder public class EndpointHitDTO { @NotBlank diff --git a/stat/stat-dto/src/main/java/ru/practicum/StatsRequestDTO.java b/stat/stat-dto/src/main/java/ru/practicum/StatsRequestDTO.java index 0e58266..6e7d402 100644 --- a/stat/stat-dto/src/main/java/ru/practicum/StatsRequestDTO.java +++ b/stat/stat-dto/src/main/java/ru/practicum/StatsRequestDTO.java @@ -1,7 +1,9 @@ package ru.practicum; +import com.fasterxml.jackson.annotation.JsonProperty; import jakarta.validation.constraints.NotNull; import lombok.AllArgsConstructor; +import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; import org.springframework.format.annotation.DateTimeFormat; @@ -12,16 +14,19 @@ @Data @NoArgsConstructor @AllArgsConstructor +@Builder public class StatsRequestDTO { @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") @NotNull(message = "Start date is required") - LocalDateTime start; + @JsonProperty(value = "start") + private LocalDateTime start; @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") @NotNull(message = "End date is required") - LocalDateTime end; + @JsonProperty(value = "end") + private LocalDateTime end; - List uris; - Boolean unique; + private List uris; + private Boolean unique; } diff --git a/stat/stat-server/src/main/java/ru/practicum/controller/ErrorHandler.java b/stat/stat-server/src/main/java/ru/practicum/controller/StatsErrorHandler.java similarity index 94% rename from stat/stat-server/src/main/java/ru/practicum/controller/ErrorHandler.java rename to stat/stat-server/src/main/java/ru/practicum/controller/StatsErrorHandler.java index 33a30e0..f258a0b 100644 --- a/stat/stat-server/src/main/java/ru/practicum/controller/ErrorHandler.java +++ b/stat/stat-server/src/main/java/ru/practicum/controller/StatsErrorHandler.java @@ -13,11 +13,11 @@ @RestControllerAdvice @Slf4j -public class ErrorHandler { +public class StatsErrorHandler { @ExceptionHandler @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR) - public ErrorResponse handleException(final Exception e) { + public ErrorResponse handleException(final RuntimeException e) { log.error("500 {}", e.getMessage(), e); StringWriter sw = new StringWriter(); PrintWriter pw = new PrintWriter(sw); diff --git a/stat/stat-server/src/main/java/ru/practicum/controller/StatsServerController.java b/stat/stat-server/src/main/java/ru/practicum/controller/StatsServerController.java index 56f2309..4ac455b 100644 --- a/stat/stat-server/src/main/java/ru/practicum/controller/StatsServerController.java +++ b/stat/stat-server/src/main/java/ru/practicum/controller/StatsServerController.java @@ -2,6 +2,7 @@ import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; +import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.*; import ru.practicum.EndpointHitDTO; import ru.practicum.StatsRequestDTO; @@ -21,6 +22,7 @@ private List viewStats(@ModelAttribute @Valid StatsRequestDTO stat } @PostMapping("/hit") + @ResponseStatus(HttpStatus.CREATED) private void createHit(@RequestBody @Valid EndpointHitDTO hitDTO) { statsService.createHit(hitDTO); } diff --git a/stat/stat-server/src/main/java/ru/practicum/service/StatsServiceImpl.java b/stat/stat-server/src/main/java/ru/practicum/service/StatsServiceImpl.java index b775c7d..3b19655 100644 --- a/stat/stat-server/src/main/java/ru/practicum/service/StatsServiceImpl.java +++ b/stat/stat-server/src/main/java/ru/practicum/service/StatsServiceImpl.java @@ -5,6 +5,7 @@ import ru.practicum.EndpointHitDTO; import ru.practicum.StatsRequestDTO; import ru.practicum.ViewStatsDTO; +import ru.practicum.exceptions.ValidationException; import ru.practicum.mapper.HitsMapper; import ru.practicum.mapper.ViewStatsMapper; import ru.practicum.model.EndpointHit; @@ -22,6 +23,11 @@ public class StatsServiceImpl implements StatsServiceInterface { @Override public List getStats(StatsRequestDTO statsRequestDTO) { + if (statsRequestDTO.getStart().isAfter(statsRequestDTO.getEnd())) { + throw new ValidationException("Start date cannot be after end date"); + } else if (statsRequestDTO.getStart() == null || statsRequestDTO.getEnd() == null) { + throw new ValidationException("Start date cannot be after end date"); + } List stats; if (statsRequestDTO.getUnique() == null) { @@ -34,9 +40,11 @@ public List getStats(StatsRequestDTO statsRequestDTO) { } else { stats = statsService.getStats(statsRequestDTO.getStart(), statsRequestDTO.getEnd()); } - return stats.stream() + List views = stats.stream() .map(viewStatsMapper::mapViewStats) .toList(); + + return views; } @Override From 65675b2d02a9142076e54dbd34499eb9365c75b6 Mon Sep 17 00:00:00 2001 From: NadezhdaTA Date: Wed, 3 Sep 2025 17:07:38 +0400 Subject: [PATCH 18/35] =?UTF-8?q?2=D0=BE=D0=B9=20=D1=8D=D1=82=D0=B0=D0=BF?= =?UTF-8?q?=20=D0=B4=D0=B8=D0=BF=D0=BB=D0=BE=D0=BC=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../practicum/Category/DTO/CategoryDTO.java | 2 + .../Admin/CategoryAdminServiceImpl.java | 10 ++- .../CompilationsListRequestParams.java | 6 ++ .../Public/CompilationPublicServiceImpl.java | 78 ++++++++++++++++++- .../Service/Admin/EventAdminServiceImpl.java | 2 +- .../Public/EventPublicServiceImpl.java | 26 ++++--- .../User/Service/UserAdminServiceImpl.java | 3 +- .../main/java/ru/practicum/StatsClient.java | 1 - 8 files changed, 109 insertions(+), 19 deletions(-) diff --git a/evm-service/src/main/java/ru/practicum/Category/DTO/CategoryDTO.java b/evm-service/src/main/java/ru/practicum/Category/DTO/CategoryDTO.java index 92996ef..a31fa6a 100644 --- a/evm-service/src/main/java/ru/practicum/Category/DTO/CategoryDTO.java +++ b/evm-service/src/main/java/ru/practicum/Category/DTO/CategoryDTO.java @@ -4,6 +4,7 @@ import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; +import org.hibernate.validator.constraints.Length; @Data @NoArgsConstructor @@ -12,5 +13,6 @@ public class CategoryDTO { private Integer id; @NotBlank + @Length(max = 50) private String name; } diff --git a/evm-service/src/main/java/ru/practicum/Category/Service/Admin/CategoryAdminServiceImpl.java b/evm-service/src/main/java/ru/practicum/Category/Service/Admin/CategoryAdminServiceImpl.java index 3e55fdf..3e13534 100644 --- a/evm-service/src/main/java/ru/practicum/Category/Service/Admin/CategoryAdminServiceImpl.java +++ b/evm-service/src/main/java/ru/practicum/Category/Service/Admin/CategoryAdminServiceImpl.java @@ -43,11 +43,17 @@ public void deleteCategory(Integer catId) { } @Override - public CategoryDTO updateCategory(int id, CategoryDTO categoryDTO) { + public CategoryDTO updateCategory(int id, CategoryDTO newCategory) { Category category = repository.findById(id) .orElseThrow(() -> new NotFoundException("Category with id " + id + " not found")); - return categoryMapper.toCategoryDTO(repository.save(categoryMapper.toCategory(categoryDTO))); + if (category.getName().equals(newCategory.getName())) { + return categoryMapper.toCategoryDTO(category); + } else { + return categoryMapper.toCategoryDTO(repository.save(categoryMapper.toCategory(newCategory))); + } + + } diff --git a/evm-service/src/main/java/ru/practicum/Compilation/CompilationDTO/CompilationsListRequestParams.java b/evm-service/src/main/java/ru/practicum/Compilation/CompilationDTO/CompilationsListRequestParams.java index 3c42369..02ca7bc 100644 --- a/evm-service/src/main/java/ru/practicum/Compilation/CompilationDTO/CompilationsListRequestParams.java +++ b/evm-service/src/main/java/ru/practicum/Compilation/CompilationDTO/CompilationsListRequestParams.java @@ -1,10 +1,16 @@ package ru.practicum.Compilation.CompilationDTO; +import jakarta.validation.constraints.Positive; +import jakarta.validation.constraints.PositiveOrZero; import lombok.Data; @Data public class CompilationsListRequestParams { private Boolean pinned; + + @PositiveOrZero private Integer from = 0; + + @Positive private Integer size = 10; } diff --git a/evm-service/src/main/java/ru/practicum/Compilation/Service/Public/CompilationPublicServiceImpl.java b/evm-service/src/main/java/ru/practicum/Compilation/Service/Public/CompilationPublicServiceImpl.java index e9ca966..ba4fc3b 100644 --- a/evm-service/src/main/java/ru/practicum/Compilation/Service/Public/CompilationPublicServiceImpl.java +++ b/evm-service/src/main/java/ru/practicum/Compilation/Service/Public/CompilationPublicServiceImpl.java @@ -10,32 +10,104 @@ import ru.practicum.Compilation.Mapper.CompilationMapper; import ru.practicum.Compilation.Model.Compilation; import ru.practicum.Compilation.Repository.CompilationRepository; +import ru.practicum.Event.Mapper.EventMapper; +import ru.practicum.Event.Model.Event; +import ru.practicum.Event.Repository.EventRepository; import ru.practicum.Exception.NotFoundException; +import ru.practicum.StatsClient; +import ru.practicum.ViewStatsDTO; +import java.time.LocalDateTime; +import java.util.HashMap; import java.util.List; +import java.util.Map; + +import static java.lang.Integer.parseInt; @Service @RequiredArgsConstructor public class CompilationPublicServiceImpl implements CompilationPublicService { private final CompilationRepository compilationRepository; private final CompilationMapper compilationMapper; + private final EventRepository eventRepository; + private final StatsClient statsClient; + private final EventMapper eventMapper; @Override public CompilationDTO getCompilation(Integer compId) { - return compilationMapper.toDto(checkCompilation(compId)); + Compilation compilation = checkCompilation(compId); + CompilationDTO compilationDTO = compilationMapper.toDto(compilation); + + List events = compilation.getEvents().stream().toList(); + + if ((events != null) && (!events.isEmpty())) { + Map views = getEvents(events); + compilationDTO.getEvents().stream() + .peek(eventShortDTO -> eventShortDTO.setViews(views.get(eventShortDTO.getId()))); + } + + return compilationDTO; } @Override public List getCompilations(CompilationsListRequestParams params) { Pageable pageable = PageRequest.of(params.getFrom(), params.getSize()); - Page compilations = compilationRepository.findCompilationByPinned(params.getPinned(), pageable); - return compilations.getContent().stream() + Page compilations = params.getPinned() == null + ? compilationRepository.findAll(pageable) + : compilationRepository.findCompilationByPinned(params.getPinned(), pageable); + + List events = compilations.stream() + .flatMap(c -> c.getEvents().stream()) + .distinct() + .toList(); + + List compilationDtos = compilations.getContent().stream() .map(compilationMapper::toDto) .toList(); + + + if ((events != null) && (!events.isEmpty())) { + Map views = getEvents(events); + compilationDtos = compilationDtos.stream().peek(compilationDTO -> { + compilationDTO.getEvents().stream() + .peek(eventShortDTO -> eventShortDTO.setViews(views.get(eventShortDTO.getId()) + )); + } + ).toList(); + } + + return compilationDtos; + } private Compilation checkCompilation(Integer compId) { return compilationRepository.findCompilationById(compId) .orElseThrow(() -> new NotFoundException("Compilation with id " + compId + " not found")); } + + private Map getEvents(List events) { + List ids = events.stream() + .map(Event::getId) + .toList(); + List events1 = eventRepository.findEventsByIdIn(ids); + + List uris = events.stream() + .map(event -> "/events/" + event.getId()) + .distinct() + .toList(); + LocalDateTime start = LocalDateTime.now().minusMonths(6); + LocalDateTime end = LocalDateTime.now().plusMinutes(1); + List viewStatsDTOS = statsClient.viewStats(start, end, uris, true); + + Map views = new HashMap<>(); + if (!viewStatsDTOS.isEmpty()) { + for (ViewStatsDTO viewStatsDTO : viewStatsDTOS) { + int eventId = parseInt(viewStatsDTO.getUri().substring("/events/".length())); + views.put(eventId, viewStatsDTO.getHits()); + } + } + + return views; + } } + diff --git a/evm-service/src/main/java/ru/practicum/Event/Service/Admin/EventAdminServiceImpl.java b/evm-service/src/main/java/ru/practicum/Event/Service/Admin/EventAdminServiceImpl.java index ae59d68..b5200e9 100644 --- a/evm-service/src/main/java/ru/practicum/Event/Service/Admin/EventAdminServiceImpl.java +++ b/evm-service/src/main/java/ru/practicum/Event/Service/Admin/EventAdminServiceImpl.java @@ -31,7 +31,7 @@ public class EventAdminServiceImpl implements EventAdminService { @Override public List getEvents(SearchEventsDTO dto) { - if (dto.getRangeStart() != null || dto.getRangeEnd() != null) { + if (dto.getRangeStart() != null && dto.getRangeEnd() != null) { if (dto.getRangeStart().isAfter(dto.getRangeEnd())) { throw new ValidationException("Range start is after range end"); } diff --git a/evm-service/src/main/java/ru/practicum/Event/Service/Public/EventPublicServiceImpl.java b/evm-service/src/main/java/ru/practicum/Event/Service/Public/EventPublicServiceImpl.java index 47d50db..3000bb5 100644 --- a/evm-service/src/main/java/ru/practicum/Event/Service/Public/EventPublicServiceImpl.java +++ b/evm-service/src/main/java/ru/practicum/Event/Service/Public/EventPublicServiceImpl.java @@ -48,8 +48,10 @@ public EventFullDTO findEventById(Integer id, HttpServletRequest request) { .orElseThrow(() -> new NotFoundException("Event with id " + id + " not found")); statsClient.createHit(request, "ewm-main-service"); - event.setViews(event.getViews() + 1); - eventRepository.save(event); + + List uris = List.of(request.getRequestURI()); + Map views = getStats(uris, request); + event.setViews(views.get(event.getId())); return eventMapper.toEventFullDTO(event); } @@ -72,8 +74,13 @@ public List findAllEvents(EventPublicParams params, HttpServletRe Pageable pageable = PageRequest.of(params.getFrom(), params.getSize(), sort); List events = eventRepository.findAll(spec, pageable).getContent(); + List uris = events.stream() + .map(event -> { + return request.getRequestURI() + "/" + event.getId(); + }) + .toList(); - Map views = getStats(events, request); + Map views = getStats(uris, request); return events.stream() .peek(event -> { if (views.containsKey(event.getId())) { @@ -84,12 +91,8 @@ public List findAllEvents(EventPublicParams params, HttpServletRe .toList(); } - private Map getStats(List events, HttpServletRequest request) { - List uris = events.stream() - .map(event -> { - return request.getRequestURI() + "/" + event.getId(); - }) - .toList(); + private Map getStats(List uris, HttpServletRequest request) { + LocalDateTime start = LocalDateTime.now().minusMonths(6); LocalDateTime end = LocalDateTime.now().plusMinutes(1); List viewStatsDTOS = statsClient.viewStats(start, end, uris, true); @@ -97,8 +100,9 @@ private Map getStats(List events, HttpServletRequest re Map eventViews = new HashMap<>(); if (!viewStatsDTOS.isEmpty()) { for (ViewStatsDTO viewStatsDTO : viewStatsDTOS) { - int eventId = parseInt(viewStatsDTO.getUri().substring("/events/".length())); - eventViews.put(eventId, viewStatsDTO.getHits()); + int index = viewStatsDTO.getUri().lastIndexOf('/') + 1; + int id = parseInt(viewStatsDTO.getUri().substring(index)); + eventViews.put(id, viewStatsDTO.getHits()); } } return eventViews; diff --git a/evm-service/src/main/java/ru/practicum/User/Service/UserAdminServiceImpl.java b/evm-service/src/main/java/ru/practicum/User/Service/UserAdminServiceImpl.java index 89e04fa..cea13ca 100644 --- a/evm-service/src/main/java/ru/practicum/User/Service/UserAdminServiceImpl.java +++ b/evm-service/src/main/java/ru/practicum/User/Service/UserAdminServiceImpl.java @@ -45,7 +45,8 @@ public UserDTO getUserById(Integer id) { @Override public List getUsers(UsersListRequest request) { - Pageable pageable = PageRequest.of(request.getFrom(), request.getSize(), Sort.by("id").ascending()); + int pageNumber = (int) Math.floor((double) request.getFrom() / request.getSize()); + Pageable pageable = PageRequest.of(pageNumber, request.getSize(), Sort.Direction.ASC, "id"); Page users = request.getIds() == null ? userRepository.findAll(pageable) : userRepository.findAllByIdIn(request.getIds(), pageable); diff --git a/stat/stat-client/src/main/java/ru/practicum/StatsClient.java b/stat/stat-client/src/main/java/ru/practicum/StatsClient.java index d0f9174..a11b07e 100644 --- a/stat/stat-client/src/main/java/ru/practicum/StatsClient.java +++ b/stat/stat-client/src/main/java/ru/practicum/StatsClient.java @@ -29,7 +29,6 @@ public StatsClient(@Value("${stat-server.url:http://stat-server:9090}") String s this.serverUrl = serverUrl; } - public ResponseEntity createHit(HttpServletRequest request, String appName) { String uri = request.getRequestURI(); EndpointHitDTO dto = getEndpointHitDTO(request, appName); From c410e3b084079dcd0a78df98d076ecb190f42228 Mon Sep 17 00:00:00 2001 From: NadezhdaTA Date: Wed, 3 Sep 2025 18:26:48 +0400 Subject: [PATCH 19/35] =?UTF-8?q?2=D0=BE=D0=B9=20=D1=8D=D1=82=D0=B0=D0=BF?= =?UTF-8?q?=20=D0=B4=D0=B8=D0=BF=D0=BB=D0=BE=D0=BC=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ru/practicum/Event/DTO/EventFullDTO.java | 2 +- .../Public/EventPublicServiceImpl.java | 37 ++++---- .../main/java/ru/practicum/StatsClient1.java | 91 +++++++++++++++++++ 3 files changed, 113 insertions(+), 17 deletions(-) create mode 100644 stat/stat-client/src/main/java/ru/practicum/StatsClient1.java diff --git a/evm-service/src/main/java/ru/practicum/Event/DTO/EventFullDTO.java b/evm-service/src/main/java/ru/practicum/Event/DTO/EventFullDTO.java index 49f5fbf..dfb1617 100644 --- a/evm-service/src/main/java/ru/practicum/Event/DTO/EventFullDTO.java +++ b/evm-service/src/main/java/ru/practicum/Event/DTO/EventFullDTO.java @@ -40,7 +40,7 @@ public class EventFullDTO { private Integer participantLimit; @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") - private LocalDateTime publishedOn; + private LocalDateTime publishedOn = LocalDateTime.now(); private Boolean requestModeration; diff --git a/evm-service/src/main/java/ru/practicum/Event/Service/Public/EventPublicServiceImpl.java b/evm-service/src/main/java/ru/practicum/Event/Service/Public/EventPublicServiceImpl.java index 3000bb5..4b4ad22 100644 --- a/evm-service/src/main/java/ru/practicum/Event/Service/Public/EventPublicServiceImpl.java +++ b/evm-service/src/main/java/ru/practicum/Event/Service/Public/EventPublicServiceImpl.java @@ -1,7 +1,5 @@ package ru.practicum.Event.Service.Public; -import jakarta.persistence.criteria.Root; -import jakarta.persistence.criteria.Subquery; import jakarta.servlet.http.HttpServletRequest; import lombok.RequiredArgsConstructor; import org.springframework.data.domain.PageRequest; @@ -19,7 +17,6 @@ import ru.practicum.Event.Repository.EventRepository; import ru.practicum.Exception.NotFoundException; import ru.practicum.Exception.ValidationException; -import ru.practicum.Request.Model.Request; import ru.practicum.Request.Repository.RequestRepository; import ru.practicum.StatsClient; import ru.practicum.ViewStatsDTO; @@ -121,10 +118,9 @@ private Specification eventSpecification(EventPublicParams params) { } if (Objects.nonNull(params.getCategories()) && !params.getCategories().isEmpty()) { - spec = spec.and((root, query, builder) -> - root.get("category").get("id").in(params.getCategories().stream() - .filter(Objects::nonNull) - .toList())); + spec = spec.and((root, query, cb) -> + root.get("category").get("id").in( + params.getCategories())); } if (Objects.nonNull(params.getPaid())) { @@ -133,15 +129,24 @@ private Specification eventSpecification(EventPublicParams params) { } if (Objects.nonNull(params.getOnlyAvailable())) { - spec = spec.and((root, query, cb) -> { - assert query != null; - Subquery subquery = query.subquery(Long.class); - Root requestRoot = subquery.from(Request.class); - subquery.select(cb.count(requestRoot.get("id"))) - .where(cb.equal(requestRoot.get("event"), root)); - - return cb.greaterThan(root.get("participantLimit"), subquery); - }); + spec = spec.and((root, query, cb) -> + cb.or( + cb.equal(root.get("participantLimit"), 0), + cb.lessThan( + root.get("confirmedRequests"), + root.get("participantLimit") + ) + )); + } + + if (Objects.nonNull(params.getRangeStart())) { + spec = spec.and((root, query, cb) -> + cb.greaterThanOrEqualTo(root.get("eventDate"), params.getRangeStart())); + } + + if (Objects.nonNull(params.getRangeEnd())) { + spec = spec.and((root, query, cb) -> + cb.lessThanOrEqualTo(root.get("eventDate"), params.getRangeEnd())); } return spec; diff --git a/stat/stat-client/src/main/java/ru/practicum/StatsClient1.java b/stat/stat-client/src/main/java/ru/practicum/StatsClient1.java new file mode 100644 index 0000000..fdaa71c --- /dev/null +++ b/stat/stat-client/src/main/java/ru/practicum/StatsClient1.java @@ -0,0 +1,91 @@ +package ru.practicum; + +import jakarta.servlet.http.HttpServletRequest; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.web.client.RestTemplateBuilder; +import org.springframework.http.*; +import org.springframework.stereotype.Component; +import org.springframework.web.client.RestTemplate; +import org.springframework.web.util.UriComponentsBuilder; + +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +@Component +public class StatsClient1 { + private final RestTemplate restTemplate; + + private final String serverUrl; + private static final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); + + @Autowired + public StatsClient1(@Value("${stats.server.url:http://stat-server:9090}") String serverUrl, + RestTemplateBuilder restTemplateBuilder) { + this.restTemplate = restTemplateBuilder.build(); + this.serverUrl = serverUrl; + + + } + + public void createHit(HttpServletRequest request, String appName) { + String uri = request.getRequestURI(); + String ip = request.getRemoteAddr(); + post("/hit", createDto(uri, ip, appName)); + } + + public ResponseEntity viewStats(LocalDateTime start, LocalDateTime end, + List uris, Boolean unique) { + Map params = new HashMap<>(); + params.put("start", start.format(formatter)); + params.put("end", end.format(formatter)); + params.put("uris", uris != null ? String.join(",", uris) : ""); + params.put("unique", unique != null ? unique : false); + + return get("/stats", params); + } + + private ResponseEntity get(String path, Map parameters) { + return makeRequest(HttpMethod.GET, path, parameters, null); + } + + private ResponseEntity post(String path, Object body) { + return makeRequest(HttpMethod.POST, path, null, body); + } + + private ResponseEntity makeRequest(HttpMethod method, String path, + Map parameters, Object body) { + String url = serverUrl + path; + + HttpHeaders headers = new HttpHeaders(); + headers.setContentType(MediaType.APPLICATION_JSON); + headers.setAccept(List.of(MediaType.APPLICATION_JSON)); + + UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl(url); + if (parameters != null) { + parameters.forEach(builder::queryParam); + } + + HttpEntity entity = new HttpEntity<>(body, headers); + + return restTemplate.exchange( + builder.build().encode().toUri(), + method, + entity, + Object.class + ); + + } + + private EndpointHitDTO createDto(String uri, String ip, String appName) { + return EndpointHitDTO.builder() + .app(appName) + .uri(uri) + .ip(ip) + .timestamp(LocalDateTime.now()) + .build(); + } +} From 511d3c12dac74861cbfe21bd95e341a40d1e311a Mon Sep 17 00:00:00 2001 From: NadezhdaTA Date: Thu, 4 Sep 2025 10:39:30 +0400 Subject: [PATCH 20/35] =?UTF-8?q?2=D0=BE=D0=B9=20=D1=8D=D1=82=D0=B0=D0=BF?= =?UTF-8?q?=20=D0=B4=D0=B8=D0=BF=D0=BB=D0=BE=D0=BC=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Public/CompilationPublicServiceImpl.java | 8 +-- .../Public/EventPublicServiceImpl.java | 49 +++++++++++-------- .../main/java/ru/practicum/StatsClient.java | 42 +++++++++------- 3 files changed, 57 insertions(+), 42 deletions(-) diff --git a/evm-service/src/main/java/ru/practicum/Compilation/Service/Public/CompilationPublicServiceImpl.java b/evm-service/src/main/java/ru/practicum/Compilation/Service/Public/CompilationPublicServiceImpl.java index ba4fc3b..1f475e5 100644 --- a/evm-service/src/main/java/ru/practicum/Compilation/Service/Public/CompilationPublicServiceImpl.java +++ b/evm-service/src/main/java/ru/practicum/Compilation/Service/Public/CompilationPublicServiceImpl.java @@ -18,9 +18,7 @@ import ru.practicum.ViewStatsDTO; import java.time.LocalDateTime; -import java.util.HashMap; -import java.util.List; -import java.util.Map; +import java.util.*; import static java.lang.Integer.parseInt; @@ -86,6 +84,10 @@ private Compilation checkCompilation(Integer compId) { } private Map getEvents(List events) { + if (events == null) { + return Collections.emptyMap(); + } + List ids = events.stream() .map(Event::getId) .toList(); diff --git a/evm-service/src/main/java/ru/practicum/Event/Service/Public/EventPublicServiceImpl.java b/evm-service/src/main/java/ru/practicum/Event/Service/Public/EventPublicServiceImpl.java index 4b4ad22..e430c3d 100644 --- a/evm-service/src/main/java/ru/practicum/Event/Service/Public/EventPublicServiceImpl.java +++ b/evm-service/src/main/java/ru/practicum/Event/Service/Public/EventPublicServiceImpl.java @@ -22,10 +22,7 @@ import ru.practicum.ViewStatsDTO; import java.time.LocalDateTime; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; +import java.util.*; import static java.lang.Integer.parseInt; @@ -62,46 +59,58 @@ public List findAllEvents(EventPublicParams params, HttpServletRe throw new ValidationException("Range start is after range end"); } } + Specification spec = eventSpecification(params); + Sort sort = null; switch (params.getSort()) { case "EVENT_DATE" -> sort = Sort.by(Sort.Direction.DESC, "eventDate"); case "VIEWS" -> sort = Sort.by(Sort.Direction.ASC, "views"); } + Pageable pageable = PageRequest.of(params.getFrom(), params.getSize(), sort); - List events = eventRepository.findAll(spec, pageable).getContent(); + List events = eventRepository.findAll(spec, pageable).getContent().stream() + .map(eventMapper::toEventShortDTO) + .toList(); + List uris = events.stream() .map(event -> { return request.getRequestURI() + "/" + event.getId(); }) .toList(); - Map views = getStats(uris, request); - return events.stream() - .peek(event -> { - if (views.containsKey(event.getId())) { - event.setViews(views.get(event.getId())); - } - }) - .map(eventMapper::toEventShortDTO) - .toList(); + if (!uris.isEmpty()) { + Map views = getStats(uris, request); + events.stream() + .peek(event -> { + if (views.containsKey(event.getId())) { + event.setViews(views.get(event.getId())); + } + }) + .toList(); + } + + return events; } private Map getStats(List uris, HttpServletRequest request) { + if (uris.isEmpty()) { + return Collections.emptyMap(); + } LocalDateTime start = LocalDateTime.now().minusMonths(6); LocalDateTime end = LocalDateTime.now().plusMinutes(1); List viewStatsDTOS = statsClient.viewStats(start, end, uris, true); Map eventViews = new HashMap<>(); - if (!viewStatsDTOS.isEmpty()) { - for (ViewStatsDTO viewStatsDTO : viewStatsDTOS) { - int index = viewStatsDTO.getUri().lastIndexOf('/') + 1; - int id = parseInt(viewStatsDTO.getUri().substring(index)); - eventViews.put(id, viewStatsDTO.getHits()); - } + + for (ViewStatsDTO viewStatsDTO : viewStatsDTOS) { + int index = viewStatsDTO.getUri().lastIndexOf('/') + 1; + int id = parseInt(viewStatsDTO.getUri().substring(index)); + eventViews.put(id, viewStatsDTO.getHits()); } + return eventViews; } diff --git a/stat/stat-client/src/main/java/ru/practicum/StatsClient.java b/stat/stat-client/src/main/java/ru/practicum/StatsClient.java index a11b07e..15fe2e8 100644 --- a/stat/stat-client/src/main/java/ru/practicum/StatsClient.java +++ b/stat/stat-client/src/main/java/ru/practicum/StatsClient.java @@ -10,6 +10,7 @@ import org.springframework.boot.web.client.RestTemplateBuilder; import org.springframework.http.*; import org.springframework.stereotype.Component; +import org.springframework.web.client.RestTemplate; import org.springframework.web.util.UriComponentsBuilder; import java.time.LocalDateTime; @@ -19,14 +20,15 @@ import java.util.Map; @Component -public class StatsClient extends BaseClient { - String serverUrl; +public class StatsClient { + private final String serverUrl; + private final RestTemplate restTemplate; @Autowired public StatsClient(@Value("${stat-server.url:http://stat-server:9090}") String serverUrl, RestTemplateBuilder builder) { - super(builder.build()); this.serverUrl = serverUrl; + this.restTemplate = builder.build(); } public ResponseEntity createHit(HttpServletRequest request, String appName) { @@ -37,7 +39,7 @@ public ResponseEntity createHit(HttpServletRequest request, String appNa } public List viewStats(LocalDateTime start, LocalDateTime end, - List uris, Boolean unique) { + List uris, Boolean unique) { DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); Map params = new HashMap<>(); params.put("start", start.format(formatter)); @@ -62,25 +64,17 @@ public List viewStats(LocalDateTime start, LocalDateTime end, return views; } - private EndpointHitDTO getEndpointHitDTO(HttpServletRequest request, String appName) { - String uri = request.getRequestURI(); - String ip = request.getRemoteAddr(); - return EndpointHitDTO.builder() - .app(appName) - .uri(uri) - .ip(ip) - .timestamp(LocalDateTime.now()) - .build(); + private ResponseEntity get(String path, Map parameters) { + return makeAndSendRequest(HttpMethod.GET, path, parameters, null); } - protected ResponseEntity get(String path, Map parameters) { - return makeGetRequest(HttpMethod.GET, path, parameters, null); + private ResponseEntity post(String path, Object body) { + return makeAndSendRequest(HttpMethod.POST, path, null, body); } - private ResponseEntity makeGetRequest(HttpMethod method, String path, - @Nullable Map parameters, - @Nullable T body) { - + private ResponseEntity makeAndSendRequest(HttpMethod method, String path, + @Nullable Map parameters, + @Nullable T body) { HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.APPLICATION_JSON); headers.setAccept(List.of(MediaType.APPLICATION_JSON)); @@ -95,4 +89,14 @@ private ResponseEntity makeGetRequest(HttpMethod method, String path return restTemplate.exchange(builder.build().encode().toUri(), method, entity, Object.class); } + + private EndpointHitDTO getEndpointHitDTO(HttpServletRequest request, String appName) { + return EndpointHitDTO.builder() + .app(appName) + .uri(request.getRequestURI()) + .ip(request.getRemoteAddr()) + .timestamp(LocalDateTime.now()) + .build(); + } + } From 4bd96ee4bc1c097d2e22e3595f5ea5612254a8be Mon Sep 17 00:00:00 2001 From: NadezhdaTA Date: Thu, 4 Sep 2025 11:15:57 +0400 Subject: [PATCH 21/35] =?UTF-8?q?2=D0=BE=D0=B9=20=D1=8D=D1=82=D0=B0=D0=BF?= =?UTF-8?q?=20=D0=B4=D0=B8=D0=BF=D0=BB=D0=BE=D0=BC=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docker-compose.yml | 1 + .../Service/Public/CompilationPublicServiceImpl.java | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/docker-compose.yml b/docker-compose.yml index b6b68dd..42bf2fd 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -10,6 +10,7 @@ services: - "9090:9090" depends_on: - stats-db + - ewm-service environment: - SPRING_DATASOURCE_URL=jdbc:postgresql://stats-db:5432/stats-service - SPRING_DATASOURCE_USERNAME=user diff --git a/evm-service/src/main/java/ru/practicum/Compilation/Service/Public/CompilationPublicServiceImpl.java b/evm-service/src/main/java/ru/practicum/Compilation/Service/Public/CompilationPublicServiceImpl.java index 1f475e5..f8a14b9 100644 --- a/evm-service/src/main/java/ru/practicum/Compilation/Service/Public/CompilationPublicServiceImpl.java +++ b/evm-service/src/main/java/ru/practicum/Compilation/Service/Public/CompilationPublicServiceImpl.java @@ -49,7 +49,8 @@ public CompilationDTO getCompilation(Integer compId) { @Override public List getCompilations(CompilationsListRequestParams params) { - Pageable pageable = PageRequest.of(params.getFrom(), params.getSize()); + int page = (int) Math.floor((double) params.getFrom() / params.getSize()); + Pageable pageable = PageRequest.of(page, params.getSize()); Page compilations = params.getPinned() == null ? compilationRepository.findAll(pageable) : compilationRepository.findCompilationByPinned(params.getPinned(), pageable); From 51e0782ca3c4b07e459d4c879e890ff783f32f2f Mon Sep 17 00:00:00 2001 From: NadezhdaTA Date: Thu, 4 Sep 2025 11:21:14 +0400 Subject: [PATCH 22/35] =?UTF-8?q?2=D0=BE=D0=B9=20=D1=8D=D1=82=D0=B0=D0=BF?= =?UTF-8?q?=20=D0=B4=D0=B8=D0=BF=D0=BB=D0=BE=D0=BC=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docker-compose.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker-compose.yml b/docker-compose.yml index 42bf2fd..be6a0fa 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -10,7 +10,6 @@ services: - "9090:9090" depends_on: - stats-db - - ewm-service environment: - SPRING_DATASOURCE_URL=jdbc:postgresql://stats-db:5432/stats-service - SPRING_DATASOURCE_USERNAME=user @@ -45,6 +44,7 @@ services: - SPRING_DATASOURCE_PASSWORD=12345 depends_on: - ewm-db + - stats-server ewm-db: image: postgres:16.1 From 85728c2024ac22e6f1787a3b3ce225e060a36d96 Mon Sep 17 00:00:00 2001 From: NadezhdaTA Date: Thu, 4 Sep 2025 14:39:35 +0400 Subject: [PATCH 23/35] =?UTF-8?q?2=D0=BE=D0=B9=20=D1=8D=D1=82=D0=B0=D0=BF?= =?UTF-8?q?=20=D0=B4=D0=B8=D0=BF=D0=BB=D0=BE=D0=BC=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docker-compose.yml | 14 +++++---- .../src/main/resources/application-docker.yml | 30 +++++++++++++++++++ .../main/java/ru/practicum/StatsClient.java | 2 +- .../src/main/resources/application-docker.yml | 25 ++++++++++++++++ 4 files changed, 64 insertions(+), 7 deletions(-) create mode 100644 evm-service/src/main/resources/application-docker.yml create mode 100644 stat/stat-server/src/main/resources/application-docker.yml diff --git a/docker-compose.yml b/docker-compose.yml index be6a0fa..c1d5b2a 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -11,9 +11,10 @@ services: depends_on: - stats-db environment: - - SPRING_DATASOURCE_URL=jdbc:postgresql://stats-db:5432/stats-service - - SPRING_DATASOURCE_USERNAME=user - - SPRING_DATASOURCE_PASSWORD=12345 + SPRING_PROFILES_ACTIVE: docker + SPRING_DATASOURCE_URL: jdbc:postgresql://stats-db:5432/stats-service + SPRING_DATASOURCE_USERNAME: user + SPRING_DATASOURCE_PASSWORD: 12345 stats-db: image: postgres:16.1 @@ -39,9 +40,10 @@ services: ports: - "8080:8080" environment: - - SPRING_DATASOURCE_URL=jdbc:postgresql://ewm-db:5432/ewm-service - - SPRING_DATASOURCE_USERNAME=user - - SPRING_DATASOURCE_PASSWORD=12345 + SPRING_PROFILES_ACTIVE: docker + SPRING_DATASOURCE_URL: jdbc:postgresql://ewm-db:5432/ewm-service + SPRING_DATASOURCE_USERNAME: user + SPRING_DATASOURCE_PASSWORD: 12345 depends_on: - ewm-db - stats-server diff --git a/evm-service/src/main/resources/application-docker.yml b/evm-service/src/main/resources/application-docker.yml new file mode 100644 index 0000000..14693c9 --- /dev/null +++ b/evm-service/src/main/resources/application-docker.yml @@ -0,0 +1,30 @@ +server: + port: 8080 + +stat-server: + url: http://stats-server:9090 + +spring: + jpa: + hibernate.ddl-auto: none + properties.hibernate.format_sql: true + + sql: + init: + mode: always + datasource: + driverClassName: org.postgresql.Driver + url: jdbc:postgresql://ewm-service:5432/ewm-service + username: user + password: 12345 + application: + name: evm-service + +logging: + level: + org: + springframework: + orm.jpa: INFO + transaction: INFO + interceptor: TRACE + JpaTransactionManager: DEBUG \ No newline at end of file diff --git a/stat/stat-client/src/main/java/ru/practicum/StatsClient.java b/stat/stat-client/src/main/java/ru/practicum/StatsClient.java index 15fe2e8..a8c272b 100644 --- a/stat/stat-client/src/main/java/ru/practicum/StatsClient.java +++ b/stat/stat-client/src/main/java/ru/practicum/StatsClient.java @@ -25,7 +25,7 @@ public class StatsClient { private final RestTemplate restTemplate; @Autowired - public StatsClient(@Value("${stat-server.url:http://stat-server:9090}") String serverUrl, + public StatsClient(@Value(value = "${stat-server.url:http://stat-server:9090}") String serverUrl, RestTemplateBuilder builder) { this.serverUrl = serverUrl; this.restTemplate = builder.build(); diff --git a/stat/stat-server/src/main/resources/application-docker.yml b/stat/stat-server/src/main/resources/application-docker.yml new file mode 100644 index 0000000..a2898d2 --- /dev/null +++ b/stat/stat-server/src/main/resources/application-docker.yml @@ -0,0 +1,25 @@ +server: + port: 9090 + +spring: + main: + allow-bean-definition-overriding: true + jpa: + hibernate: + ddl-auto: none + properties: + hibernate: + dialect: org.hibernate.dialect.PostgreSQLDialect + format_sql: true + jdbc: + lob: + non_contextual_creation: true + show-sql: true + sql: + init: + mode: always + datasource: + driverClassName: org.postgresql.Driver + url: jdbc:postgresql://stats-server:5432/stats-server + username: user + password: 12345 \ No newline at end of file From 65d0853b55c0ed6254df1f625a15611fabda1fbb Mon Sep 17 00:00:00 2001 From: NadezhdaTA Date: Thu, 4 Sep 2025 14:56:13 +0400 Subject: [PATCH 24/35] =?UTF-8?q?2=D0=BE=D0=B9=20=D1=8D=D1=82=D0=B0=D0=BF?= =?UTF-8?q?=20=D0=B4=D0=B8=D0=BF=D0=BB=D0=BE=D0=BC=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/ru/practicum/User/Repository/UserRepository.java | 6 +----- .../ru/practicum/User/Service/UserAdminServiceImpl.java | 4 ++-- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/evm-service/src/main/java/ru/practicum/User/Repository/UserRepository.java b/evm-service/src/main/java/ru/practicum/User/Repository/UserRepository.java index 3306878..4f34f21 100644 --- a/evm-service/src/main/java/ru/practicum/User/Repository/UserRepository.java +++ b/evm-service/src/main/java/ru/practicum/User/Repository/UserRepository.java @@ -11,11 +11,7 @@ public interface UserRepository extends JpaRepository { User save(User newUser); - void deleteUserById(Integer id); - Optional findUserById(Integer id); - Page findAll(Pageable pageable); - - Page findAllByIdIn(Collection ids, Pageable pageable); + Page findByIdIn(Collection ids, Pageable pageable); } diff --git a/evm-service/src/main/java/ru/practicum/User/Service/UserAdminServiceImpl.java b/evm-service/src/main/java/ru/practicum/User/Service/UserAdminServiceImpl.java index cea13ca..ef4c1c6 100644 --- a/evm-service/src/main/java/ru/practicum/User/Service/UserAdminServiceImpl.java +++ b/evm-service/src/main/java/ru/practicum/User/Service/UserAdminServiceImpl.java @@ -46,10 +46,10 @@ public UserDTO getUserById(Integer id) { @Override public List getUsers(UsersListRequest request) { int pageNumber = (int) Math.floor((double) request.getFrom() / request.getSize()); - Pageable pageable = PageRequest.of(pageNumber, request.getSize(), Sort.Direction.ASC, "id"); + Pageable pageable = PageRequest.of(pageNumber, request.getSize(), Sort.by("id").ascending()); Page users = request.getIds() == null ? userRepository.findAll(pageable) - : userRepository.findAllByIdIn(request.getIds(), pageable); + : userRepository.findByIdIn(request.getIds(), pageable); return users.getContent().stream() .map(userMapper::toUserDTO) From b3c340c4aa135c702b21489f2b3af885212df64d Mon Sep 17 00:00:00 2001 From: NadezhdaTA Date: Thu, 4 Sep 2025 17:04:15 +0400 Subject: [PATCH 25/35] =?UTF-8?q?2=D0=BE=D0=B9=20=D1=8D=D1=82=D0=B0=D0=BF?= =?UTF-8?q?=20=D0=B4=D0=B8=D0=BF=D0=BB=D0=BE=D0=BC=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/ru/practicum/User/Service/UserAdminServiceImpl.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/evm-service/src/main/java/ru/practicum/User/Service/UserAdminServiceImpl.java b/evm-service/src/main/java/ru/practicum/User/Service/UserAdminServiceImpl.java index ef4c1c6..692489a 100644 --- a/evm-service/src/main/java/ru/practicum/User/Service/UserAdminServiceImpl.java +++ b/evm-service/src/main/java/ru/practicum/User/Service/UserAdminServiceImpl.java @@ -16,6 +16,7 @@ import java.util.List; + @Service @RequiredArgsConstructor public class UserAdminServiceImpl implements UserAdminService { @@ -45,8 +46,8 @@ public UserDTO getUserById(Integer id) { @Override public List getUsers(UsersListRequest request) { - int pageNumber = (int) Math.floor((double) request.getFrom() / request.getSize()); - Pageable pageable = PageRequest.of(pageNumber, request.getSize(), Sort.by("id").ascending()); + Pageable pageable = PageRequest.of(request.getFrom() / request.getSize(), request.getSize(), Sort.by("id").ascending()); + Page users = request.getIds() == null ? userRepository.findAll(pageable) : userRepository.findByIdIn(request.getIds(), pageable); From c2dcf610c5410b4d2f349d5768d0abcac4cd6bd9 Mon Sep 17 00:00:00 2001 From: NadezhdaTA Date: Thu, 4 Sep 2025 17:54:23 +0400 Subject: [PATCH 26/35] =?UTF-8?q?2=D0=BE=D0=B9=20=D1=8D=D1=82=D0=B0=D0=BF?= =?UTF-8?q?=20=D0=B4=D0=B8=D0=BF=D0=BB=D0=BE=D0=BC=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../practicum/User/Repository/UserRepository.java | 3 +++ .../User/Service/UserAdminServiceImpl.java | 14 ++++---------- 2 files changed, 7 insertions(+), 10 deletions(-) diff --git a/evm-service/src/main/java/ru/practicum/User/Repository/UserRepository.java b/evm-service/src/main/java/ru/practicum/User/Repository/UserRepository.java index 4f34f21..67f51a0 100644 --- a/evm-service/src/main/java/ru/practicum/User/Repository/UserRepository.java +++ b/evm-service/src/main/java/ru/practicum/User/Repository/UserRepository.java @@ -6,6 +6,7 @@ import ru.practicum.User.Model.User; import java.util.Collection; +import java.util.List; import java.util.Optional; public interface UserRepository extends JpaRepository { @@ -14,4 +15,6 @@ public interface UserRepository extends JpaRepository { Optional findUserById(Integer id); Page findByIdIn(Collection ids, Pageable pageable); + + List findUsersByIdIn(Collection ids); } diff --git a/evm-service/src/main/java/ru/practicum/User/Service/UserAdminServiceImpl.java b/evm-service/src/main/java/ru/practicum/User/Service/UserAdminServiceImpl.java index 692489a..b7d4382 100644 --- a/evm-service/src/main/java/ru/practicum/User/Service/UserAdminServiceImpl.java +++ b/evm-service/src/main/java/ru/practicum/User/Service/UserAdminServiceImpl.java @@ -1,10 +1,6 @@ package ru.practicum.User.Service; import lombok.RequiredArgsConstructor; -import org.springframework.data.domain.Page; -import org.springframework.data.domain.PageRequest; -import org.springframework.data.domain.Pageable; -import org.springframework.data.domain.Sort; import org.springframework.stereotype.Service; import ru.practicum.Exception.NotFoundException; import ru.practicum.User.DTO.NewUserRequest; @@ -46,13 +42,11 @@ public UserDTO getUserById(Integer id) { @Override public List getUsers(UsersListRequest request) { - Pageable pageable = PageRequest.of(request.getFrom() / request.getSize(), request.getSize(), Sort.by("id").ascending()); + List users = request.getIds() == null + ? userRepository.findAll() + : userRepository.findUsersByIdIn(request.getIds()); - Page users = request.getIds() == null - ? userRepository.findAll(pageable) - : userRepository.findByIdIn(request.getIds(), pageable); - - return users.getContent().stream() + return users.stream() .map(userMapper::toUserDTO) .toList(); } From 36ec5fb49c138e23ce7f9545439f50604f1227e4 Mon Sep 17 00:00:00 2001 From: NadezhdaTA Date: Fri, 5 Sep 2025 16:40:51 +0400 Subject: [PATCH 27/35] =?UTF-8?q?2=D0=BE=D0=B9=20=D1=8D=D1=82=D0=B0=D0=BF?= =?UTF-8?q?=20=D0=B4=D0=B8=D0=BF=D0=BB=D0=BE=D0=BC=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../practicum/User/Service/UserAdminServiceImpl.java | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/evm-service/src/main/java/ru/practicum/User/Service/UserAdminServiceImpl.java b/evm-service/src/main/java/ru/practicum/User/Service/UserAdminServiceImpl.java index b7d4382..5ff863c 100644 --- a/evm-service/src/main/java/ru/practicum/User/Service/UserAdminServiceImpl.java +++ b/evm-service/src/main/java/ru/practicum/User/Service/UserAdminServiceImpl.java @@ -1,6 +1,9 @@ package ru.practicum.User.Service; import lombok.RequiredArgsConstructor; +import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Sort; import org.springframework.stereotype.Service; import ru.practicum.Exception.NotFoundException; import ru.practicum.User.DTO.NewUserRequest; @@ -42,9 +45,12 @@ public UserDTO getUserById(Integer id) { @Override public List getUsers(UsersListRequest request) { - List users = request.getIds() == null - ? userRepository.findAll() - : userRepository.findUsersByIdIn(request.getIds()); + int page = request.getFrom() / request.getSize(); + Pageable pageable = PageRequest.of(page, request.getSize(), Sort.by("id").ascending()); + + List users = request.getIds() == null || request.getIds().isEmpty() + ? userRepository.findAll(pageable).getContent() + : userRepository.findByIdIn(request.getIds(), pageable).getContent(); return users.stream() .map(userMapper::toUserDTO) From 5a888ea8a7815e5f01e3f7f69d4b88dedbb5a772 Mon Sep 17 00:00:00 2001 From: NadezhdaTA Date: Fri, 5 Sep 2025 17:52:23 +0400 Subject: [PATCH 28/35] =?UTF-8?q?2=D0=BE=D0=B9=20=D1=8D=D1=82=D0=B0=D0=BF?= =?UTF-8?q?=20=D0=B4=D0=B8=D0=BF=D0=BB=D0=BE=D0=BC=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docker-compose.yml | 2 ++ evm-service/src/main/resources/application.yml | 2 +- evm-service/src/main/resources/schema.sql | 9 ++++++--- stat/stat-server/src/main/resources/application.yml | 2 +- 4 files changed, 10 insertions(+), 5 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index c1d5b2a..131561a 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -11,6 +11,7 @@ services: depends_on: - stats-db environment: + SPRING_JPA_HIBERNATE_DDL_AUTO: update SPRING_PROFILES_ACTIVE: docker SPRING_DATASOURCE_URL: jdbc:postgresql://stats-db:5432/stats-service SPRING_DATASOURCE_USERNAME: user @@ -40,6 +41,7 @@ services: ports: - "8080:8080" environment: + SPRING_JPA_HIBERNATE_DDL_AUTO: update SPRING_PROFILES_ACTIVE: docker SPRING_DATASOURCE_URL: jdbc:postgresql://ewm-db:5432/ewm-service SPRING_DATASOURCE_USERNAME: user diff --git a/evm-service/src/main/resources/application.yml b/evm-service/src/main/resources/application.yml index e2e1cd1..b01c75d 100644 --- a/evm-service/src/main/resources/application.yml +++ b/evm-service/src/main/resources/application.yml @@ -6,7 +6,7 @@ stat-server: spring: jpa: - hibernate.ddl-auto: none + hibernate.ddl-auto: update properties.hibernate.format_sql: true sql: diff --git a/evm-service/src/main/resources/schema.sql b/evm-service/src/main/resources/schema.sql index d033c92..1e47901 100644 --- a/evm-service/src/main/resources/schema.sql +++ b/evm-service/src/main/resources/schema.sql @@ -1,14 +1,17 @@ +DROP TABLE IF EXISTS users, categories, events, requests, compilations, compilation_events; CREATE TABLE IF NOT EXISTS users ( id INT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, name CHARACTER VARYING(255) NOT NULL, - email CHARACTER VARYING(500) NOT NULL UNIQUE + email CHARACTER VARYING(500) NOT NULL UNIQUE, + CONSTRAINT UQ_USER_EMAIL UNIQUE (email) ); CREATE TABLE IF NOT EXISTS categories ( id INT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, - name CHARACTER VARYING(255) UNIQUE NOT NULL + name CHARACTER VARYING(255) UNIQUE NOT NULL, + CONSTRAINT UQ_CATEGORY_NAME UNIQUE (name) ); CREATE TABLE IF NOT EXISTS state ( @@ -16,7 +19,7 @@ CREATE TABLE IF NOT EXISTS state ( name CHARACTER VARYING (50) ); -CREATE TABLE IF NOT EXISTS events ( +CREATE TABLE IF NOT EXISTS events ( id INT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, title CHARACTER VARYING (200) NOT NULL, annotation CHARACTER VARYING (2000) NOT NULL, diff --git a/stat/stat-server/src/main/resources/application.yml b/stat/stat-server/src/main/resources/application.yml index 103c584..4531ab8 100644 --- a/stat/stat-server/src/main/resources/application.yml +++ b/stat/stat-server/src/main/resources/application.yml @@ -6,7 +6,7 @@ spring: allow-bean-definition-overriding: true jpa: hibernate: - ddl-auto: none + ddl-auto: update properties: hibernate: dialect: org.hibernate.dialect.PostgreSQLDialect From ad83fd1f20a67da36923ef12e1f7fed63f37fbd3 Mon Sep 17 00:00:00 2001 From: NadezhdaTA Date: Fri, 5 Sep 2025 18:23:26 +0400 Subject: [PATCH 29/35] =?UTF-8?q?2=D0=BE=D0=B9=20=D1=8D=D1=82=D0=B0=D0=BF?= =?UTF-8?q?=20=D0=B4=D0=B8=D0=BF=D0=BB=D0=BE=D0=BC=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docker-compose.yml | 2 -- evm-service/src/main/resources/application.yml | 2 +- stat/stat-server/src/main/resources/application.yml | 2 +- 3 files changed, 2 insertions(+), 4 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index 131561a..c1d5b2a 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -11,7 +11,6 @@ services: depends_on: - stats-db environment: - SPRING_JPA_HIBERNATE_DDL_AUTO: update SPRING_PROFILES_ACTIVE: docker SPRING_DATASOURCE_URL: jdbc:postgresql://stats-db:5432/stats-service SPRING_DATASOURCE_USERNAME: user @@ -41,7 +40,6 @@ services: ports: - "8080:8080" environment: - SPRING_JPA_HIBERNATE_DDL_AUTO: update SPRING_PROFILES_ACTIVE: docker SPRING_DATASOURCE_URL: jdbc:postgresql://ewm-db:5432/ewm-service SPRING_DATASOURCE_USERNAME: user diff --git a/evm-service/src/main/resources/application.yml b/evm-service/src/main/resources/application.yml index b01c75d..e2e1cd1 100644 --- a/evm-service/src/main/resources/application.yml +++ b/evm-service/src/main/resources/application.yml @@ -6,7 +6,7 @@ stat-server: spring: jpa: - hibernate.ddl-auto: update + hibernate.ddl-auto: none properties.hibernate.format_sql: true sql: diff --git a/stat/stat-server/src/main/resources/application.yml b/stat/stat-server/src/main/resources/application.yml index 4531ab8..103c584 100644 --- a/stat/stat-server/src/main/resources/application.yml +++ b/stat/stat-server/src/main/resources/application.yml @@ -6,7 +6,7 @@ spring: allow-bean-definition-overriding: true jpa: hibernate: - ddl-auto: update + ddl-auto: none properties: hibernate: dialect: org.hibernate.dialect.PostgreSQLDialect From 63dc192f46a2a35aa705bb601a7057faa1ebe55d Mon Sep 17 00:00:00 2001 From: NadezhdaTA Date: Fri, 5 Sep 2025 22:37:24 +0400 Subject: [PATCH 30/35] =?UTF-8?q?2=D0=BE=D0=B9=20=D1=8D=D1=82=D0=B0=D0=BF?= =?UTF-8?q?=20=D0=B4=D0=B8=D0=BF=D0=BB=D0=BE=D0=BC=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../practicum/Category/DTO/CategoryDTO.java | 4 ++-- .../Category/DTO/NewCategoryDTO.java | 4 ++-- .../ru/practicum/Category/Model/Category.java | 2 +- .../CompilationDTO/NewCompilationDTO.java | 4 ++-- .../UpdateCompilationRequest.java | 5 +++-- .../DTO/EventRequestStatusUpdateRequest.java | 7 +++++++ .../ru/practicum/Event/DTO/NewEventDTO.java | 7 +++---- .../Event/DTO/UpdateEventAdminRequest.java | 8 ++++---- .../Event/DTO/UpdateEventUserRequest.java | 14 ++++++++------ .../java/ru/practicum/Event/Model/Event.java | 6 +++--- .../User/Controller/UserAdminController.java | 8 ++++++-- .../ru/practicum/User/DTO/NewUserRequest.java | 6 +++--- .../practicum/User/DTO/UsersListRequest.java | 19 +++++-------------- .../java/ru/practicum/User/Model/User.java | 4 ++-- .../User/Service/UserAdminServiceImpl.java | 8 ++++---- .../src/main/resources/application-docker.yml | 9 ++++++++- evm-service/src/main/resources/schema.sql | 16 ++++++++-------- .../stat-server/src/main/resources/schema.sql | 8 +++++--- 18 files changed, 76 insertions(+), 63 deletions(-) diff --git a/evm-service/src/main/java/ru/practicum/Category/DTO/CategoryDTO.java b/evm-service/src/main/java/ru/practicum/Category/DTO/CategoryDTO.java index a31fa6a..fdc9e3d 100644 --- a/evm-service/src/main/java/ru/practicum/Category/DTO/CategoryDTO.java +++ b/evm-service/src/main/java/ru/practicum/Category/DTO/CategoryDTO.java @@ -1,10 +1,10 @@ package ru.practicum.Category.DTO; import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.Size; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; -import org.hibernate.validator.constraints.Length; @Data @NoArgsConstructor @@ -13,6 +13,6 @@ public class CategoryDTO { private Integer id; @NotBlank - @Length(max = 50) + @Size(max = 50) private String name; } diff --git a/evm-service/src/main/java/ru/practicum/Category/DTO/NewCategoryDTO.java b/evm-service/src/main/java/ru/practicum/Category/DTO/NewCategoryDTO.java index 1154a12..0e0dbfc 100644 --- a/evm-service/src/main/java/ru/practicum/Category/DTO/NewCategoryDTO.java +++ b/evm-service/src/main/java/ru/practicum/Category/DTO/NewCategoryDTO.java @@ -1,16 +1,16 @@ package ru.practicum.Category.DTO; import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.Size; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; -import org.hibernate.validator.constraints.Length; @Data @NoArgsConstructor @AllArgsConstructor public class NewCategoryDTO { @NotBlank - @Length(max = 50) + @Size(max = 50) private String name; } diff --git a/evm-service/src/main/java/ru/practicum/Category/Model/Category.java b/evm-service/src/main/java/ru/practicum/Category/Model/Category.java index b30954c..92b44d1 100644 --- a/evm-service/src/main/java/ru/practicum/Category/Model/Category.java +++ b/evm-service/src/main/java/ru/practicum/Category/Model/Category.java @@ -17,6 +17,6 @@ public class Category { @Column(name = "id") private Integer id; - @Column(name = "name") + @Column(name = "name", length = 50) private String name; } diff --git a/evm-service/src/main/java/ru/practicum/Compilation/CompilationDTO/NewCompilationDTO.java b/evm-service/src/main/java/ru/practicum/Compilation/CompilationDTO/NewCompilationDTO.java index fb7be3a..6286f29 100644 --- a/evm-service/src/main/java/ru/practicum/Compilation/CompilationDTO/NewCompilationDTO.java +++ b/evm-service/src/main/java/ru/practicum/Compilation/CompilationDTO/NewCompilationDTO.java @@ -1,10 +1,10 @@ package ru.practicum.Compilation.CompilationDTO; import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.Size; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; -import org.hibernate.validator.constraints.Length; import java.util.ArrayList; @@ -16,6 +16,6 @@ public class NewCompilationDTO { private Boolean pinned = false; @NotBlank - @Length(min = 1, max = 50) + @Size(min = 1, max = 50) private String title; } diff --git a/evm-service/src/main/java/ru/practicum/Compilation/CompilationDTO/UpdateCompilationRequest.java b/evm-service/src/main/java/ru/practicum/Compilation/CompilationDTO/UpdateCompilationRequest.java index 56663cd..9339d0e 100644 --- a/evm-service/src/main/java/ru/practicum/Compilation/CompilationDTO/UpdateCompilationRequest.java +++ b/evm-service/src/main/java/ru/practicum/Compilation/CompilationDTO/UpdateCompilationRequest.java @@ -1,9 +1,10 @@ package ru.practicum.Compilation.CompilationDTO; +import jakarta.validation.constraints.Size; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; -import org.hibernate.validator.constraints.Length; + import java.util.ArrayList; @@ -14,6 +15,6 @@ public class UpdateCompilationRequest { private ArrayList events; private Boolean pinned; - @Length(min = 1, max = 50) + @Size(min = 1, max = 50) private String title; } diff --git a/evm-service/src/main/java/ru/practicum/Event/DTO/EventRequestStatusUpdateRequest.java b/evm-service/src/main/java/ru/practicum/Event/DTO/EventRequestStatusUpdateRequest.java index 1aab0a3..b7bade6 100644 --- a/evm-service/src/main/java/ru/practicum/Event/DTO/EventRequestStatusUpdateRequest.java +++ b/evm-service/src/main/java/ru/practicum/Event/DTO/EventRequestStatusUpdateRequest.java @@ -1,5 +1,7 @@ package ru.practicum.Event.DTO; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; @@ -11,7 +13,12 @@ @NoArgsConstructor @AllArgsConstructor public class EventRequestStatusUpdateRequest { + + @NotNull + @NotEmpty private ArrayList requestIds; + + @NotNull private State status; } diff --git a/evm-service/src/main/java/ru/practicum/Event/DTO/NewEventDTO.java b/evm-service/src/main/java/ru/practicum/Event/DTO/NewEventDTO.java index f92438a..f9cd4ca 100644 --- a/evm-service/src/main/java/ru/practicum/Event/DTO/NewEventDTO.java +++ b/evm-service/src/main/java/ru/practicum/Event/DTO/NewEventDTO.java @@ -6,7 +6,6 @@ import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; -import org.hibernate.validator.constraints.Length; import ru.practicum.Event.Model.Location; import java.time.LocalDateTime; @@ -16,7 +15,7 @@ @AllArgsConstructor public class NewEventDTO { @NotBlank - @Length(min = 20, max = 2000) + @Size(min = 20, max = 2000) private String annotation; @NotNull @@ -24,7 +23,7 @@ public class NewEventDTO { private Integer categoryId; @NotBlank - @Length(min = 20, max = 7000) + @Size(min = 20, max = 7000) private String description; @NotNull @@ -43,6 +42,6 @@ public class NewEventDTO { private Boolean requestModeration = true; @NotBlank - @Length(min = 3, max = 120) + @Size(min = 3, max = 120) private String title; } diff --git a/evm-service/src/main/java/ru/practicum/Event/DTO/UpdateEventAdminRequest.java b/evm-service/src/main/java/ru/practicum/Event/DTO/UpdateEventAdminRequest.java index 823a3a6..7f4ba78 100644 --- a/evm-service/src/main/java/ru/practicum/Event/DTO/UpdateEventAdminRequest.java +++ b/evm-service/src/main/java/ru/practicum/Event/DTO/UpdateEventAdminRequest.java @@ -2,10 +2,10 @@ import com.fasterxml.jackson.annotation.JsonFormat; import jakarta.validation.constraints.Future; +import jakarta.validation.constraints.Size; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; -import org.hibernate.validator.constraints.Length; import ru.practicum.Event.Model.Location; import ru.practicum.Event.Model.State; @@ -16,12 +16,12 @@ @AllArgsConstructor public class UpdateEventAdminRequest { - @Length(min = 20, max = 2000) + @Size(min = 20, max = 2000) private String annotation; private Integer category; - @Length(min = 20, max = 7000) + @Size(min = 20, max = 7000) private String description; @Future @@ -38,7 +38,7 @@ public class UpdateEventAdminRequest { private State stateAction; - @Length(min = 3, max = 120) + @Size(min = 3, max = 120) private String title; } diff --git a/evm-service/src/main/java/ru/practicum/Event/DTO/UpdateEventUserRequest.java b/evm-service/src/main/java/ru/practicum/Event/DTO/UpdateEventUserRequest.java index 37ee576..19eb6e8 100644 --- a/evm-service/src/main/java/ru/practicum/Event/DTO/UpdateEventUserRequest.java +++ b/evm-service/src/main/java/ru/practicum/Event/DTO/UpdateEventUserRequest.java @@ -1,11 +1,12 @@ package ru.practicum.Event.DTO; import com.fasterxml.jackson.annotation.JsonFormat; -import jakarta.validation.constraints.Positive; +import jakarta.validation.constraints.Future; +import jakarta.validation.constraints.PositiveOrZero; +import jakarta.validation.constraints.Size; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; -import org.hibernate.validator.constraints.Length; import ru.practicum.Event.Model.Location; import ru.practicum.Event.Model.State; @@ -16,28 +17,29 @@ @AllArgsConstructor public class UpdateEventUserRequest { - @Length(min = 20, max = 2000) + @Size(min = 20, max = 2000) private String annotation; private Integer categoryId; - @Length(min = 20, max = 7000) + @Size(min = 20, max = 7000) private String description; @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @Future private LocalDateTime eventDate; private Location location; private Boolean paid; - @Positive + @PositiveOrZero private Integer participantLimit; private Boolean requestModeration; private State stateAction; - @Length(min = 3, max = 120) + @Size(min = 3, max = 120) private String title; } diff --git a/evm-service/src/main/java/ru/practicum/Event/Model/Event.java b/evm-service/src/main/java/ru/practicum/Event/Model/Event.java index 35f91ad..2b81c22 100644 --- a/evm-service/src/main/java/ru/practicum/Event/Model/Event.java +++ b/evm-service/src/main/java/ru/practicum/Event/Model/Event.java @@ -21,10 +21,10 @@ public class Event { @Column(name = "id") private Integer id; - @Column(name = "title") + @Column(name = "title", length = 200) private String title; - @Column(name = "annotation") + @Column(name = "annotation", length = 2000) private String annotation; @ManyToOne(fetch = FetchType.EAGER) @@ -36,7 +36,7 @@ public class Event { @Column(name = "created_on") private LocalDateTime createdOn = LocalDateTime.now(); - @Column(name = "description") + @Column(name = "description", length = 7000) private String description; @Column(name = "event_date") diff --git a/evm-service/src/main/java/ru/practicum/User/Controller/UserAdminController.java b/evm-service/src/main/java/ru/practicum/User/Controller/UserAdminController.java index 02134b5..3ee9657 100644 --- a/evm-service/src/main/java/ru/practicum/User/Controller/UserAdminController.java +++ b/evm-service/src/main/java/ru/practicum/User/Controller/UserAdminController.java @@ -1,6 +1,8 @@ package ru.practicum.User.Controller; import jakarta.validation.Valid; +import jakarta.validation.constraints.Positive; +import jakarta.validation.constraints.PositiveOrZero; import lombok.RequiredArgsConstructor; import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.*; @@ -31,8 +33,10 @@ public UserDTO getUserById(@PathVariable Integer userId) { @GetMapping @ResponseStatus(HttpStatus.OK) - public List getUsers(@ModelAttribute UsersListRequest request) { - return userAdminService.getUsers(request); + public List getUsers(@RequestParam(required = false) List ids, + @RequestParam(defaultValue = "0") @PositiveOrZero int from, + @RequestParam(defaultValue = "10") @Positive int size) { + return userAdminService.getUsers(new UsersListRequest(ids, from, size)); } @DeleteMapping("/{userId}") diff --git a/evm-service/src/main/java/ru/practicum/User/DTO/NewUserRequest.java b/evm-service/src/main/java/ru/practicum/User/DTO/NewUserRequest.java index 54d2534..9e2e7f4 100644 --- a/evm-service/src/main/java/ru/practicum/User/DTO/NewUserRequest.java +++ b/evm-service/src/main/java/ru/practicum/User/DTO/NewUserRequest.java @@ -2,10 +2,10 @@ import jakarta.validation.constraints.Email; import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.Size; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; -import org.hibernate.validator.constraints.Length; @Data @NoArgsConstructor @@ -13,11 +13,11 @@ public class NewUserRequest { @Email @NotBlank - @Length(min = 6, max = 254) + @Size(min = 6, max = 254) private String email; @NotBlank - @Length(min = 2, max = 250) + @Size(min = 2, max = 250) private String name; } diff --git a/evm-service/src/main/java/ru/practicum/User/DTO/UsersListRequest.java b/evm-service/src/main/java/ru/practicum/User/DTO/UsersListRequest.java index 4c85167..c194ba8 100644 --- a/evm-service/src/main/java/ru/practicum/User/DTO/UsersListRequest.java +++ b/evm-service/src/main/java/ru/practicum/User/DTO/UsersListRequest.java @@ -1,18 +1,9 @@ package ru.practicum.User.DTO; -import jakarta.validation.constraints.Positive; -import jakarta.validation.constraints.PositiveOrZero; -import lombok.Data; +import java.util.List; -import java.util.Set; - -@Data -public class UsersListRequest { - private Set ids; - - @PositiveOrZero - private final Integer from = 0; - - @Positive - private final Integer size = 10; +public record UsersListRequest( + List ids, + Integer from, + Integer size) { } diff --git a/evm-service/src/main/java/ru/practicum/User/Model/User.java b/evm-service/src/main/java/ru/practicum/User/Model/User.java index eaad6a0..9e08ef5 100644 --- a/evm-service/src/main/java/ru/practicum/User/Model/User.java +++ b/evm-service/src/main/java/ru/practicum/User/Model/User.java @@ -16,9 +16,9 @@ public class User { @Column(name = "id") private Integer id; - @Column(name = "email") + @Column(name = "email", length = 500) private String email; - @Column(name = "name") + @Column(name = "name", length = 250) private String name; } diff --git a/evm-service/src/main/java/ru/practicum/User/Service/UserAdminServiceImpl.java b/evm-service/src/main/java/ru/practicum/User/Service/UserAdminServiceImpl.java index 5ff863c..378cbf0 100644 --- a/evm-service/src/main/java/ru/practicum/User/Service/UserAdminServiceImpl.java +++ b/evm-service/src/main/java/ru/practicum/User/Service/UserAdminServiceImpl.java @@ -45,12 +45,12 @@ public UserDTO getUserById(Integer id) { @Override public List getUsers(UsersListRequest request) { - int page = request.getFrom() / request.getSize(); - Pageable pageable = PageRequest.of(page, request.getSize(), Sort.by("id").ascending()); + int page = request.from() / request.size(); + Pageable pageable = PageRequest.of(page, request.size(), Sort.by("id").ascending()); - List users = request.getIds() == null || request.getIds().isEmpty() + List users = request.ids() == null || request.ids().isEmpty() ? userRepository.findAll(pageable).getContent() - : userRepository.findByIdIn(request.getIds(), pageable).getContent(); + : userRepository.findByIdIn(request.ids(), pageable).getContent(); return users.stream() .map(userMapper::toUserDTO) diff --git a/evm-service/src/main/resources/application-docker.yml b/evm-service/src/main/resources/application-docker.yml index 14693c9..51ed0b1 100644 --- a/evm-service/src/main/resources/application-docker.yml +++ b/evm-service/src/main/resources/application-docker.yml @@ -7,7 +7,14 @@ stat-server: spring: jpa: hibernate.ddl-auto: none - properties.hibernate.format_sql: true + properties: + hibernate: + dialect: org.hibernate.dialect.PostgreSQLDialect + format_sql: true + jdbc: + lob: + non_contextual_creation: true + show-sql: true sql: init: diff --git a/evm-service/src/main/resources/schema.sql b/evm-service/src/main/resources/schema.sql index 1e47901..97956c5 100644 --- a/evm-service/src/main/resources/schema.sql +++ b/evm-service/src/main/resources/schema.sql @@ -2,31 +2,31 @@ DROP TABLE IF EXISTS users, categories, events, requests, compilations, compilat CREATE TABLE IF NOT EXISTS users ( id INT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, - name CHARACTER VARYING(255) NOT NULL, - email CHARACTER VARYING(500) NOT NULL UNIQUE, + name VARCHAR(250) NOT NULL, + email VARCHAR(500) NOT NULL UNIQUE, CONSTRAINT UQ_USER_EMAIL UNIQUE (email) ); CREATE TABLE IF NOT EXISTS categories ( id INT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, - name CHARACTER VARYING(255) UNIQUE NOT NULL, + name VARCHAR(50) UNIQUE NOT NULL, CONSTRAINT UQ_CATEGORY_NAME UNIQUE (name) ); CREATE TABLE IF NOT EXISTS state ( id INT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, - name CHARACTER VARYING (50) + name VARCHAR(50) ); CREATE TABLE IF NOT EXISTS events ( id INT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, - title CHARACTER VARYING (200) NOT NULL, - annotation CHARACTER VARYING (2000) NOT NULL, + title VARCHAR(205) NOT NULL, + annotation VARCHAR(2000) NOT NULL, category_id INT NOT NULL, confirmed_requests INT, created_on TIMESTAMP WITHOUT TIME ZONE, - description CHARACTER VARYING (7000), + description VARCHAR(7000), event_date TIMESTAMP WITHOUT TIME ZONE NOT NULL, initiator_id INT NOT NULL, lat INT NOT NULL, @@ -44,7 +44,7 @@ CREATE TABLE IF NOT EXISTS events ( CREATE TABLE IF NOT EXISTS compilations ( id INT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, pinned BOOLEAN, - title VARCHAR NOT NULL + title VARCHAR(150) NOT NULL ); CREATE TABLE IF NOT EXISTS requests ( diff --git a/stat/stat-server/src/main/resources/schema.sql b/stat/stat-server/src/main/resources/schema.sql index ae2d69d..fb8f050 100644 --- a/stat/stat-server/src/main/resources/schema.sql +++ b/stat/stat-server/src/main/resources/schema.sql @@ -1,7 +1,9 @@ +DROP TABLE IF EXISTS hits; + CREATE TABLE IF NOT EXISTS hits ( id BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, - app CHARACTER VARYING(255) NOT NULL, - uri CHARACTER VARYING(100) NOT NULL, - ip CHARACTER VARYING(50) NOT NULL, + app VARCHAR (255) NOT NULL, + uri VARCHAR (100) NOT NULL, + ip VARCHAR (50) NOT NULL, timestamp TIMESTAMP WITHOUT TIME ZONE ); From aaf552536dc4f7528c6b3863ee9127560146aae4 Mon Sep 17 00:00:00 2001 From: NadezhdaTA Date: Sat, 6 Sep 2025 10:58:44 +0400 Subject: [PATCH 31/35] =?UTF-8?q?2=D0=BE=D0=B9=20=D1=8D=D1=82=D0=B0=D0=BF?= =?UTF-8?q?=20=D0=B4=D0=B8=D0=BF=D0=BB=D0=BE=D0=BC=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- evm-service/src/main/resources/application-docker.yml | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/evm-service/src/main/resources/application-docker.yml b/evm-service/src/main/resources/application-docker.yml index 51ed0b1..14693c9 100644 --- a/evm-service/src/main/resources/application-docker.yml +++ b/evm-service/src/main/resources/application-docker.yml @@ -7,14 +7,7 @@ stat-server: spring: jpa: hibernate.ddl-auto: none - properties: - hibernate: - dialect: org.hibernate.dialect.PostgreSQLDialect - format_sql: true - jdbc: - lob: - non_contextual_creation: true - show-sql: true + properties.hibernate.format_sql: true sql: init: From 9f20cceba5dbc12e9bfb5d91efd27ce2f71595cf Mon Sep 17 00:00:00 2001 From: NadezhdaTA Date: Sat, 6 Sep 2025 13:12:38 +0400 Subject: [PATCH 32/35] =?UTF-8?q?2=D0=BE=D0=B9=20=D1=8D=D1=82=D0=B0=D0=BF?= =?UTF-8?q?=20=D0=B4=D0=B8=D0=BF=D0=BB=D0=BE=D0=BC=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ru/practicum/Category/Model/Category.java | 2 +- .../java/ru/practicum/Event/Model/Event.java | 6 +- .../User/Controller/UserAdminController.java | 8 +- .../practicum/User/DTO/UsersListRequest.java | 19 +--- .../java/ru/practicum/User/Model/User.java | 4 +- .../User/Repository/UserRepository.java | 1 + .../User/Service/UserAdminServiceImpl.java | 15 +-- evm-service/src/main/resources/schema.sql | 21 +++-- .../main/java/ru/practicum/BaseClient.java | 54 ----------- .../main/java/ru/practicum/StatsClient1.java | 91 ------------------- .../practicum/service/StatsServiceImpl.java | 26 +++--- .../src/main/resources/application-docker.yml | 9 +- .../stat-server/src/main/resources/schema.sql | 8 +- 13 files changed, 57 insertions(+), 207 deletions(-) delete mode 100644 stat/stat-client/src/main/java/ru/practicum/BaseClient.java delete mode 100644 stat/stat-client/src/main/java/ru/practicum/StatsClient1.java diff --git a/evm-service/src/main/java/ru/practicum/Category/Model/Category.java b/evm-service/src/main/java/ru/practicum/Category/Model/Category.java index b30954c..92b44d1 100644 --- a/evm-service/src/main/java/ru/practicum/Category/Model/Category.java +++ b/evm-service/src/main/java/ru/practicum/Category/Model/Category.java @@ -17,6 +17,6 @@ public class Category { @Column(name = "id") private Integer id; - @Column(name = "name") + @Column(name = "name", length = 50) private String name; } diff --git a/evm-service/src/main/java/ru/practicum/Event/Model/Event.java b/evm-service/src/main/java/ru/practicum/Event/Model/Event.java index 35f91ad..2b81c22 100644 --- a/evm-service/src/main/java/ru/practicum/Event/Model/Event.java +++ b/evm-service/src/main/java/ru/practicum/Event/Model/Event.java @@ -21,10 +21,10 @@ public class Event { @Column(name = "id") private Integer id; - @Column(name = "title") + @Column(name = "title", length = 200) private String title; - @Column(name = "annotation") + @Column(name = "annotation", length = 2000) private String annotation; @ManyToOne(fetch = FetchType.EAGER) @@ -36,7 +36,7 @@ public class Event { @Column(name = "created_on") private LocalDateTime createdOn = LocalDateTime.now(); - @Column(name = "description") + @Column(name = "description", length = 7000) private String description; @Column(name = "event_date") diff --git a/evm-service/src/main/java/ru/practicum/User/Controller/UserAdminController.java b/evm-service/src/main/java/ru/practicum/User/Controller/UserAdminController.java index 02134b5..3ee9657 100644 --- a/evm-service/src/main/java/ru/practicum/User/Controller/UserAdminController.java +++ b/evm-service/src/main/java/ru/practicum/User/Controller/UserAdminController.java @@ -1,6 +1,8 @@ package ru.practicum.User.Controller; import jakarta.validation.Valid; +import jakarta.validation.constraints.Positive; +import jakarta.validation.constraints.PositiveOrZero; import lombok.RequiredArgsConstructor; import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.*; @@ -31,8 +33,10 @@ public UserDTO getUserById(@PathVariable Integer userId) { @GetMapping @ResponseStatus(HttpStatus.OK) - public List getUsers(@ModelAttribute UsersListRequest request) { - return userAdminService.getUsers(request); + public List getUsers(@RequestParam(required = false) List ids, + @RequestParam(defaultValue = "0") @PositiveOrZero int from, + @RequestParam(defaultValue = "10") @Positive int size) { + return userAdminService.getUsers(new UsersListRequest(ids, from, size)); } @DeleteMapping("/{userId}") diff --git a/evm-service/src/main/java/ru/practicum/User/DTO/UsersListRequest.java b/evm-service/src/main/java/ru/practicum/User/DTO/UsersListRequest.java index 4c85167..c194ba8 100644 --- a/evm-service/src/main/java/ru/practicum/User/DTO/UsersListRequest.java +++ b/evm-service/src/main/java/ru/practicum/User/DTO/UsersListRequest.java @@ -1,18 +1,9 @@ package ru.practicum.User.DTO; -import jakarta.validation.constraints.Positive; -import jakarta.validation.constraints.PositiveOrZero; -import lombok.Data; +import java.util.List; -import java.util.Set; - -@Data -public class UsersListRequest { - private Set ids; - - @PositiveOrZero - private final Integer from = 0; - - @Positive - private final Integer size = 10; +public record UsersListRequest( + List ids, + Integer from, + Integer size) { } diff --git a/evm-service/src/main/java/ru/practicum/User/Model/User.java b/evm-service/src/main/java/ru/practicum/User/Model/User.java index eaad6a0..9e08ef5 100644 --- a/evm-service/src/main/java/ru/practicum/User/Model/User.java +++ b/evm-service/src/main/java/ru/practicum/User/Model/User.java @@ -16,9 +16,9 @@ public class User { @Column(name = "id") private Integer id; - @Column(name = "email") + @Column(name = "email", length = 500) private String email; - @Column(name = "name") + @Column(name = "name", length = 250) private String name; } diff --git a/evm-service/src/main/java/ru/practicum/User/Repository/UserRepository.java b/evm-service/src/main/java/ru/practicum/User/Repository/UserRepository.java index 4f34f21..b9596f5 100644 --- a/evm-service/src/main/java/ru/practicum/User/Repository/UserRepository.java +++ b/evm-service/src/main/java/ru/practicum/User/Repository/UserRepository.java @@ -14,4 +14,5 @@ public interface UserRepository extends JpaRepository { Optional findUserById(Integer id); Page findByIdIn(Collection ids, Pageable pageable); + } diff --git a/evm-service/src/main/java/ru/practicum/User/Service/UserAdminServiceImpl.java b/evm-service/src/main/java/ru/practicum/User/Service/UserAdminServiceImpl.java index ef4c1c6..378cbf0 100644 --- a/evm-service/src/main/java/ru/practicum/User/Service/UserAdminServiceImpl.java +++ b/evm-service/src/main/java/ru/practicum/User/Service/UserAdminServiceImpl.java @@ -1,7 +1,6 @@ package ru.practicum.User.Service; import lombok.RequiredArgsConstructor; -import org.springframework.data.domain.Page; import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Sort; @@ -16,6 +15,7 @@ import java.util.List; + @Service @RequiredArgsConstructor public class UserAdminServiceImpl implements UserAdminService { @@ -45,13 +45,14 @@ public UserDTO getUserById(Integer id) { @Override public List getUsers(UsersListRequest request) { - int pageNumber = (int) Math.floor((double) request.getFrom() / request.getSize()); - Pageable pageable = PageRequest.of(pageNumber, request.getSize(), Sort.by("id").ascending()); - Page users = request.getIds() == null - ? userRepository.findAll(pageable) - : userRepository.findByIdIn(request.getIds(), pageable); + int page = request.from() / request.size(); + Pageable pageable = PageRequest.of(page, request.size(), Sort.by("id").ascending()); + + List users = request.ids() == null || request.ids().isEmpty() + ? userRepository.findAll(pageable).getContent() + : userRepository.findByIdIn(request.ids(), pageable).getContent(); - return users.getContent().stream() + return users.stream() .map(userMapper::toUserDTO) .toList(); } diff --git a/evm-service/src/main/resources/schema.sql b/evm-service/src/main/resources/schema.sql index d033c92..97956c5 100644 --- a/evm-service/src/main/resources/schema.sql +++ b/evm-service/src/main/resources/schema.sql @@ -1,29 +1,32 @@ +DROP TABLE IF EXISTS users, categories, events, requests, compilations, compilation_events; CREATE TABLE IF NOT EXISTS users ( id INT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, - name CHARACTER VARYING(255) NOT NULL, - email CHARACTER VARYING(500) NOT NULL UNIQUE + name VARCHAR(250) NOT NULL, + email VARCHAR(500) NOT NULL UNIQUE, + CONSTRAINT UQ_USER_EMAIL UNIQUE (email) ); CREATE TABLE IF NOT EXISTS categories ( id INT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, - name CHARACTER VARYING(255) UNIQUE NOT NULL + name VARCHAR(50) UNIQUE NOT NULL, + CONSTRAINT UQ_CATEGORY_NAME UNIQUE (name) ); CREATE TABLE IF NOT EXISTS state ( id INT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, - name CHARACTER VARYING (50) + name VARCHAR(50) ); -CREATE TABLE IF NOT EXISTS events ( +CREATE TABLE IF NOT EXISTS events ( id INT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, - title CHARACTER VARYING (200) NOT NULL, - annotation CHARACTER VARYING (2000) NOT NULL, + title VARCHAR(205) NOT NULL, + annotation VARCHAR(2000) NOT NULL, category_id INT NOT NULL, confirmed_requests INT, created_on TIMESTAMP WITHOUT TIME ZONE, - description CHARACTER VARYING (7000), + description VARCHAR(7000), event_date TIMESTAMP WITHOUT TIME ZONE NOT NULL, initiator_id INT NOT NULL, lat INT NOT NULL, @@ -41,7 +44,7 @@ CREATE TABLE IF NOT EXISTS events ( CREATE TABLE IF NOT EXISTS compilations ( id INT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, pinned BOOLEAN, - title VARCHAR NOT NULL + title VARCHAR(150) NOT NULL ); CREATE TABLE IF NOT EXISTS requests ( diff --git a/stat/stat-client/src/main/java/ru/practicum/BaseClient.java b/stat/stat-client/src/main/java/ru/practicum/BaseClient.java deleted file mode 100644 index 7cfa5e5..0000000 --- a/stat/stat-client/src/main/java/ru/practicum/BaseClient.java +++ /dev/null @@ -1,54 +0,0 @@ -package ru.practicum; - -import io.micrometer.common.lang.Nullable; -import org.springframework.http.*; -import org.springframework.web.client.RestTemplate; - -import java.util.List; -import java.util.Map; - -public class BaseClient { - protected final RestTemplate restTemplate; - - public BaseClient(RestTemplate restTemplate) { - this.restTemplate = restTemplate; - } - - - - protected ResponseEntity post(String path, Object body) { - return makeAndSendRequest(HttpMethod.POST, path, null, body); - } - - private ResponseEntity makeAndSendRequest(HttpMethod method, String path, - @Nullable Map parameters, - @Nullable T body) { - HttpEntity requestEntity = new HttpEntity<>(body, defaultHeaders()); - ResponseEntity statsServiceResponse; - if (parameters != null) { - statsServiceResponse = restTemplate.exchange(path, method, requestEntity, Object.class, parameters); - } else { - statsServiceResponse = restTemplate.exchange(path, method, requestEntity, Object.class); - } - - return prepareResponse(statsServiceResponse); - } - - private HttpHeaders defaultHeaders() { - HttpHeaders headers = new HttpHeaders(); - headers.setContentType(MediaType.APPLICATION_JSON); - headers.setAccept(List.of(MediaType.APPLICATION_JSON)); - return headers; - } - - private static ResponseEntity prepareResponse(ResponseEntity response) { - if (response.getStatusCode().is2xxSuccessful()) { - return response; - } - ResponseEntity.BodyBuilder responseBuilder = ResponseEntity.status(response.getStatusCode()); - if (response.hasBody()) { - return responseBuilder.body(response.getBody()); - } - return responseBuilder.build(); - } -} \ No newline at end of file diff --git a/stat/stat-client/src/main/java/ru/practicum/StatsClient1.java b/stat/stat-client/src/main/java/ru/practicum/StatsClient1.java deleted file mode 100644 index fdaa71c..0000000 --- a/stat/stat-client/src/main/java/ru/practicum/StatsClient1.java +++ /dev/null @@ -1,91 +0,0 @@ -package ru.practicum; - -import jakarta.servlet.http.HttpServletRequest; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.boot.web.client.RestTemplateBuilder; -import org.springframework.http.*; -import org.springframework.stereotype.Component; -import org.springframework.web.client.RestTemplate; -import org.springframework.web.util.UriComponentsBuilder; - -import java.time.LocalDateTime; -import java.time.format.DateTimeFormatter; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -@Component -public class StatsClient1 { - private final RestTemplate restTemplate; - - private final String serverUrl; - private static final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); - - @Autowired - public StatsClient1(@Value("${stats.server.url:http://stat-server:9090}") String serverUrl, - RestTemplateBuilder restTemplateBuilder) { - this.restTemplate = restTemplateBuilder.build(); - this.serverUrl = serverUrl; - - - } - - public void createHit(HttpServletRequest request, String appName) { - String uri = request.getRequestURI(); - String ip = request.getRemoteAddr(); - post("/hit", createDto(uri, ip, appName)); - } - - public ResponseEntity viewStats(LocalDateTime start, LocalDateTime end, - List uris, Boolean unique) { - Map params = new HashMap<>(); - params.put("start", start.format(formatter)); - params.put("end", end.format(formatter)); - params.put("uris", uris != null ? String.join(",", uris) : ""); - params.put("unique", unique != null ? unique : false); - - return get("/stats", params); - } - - private ResponseEntity get(String path, Map parameters) { - return makeRequest(HttpMethod.GET, path, parameters, null); - } - - private ResponseEntity post(String path, Object body) { - return makeRequest(HttpMethod.POST, path, null, body); - } - - private ResponseEntity makeRequest(HttpMethod method, String path, - Map parameters, Object body) { - String url = serverUrl + path; - - HttpHeaders headers = new HttpHeaders(); - headers.setContentType(MediaType.APPLICATION_JSON); - headers.setAccept(List.of(MediaType.APPLICATION_JSON)); - - UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl(url); - if (parameters != null) { - parameters.forEach(builder::queryParam); - } - - HttpEntity entity = new HttpEntity<>(body, headers); - - return restTemplate.exchange( - builder.build().encode().toUri(), - method, - entity, - Object.class - ); - - } - - private EndpointHitDTO createDto(String uri, String ip, String appName) { - return EndpointHitDTO.builder() - .app(appName) - .uri(uri) - .ip(ip) - .timestamp(LocalDateTime.now()) - .build(); - } -} diff --git a/stat/stat-server/src/main/java/ru/practicum/service/StatsServiceImpl.java b/stat/stat-server/src/main/java/ru/practicum/service/StatsServiceImpl.java index 3b19655..b6f182d 100644 --- a/stat/stat-server/src/main/java/ru/practicum/service/StatsServiceImpl.java +++ b/stat/stat-server/src/main/java/ru/practicum/service/StatsServiceImpl.java @@ -9,9 +9,9 @@ import ru.practicum.mapper.HitsMapper; import ru.practicum.mapper.ViewStatsMapper; import ru.practicum.model.EndpointHit; -import ru.practicum.model.ViewStats; import ru.practicum.repository.StatsServerRepository; +import java.util.ArrayList; import java.util.List; @Service @@ -29,22 +29,22 @@ public List getStats(StatsRequestDTO statsRequestDTO) { throw new ValidationException("Start date cannot be after end date"); } - List stats; - if (statsRequestDTO.getUnique() == null) { + List stats = new ArrayList<>(); + if (statsRequestDTO.getUnique() != null && statsRequestDTO.getUnique()) { + stats = statsService.getStatsUnique(statsRequestDTO.getStart(), statsRequestDTO.getEnd(), + statsRequestDTO.getUris()).stream() + .map(viewStatsMapper::mapViewStats) + .toList(); + } + + if (statsRequestDTO.getUnique() == null || statsRequestDTO.getUnique().equals(false)) { stats = statsService.getStats(statsRequestDTO.getStart(), statsRequestDTO.getEnd()).stream() .filter(viewStats -> statsRequestDTO.getUris().contains(viewStats.getUri())) + .map(viewStatsMapper::mapViewStats) .toList(); - } else if (statsRequestDTO.getUnique().equals(true)) { - stats = statsService.getStatsUnique(statsRequestDTO.getStart(), statsRequestDTO.getEnd(), - statsRequestDTO.getUris()); - } else { - stats = statsService.getStats(statsRequestDTO.getStart(), statsRequestDTO.getEnd()); - } - List views = stats.stream() - .map(viewStatsMapper::mapViewStats) - .toList(); - return views; + } + return stats; } @Override diff --git a/stat/stat-server/src/main/resources/application-docker.yml b/stat/stat-server/src/main/resources/application-docker.yml index a2898d2..fd0caa7 100644 --- a/stat/stat-server/src/main/resources/application-docker.yml +++ b/stat/stat-server/src/main/resources/application-docker.yml @@ -7,14 +7,7 @@ spring: jpa: hibernate: ddl-auto: none - properties: - hibernate: - dialect: org.hibernate.dialect.PostgreSQLDialect - format_sql: true - jdbc: - lob: - non_contextual_creation: true - show-sql: true + properties.hibernate.format_sql: true sql: init: mode: always diff --git a/stat/stat-server/src/main/resources/schema.sql b/stat/stat-server/src/main/resources/schema.sql index ae2d69d..fb8f050 100644 --- a/stat/stat-server/src/main/resources/schema.sql +++ b/stat/stat-server/src/main/resources/schema.sql @@ -1,7 +1,9 @@ +DROP TABLE IF EXISTS hits; + CREATE TABLE IF NOT EXISTS hits ( id BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, - app CHARACTER VARYING(255) NOT NULL, - uri CHARACTER VARYING(100) NOT NULL, - ip CHARACTER VARYING(50) NOT NULL, + app VARCHAR (255) NOT NULL, + uri VARCHAR (100) NOT NULL, + ip VARCHAR (50) NOT NULL, timestamp TIMESTAMP WITHOUT TIME ZONE ); From 3eaebbd59ff47f386e9c60d8f5bed153661ed4da Mon Sep 17 00:00:00 2001 From: NadezhdaTA Date: Mon, 8 Sep 2025 07:56:16 +0400 Subject: [PATCH 33/35] =?UTF-8?q?2=D0=BE=D0=B9=20=D1=8D=D1=82=D0=B0=D0=BF?= =?UTF-8?q?=20=D0=B4=D0=B8=D0=BF=D0=BB=D0=BE=D0=BC=D0=B0(=D1=81=20=D0=B8?= =?UTF-8?q?=D1=81=D0=BF=D1=80=D0=B0=D0=B2=D0=BB=D0=B5=D0=BD=D0=B8=D1=8F?= =?UTF-8?q?=D0=BC=D0=B8)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- evm-service/pom.xml | 3 -- .../ru/practicum/Exception/ErrorResponse.java | 1 - .../practicum/Exception/EvmErrorHandler.java | 38 +++---------------- pom.xml | 1 + stat/pom.xml | 14 +------ stat/stat-client/pom.xml | 6 --- stat/stat-dto/pom.xml | 6 --- .../java/ru/practicum/StatsRequestDTO.java | 10 ++--- stat/stat-server/pom.xml | 3 -- .../practicum/service/StatsServiceImpl.java | 2 - 10 files changed, 11 insertions(+), 73 deletions(-) diff --git a/evm-service/pom.xml b/evm-service/pom.xml index 3d6ab9f..96ad8a3 100644 --- a/evm-service/pom.xml +++ b/evm-service/pom.xml @@ -12,12 +12,9 @@ evm-service - 23 - 23 5.0.0 1.6.3 0.2.0 - UTF-8 diff --git a/evm-service/src/main/java/ru/practicum/Exception/ErrorResponse.java b/evm-service/src/main/java/ru/practicum/Exception/ErrorResponse.java index edff969..eefbe00 100644 --- a/evm-service/src/main/java/ru/practicum/Exception/ErrorResponse.java +++ b/evm-service/src/main/java/ru/practicum/Exception/ErrorResponse.java @@ -12,7 +12,6 @@ public class ErrorResponse { private HttpStatus status; private String message; - private String stackTrace; @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") private LocalDateTime timestamp; diff --git a/evm-service/src/main/java/ru/practicum/Exception/EvmErrorHandler.java b/evm-service/src/main/java/ru/practicum/Exception/EvmErrorHandler.java index 62e99cf..7d23cde 100644 --- a/evm-service/src/main/java/ru/practicum/Exception/EvmErrorHandler.java +++ b/evm-service/src/main/java/ru/practicum/Exception/EvmErrorHandler.java @@ -8,8 +8,6 @@ import org.springframework.web.bind.annotation.ResponseStatus; import org.springframework.web.bind.annotation.RestControllerAdvice; -import java.io.PrintWriter; -import java.io.StringWriter; import java.time.LocalDateTime; @RestControllerAdvice @@ -20,71 +18,47 @@ public class EvmErrorHandler { @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR) public ErrorResponse handleException(final RuntimeException e) { log.error("500 {}", e.getMessage(), e); - StringWriter sw = new StringWriter(); - PrintWriter pw = new PrintWriter(sw); - e.printStackTrace(pw); - String stackTrace = sw.toString(); LocalDateTime timestamp = LocalDateTime.now(); - return new ErrorResponse(HttpStatus.INTERNAL_SERVER_ERROR, e.getMessage(), stackTrace, timestamp); + return new ErrorResponse(HttpStatus.INTERNAL_SERVER_ERROR, e.getMessage(), timestamp); } @ExceptionHandler(ValidationException.class) @ResponseStatus(HttpStatus.BAD_REQUEST) public ErrorResponse handleValidationException(final ValidationException e) { log.error("400 {}", e.getMessage(), e); - StringWriter sw = new StringWriter(); - PrintWriter pw = new PrintWriter(sw); - e.printStackTrace(pw); - String stackTrace = sw.toString(); LocalDateTime timestamp = LocalDateTime.now(); - return new ErrorResponse(HttpStatus.BAD_REQUEST, e.getMessage(), stackTrace, timestamp); + return new ErrorResponse(HttpStatus.BAD_REQUEST, e.getMessage(), timestamp); } @ExceptionHandler(NotFoundException.class) @ResponseStatus(HttpStatus.NOT_FOUND) public ErrorResponse handleNotFoundException(final NotFoundException e) { log.error("404 {}", e.getMessage(), e); - StringWriter sw = new StringWriter(); - PrintWriter pw = new PrintWriter(sw); - e.printStackTrace(pw); - String stackTrace = sw.toString(); LocalDateTime timestamp = LocalDateTime.now(); - return new ErrorResponse(HttpStatus.NOT_FOUND, e.getMessage(), stackTrace, timestamp); + return new ErrorResponse(HttpStatus.NOT_FOUND, e.getMessage(), timestamp); } @ExceptionHandler(ConflictException.class) @ResponseStatus(HttpStatus.CONFLICT) public ErrorResponse handleConflictException(final ConflictException e) { log.error("409 {}", e.getMessage(), e); - StringWriter sw = new StringWriter(); - PrintWriter pw = new PrintWriter(sw); - e.printStackTrace(pw); - String stackTrace = sw.toString(); LocalDateTime timestamp = LocalDateTime.now(); - return new ErrorResponse(HttpStatus.CONFLICT, e.getMessage(), stackTrace, timestamp); + return new ErrorResponse(HttpStatus.CONFLICT, e.getMessage(), timestamp); } @ExceptionHandler(MissingServletRequestParameterException.class) @ResponseStatus(HttpStatus.BAD_REQUEST) public ErrorResponse handleMissingPathVariableException(final MissingServletRequestParameterException e) { log.error("400 {}", e.getMessage(), e); - StringWriter sw = new StringWriter(); - PrintWriter pw = new PrintWriter(sw); - e.printStackTrace(pw); - String stackTrace = sw.toString(); LocalDateTime timestamp = LocalDateTime.now(); - return new ErrorResponse(HttpStatus.BAD_REQUEST, e.getMessage(), stackTrace, timestamp); + return new ErrorResponse(HttpStatus.BAD_REQUEST, e.getMessage(), timestamp); } @ExceptionHandler(DataIntegrityViolationException.class) @ResponseStatus(HttpStatus.CONFLICT) public ErrorResponse handSQLException(final DataIntegrityViolationException e) { log.error("409 {}", e.getMessage(), e); - StringWriter sw = new StringWriter(); - PrintWriter pw = new PrintWriter(sw); - e.printStackTrace(pw); - String stackTrace = sw.toString(); LocalDateTime timestamp = LocalDateTime.now(); - return new ErrorResponse(HttpStatus.CONFLICT, e.getMessage(), stackTrace, timestamp); + return new ErrorResponse(HttpStatus.CONFLICT, e.getMessage(), timestamp); } } diff --git a/pom.xml b/pom.xml index 7137ae7..c2e49de 100644 --- a/pom.xml +++ b/pom.xml @@ -24,6 +24,7 @@ 21 + 21 UTF-8 diff --git a/stat/pom.xml b/stat/pom.xml index 8d45d67..81221fe 100644 --- a/stat/pom.xml +++ b/stat/pom.xml @@ -11,23 +11,11 @@ stat pom + stat-client stat-dto stat-server - - 21 - 1.6.3 - 0.2.0 - UTF-8 - - - - - - - - \ No newline at end of file diff --git a/stat/stat-client/pom.xml b/stat/stat-client/pom.xml index a5fc936..b3c1366 100644 --- a/stat/stat-client/pom.xml +++ b/stat/stat-client/pom.xml @@ -11,12 +11,6 @@ stat-client - - 23 - 23 - UTF-8 - - ru.practicum diff --git a/stat/stat-dto/pom.xml b/stat/stat-dto/pom.xml index 592a310..0bb3dfe 100644 --- a/stat/stat-dto/pom.xml +++ b/stat/stat-dto/pom.xml @@ -11,12 +11,6 @@ stat-dto - - 23 - 23 - UTF-8 - - org.springframework.boot diff --git a/stat/stat-dto/src/main/java/ru/practicum/StatsRequestDTO.java b/stat/stat-dto/src/main/java/ru/practicum/StatsRequestDTO.java index 6e7d402..648490f 100644 --- a/stat/stat-dto/src/main/java/ru/practicum/StatsRequestDTO.java +++ b/stat/stat-dto/src/main/java/ru/practicum/StatsRequestDTO.java @@ -1,30 +1,26 @@ package ru.practicum; -import com.fasterxml.jackson.annotation.JsonProperty; import jakarta.validation.constraints.NotNull; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; -import lombok.NoArgsConstructor; import org.springframework.format.annotation.DateTimeFormat; import java.time.LocalDateTime; import java.util.List; @Data -@NoArgsConstructor @AllArgsConstructor @Builder public class StatsRequestDTO { + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") @NotNull(message = "Start date is required") - @JsonProperty(value = "start") - private LocalDateTime start; + private final LocalDateTime start; @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") @NotNull(message = "End date is required") - @JsonProperty(value = "end") - private LocalDateTime end; + private final LocalDateTime end; private List uris; private Boolean unique; diff --git a/stat/stat-server/pom.xml b/stat/stat-server/pom.xml index e85d47c..9b85989 100644 --- a/stat/stat-server/pom.xml +++ b/stat/stat-server/pom.xml @@ -12,9 +12,6 @@ stat-server - 23 - 23 - UTF-8 1.6.3 0.2.0 diff --git a/stat/stat-server/src/main/java/ru/practicum/service/StatsServiceImpl.java b/stat/stat-server/src/main/java/ru/practicum/service/StatsServiceImpl.java index b6f182d..c824a8c 100644 --- a/stat/stat-server/src/main/java/ru/practicum/service/StatsServiceImpl.java +++ b/stat/stat-server/src/main/java/ru/practicum/service/StatsServiceImpl.java @@ -25,8 +25,6 @@ public class StatsServiceImpl implements StatsServiceInterface { public List getStats(StatsRequestDTO statsRequestDTO) { if (statsRequestDTO.getStart().isAfter(statsRequestDTO.getEnd())) { throw new ValidationException("Start date cannot be after end date"); - } else if (statsRequestDTO.getStart() == null || statsRequestDTO.getEnd() == null) { - throw new ValidationException("Start date cannot be after end date"); } List stats = new ArrayList<>(); From 451c04095c9d7918973becec6493fce8632d09a6 Mon Sep 17 00:00:00 2001 From: NadezhdaTA Date: Mon, 8 Sep 2025 14:30:30 +0400 Subject: [PATCH 34/35] =?UTF-8?q?2=D0=BE=D0=B9=20=D1=8D=D1=82=D0=B0=D0=BF?= =?UTF-8?q?=20=D0=B4=D0=B8=D0=BF=D0=BB=D0=BE=D0=BC=D0=B0(=D1=81=20=D0=B8?= =?UTF-8?q?=D1=81=D0=BF=D1=80=D0=B0=D0=B2=D0=BB=D0=B5=D0=BD=D0=B8=D1=8F?= =?UTF-8?q?=D0=BC=D0=B8)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/java/ru/practicum/Event/DTO/EventFullDTO.java | 7 ++++--- .../java/ru/practicum/Event/DTO/EventPublicParams.java | 7 ++++--- .../main/java/ru/practicum/Event/DTO/EventShortDTO.java | 3 ++- .../src/main/java/ru/practicum/Event/DTO/NewEventDTO.java | 3 ++- .../main/java/ru/practicum/Event/DTO/SearchEventsDTO.java | 5 +++-- .../ru/practicum/Event/DTO/UpdateEventAdminRequest.java | 3 ++- .../ru/practicum/Event/DTO/UpdateEventUserRequest.java | 3 ++- .../src/main/java/ru/practicum/StatsClient.java | 2 +- .../src/main/java/ru/practicum/EndpointHitDTO.java | 2 +- .../src/main/java/ru/practicum/StatsRequestDTO.java | 5 +++-- 10 files changed, 24 insertions(+), 16 deletions(-) diff --git a/evm-service/src/main/java/ru/practicum/Event/DTO/EventFullDTO.java b/evm-service/src/main/java/ru/practicum/Event/DTO/EventFullDTO.java index dfb1617..71d8c1e 100644 --- a/evm-service/src/main/java/ru/practicum/Event/DTO/EventFullDTO.java +++ b/evm-service/src/main/java/ru/practicum/Event/DTO/EventFullDTO.java @@ -5,6 +5,7 @@ import lombok.Data; import lombok.NoArgsConstructor; import ru.practicum.Category.DTO.CategoryDTO; +import ru.practicum.StatsRequestDTO; import ru.practicum.User.DTO.UserShortDTO; import ru.practicum.Event.Model.Location; import ru.practicum.Event.Model.State; @@ -23,12 +24,12 @@ public class EventFullDTO { private Integer confirmedRequests; - @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @JsonFormat(pattern = StatsRequestDTO.DATE_FORMAT) private LocalDateTime createdOn; private String description; - @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @JsonFormat(pattern = StatsRequestDTO.DATE_FORMAT) private LocalDateTime eventDate; private UserShortDTO initiator; @@ -39,7 +40,7 @@ public class EventFullDTO { private Integer participantLimit; - @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @JsonFormat(pattern = StatsRequestDTO.DATE_FORMAT) private LocalDateTime publishedOn = LocalDateTime.now(); private Boolean requestModeration; diff --git a/evm-service/src/main/java/ru/practicum/Event/DTO/EventPublicParams.java b/evm-service/src/main/java/ru/practicum/Event/DTO/EventPublicParams.java index cf1d19b..0224c91 100644 --- a/evm-service/src/main/java/ru/practicum/Event/DTO/EventPublicParams.java +++ b/evm-service/src/main/java/ru/practicum/Event/DTO/EventPublicParams.java @@ -6,6 +6,7 @@ import lombok.Data; import lombok.NoArgsConstructor; import org.springframework.format.annotation.DateTimeFormat; +import ru.practicum.StatsRequestDTO; import java.time.LocalDateTime; import java.util.ArrayList; @@ -18,15 +19,15 @@ public class EventPublicParams { public ArrayList categories; private Boolean paid; - @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @DateTimeFormat(pattern = StatsRequestDTO.DATE_FORMAT) private LocalDateTime rangeStart; - @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @DateTimeFormat(pattern = StatsRequestDTO.DATE_FORMAT) private LocalDateTime rangeEnd; private Boolean onlyAvailable = false; - private String sort = "EVENT_DATE"; + private String sort; @PositiveOrZero private Integer from = 0; diff --git a/evm-service/src/main/java/ru/practicum/Event/DTO/EventShortDTO.java b/evm-service/src/main/java/ru/practicum/Event/DTO/EventShortDTO.java index 382329e..b268a70 100644 --- a/evm-service/src/main/java/ru/practicum/Event/DTO/EventShortDTO.java +++ b/evm-service/src/main/java/ru/practicum/Event/DTO/EventShortDTO.java @@ -7,6 +7,7 @@ import lombok.Data; import lombok.NoArgsConstructor; import ru.practicum.Category.DTO.CategoryDTO; +import ru.practicum.StatsRequestDTO; import ru.practicum.User.DTO.UserShortDTO; import java.time.LocalDateTime; @@ -26,7 +27,7 @@ public class EventShortDTO { private Integer confirmedRequests; @NotNull - @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @JsonFormat(pattern = StatsRequestDTO.DATE_FORMAT) private LocalDateTime eventDate; @NotNull diff --git a/evm-service/src/main/java/ru/practicum/Event/DTO/NewEventDTO.java b/evm-service/src/main/java/ru/practicum/Event/DTO/NewEventDTO.java index f9cd4ca..8d840c2 100644 --- a/evm-service/src/main/java/ru/practicum/Event/DTO/NewEventDTO.java +++ b/evm-service/src/main/java/ru/practicum/Event/DTO/NewEventDTO.java @@ -7,6 +7,7 @@ import lombok.Data; import lombok.NoArgsConstructor; import ru.practicum.Event.Model.Location; +import ru.practicum.StatsRequestDTO; import java.time.LocalDateTime; @@ -28,7 +29,7 @@ public class NewEventDTO { @NotNull @Future - @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @JsonFormat(pattern = StatsRequestDTO.DATE_FORMAT) private LocalDateTime eventDate; @NotNull diff --git a/evm-service/src/main/java/ru/practicum/Event/DTO/SearchEventsDTO.java b/evm-service/src/main/java/ru/practicum/Event/DTO/SearchEventsDTO.java index 2f7a25f..f037783 100644 --- a/evm-service/src/main/java/ru/practicum/Event/DTO/SearchEventsDTO.java +++ b/evm-service/src/main/java/ru/practicum/Event/DTO/SearchEventsDTO.java @@ -7,6 +7,7 @@ import lombok.NoArgsConstructor; import org.springframework.format.annotation.DateTimeFormat; import ru.practicum.Event.Model.State; +import ru.practicum.StatsRequestDTO; import java.time.LocalDateTime; import java.util.List; @@ -19,10 +20,10 @@ public class SearchEventsDTO { private List states; private List categories; - @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @DateTimeFormat(pattern = StatsRequestDTO.DATE_FORMAT) private LocalDateTime rangeStart = LocalDateTime.now(); - @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @DateTimeFormat(pattern = StatsRequestDTO.DATE_FORMAT) private LocalDateTime rangeEnd; @PositiveOrZero diff --git a/evm-service/src/main/java/ru/practicum/Event/DTO/UpdateEventAdminRequest.java b/evm-service/src/main/java/ru/practicum/Event/DTO/UpdateEventAdminRequest.java index 7f4ba78..52d08f6 100644 --- a/evm-service/src/main/java/ru/practicum/Event/DTO/UpdateEventAdminRequest.java +++ b/evm-service/src/main/java/ru/practicum/Event/DTO/UpdateEventAdminRequest.java @@ -8,6 +8,7 @@ import lombok.NoArgsConstructor; import ru.practicum.Event.Model.Location; import ru.practicum.Event.Model.State; +import ru.practicum.StatsRequestDTO; import java.time.LocalDateTime; @@ -25,7 +26,7 @@ public class UpdateEventAdminRequest { private String description; @Future - @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @JsonFormat(pattern = StatsRequestDTO.DATE_FORMAT) private LocalDateTime eventDate; private Location location; diff --git a/evm-service/src/main/java/ru/practicum/Event/DTO/UpdateEventUserRequest.java b/evm-service/src/main/java/ru/practicum/Event/DTO/UpdateEventUserRequest.java index 19eb6e8..b605ab0 100644 --- a/evm-service/src/main/java/ru/practicum/Event/DTO/UpdateEventUserRequest.java +++ b/evm-service/src/main/java/ru/practicum/Event/DTO/UpdateEventUserRequest.java @@ -9,6 +9,7 @@ import lombok.NoArgsConstructor; import ru.practicum.Event.Model.Location; import ru.practicum.Event.Model.State; +import ru.practicum.StatsRequestDTO; import java.time.LocalDateTime; @@ -25,7 +26,7 @@ public class UpdateEventUserRequest { @Size(min = 20, max = 7000) private String description; - @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @JsonFormat(pattern = StatsRequestDTO.DATE_FORMAT) @Future private LocalDateTime eventDate; diff --git a/stat/stat-client/src/main/java/ru/practicum/StatsClient.java b/stat/stat-client/src/main/java/ru/practicum/StatsClient.java index a8c272b..fef47fe 100644 --- a/stat/stat-client/src/main/java/ru/practicum/StatsClient.java +++ b/stat/stat-client/src/main/java/ru/practicum/StatsClient.java @@ -40,7 +40,7 @@ public ResponseEntity createHit(HttpServletRequest request, String appNa public List viewStats(LocalDateTime start, LocalDateTime end, List uris, Boolean unique) { - DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); + DateTimeFormatter formatter = DateTimeFormatter.ofPattern(StatsRequestDTO.DATE_FORMAT); Map params = new HashMap<>(); params.put("start", start.format(formatter)); params.put("end", end.format(formatter)); diff --git a/stat/stat-dto/src/main/java/ru/practicum/EndpointHitDTO.java b/stat/stat-dto/src/main/java/ru/practicum/EndpointHitDTO.java index d0953f9..17d2cb3 100644 --- a/stat/stat-dto/src/main/java/ru/practicum/EndpointHitDTO.java +++ b/stat/stat-dto/src/main/java/ru/practicum/EndpointHitDTO.java @@ -24,6 +24,6 @@ public class EndpointHitDTO { @NotBlank private String ip; - @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @JsonFormat(pattern = StatsRequestDTO.DATE_FORMAT) private LocalDateTime timestamp; } diff --git a/stat/stat-dto/src/main/java/ru/practicum/StatsRequestDTO.java b/stat/stat-dto/src/main/java/ru/practicum/StatsRequestDTO.java index 648490f..50dec47 100644 --- a/stat/stat-dto/src/main/java/ru/practicum/StatsRequestDTO.java +++ b/stat/stat-dto/src/main/java/ru/practicum/StatsRequestDTO.java @@ -13,12 +13,13 @@ @AllArgsConstructor @Builder public class StatsRequestDTO { + public static final String DATE_FORMAT = "yyyy-MM-dd HH:mm:ss"; - @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @DateTimeFormat(pattern = DATE_FORMAT) @NotNull(message = "Start date is required") private final LocalDateTime start; - @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @DateTimeFormat(pattern = DATE_FORMAT) @NotNull(message = "End date is required") private final LocalDateTime end; From d2803ef03c13efc5889d6255bf202f67ce0c90a9 Mon Sep 17 00:00:00 2001 From: NadezhdaTA Date: Mon, 8 Sep 2025 14:54:47 +0400 Subject: [PATCH 35/35] =?UTF-8?q?2=D0=BE=D0=B9=20=D1=8D=D1=82=D0=B0=D0=BF?= =?UTF-8?q?=20=D0=B4=D0=B8=D0=BF=D0=BB=D0=BE=D0=BC=D0=B0(=D1=81=20=D0=B8?= =?UTF-8?q?=D1=81=D0=BF=D1=80=D0=B0=D0=B2=D0=BB=D0=B5=D0=BD=D0=B8=D1=8F?= =?UTF-8?q?=D0=BC=D0=B8)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Event/Service/Public/EventPublicServiceImpl.java | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/evm-service/src/main/java/ru/practicum/Event/Service/Public/EventPublicServiceImpl.java b/evm-service/src/main/java/ru/practicum/Event/Service/Public/EventPublicServiceImpl.java index e430c3d..044d22f 100644 --- a/evm-service/src/main/java/ru/practicum/Event/Service/Public/EventPublicServiceImpl.java +++ b/evm-service/src/main/java/ru/practicum/Event/Service/Public/EventPublicServiceImpl.java @@ -63,11 +63,16 @@ public List findAllEvents(EventPublicParams params, HttpServletRe Specification spec = eventSpecification(params); Sort sort = null; - switch (params.getSort()) { - case "EVENT_DATE" -> sort = Sort.by(Sort.Direction.DESC, "eventDate"); - case "VIEWS" -> sort = Sort.by(Sort.Direction.ASC, "views"); + if (params.getSort() != null) { + switch (params.getSort()) { + case "EVENT_DATE" -> sort = Sort.by(Sort.Direction.DESC, "eventDate"); + case "VIEWS" -> sort = Sort.by(Sort.Direction.ASC, "views"); + } + } else { + sort = Sort.by(Sort.Direction.DESC, "eventDate"); } + Pageable pageable = PageRequest.of(params.getFrom(), params.getSize(), sort); List events = eventRepository.findAll(spec, pageable).getContent().stream()