From 7b2de53b0e7f4397c7067ce7eeb829e007dbaceb Mon Sep 17 00:00:00 2001 From: vladp Date: Mon, 30 Mar 2026 22:09:03 +0700 Subject: [PATCH 01/47] add deploy pipe --- Dockerfile | 2 +- infrastrucure/deploy.groovy | 192 ++++++++++++++++++++++------ src/main/resources/application.yaml | 2 +- 3 files changed, 158 insertions(+), 38 deletions(-) diff --git a/Dockerfile b/Dockerfile index 35301ca..f64e7bc 100644 --- a/Dockerfile +++ b/Dockerfile @@ -9,6 +9,6 @@ FROM eclipse-temurin:21-jre WORKDIR /app COPY --from=build /app/build/libs/*.jar app.jar -EXPOSE 8080 +EXPOSE 8082 CMD ["java", "-jar", "app.jar"] \ No newline at end of file diff --git a/infrastrucure/deploy.groovy b/infrastrucure/deploy.groovy index c4cbd17..a892480 100644 --- a/infrastrucure/deploy.groovy +++ b/infrastrucure/deploy.groovy @@ -2,68 +2,188 @@ pipeline { agent any parameters { - string(name: 'BRANCH', defaultValue: 'dev', description: 'Ветка для деплоя') - string(name: 'SERVER', defaultValue: '92.242.61.23', description: 'Сервер для деплоя') + string( + name: 'BRANCH', + defaultValue: 'dev', + description: 'Ветка для деплоя' + ) + string( + name: 'PORT', + defaultValue: '8082', + description: 'Порт для запуска admin-panel' + ) + string( + name: 'SERVER', + defaultValue: '92.242.61.23', + description: 'Сервер для деплоя' + ) + string( + name: 'NETWORK', + defaultValue: 'app-network', + description: 'Имя сети (будет создана если не существует)' + ) + string( + name: 'DB_HOST', + defaultValue: 'db', + description: 'Хост базы данных' + ) + choice( + name: 'SPRING_PROFILE', + choices: ['dev', 'prod'], + description: 'Профиль Spring для запуска' + ) } stages { stage('Git pull') { steps { cleanWs() - git branch: params.BRANCH, url: 'https://code.3err0.ru/backdev/admin-panel.git', credentialsId: 'nx-jen' + script { + checkout([ + $class: 'GitSCM', + branches: [[name: params.BRANCH]], + userRemoteConfigs: [[ + url: 'https://code.3err0.ru/backdev/admin-panel.git', + credentialsId: 'nx-jen' + ]] + ]) + } } } - stage('Deploy with docker-compose') { + stage('Copy to server') { + steps { + script { + withCredentials([ + usernamePassword( + credentialsId: 'server-root-password', + usernameVariable: 'SSH_USER', + passwordVariable: 'SSH_PASS' + ) + ]) { + sh """ + sshpass -p '${SSH_PASS}' ssh -o StrictHostKeyChecking=no ${SSH_USER}@${params.SERVER} " + rm -rf /opt/deployments/admin-panel-${params.PORT}/* + mkdir -p /opt/deployments/admin-panel-${params.PORT} + " + + sshpass -p '${SSH_PASS}' rsync -av --delete \\ + --exclude=.git \\ + --exclude=.gradle \\ + --exclude=build \\ + --exclude=**/build \\ + --exclude=.idea \\ + --exclude=out \\ + . ${SSH_USER}@${params.SERVER}:/opt/deployments/admin-panel-${params.PORT}/ + """ + } + } + } + } + + stage('Deploy admin-panel') { steps { script { def buildTime = sh(script: "TZ='Asia/Novosibirsk' date '+%d-%m-%Y %H:%M:%S'", returnStdout: true).trim() + def springProfile = params.SPRING_PROFILE withCredentials([ - usernamePassword(credentialsId: 'server-root-password', usernameVariable: 'SSH_USER', passwordVariable: 'SSH_PASS'), + usernamePassword( + credentialsId: 'server-root-password', + usernameVariable: 'SSH_USER', + passwordVariable: 'SSH_PASS' + ), string(credentialsId: 'DB_USER', variable: 'DB_USER'), string(credentialsId: 'DB_PASSWORD', variable: 'DB_PASSWORD') ]) { sh """ - sshpass -p '$SSH_PASS' ssh -o StrictHostKeyChecking=no $SSH_USER@$SERVER ' - cd /opt/deployments/admin-panel || mkdir -p /opt/deployments/admin-panel && cd /opt/deployments/admin-panel + sshpass -p '${SSH_PASS}' ssh -o StrictHostKeyChecking=no ${SSH_USER}@${params.SERVER} " + cd /opt/deployments/admin-panel-${params.PORT} - echo "1. Остановка старого контейнера..." - docker stop admin-backend 2>/dev/null || echo "Контейнер не найден" - docker rm admin-backend 2>/dev/null || echo "Контейнер не найден" + echo '1. Проверяем/создаем сеть ${params.NETWORK}...' + if ! docker network ls --format '{{.Name}}' | grep -q '^${params.NETWORK}\$'; then + docker network create ${params.NETWORK} + echo 'Сеть ${params.NETWORK} создана' + else + echo 'Сеть ${params.NETWORK} уже существует' + fi - echo "2. Копирование файлов..." - rsync -av --delete --exclude=.git --exclude=build . $SSH_USER@$SERVER:/opt/deployments/admin-panel/ + echo '2. Останавливаем старый контейнер...' + docker stop admin-panel-${params.PORT} 2>/dev/null || echo 'Контейнер не найден' + docker rm admin-panel-${params.PORT} 2>/dev/null || echo 'Контейнер не найден' - echo "3. Сборка образа..." - docker build --no-cache -t admin-backend:latest . + echo '3. Собираем образ...' + docker build --no-cache -t admin-panel-${params.PORT}:latest . - echo "4. Запуск контейнера..." - docker run -d \ - --name admin-backend \ - --network app-network \ - --network-alias admin \ - -p 8082:8082 \ - -v uploads_data:/data/uploads:rw \ - -e POSTGRES_DB=no_copy_ \ - -e POSTGRES_USER=$DB_USER \ - -e POSTGRES_PASSWORD=$DB_PASSWORD \ - -e POSTGRES_PORT=5432 \ - -e POSTGRES_HOST=db \ - -e BUILD_TIME='${buildTime}' \ - --restart unless-stopped \ - admin-backend:latest + echo '4. Запускаем контейнер...' + docker run -d \\ + --name admin-panel-${params.PORT} \\ + --network ${params.NETWORK} \\ + --network-alias admin \\ + --network-alias admin-${params.PORT} \\ + -p ${params.PORT}:8082 \\ + -v uploads_data:/data/uploads:rw \\ + -e POSTGRES_DB=no_copy_ \\ + -e POSTGRES_USER=${DB_USER} \\ + -e POSTGRES_PASSWORD=${DB_PASSWORD} \\ + -e POSTGRES_PORT=5432 \\ + -e POSTGRES_HOST=${params.DB_HOST} \\ + -e SPRING_PROFILES_ACTIVE=${springProfile} \\ + -e BUILD_TIME='${buildTime}' \\ + --restart unless-stopped \\ + admin-panel-${params.PORT}:latest - echo "5. Проверка health..." - if curl -s -f http://localhost:8082/actuator/health; then - echo "Admin backend работает" - else - echo "Проблема с запуском admin-backend" - fi - ' + echo '5. Проверка...' + sleep 10 + + if curl -s -f http://localhost:${params.PORT}/actuator/health > /dev/null 2>&1; then + echo 'Admin-panel работает на порту ${params.PORT}' + echo 'URL: http://${params.SERVER}:${params.PORT}' + else + echo 'Проверка health не удалась' + docker logs admin-panel-${params.PORT} --tail=20 + fi + " + """ + } + } + } + } + + stage('Verify network') { + steps { + script { + withCredentials([ + usernamePassword( + credentialsId: 'server-root-password', + usernameVariable: 'SSH_USER', + passwordVariable: 'SSH_PASS' + ) + ]) { + sh """ + sshpass -p '${SSH_PASS}' ssh -o StrictHostKeyChecking=no ${SSH_USER}@${params.SERVER} " + echo 'Проверяем подключение к сети ${params.NETWORK}' + docker network inspect ${params.NETWORK} --format='{{.Name}}: {{range .Containers}}{{.Name}} {{end}}' + + echo 'Проверяем алиас admin для контейнера admin-panel-${params.PORT}' + docker inspect admin-panel-${params.PORT} | grep -A 5 'Aliases' + " """ } } } } } + + post { + success { + echo "Deployment successful" + echo "Admin panel URL: http://${params.SERVER}:${params.PORT}" + } + failure { + echo "Deployment failed for branch ${params.BRANCH} on port ${params.PORT}" + } + always { + echo "Deployment process finished" + } + } } \ No newline at end of file diff --git a/src/main/resources/application.yaml b/src/main/resources/application.yaml index 4a86184..eebf038 100644 --- a/src/main/resources/application.yaml +++ b/src/main/resources/application.yaml @@ -9,4 +9,4 @@ spring: ddl-auto: validate server: - port: 8080 \ No newline at end of file + port: 8082 \ No newline at end of file -- 2.54.0 From feb8ab6b28a6a8af1944ca66d8cc693b5568f2cb Mon Sep 17 00:00:00 2001 From: vladp Date: Wed, 8 Apr 2026 11:17:08 +0700 Subject: [PATCH 02/47] add admin user logic --- build.gradle | 2 + .../nocopy/adminpanel/config/AppConfig.java | 44 +++ .../controller/AdminController.java | 58 ++++ .../nocopy/adminpanel/dto/ActionResponse.java | 17 ++ .../adminpanel/dto/AdminUserRequest.java | 28 ++ .../adminpanel/dto/AdminUserResponse.java | 28 ++ .../nocopy/adminpanel/dto/BaseRequest.java | 21 ++ .../nocopy/adminpanel/dto/BaseResponse.java | 25 ++ .../nocopy/adminpanel/dto/LoginResponse.java | 18 ++ .../nocopy/adminpanel/entity/AdminUser.java | 59 ++++ .../AdminUserNotFoundException.java | 7 + .../EmailAlreadyExistsException.java | 7 + .../adminpanel/handler/AdminUserHandler.java | 267 ++++++++++++++++++ .../adminpanel/handler/RequestHandler.java | 8 + .../permission/AdminPermission.java | 21 ++ .../permission/PermissionChecker.java | 21 ++ .../repository/AdminUserRepository.java | 14 + .../adminpanel/service/AdminUserService.java | 99 +++++++ .../nocopy/adminpanel/util/JwtAuthFilter.java | 54 ++++ .../soune/nocopy/adminpanel/util/JwtUtil.java | 64 +++++ .../nocopy/adminpanel/util/MessageCode.java | 23 ++ src/main/resources/application.yaml | 6 +- 22 files changed, 890 insertions(+), 1 deletion(-) create mode 100644 src/main/java/ru/soune/nocopy/adminpanel/config/AppConfig.java create mode 100644 src/main/java/ru/soune/nocopy/adminpanel/controller/AdminController.java create mode 100644 src/main/java/ru/soune/nocopy/adminpanel/dto/ActionResponse.java create mode 100644 src/main/java/ru/soune/nocopy/adminpanel/dto/AdminUserRequest.java create mode 100644 src/main/java/ru/soune/nocopy/adminpanel/dto/AdminUserResponse.java create mode 100644 src/main/java/ru/soune/nocopy/adminpanel/dto/BaseRequest.java create mode 100644 src/main/java/ru/soune/nocopy/adminpanel/dto/BaseResponse.java create mode 100644 src/main/java/ru/soune/nocopy/adminpanel/dto/LoginResponse.java create mode 100644 src/main/java/ru/soune/nocopy/adminpanel/entity/AdminUser.java create mode 100644 src/main/java/ru/soune/nocopy/adminpanel/exceptions/AdminUserNotFoundException.java create mode 100644 src/main/java/ru/soune/nocopy/adminpanel/exceptions/EmailAlreadyExistsException.java create mode 100644 src/main/java/ru/soune/nocopy/adminpanel/handler/AdminUserHandler.java create mode 100644 src/main/java/ru/soune/nocopy/adminpanel/handler/RequestHandler.java create mode 100644 src/main/java/ru/soune/nocopy/adminpanel/permission/AdminPermission.java create mode 100644 src/main/java/ru/soune/nocopy/adminpanel/permission/PermissionChecker.java create mode 100644 src/main/java/ru/soune/nocopy/adminpanel/repository/AdminUserRepository.java create mode 100644 src/main/java/ru/soune/nocopy/adminpanel/service/AdminUserService.java create mode 100644 src/main/java/ru/soune/nocopy/adminpanel/util/JwtAuthFilter.java create mode 100644 src/main/java/ru/soune/nocopy/adminpanel/util/JwtUtil.java create mode 100644 src/main/java/ru/soune/nocopy/adminpanel/util/MessageCode.java diff --git a/build.gradle b/build.gradle index bd00b16..d1c6244 100644 --- a/build.gradle +++ b/build.gradle @@ -32,6 +32,8 @@ dependencies { implementation 'org.springframework.boot:spring-boot-starter-data-jpa' implementation 'org.springframework.boot:spring-boot-starter-validation' implementation 'org.springframework.boot:spring-boot-starter-web' + implementation 'org.springframework.security:spring-security-crypto:6.5.3' + implementation("io.jsonwebtoken:jjwt:0.13.0") compileOnly 'org.projectlombok:lombok' developmentOnly 'org.springframework.boot:spring-boot-devtools' runtimeOnly 'org.postgresql:postgresql' diff --git a/src/main/java/ru/soune/nocopy/adminpanel/config/AppConfig.java b/src/main/java/ru/soune/nocopy/adminpanel/config/AppConfig.java new file mode 100644 index 0000000..d369206 --- /dev/null +++ b/src/main/java/ru/soune/nocopy/adminpanel/config/AppConfig.java @@ -0,0 +1,44 @@ +package ru.soune.nocopy.adminpanel.config; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; +import org.springframework.security.crypto.password.PasswordEncoder; +import org.springframework.web.cors.CorsConfiguration; +import org.springframework.web.cors.UrlBasedCorsConfigurationSource; +import org.springframework.web.filter.CorsFilter; +import ru.soune.nocopy.adminpanel.handler.AdminUserHandler; +import ru.soune.nocopy.adminpanel.handler.RequestHandler; + +import java.util.HashMap; +import java.util.Map; + +@Configuration +public class AppConfig { + + @Bean + PasswordEncoder passwordEncoder() { + return new BCryptPasswordEncoder(); + } + + @Bean + public CorsFilter corsFilter() { + UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); + CorsConfiguration config = new CorsConfiguration(); + config.addAllowedOrigin("*"); + config.addAllowedMethod("*"); + config.addAllowedHeader("*"); + source.registerCorsConfiguration("/**", config); + + return new CorsFilter(source); + } + + @Bean + public Map handlers(AdminUserHandler adminUserHandler) { + Map map = new HashMap<>(); + map.put(100, adminUserHandler); + + return map; + } + +} diff --git a/src/main/java/ru/soune/nocopy/adminpanel/controller/AdminController.java b/src/main/java/ru/soune/nocopy/adminpanel/controller/AdminController.java new file mode 100644 index 0000000..d408846 --- /dev/null +++ b/src/main/java/ru/soune/nocopy/adminpanel/controller/AdminController.java @@ -0,0 +1,58 @@ +package ru.soune.nocopy.adminpanel.controller; + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; +import ru.soune.nocopy.adminpanel.dto.BaseRequest; +import ru.soune.nocopy.adminpanel.dto.BaseResponse; +import ru.soune.nocopy.adminpanel.handler.RequestHandler; +import ru.soune.nocopy.adminpanel.util.MessageCode; + +import java.util.Map; + +@RestController +@RequestMapping("/api/admin") +@RequiredArgsConstructor +@Slf4j +public class AdminController { + + private final Map handlers; + + @PostMapping + public ResponseEntity handleRequest(@RequestBody BaseRequest request) { + log.info("Received request: msg_id={}, version={}", request.getMsgId(), request.getVersion()); + + try { + RequestHandler handler = handlers.get(request.getMsgId()); + + if (handler == null) { + log.warn("No handler found for msg_id: {}", request.getMsgId()); + return ResponseEntity.ok( + BaseResponse.builder() + .msgId(request.getMsgId()) + .messageCode(MessageCode.INVALID_ACTION.getCode()) + .messageDesc("No handler for msg_id: " + request.getMsgId()) + .build() + ); + } + + BaseResponse response = handler.handle(request); + log.info("Request processed successfully: msg_id={}", request.getMsgId()); + return ResponseEntity.ok(response); + + } catch (Exception e) { + log.error("Error processing request: msg_id={}", request.getMsgId(), e); + return ResponseEntity.ok( + BaseResponse.builder() + .msgId(request.getMsgId()) + .messageCode(MessageCode.INVALID_ACTION.getCode()) + .messageDesc("Internal server error: " + e.getMessage()) + .build() + ); + } + } +} diff --git a/src/main/java/ru/soune/nocopy/adminpanel/dto/ActionResponse.java b/src/main/java/ru/soune/nocopy/adminpanel/dto/ActionResponse.java new file mode 100644 index 0000000..be5d535 --- /dev/null +++ b/src/main/java/ru/soune/nocopy/adminpanel/dto/ActionResponse.java @@ -0,0 +1,17 @@ +package ru.soune.nocopy.adminpanel.dto; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Builder; +import lombok.Data; + +import java.util.List; + +@Data +@Builder +public class ActionResponse { + @JsonProperty("action") + private String action; + + @JsonProperty("available_actions") + private List availableActions; +} diff --git a/src/main/java/ru/soune/nocopy/adminpanel/dto/AdminUserRequest.java b/src/main/java/ru/soune/nocopy/adminpanel/dto/AdminUserRequest.java new file mode 100644 index 0000000..c016b18 --- /dev/null +++ b/src/main/java/ru/soune/nocopy/adminpanel/dto/AdminUserRequest.java @@ -0,0 +1,28 @@ +package ru.soune.nocopy.adminpanel.dto; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Data; + +@Data +public class AdminUserRequest { + @JsonProperty("action") + private String action; + + @JsonProperty("admin_id") + private Long adminId; + + @JsonProperty("full_name") + private String fullName; + + @JsonProperty("email") + private String email; + + @JsonProperty("password") + private String password; + + @JsonProperty("is_super_admin") + private Boolean isSuperAdmin; + + @JsonProperty("is_active") + private Boolean isActive; +} diff --git a/src/main/java/ru/soune/nocopy/adminpanel/dto/AdminUserResponse.java b/src/main/java/ru/soune/nocopy/adminpanel/dto/AdminUserResponse.java new file mode 100644 index 0000000..a06f8e2 --- /dev/null +++ b/src/main/java/ru/soune/nocopy/adminpanel/dto/AdminUserResponse.java @@ -0,0 +1,28 @@ +package ru.soune.nocopy.adminpanel.dto; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Builder; +import lombok.Data; + +@Data +@Builder +public class AdminUserResponse { + @JsonProperty("id") + private Long id; + + @JsonProperty("full_name") + private String fullName; + + @JsonProperty("email") + private String email; + + @JsonProperty("is_active") + private Boolean isActive; + + @JsonProperty("is_super_admin") + private Boolean isSuperAdmin; + + @JsonProperty("created_at") + private String createdAt; +} + diff --git a/src/main/java/ru/soune/nocopy/adminpanel/dto/BaseRequest.java b/src/main/java/ru/soune/nocopy/adminpanel/dto/BaseRequest.java new file mode 100644 index 0000000..d960005 --- /dev/null +++ b/src/main/java/ru/soune/nocopy/adminpanel/dto/BaseRequest.java @@ -0,0 +1,21 @@ +package ru.soune.nocopy.adminpanel.dto; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Data; + +@Data +@JsonFormat(with = JsonFormat.Feature.ACCEPT_CASE_INSENSITIVE_PROPERTIES) +public class BaseRequest { + @JsonProperty("version") + Integer version; + + @JsonProperty("msg_id") + Integer msgId; + + @JsonProperty("token") + String token; + + @JsonProperty("message_body") + Object messageBody; +} diff --git a/src/main/java/ru/soune/nocopy/adminpanel/dto/BaseResponse.java b/src/main/java/ru/soune/nocopy/adminpanel/dto/BaseResponse.java new file mode 100644 index 0000000..54b84e3 --- /dev/null +++ b/src/main/java/ru/soune/nocopy/adminpanel/dto/BaseResponse.java @@ -0,0 +1,25 @@ +package ru.soune.nocopy.adminpanel.dto; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; + +@Data +@AllArgsConstructor +@Builder +@JsonFormat(with = JsonFormat.Feature.ACCEPT_CASE_INSENSITIVE_PROPERTIES) +public class BaseResponse { + @JsonProperty("msg_id") + private Integer msgId; + + @JsonProperty("message_code") + private Integer messageCode; + + @JsonProperty("message_desc") + private String messageDesc; + + @JsonProperty("message_body") + private Object messageBody; +} diff --git a/src/main/java/ru/soune/nocopy/adminpanel/dto/LoginResponse.java b/src/main/java/ru/soune/nocopy/adminpanel/dto/LoginResponse.java new file mode 100644 index 0000000..c1f66ed --- /dev/null +++ b/src/main/java/ru/soune/nocopy/adminpanel/dto/LoginResponse.java @@ -0,0 +1,18 @@ +package ru.soune.nocopy.adminpanel.dto; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Builder; +import lombok.Data; + +@Data +@Builder +public class LoginResponse { + @JsonProperty("success") + private Boolean success; + + @JsonProperty("token") + private String token; + + @JsonProperty("admin") + private AdminUserResponse admin; +} diff --git a/src/main/java/ru/soune/nocopy/adminpanel/entity/AdminUser.java b/src/main/java/ru/soune/nocopy/adminpanel/entity/AdminUser.java new file mode 100644 index 0000000..0d99281 --- /dev/null +++ b/src/main/java/ru/soune/nocopy/adminpanel/entity/AdminUser.java @@ -0,0 +1,59 @@ +package ru.soune.nocopy.adminpanel.entity; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import jakarta.persistence.*; +import jakarta.validation.constraints.Size; +import lombok.*; +import org.springframework.data.annotation.CreatedDate; +import org.springframework.data.annotation.LastModifiedDate; +import org.springframework.data.jpa.domain.support.AuditingEntityListener; +import ru.soune.nocopy.adminpanel.permission.AdminPermission; + +import java.time.LocalDateTime; +import java.util.HashSet; +import java.util.Set; + +@Entity +@Table(name = "admin_users") +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +@ToString(exclude = {"password", "permissions"}) +@EntityListeners(AuditingEntityListener.class) +public class AdminUser { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @Column(name = "full_name") + private String fullName; + + @Size(max = 1024) + @Column(name = "email", length = 1024, unique = true) + private String email; + + @Column(nullable = false) + @Size(min = 6) + @JsonIgnore + private String password; + + @CreatedDate + @Column(name = "created_at", updatable = false, nullable = false) + private LocalDateTime createdAt; + + @LastModifiedDate + @Column(name = "updated_at") + private LocalDateTime updatedAt; + + @Column(name = "is_active", nullable = false) + private Boolean isActive = true; + + @Column(name = "is_super_admin", nullable = false) + private Boolean isSuperAdmin = false; + + @Column(name = "permissions", nullable = false) + private Long permissions = AdminPermission.DEFAULT_PERMISSIONS; + +} diff --git a/src/main/java/ru/soune/nocopy/adminpanel/exceptions/AdminUserNotFoundException.java b/src/main/java/ru/soune/nocopy/adminpanel/exceptions/AdminUserNotFoundException.java new file mode 100644 index 0000000..89c02cd --- /dev/null +++ b/src/main/java/ru/soune/nocopy/adminpanel/exceptions/AdminUserNotFoundException.java @@ -0,0 +1,7 @@ +package ru.soune.nocopy.adminpanel.exceptions; + +public class AdminUserNotFoundException extends RuntimeException { + public AdminUserNotFoundException(String message) { + super(message); + } +} diff --git a/src/main/java/ru/soune/nocopy/adminpanel/exceptions/EmailAlreadyExistsException.java b/src/main/java/ru/soune/nocopy/adminpanel/exceptions/EmailAlreadyExistsException.java new file mode 100644 index 0000000..38395dc --- /dev/null +++ b/src/main/java/ru/soune/nocopy/adminpanel/exceptions/EmailAlreadyExistsException.java @@ -0,0 +1,7 @@ +package ru.soune.nocopy.adminpanel.exceptions; + +public class EmailAlreadyExistsException extends RuntimeException { + public EmailAlreadyExistsException(String message) { + super(message); + } +} diff --git a/src/main/java/ru/soune/nocopy/adminpanel/handler/AdminUserHandler.java b/src/main/java/ru/soune/nocopy/adminpanel/handler/AdminUserHandler.java new file mode 100644 index 0000000..45b00bb --- /dev/null +++ b/src/main/java/ru/soune/nocopy/adminpanel/handler/AdminUserHandler.java @@ -0,0 +1,267 @@ +package ru.soune.nocopy.adminpanel.handler; + +import com.fasterxml.jackson.databind.ObjectMapper; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; +import ru.soune.nocopy.adminpanel.dto.*; +import ru.soune.nocopy.adminpanel.entity.AdminUser; +import ru.soune.nocopy.adminpanel.exceptions.AdminUserNotFoundException; +import ru.soune.nocopy.adminpanel.exceptions.EmailAlreadyExistsException; +import ru.soune.nocopy.adminpanel.permission.AdminPermission; +import ru.soune.nocopy.adminpanel.service.AdminUserService; +import ru.soune.nocopy.adminpanel.util.JwtUtil; +import ru.soune.nocopy.adminpanel.util.MessageCode; + +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; + +@Component +@RequiredArgsConstructor +@Slf4j +public class AdminUserHandler implements RequestHandler { + + private final ObjectMapper objectMapper; + + private final AdminUserService adminUserService; + + private final JwtUtil jwtUtil; + + @Override + public BaseResponse handle(BaseRequest request) throws Exception { + AdminUserRequest adminRequest = objectMapper.convertValue(request.getMessageBody(), AdminUserRequest.class); + String action = adminRequest.getAction(); + + return switch (action) { + case "login" -> handleLogin(request, adminRequest); + case "create" -> handleCreate(request, adminRequest); + case "get_all" -> handleGetAll(request); + case "get_by_id" -> handleGetById(request, adminRequest); + case "update" -> handleUpdate(request, adminRequest); + case "set_super_admin" -> handleSetSuperAdmin(request, adminRequest); + case "toggle_active" -> handleToggleActive(request, adminRequest); + case "delete" -> handleDelete(request, adminRequest); + default -> handleInvalidAction(request, action); + }; + } + + private BaseResponse handleLogin(BaseRequest request, AdminUserRequest adminRequest) { + String email = adminRequest.getEmail(); + String password = adminRequest.getPassword(); + + boolean authenticated = adminUserService.authenticate(email, password); + + if (!authenticated) { + return BaseResponse.builder() + .msgId(request.getMsgId()) + .messageCode(MessageCode.INVALID_CREDENTIALS.getCode()) + .messageDesc(MessageCode.INVALID_CREDENTIALS.getDescription()) + .build(); + } + + try { + AdminUser admin = adminUserService.findByEmail(email); + + if (!admin.getIsActive()) { + return BaseResponse.builder() + .msgId(request.getMsgId()) + .messageCode(MessageCode.ADMIN_INACTIVE.getCode()) + .messageDesc(MessageCode.ADMIN_INACTIVE.getDescription()) + .build(); + } + + String token = jwtUtil.generateToken(admin.getEmail(), admin.getId()); + + LoginResponse loginResponse = LoginResponse.builder() + .success(true) + .token(token) + .admin(convertToResponse(admin)) + .build(); + + return BaseResponse.builder() + .msgId(request.getMsgId()) + .messageCode(MessageCode.SUCCESS.getCode()) + .messageDesc(MessageCode.SUCCESS.getDescription()) + .messageBody(loginResponse) + .build(); + } catch (AdminUserNotFoundException e) { + return BaseResponse.builder() + .msgId(request.getMsgId()) + .messageCode(MessageCode.ADMIN_NOT_FOUND.getCode()) + .messageDesc(MessageCode.ADMIN_NOT_FOUND.getDescription()) + .build(); + } + } + + private BaseResponse handleCreate(BaseRequest request, AdminUserRequest adminRequest) { + try { + boolean superAdmin = adminRequest.getIsSuperAdmin() != null && adminRequest.getIsSuperAdmin(); + AdminUser admin = adminUserService.create( + adminRequest.getFullName(), + adminRequest.getEmail(), + adminRequest.getPassword(), + superAdmin + ); + + return BaseResponse.builder() + .msgId(request.getMsgId()) + .messageCode(MessageCode.SUCCESS.getCode()) + .messageDesc(MessageCode.SUCCESS.getDescription()) + .messageBody(convertToResponse(admin)) + .build(); + } catch (EmailAlreadyExistsException e) { + return BaseResponse.builder() + .msgId(request.getMsgId()) + .messageCode(MessageCode.EMAIL_ALREADY_EXISTS.getCode()) + .messageDesc(MessageCode.EMAIL_ALREADY_EXISTS.getDescription()) + .build(); + } + } + + private BaseResponse handleGetAll(BaseRequest request) { + List admins = adminUserService.findAll().stream() + .map(this::convertToResponse) + .collect(Collectors.toList()); + + return BaseResponse.builder() + .msgId(request.getMsgId()) + .messageCode(MessageCode.SUCCESS.getCode()) + .messageDesc(MessageCode.SUCCESS.getDescription()) + .messageBody(admins) + .build(); + } + + private BaseResponse handleGetById(BaseRequest request, AdminUserRequest adminRequest) { + try { + AdminUser admin = adminUserService.findById(adminRequest.getAdminId()); + return BaseResponse.builder() + .msgId(request.getMsgId()) + .messageCode(MessageCode.SUCCESS.getCode()) + .messageDesc(MessageCode.SUCCESS.getDescription()) + .messageBody(convertToResponse(admin)) + .build(); + } catch (AdminUserNotFoundException e) { + return BaseResponse.builder() + .msgId(request.getMsgId()) + .messageCode(MessageCode.ADMIN_NOT_FOUND.getCode()) + .messageDesc(MessageCode.ADMIN_NOT_FOUND.getDescription()) + .build(); + } + } + + private BaseResponse handleUpdate(BaseRequest request, AdminUserRequest adminRequest) { + try { + AdminUser admin = adminUserService.update( + adminRequest.getAdminId(), + adminRequest.getFullName(), + adminRequest.getEmail(), + adminRequest.getPassword() + ); + + return BaseResponse.builder() + .msgId(request.getMsgId()) + .messageCode(MessageCode.SUCCESS.getCode()) + .messageDesc(MessageCode.SUCCESS.getDescription()) + .messageBody(convertToResponse(admin)) + .build(); + } catch (AdminUserNotFoundException e) { + return BaseResponse.builder() + .msgId(request.getMsgId()) + .messageCode(MessageCode.ADMIN_NOT_FOUND.getCode()) + .messageDesc(MessageCode.ADMIN_NOT_FOUND.getDescription()) + .build(); + } catch (EmailAlreadyExistsException e) { + return BaseResponse.builder() + .msgId(request.getMsgId()) + .messageCode(MessageCode.EMAIL_ALREADY_EXISTS.getCode()) + .messageDesc(MessageCode.EMAIL_ALREADY_EXISTS.getDescription()) + .build(); + } + } + + private BaseResponse handleSetSuperAdmin(BaseRequest request, AdminUserRequest adminRequest) { + try { + AdminUser admin = adminUserService.setSuperAdmin(adminRequest.getAdminId(), adminRequest.getIsSuperAdmin()); + + return BaseResponse.builder() + .msgId(request.getMsgId()) + .messageCode(MessageCode.SUCCESS.getCode()) + .messageDesc(MessageCode.SUCCESS.getDescription()) + .messageBody(convertToResponse(admin)) + .build(); + } catch (AdminUserNotFoundException e) { + return BaseResponse.builder() + .msgId(request.getMsgId()) + .messageCode(MessageCode.ADMIN_NOT_FOUND.getCode()) + .messageDesc(MessageCode.ADMIN_NOT_FOUND.getDescription()) + .build(); + } + } + + private BaseResponse handleToggleActive(BaseRequest request, AdminUserRequest adminRequest) { + try { + adminUserService.toggleActive(adminRequest.getAdminId(), adminRequest.getIsActive()); + AdminUser admin = adminUserService.findById(adminRequest.getAdminId()); + + return BaseResponse.builder() + .msgId(request.getMsgId()) + .messageCode(MessageCode.SUCCESS.getCode()) + .messageDesc(MessageCode.SUCCESS.getDescription()) + .messageBody(convertToResponse(admin)) + .build(); + } catch (AdminUserNotFoundException e) { + return BaseResponse.builder() + .msgId(request.getMsgId()) + .messageCode(MessageCode.ADMIN_NOT_FOUND.getCode()) + .messageDesc(MessageCode.ADMIN_NOT_FOUND.getDescription()) + .build(); + } + } + + private BaseResponse handleDelete(BaseRequest request, AdminUserRequest adminRequest) { + try { + adminUserService.delete(adminRequest.getAdminId()); + + return BaseResponse.builder() + .msgId(request.getMsgId()) + .messageCode(MessageCode.SUCCESS.getCode()) + .messageDesc(MessageCode.SUCCESS.getDescription()) + .messageBody("Admin deleted successfully") + .build(); + } catch (AdminUserNotFoundException e) { + return BaseResponse.builder() + .msgId(request.getMsgId()) + .messageCode(MessageCode.ADMIN_NOT_FOUND.getCode()) + .messageDesc(MessageCode.ADMIN_NOT_FOUND.getDescription()) + .build(); + } + } + + private BaseResponse handleInvalidAction(BaseRequest request, String action) { + ActionResponse response = ActionResponse.builder() + .action(action) + .availableActions(Arrays.asList( + "login", "create", "get_all", "get_by_id", + "update", "set_super_admin", "toggle_active", "delete")) + .build(); + + return BaseResponse.builder() + .msgId(request.getMsgId()) + .messageCode(MessageCode.INVALID_ACTION.getCode()) + .messageDesc(MessageCode.INVALID_ACTION.getDescription()) + .messageBody(response) + .build(); + } + + private AdminUserResponse convertToResponse(AdminUser admin) { + return AdminUserResponse.builder() + .id(admin.getId()) + .fullName(admin.getFullName()) + .email(admin.getEmail()) + .isActive(admin.getIsActive()) + .isSuperAdmin(AdminPermission.isSuperAdmin(admin.getPermissions())) + .createdAt(admin.getCreatedAt().toString()) + .build(); + } +} diff --git a/src/main/java/ru/soune/nocopy/adminpanel/handler/RequestHandler.java b/src/main/java/ru/soune/nocopy/adminpanel/handler/RequestHandler.java new file mode 100644 index 0000000..260fdbc --- /dev/null +++ b/src/main/java/ru/soune/nocopy/adminpanel/handler/RequestHandler.java @@ -0,0 +1,8 @@ +package ru.soune.nocopy.adminpanel.handler; + +import ru.soune.nocopy.adminpanel.dto.BaseRequest; +import ru.soune.nocopy.adminpanel.dto.BaseResponse; + +public interface RequestHandler { + BaseResponse handle(BaseRequest request) throws Exception; +} diff --git a/src/main/java/ru/soune/nocopy/adminpanel/permission/AdminPermission.java b/src/main/java/ru/soune/nocopy/adminpanel/permission/AdminPermission.java new file mode 100644 index 0000000..e2728b3 --- /dev/null +++ b/src/main/java/ru/soune/nocopy/adminpanel/permission/AdminPermission.java @@ -0,0 +1,21 @@ +package ru.soune.nocopy.adminpanel.permission; + +public class AdminPermission { + public static final long ADMIN_BIT = 1L; + public static final long SUPER_ADMIN_BIT = 1L << 1; + + public static final long DEFAULT_PERMISSIONS = ADMIN_BIT; + public static final long SUPER_ADMIN_PERMISSIONS = ADMIN_BIT | SUPER_ADMIN_BIT; + + public static boolean hasPermission(long userPermissions, long permissionBit) { + return (userPermissions & permissionBit) != 0; + } + + public static boolean isAdmin(long permissions) { + return hasPermission(permissions, ADMIN_BIT); + } + + public static boolean isSuperAdmin(long permissions) { + return hasPermission(permissions, SUPER_ADMIN_BIT); + } +} diff --git a/src/main/java/ru/soune/nocopy/adminpanel/permission/PermissionChecker.java b/src/main/java/ru/soune/nocopy/adminpanel/permission/PermissionChecker.java new file mode 100644 index 0000000..bb3ad9c --- /dev/null +++ b/src/main/java/ru/soune/nocopy/adminpanel/permission/PermissionChecker.java @@ -0,0 +1,21 @@ +package ru.soune.nocopy.adminpanel.permission; + +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Component; +import ru.soune.nocopy.adminpanel.entity.AdminUser; + +@Component +@RequiredArgsConstructor +public class PermissionChecker { + + public boolean isSuperAdmin(AdminUser admin) { + if (admin == null || !admin.getIsActive()) return false; + return AdminPermission.isSuperAdmin(admin.getPermissions()); + } + + public void checkSuperAdmin(AdminUser admin) { + if (!isSuperAdmin(admin)) { + throw new SecurityException("Super admin permission required"); + } + } +} diff --git a/src/main/java/ru/soune/nocopy/adminpanel/repository/AdminUserRepository.java b/src/main/java/ru/soune/nocopy/adminpanel/repository/AdminUserRepository.java new file mode 100644 index 0000000..b382e9f --- /dev/null +++ b/src/main/java/ru/soune/nocopy/adminpanel/repository/AdminUserRepository.java @@ -0,0 +1,14 @@ +package ru.soune.nocopy.adminpanel.repository; + +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; +import ru.soune.nocopy.adminpanel.entity.AdminUser; + +import java.util.Optional; + +@Repository +public interface AdminUserRepository extends JpaRepository { + Optional findByEmail(String email); + + boolean existsByEmail(String email); +} diff --git a/src/main/java/ru/soune/nocopy/adminpanel/service/AdminUserService.java b/src/main/java/ru/soune/nocopy/adminpanel/service/AdminUserService.java new file mode 100644 index 0000000..dbdcb6b --- /dev/null +++ b/src/main/java/ru/soune/nocopy/adminpanel/service/AdminUserService.java @@ -0,0 +1,99 @@ +package ru.soune.nocopy.adminpanel.service; + +import lombok.RequiredArgsConstructor; +import org.springframework.security.crypto.password.PasswordEncoder; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import ru.soune.nocopy.adminpanel.entity.AdminUser; +import ru.soune.nocopy.adminpanel.exceptions.AdminUserNotFoundException; +import ru.soune.nocopy.adminpanel.exceptions.EmailAlreadyExistsException; +import ru.soune.nocopy.adminpanel.permission.AdminPermission; +import ru.soune.nocopy.adminpanel.repository.AdminUserRepository; + +import java.time.LocalDateTime; +import java.util.List; + +@Service +@RequiredArgsConstructor +public class AdminUserService { + + private final AdminUserRepository adminUserRepository; + private final PasswordEncoder passwordEncoder; + + @Transactional + public AdminUser create(String fullName, String email, String password, boolean superAdmin) { + if (adminUserRepository.existsByEmail(email)) { + throw new EmailAlreadyExistsException("Email already exists: " + email); + } + + AdminUser admin = new AdminUser(); + admin.setFullName(fullName); + admin.setEmail(email); + admin.setPassword(passwordEncoder.encode(password)); + admin.setCreatedAt(LocalDateTime.now()); + admin.setIsActive(true); + admin.setPermissions(superAdmin ? AdminPermission.SUPER_ADMIN_PERMISSIONS : AdminPermission.DEFAULT_PERMISSIONS); + + return adminUserRepository.save(admin); + } + + public AdminUser findById(Long id) { + return adminUserRepository.findById(id) + .orElseThrow(() -> new AdminUserNotFoundException("Admin not found: " + id)); + } + + public AdminUser findByEmail(String email) { + return adminUserRepository.findByEmail(email) + .orElseThrow(() -> new AdminUserNotFoundException("Admin not found: " + email)); + } + + public List findAll() { + return adminUserRepository.findAll(); + } + + @Transactional + public AdminUser update(Long id, String fullName, String email, String password) { + AdminUser admin = findById(id); + + if (fullName != null) admin.setFullName(fullName); + + if (email != null && !email.equals(admin.getEmail())) { + if (adminUserRepository.existsByEmail(email)) { + throw new EmailAlreadyExistsException("Email already exists: " + email); + } + admin.setEmail(email); + } + + if (password != null && !password.isEmpty()) { + admin.setPassword(passwordEncoder.encode(password)); + } + + return adminUserRepository.save(admin); + } + + @Transactional + public AdminUser setSuperAdmin(Long id, boolean superAdmin) { + AdminUser admin = findById(id); + admin.setPermissions(superAdmin ? AdminPermission.SUPER_ADMIN_PERMISSIONS : AdminPermission.DEFAULT_PERMISSIONS); + return adminUserRepository.save(admin); + } + + @Transactional + public void toggleActive(Long id, Boolean isActive) { + AdminUser admin = findById(id); + admin.setIsActive(isActive); + adminUserRepository.save(admin); + } + + @Transactional + public void delete(Long id) { + adminUserRepository.deleteById(id); + } + + public boolean authenticate(String email, String password) { + return adminUserRepository.findByEmail(email) + .filter(AdminUser::getIsActive) + .map(admin -> passwordEncoder.matches(password, admin.getPassword())) + .orElse(false); + } +} diff --git a/src/main/java/ru/soune/nocopy/adminpanel/util/JwtAuthFilter.java b/src/main/java/ru/soune/nocopy/adminpanel/util/JwtAuthFilter.java new file mode 100644 index 0000000..31304a2 --- /dev/null +++ b/src/main/java/ru/soune/nocopy/adminpanel/util/JwtAuthFilter.java @@ -0,0 +1,54 @@ +package ru.soune.nocopy.adminpanel.util; + +import com.fasterxml.jackson.databind.ObjectMapper; +import jakarta.servlet.FilterChain; +import jakarta.servlet.ServletException; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Component; +import org.springframework.web.filter.OncePerRequestFilter; +import ru.soune.nocopy.adminpanel.dto.BaseResponse; + +import java.io.IOException; + +@Component +@RequiredArgsConstructor +public class JwtAuthFilter extends OncePerRequestFilter { + + private final JwtUtil jwtUtil; + private final ObjectMapper objectMapper; + + @Override + protected void doFilterInternal(HttpServletRequest request, + HttpServletResponse response, + FilterChain filterChain) throws ServletException, IOException { + + String authHeader = request.getHeader("Authorization"); + + if (authHeader == null || !authHeader.startsWith("Bearer ")) { + filterChain.doFilter(request, response); + return; + } + + String token = authHeader.substring(7); + + if (!jwtUtil.validateToken(token)) { + response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); + response.setContentType("application/json"); + + BaseResponse errorResponse = BaseResponse.builder() + .messageCode(MessageCode.INVALID_CREDENTIALS.getCode()) + .messageDesc("Invalid or expired token") + .build(); + + response.getWriter().write(objectMapper.writeValueAsString(errorResponse)); + return; + } + + request.setAttribute("userId", jwtUtil.extractUserId(token)); + request.setAttribute("email", jwtUtil.extractEmail(token)); + + filterChain.doFilter(request, response); + } +} diff --git a/src/main/java/ru/soune/nocopy/adminpanel/util/JwtUtil.java b/src/main/java/ru/soune/nocopy/adminpanel/util/JwtUtil.java new file mode 100644 index 0000000..129be81 --- /dev/null +++ b/src/main/java/ru/soune/nocopy/adminpanel/util/JwtUtil.java @@ -0,0 +1,64 @@ +package ru.soune.nocopy.adminpanel.util; + +import io.jsonwebtoken.Claims; +import io.jsonwebtoken.Jwts; +import io.jsonwebtoken.SignatureAlgorithm; +import io.jsonwebtoken.security.Keys; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +import javax.crypto.SecretKey; +import java.nio.charset.StandardCharsets; +import java.util.Date; + +@Component +public class JwtUtil { + + @Value("${jwt.secret:Z29nb3Bvd2VycmFuZ2VydHVtYmF5YW1iZjMyNDIyMjh3aW5lcndpbmVy}") + private String secret; + + @Value("${jwt.expiration:3600000}") + private Long expiration; + + private SecretKey getSigningKey() { + return Keys.hmacShaKeyFor(secret.getBytes(StandardCharsets.UTF_8)); + } + + public String generateToken(String email, Long userId) { + return Jwts.builder() + .setSubject(email) + .claim("userId", userId) + .setIssuedAt(new Date()) + .setExpiration(new Date(System.currentTimeMillis() + expiration)) + .signWith(getSigningKey(), SignatureAlgorithm.HS256) + .compact(); + } + + public Claims extractClaims(String token) { + return Jwts.parser() + .setSigningKey(getSigningKey()) + .build() + .parseClaimsJws(token) + .getBody(); + } + + public String extractEmail(String token) { + return extractClaims(token).getSubject(); + } + + public Long extractUserId(String token) { + return extractClaims(token).get("userId", Long.class); + } + + public boolean isTokenExpired(String token) { + return extractClaims(token).getExpiration().before(new Date()); + } + + public boolean validateToken(String token) { + try { + return !isTokenExpired(token); + } catch (Exception e) { + return false; + } + } +} diff --git a/src/main/java/ru/soune/nocopy/adminpanel/util/MessageCode.java b/src/main/java/ru/soune/nocopy/adminpanel/util/MessageCode.java new file mode 100644 index 0000000..b3e7ecf --- /dev/null +++ b/src/main/java/ru/soune/nocopy/adminpanel/util/MessageCode.java @@ -0,0 +1,23 @@ +package ru.soune.nocopy.adminpanel.util; + +import lombok.Getter; + +@Getter +public enum MessageCode { + SUCCESS(0, "Success"), + INVALID_ACTION(2, "Invalid action"), + ADMIN_NOT_FOUND(4, "Admin not found"), + EMAIL_ALREADY_EXISTS(2, "Email already exists"), + INVALID_CREDENTIALS(2, "Invalid credentials"), + PERMISSION_DENIED(2, "Permission denied"), + ADMIN_INACTIVE(2, "Admin is inactive"); + + private final int code; + private final String description; + + MessageCode(int code, String description) { + this.code = code; + this.description = description; + } + +} diff --git a/src/main/resources/application.yaml b/src/main/resources/application.yaml index eebf038..4248496 100644 --- a/src/main/resources/application.yaml +++ b/src/main/resources/application.yaml @@ -9,4 +9,8 @@ spring: ddl-auto: validate server: - port: 8082 \ No newline at end of file + port: 8082 + +jwt: + secret: Z29nb3Bvd2VycmFuZ2VydHVtYmF5YW1iZjMyNDIyMjh3aW5lcndpbmVy + expiration: 3600000 \ No newline at end of file -- 2.54.0 From 91c85173e4165599e8875fc64c0f2f0e303d5df2 Mon Sep 17 00:00:00 2001 From: vladp Date: Wed, 8 Apr 2026 11:57:27 +0700 Subject: [PATCH 03/47] add admin user logic --- infrastrucure/deploy.groovy | 10 ++-------- src/main/resources/application.yaml | 2 +- 2 files changed, 3 insertions(+), 9 deletions(-) diff --git a/infrastrucure/deploy.groovy b/infrastrucure/deploy.groovy index a892480..2584401 100644 --- a/infrastrucure/deploy.groovy +++ b/infrastrucure/deploy.groovy @@ -27,11 +27,6 @@ pipeline { defaultValue: 'db', description: 'Хост базы данных' ) - choice( - name: 'SPRING_PROFILE', - choices: ['dev', 'prod'], - description: 'Профиль Spring для запуска' - ) } stages { @@ -85,7 +80,6 @@ pipeline { steps { script { def buildTime = sh(script: "TZ='Asia/Novosibirsk' date '+%d-%m-%Y %H:%M:%S'", returnStdout: true).trim() - def springProfile = params.SPRING_PROFILE withCredentials([ usernamePassword( credentialsId: 'server-root-password', @@ -120,14 +114,14 @@ pipeline { --network ${params.NETWORK} \\ --network-alias admin \\ --network-alias admin-${params.PORT} \\ - -p ${params.PORT}:8082 \\ + -p ${params.PORT}:${params.PORT} \\ -v uploads_data:/data/uploads:rw \\ -e POSTGRES_DB=no_copy_ \\ -e POSTGRES_USER=${DB_USER} \\ -e POSTGRES_PASSWORD=${DB_PASSWORD} \\ -e POSTGRES_PORT=5432 \\ -e POSTGRES_HOST=${params.DB_HOST} \\ - -e SPRING_PROFILES_ACTIVE=${springProfile} \\ + -e SERVER_PORT=${params.PORT} \\ -e BUILD_TIME='${buildTime}' \\ --restart unless-stopped \\ admin-panel-${params.PORT}:latest diff --git a/src/main/resources/application.yaml b/src/main/resources/application.yaml index 4248496..3efd934 100644 --- a/src/main/resources/application.yaml +++ b/src/main/resources/application.yaml @@ -6,7 +6,7 @@ spring: jpa: hibernate: - ddl-auto: validate + ddl-auto: update server: port: 8082 -- 2.54.0 From 200d070fa5fa223dd032c5f6827d49acf69e91ed Mon Sep 17 00:00:00 2001 From: backdev-1 Date: Thu, 7 May 2026 15:24:25 +0700 Subject: [PATCH 04/47] add section admin permission --- .../adminpanel/dto/AdminUserRequest.java | 6 + .../adminpanel/dto/AdminUserResponse.java | 4 + .../adminpanel/entity/AdminSection.java | 17 +++ .../entity/AdminSectionPermission.java | 74 ++++++++++++ .../adminpanel/handler/AdminUserHandler.java | 110 +++++++++++++++++- .../permission/PermissionChecker.java | 20 ++++ .../permission/SectionPermissions.java | 15 +++ .../AdminSectionPermissionRepository.java | 12 ++ .../AdminSectionPermissionService.java | 107 +++++++++++++++++ 9 files changed, 364 insertions(+), 1 deletion(-) create mode 100644 src/main/java/ru/soune/nocopy/adminpanel/entity/AdminSection.java create mode 100644 src/main/java/ru/soune/nocopy/adminpanel/entity/AdminSectionPermission.java create mode 100644 src/main/java/ru/soune/nocopy/adminpanel/permission/SectionPermissions.java create mode 100644 src/main/java/ru/soune/nocopy/adminpanel/repository/AdminSectionPermissionRepository.java create mode 100644 src/main/java/ru/soune/nocopy/adminpanel/service/AdminSectionPermissionService.java diff --git a/src/main/java/ru/soune/nocopy/adminpanel/dto/AdminUserRequest.java b/src/main/java/ru/soune/nocopy/adminpanel/dto/AdminUserRequest.java index c016b18..698118a 100644 --- a/src/main/java/ru/soune/nocopy/adminpanel/dto/AdminUserRequest.java +++ b/src/main/java/ru/soune/nocopy/adminpanel/dto/AdminUserRequest.java @@ -3,6 +3,8 @@ package ru.soune.nocopy.adminpanel.dto; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.Data; +import java.util.Map; + @Data public class AdminUserRequest { @JsonProperty("action") @@ -25,4 +27,8 @@ public class AdminUserRequest { @JsonProperty("is_active") private Boolean isActive; + + @JsonProperty("permissions") + private Map permissions; + } diff --git a/src/main/java/ru/soune/nocopy/adminpanel/dto/AdminUserResponse.java b/src/main/java/ru/soune/nocopy/adminpanel/dto/AdminUserResponse.java index a06f8e2..a155fa8 100644 --- a/src/main/java/ru/soune/nocopy/adminpanel/dto/AdminUserResponse.java +++ b/src/main/java/ru/soune/nocopy/adminpanel/dto/AdminUserResponse.java @@ -4,6 +4,8 @@ import com.fasterxml.jackson.annotation.JsonProperty; import lombok.Builder; import lombok.Data; +import java.util.Map; + @Data @Builder public class AdminUserResponse { @@ -24,5 +26,7 @@ public class AdminUserResponse { @JsonProperty("created_at") private String createdAt; + + private Map permissions; } diff --git a/src/main/java/ru/soune/nocopy/adminpanel/entity/AdminSection.java b/src/main/java/ru/soune/nocopy/adminpanel/entity/AdminSection.java new file mode 100644 index 0000000..13b43fa --- /dev/null +++ b/src/main/java/ru/soune/nocopy/adminpanel/entity/AdminSection.java @@ -0,0 +1,17 @@ +package ru.soune.nocopy.adminpanel.entity; + +public enum AdminSection { + DASH, + USERS, + STAFF, + SUBSCRIPTIONS, + TARIFFS, + CONTENT_MODERATION, + COMPLAINTS, + CLAIMS, + MAILINGS, + API, + MONEY, + KYC, + AGREEMENTS +} diff --git a/src/main/java/ru/soune/nocopy/adminpanel/entity/AdminSectionPermission.java b/src/main/java/ru/soune/nocopy/adminpanel/entity/AdminSectionPermission.java new file mode 100644 index 0000000..e1aeff9 --- /dev/null +++ b/src/main/java/ru/soune/nocopy/adminpanel/entity/AdminSectionPermission.java @@ -0,0 +1,74 @@ +package ru.soune.nocopy.adminpanel.entity; + +import jakarta.persistence.*; +import lombok.*; +import org.springframework.data.annotation.CreatedDate; +import org.springframework.data.annotation.LastModifiedDate; +import org.springframework.data.jpa.domain.support.AuditingEntityListener; + +import java.time.LocalDateTime; + +@Entity +@Table(name = "admin_section_permissions") +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +@Builder +@EntityListeners(AuditingEntityListener.class) +public class AdminSectionPermission { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @Column(name = "user_id", nullable = false, unique = true) + private Long userId; + + @Column(name = "dash", nullable = false) + private Integer dash = 0b00; + + @Column(name = "users", nullable = false) + private Integer users = 0b00; + + @Column(name = "staff", nullable = false) + private Integer staff = 0b00; + + @Column(name = "subscriptions", nullable = false) + private Integer subscriptions = 0b00; + + @Column(name = "tariffs", nullable = false) + private Integer tariffs = 0b00; + + @Column(name = "content_moderation", nullable = false) + private Integer contentModeration = 0b00; + + @Column(name = "complaints", nullable = false) + private Integer complaints = 0b00; + + @Column(name = "claims", nullable = false) + private Integer claims = 0b00; + + @Column(name = "mailings", nullable = false) + private Integer mailings = 0b00; + + @Column(name = "api", nullable = false) + private Integer api = 0b00; + + @Column(name = "money", nullable = false) + private Integer money = 0b00; + + @Column(name = "kyc", nullable = false) + private Integer kyc = 0b00; + + @Column(name = "agreements", nullable = false) + private Integer agreements = 0b00; + + @CreatedDate + @Column(name = "created_at", updatable = false) + private LocalDateTime createdAt; + + @LastModifiedDate + @Column(name = "updated_at") + private LocalDateTime updatedAt; +} diff --git a/src/main/java/ru/soune/nocopy/adminpanel/handler/AdminUserHandler.java b/src/main/java/ru/soune/nocopy/adminpanel/handler/AdminUserHandler.java index 45b00bb..8a87c6d 100644 --- a/src/main/java/ru/soune/nocopy/adminpanel/handler/AdminUserHandler.java +++ b/src/main/java/ru/soune/nocopy/adminpanel/handler/AdminUserHandler.java @@ -5,16 +5,20 @@ import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; import ru.soune.nocopy.adminpanel.dto.*; +import ru.soune.nocopy.adminpanel.entity.AdminSection; import ru.soune.nocopy.adminpanel.entity.AdminUser; import ru.soune.nocopy.adminpanel.exceptions.AdminUserNotFoundException; import ru.soune.nocopy.adminpanel.exceptions.EmailAlreadyExistsException; import ru.soune.nocopy.adminpanel.permission.AdminPermission; +import ru.soune.nocopy.adminpanel.service.AdminSectionPermissionService; import ru.soune.nocopy.adminpanel.service.AdminUserService; import ru.soune.nocopy.adminpanel.util.JwtUtil; import ru.soune.nocopy.adminpanel.util.MessageCode; import java.util.Arrays; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.stream.Collectors; @Component @@ -28,6 +32,8 @@ public class AdminUserHandler implements RequestHandler { private final JwtUtil jwtUtil; + private final AdminSectionPermissionService permissionService; + @Override public BaseResponse handle(BaseRequest request) throws Exception { AdminUserRequest adminRequest = objectMapper.convertValue(request.getMessageBody(), AdminUserRequest.class); @@ -42,6 +48,8 @@ public class AdminUserHandler implements RequestHandler { case "set_super_admin" -> handleSetSuperAdmin(request, adminRequest); case "toggle_active" -> handleToggleActive(request, adminRequest); case "delete" -> handleDelete(request, adminRequest); + case "get_permissions" -> handleGetPermissions(request, adminRequest); + case "update_permissions" -> handleUpdatePermissions(request, adminRequest); default -> handleInvalidAction(request, action); }; } @@ -243,7 +251,8 @@ public class AdminUserHandler implements RequestHandler { .action(action) .availableActions(Arrays.asList( "login", "create", "get_all", "get_by_id", - "update", "set_super_admin", "toggle_active", "delete")) + "update", "set_super_admin", "toggle_active", "delete", + "get_permissions", "update_permissions")) .build(); return BaseResponse.builder() @@ -254,6 +263,105 @@ public class AdminUserHandler implements RequestHandler { .build(); } + private BaseResponse handleGetPermissions(BaseRequest request, AdminUserRequest adminRequest) { + try { + Long userId = adminRequest.getAdminId(); + AdminUser admin = adminUserService.findById(userId); + + Map sectionPermissions = permissionService.getAllPermissions(userId); + + Map permissionsMap = new HashMap<>(); + sectionPermissions.forEach((section, value) -> + permissionsMap.put(section.name().toLowerCase(), value)); + + AdminUserResponse response = AdminUserResponse.builder() + .id(admin.getId()) + .fullName(admin.getFullName()) + .email(admin.getEmail()) + .isActive(admin.getIsActive()) + .isSuperAdmin(AdminPermission.isSuperAdmin(admin.getPermissions())) + .createdAt(admin.getCreatedAt().toString()) + .permissions(permissionsMap) + .build(); + + return BaseResponse.builder() + .msgId(request.getMsgId()) + .messageCode(MessageCode.SUCCESS.getCode()) + .messageDesc(MessageCode.SUCCESS.getDescription()) + .messageBody(response) + .build(); + } catch (AdminUserNotFoundException e) { + return BaseResponse.builder() + .msgId(request.getMsgId()) + .messageCode(MessageCode.ADMIN_NOT_FOUND.getCode()) + .messageDesc(MessageCode.ADMIN_NOT_FOUND.getDescription()) + .build(); + } + } + + private BaseResponse handleUpdatePermissions(BaseRequest request, AdminUserRequest adminRequest) { + try { + Long userId = adminRequest.getAdminId(); + Map permissionsMap = adminRequest.getPermissions(); + + if (permissionsMap == null || permissionsMap.isEmpty()) { + return BaseResponse.builder() + .msgId(request.getMsgId()) + .messageCode(MessageCode.INVALID_ACTION.getCode()) + .messageDesc("Permissions map is required") + .build(); + } + + Map permissions = new HashMap<>(); + + for (Map.Entry entry : permissionsMap.entrySet()) { + try { + AdminSection section = AdminSection.valueOf(entry.getKey().toUpperCase()); + permissions.put(section, entry.getValue()); + } catch (IllegalArgumentException e) { + return BaseResponse.builder() + .msgId(request.getMsgId()) + .messageCode(MessageCode.INVALID_ACTION.getCode()) + .messageDesc("Invalid section: " + entry.getKey() + + ". Valid sections: " + Arrays.toString(AdminSection.values())) + .build(); + } + } + + permissionService.setAllPermissions(userId, permissions); + + AdminUser admin = adminUserService.findById(userId); + Map updatedPermissions = permissionService.getAllPermissions(userId); + + Map updatedPermissionsMap = new HashMap<>(); + updatedPermissions.forEach((section, value) -> + updatedPermissionsMap.put(section.name().toLowerCase(), value)); + + AdminUserResponse response = AdminUserResponse.builder() + .id(admin.getId()) + .fullName(admin.getFullName()) + .email(admin.getEmail()) + .isActive(admin.getIsActive()) + .isSuperAdmin(AdminPermission.isSuperAdmin(admin.getPermissions())) + .createdAt(admin.getCreatedAt().toString()) + .permissions(updatedPermissionsMap) + .build(); + + return BaseResponse.builder() + .msgId(request.getMsgId()) + .messageCode(MessageCode.SUCCESS.getCode()) + .messageDesc("Permissions updated successfully") + .messageBody(response) + .build(); + } catch (AdminUserNotFoundException e) { + return BaseResponse.builder() + .msgId(request.getMsgId()) + .messageCode(MessageCode.ADMIN_NOT_FOUND.getCode()) + .messageDesc(MessageCode.ADMIN_NOT_FOUND.getDescription()) + .build(); + } + } + private AdminUserResponse convertToResponse(AdminUser admin) { return AdminUserResponse.builder() .id(admin.getId()) diff --git a/src/main/java/ru/soune/nocopy/adminpanel/permission/PermissionChecker.java b/src/main/java/ru/soune/nocopy/adminpanel/permission/PermissionChecker.java index bb3ad9c..29d600d 100644 --- a/src/main/java/ru/soune/nocopy/adminpanel/permission/PermissionChecker.java +++ b/src/main/java/ru/soune/nocopy/adminpanel/permission/PermissionChecker.java @@ -2,12 +2,17 @@ package ru.soune.nocopy.adminpanel.permission; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Component; +import ru.soune.nocopy.adminpanel.entity.AdminSection; import ru.soune.nocopy.adminpanel.entity.AdminUser; +import ru.soune.nocopy.adminpanel.service.AdminSectionPermissionService; + @Component @RequiredArgsConstructor public class PermissionChecker { + private final AdminSectionPermissionService sectionPermissionService; + public boolean isSuperAdmin(AdminUser admin) { if (admin == null || !admin.getIsActive()) return false; return AdminPermission.isSuperAdmin(admin.getPermissions()); @@ -18,4 +23,19 @@ public class PermissionChecker { throw new SecurityException("Super admin permission required"); } } + + public boolean canReadSection(AdminUser admin, AdminSection section) { + if (admin == null || !admin.getIsActive()) return false; + if (isSuperAdmin(admin)) return true; + + return sectionPermissionService.canRead(admin.getId(), section); + } + + public boolean canWriteSection(AdminUser admin, AdminSection section) { + if (admin == null || !admin.getIsActive()) return false; + if (isSuperAdmin(admin)) return true; + + return sectionPermissionService.canWrite(admin.getId(), section); + } } + diff --git a/src/main/java/ru/soune/nocopy/adminpanel/permission/SectionPermissions.java b/src/main/java/ru/soune/nocopy/adminpanel/permission/SectionPermissions.java new file mode 100644 index 0000000..a42c186 --- /dev/null +++ b/src/main/java/ru/soune/nocopy/adminpanel/permission/SectionPermissions.java @@ -0,0 +1,15 @@ +package ru.soune.nocopy.adminpanel.permission; + +public class SectionPermissions { + public static final int NONE = 0b00; + public static final int READ = 0b01; + public static final int WRITE = 0b11; + + public static boolean canRead(int permission) { + return (permission & READ) == READ; + } + + public static boolean canWrite(int permission) { + return (permission & WRITE) == WRITE; + } +} diff --git a/src/main/java/ru/soune/nocopy/adminpanel/repository/AdminSectionPermissionRepository.java b/src/main/java/ru/soune/nocopy/adminpanel/repository/AdminSectionPermissionRepository.java new file mode 100644 index 0000000..0debab7 --- /dev/null +++ b/src/main/java/ru/soune/nocopy/adminpanel/repository/AdminSectionPermissionRepository.java @@ -0,0 +1,12 @@ +package ru.soune.nocopy.adminpanel.repository; + +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; +import ru.soune.nocopy.adminpanel.entity.AdminSectionPermission; + +import java.util.Optional; + +@Repository +public interface AdminSectionPermissionRepository extends JpaRepository { + Optional findByUserId(Long userId); +} diff --git a/src/main/java/ru/soune/nocopy/adminpanel/service/AdminSectionPermissionService.java b/src/main/java/ru/soune/nocopy/adminpanel/service/AdminSectionPermissionService.java new file mode 100644 index 0000000..331b092 --- /dev/null +++ b/src/main/java/ru/soune/nocopy/adminpanel/service/AdminSectionPermissionService.java @@ -0,0 +1,107 @@ +package ru.soune.nocopy.adminpanel.service; + +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import ru.soune.nocopy.adminpanel.entity.AdminSectionPermission; +import ru.soune.nocopy.adminpanel.entity.AdminSection; +import ru.soune.nocopy.adminpanel.permission.SectionPermissions; +import ru.soune.nocopy.adminpanel.repository.AdminSectionPermissionRepository; + +import java.util.HashMap; +import java.util.Map; + +@Service +@RequiredArgsConstructor +public class AdminSectionPermissionService { + + private final AdminSectionPermissionRepository repository; + + @Transactional + public AdminSectionPermission getOrCreate(Long userId) { + return repository.findByUserId(userId) + .orElseGet(() -> { + AdminSectionPermission permission = new AdminSectionPermission(); + permission.setUserId(userId); + return repository.save(permission); + }); + } + + public boolean canRead(Long userId, AdminSection section) { + AdminSectionPermission permission = getOrCreate(userId); + int value = getSectionValue(permission, section); + return SectionPermissions.canRead(value); + } + + public boolean canWrite(Long userId, AdminSection section) { + AdminSectionPermission permission = getOrCreate(userId); + int value = getSectionValue(permission, section); + return SectionPermissions.canWrite(value); + } + + @Transactional + public void setPermission(Long userId, AdminSection section, int permissionValue) { + AdminSectionPermission permission = getOrCreate(userId); + setSectionValue(permission, section, permissionValue); + repository.save(permission); + } + + @Transactional + public void setAllPermissions(Long userId, Map permissions) { + AdminSectionPermission permission = getOrCreate(userId); + permissions.forEach((section, value) -> setSectionValue(permission, section, value)); + repository.save(permission); + } + + public Map getAllPermissions(Long userId) { + AdminSectionPermission permission = getOrCreate(userId); + Map result = new HashMap<>(); + + for (AdminSection section : AdminSection.values()) { + result.put(section, getSectionValue(permission, section)); + } + + return result; + } + + private int getSectionValue(AdminSectionPermission permission, AdminSection section) { + return switch (section) { + case DASH -> permission.getDash(); + case USERS -> permission.getUsers(); + case STAFF -> permission.getStaff(); + case SUBSCRIPTIONS -> permission.getSubscriptions(); + case TARIFFS -> permission.getTariffs(); + case CONTENT_MODERATION -> permission.getContentModeration(); + case COMPLAINTS -> permission.getComplaints(); + case CLAIMS -> permission.getClaims(); + case MAILINGS -> permission.getMailings(); + case API -> permission.getApi(); + case MONEY -> permission.getMoney(); + case KYC -> permission.getKyc(); + case AGREEMENTS -> permission.getAgreements(); + }; + } + + private void setSectionValue(AdminSectionPermission permission, AdminSection section, int value) { + if (value == SectionPermissions.WRITE) { + value = SectionPermissions.WRITE; + } + + switch (section) { + case DASH -> permission.setDash(value); + case USERS -> permission.setUsers(value); + case STAFF -> permission.setStaff(value); + case SUBSCRIPTIONS -> permission.setSubscriptions(value); + case TARIFFS -> permission.setTariffs(value); + case CONTENT_MODERATION -> permission.setContentModeration(value); + case COMPLAINTS -> permission.setComplaints(value); + case CLAIMS -> permission.setClaims(value); + case MAILINGS -> permission.setMailings(value); + case API -> permission.setApi(value); + case MONEY -> permission.setMoney(value); + case KYC -> permission.setKyc(value); + case AGREEMENTS -> permission.setAgreements(value); + } + } +} + -- 2.54.0 From 8da1c6e5b8a23633791f442c1591bbb9ef47a153 Mon Sep 17 00:00:00 2001 From: backdev-1 Date: Thu, 7 May 2026 16:07:02 +0700 Subject: [PATCH 05/47] add section admin permission --- .../adminpanel/handler/AdminUserHandler.java | 49 ++++++++++++++++++- 1 file changed, 47 insertions(+), 2 deletions(-) diff --git a/src/main/java/ru/soune/nocopy/adminpanel/handler/AdminUserHandler.java b/src/main/java/ru/soune/nocopy/adminpanel/handler/AdminUserHandler.java index 8a87c6d..2e84c40 100644 --- a/src/main/java/ru/soune/nocopy/adminpanel/handler/AdminUserHandler.java +++ b/src/main/java/ru/soune/nocopy/adminpanel/handler/AdminUserHandler.java @@ -48,7 +48,8 @@ public class AdminUserHandler implements RequestHandler { case "set_super_admin" -> handleSetSuperAdmin(request, adminRequest); case "toggle_active" -> handleToggleActive(request, adminRequest); case "delete" -> handleDelete(request, adminRequest); - case "get_permissions" -> handleGetPermissions(request, adminRequest); + case "get_permissions_by_id" -> handleGetPermissionsById(request, adminRequest); + case "get_permissions_by_token" -> handleGetPermissionsByToken(request); case "update_permissions" -> handleUpdatePermissions(request, adminRequest); default -> handleInvalidAction(request, action); }; @@ -263,7 +264,7 @@ public class AdminUserHandler implements RequestHandler { .build(); } - private BaseResponse handleGetPermissions(BaseRequest request, AdminUserRequest adminRequest) { + private BaseResponse handleGetPermissionsById(BaseRequest request, AdminUserRequest adminRequest) { try { Long userId = adminRequest.getAdminId(); AdminUser admin = adminUserService.findById(userId); @@ -299,6 +300,50 @@ public class AdminUserHandler implements RequestHandler { } } + private BaseResponse handleGetPermissionsByToken(BaseRequest request) { + try { + String token = request.getToken(); + if (token == null || token.isEmpty()) { + return BaseResponse.builder() + .msgId(request.getMsgId()) + .messageCode(MessageCode.INVALID_CREDENTIALS.getCode()) + .messageDesc("Token is required") + .build(); + } + + String email = jwtUtil.extractEmail(token); + AdminUser admin = adminUserService.findByEmail(email); + Map sectionPermissions = permissionService.getAllPermissions(admin.getId()); + + Map permissionsMap = new HashMap<>(); + sectionPermissions.forEach((section, value) -> + permissionsMap.put(section.name().toLowerCase(), value)); + + AdminUserResponse response = AdminUserResponse.builder() + .id(admin.getId()) + .fullName(admin.getFullName()) + .email(admin.getEmail()) + .isActive(admin.getIsActive()) + .isSuperAdmin(AdminPermission.isSuperAdmin(admin.getPermissions())) + .createdAt(admin.getCreatedAt().toString()) + .permissions(permissionsMap) + .build(); + + return BaseResponse.builder() + .msgId(request.getMsgId()) + .messageCode(MessageCode.SUCCESS.getCode()) + .messageDesc(MessageCode.SUCCESS.getDescription()) + .messageBody(response) + .build(); + } catch (AdminUserNotFoundException e) { + return BaseResponse.builder() + .msgId(request.getMsgId()) + .messageCode(MessageCode.ADMIN_NOT_FOUND.getCode()) + .messageDesc(MessageCode.ADMIN_NOT_FOUND.getDescription()) + .build(); + } + } + private BaseResponse handleUpdatePermissions(BaseRequest request, AdminUserRequest adminRequest) { try { Long userId = adminRequest.getAdminId(); -- 2.54.0 From cbd73d64583349271212cbe2e52af301d2815017 Mon Sep 17 00:00:00 2001 From: backdev-1 Date: Fri, 8 May 2026 16:54:51 +0700 Subject: [PATCH 06/47] add section admin permission --- build.gradle | 6 ++++++ .../nocopy/adminpanel/AdminPanelApplication.java | 2 ++ .../adminpanel/client/DashBoardAppClient.java | 15 +++++++++++++++ .../adminpanel/controller/AdminController.java | 16 ++++++++++++++++ src/main/resources/application.yaml | 8 +++++++- 5 files changed, 46 insertions(+), 1 deletion(-) create mode 100644 src/main/java/ru/soune/nocopy/adminpanel/client/DashBoardAppClient.java diff --git a/build.gradle b/build.gradle index d1c6244..4411033 100644 --- a/build.gradle +++ b/build.gradle @@ -20,6 +20,11 @@ configurations { } } +dependencyManagement { + imports { + mavenBom "org.springframework.cloud:spring-cloud-dependencies:2023.0.0" + } +} repositories { mavenCentral() @@ -41,5 +46,6 @@ dependencies { testImplementation 'org.springframework.boot:spring-boot-starter-data-jpa-test' testImplementation 'org.springframework.boot:spring-boot-starter-webmvc-test' testRuntimeOnly 'org.junit.platform:junit-platform-launcher' + implementation 'org.springframework.cloud:spring-cloud-starter-openfeign:4.1.0' } diff --git a/src/main/java/ru/soune/nocopy/adminpanel/AdminPanelApplication.java b/src/main/java/ru/soune/nocopy/adminpanel/AdminPanelApplication.java index 0fc77f6..a998898 100644 --- a/src/main/java/ru/soune/nocopy/adminpanel/AdminPanelApplication.java +++ b/src/main/java/ru/soune/nocopy/adminpanel/AdminPanelApplication.java @@ -1,9 +1,11 @@ package ru.soune.nocopy.adminpanel; import org.springframework.boot.SpringApplication; +import org.springframework.cloud.openfeign.EnableFeignClients; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication +@EnableFeignClients public class AdminPanelApplication { public static void main(String[] args) { diff --git a/src/main/java/ru/soune/nocopy/adminpanel/client/DashBoardAppClient.java b/src/main/java/ru/soune/nocopy/adminpanel/client/DashBoardAppClient.java new file mode 100644 index 0000000..795e39c --- /dev/null +++ b/src/main/java/ru/soune/nocopy/adminpanel/client/DashBoardAppClient.java @@ -0,0 +1,15 @@ +package ru.soune.nocopy.adminpanel.client; + +import org.springframework.cloud.openfeign.FeignClient; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import ru.soune.nocopy.adminpanel.dto.BaseRequest; + +import java.util.Map; + +@FeignClient(name = "dashboard", url = "${nocopy-dashboard.url}") +public interface DashBoardAppClient { + + @PostMapping("/api/v1/data") + Map getUsersWithPagination(@RequestBody BaseRequest request); +} diff --git a/src/main/java/ru/soune/nocopy/adminpanel/controller/AdminController.java b/src/main/java/ru/soune/nocopy/adminpanel/controller/AdminController.java index d408846..9b079ed 100644 --- a/src/main/java/ru/soune/nocopy/adminpanel/controller/AdminController.java +++ b/src/main/java/ru/soune/nocopy/adminpanel/controller/AdminController.java @@ -7,6 +7,7 @@ import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; +import ru.soune.nocopy.adminpanel.client.DashBoardAppClient; import ru.soune.nocopy.adminpanel.dto.BaseRequest; import ru.soune.nocopy.adminpanel.dto.BaseResponse; import ru.soune.nocopy.adminpanel.handler.RequestHandler; @@ -22,6 +23,8 @@ public class AdminController { private final Map handlers; + private final DashBoardAppClient dashBoardAppClient; + @PostMapping public ResponseEntity handleRequest(@RequestBody BaseRequest request) { log.info("Received request: msg_id={}, version={}", request.getMsgId(), request.getVersion()); @@ -55,4 +58,17 @@ public class AdminController { ); } } + + @PostMapping("/get-users") + public ResponseEntity handleUsers(@RequestBody BaseRequest request) { + Map response = dashBoardAppClient.getUsersWithPagination(request); + + return ResponseEntity.ok( + BaseResponse.builder() + .msgId(request.getMsgId()) + .messageCode(MessageCode.SUCCESS.getCode()) + .messageDesc(MessageCode.SUCCESS.getDescription()) + .messageBody(response) + .build()); + } } diff --git a/src/main/resources/application.yaml b/src/main/resources/application.yaml index 3efd934..28764bf 100644 --- a/src/main/resources/application.yaml +++ b/src/main/resources/application.yaml @@ -1,4 +1,7 @@ spring: + cloud: + compatibility-verifier: + enabled: false datasource: url: jdbc:postgresql://${POSTGRES_HOST}:${POSTGRES_PORT}/${POSTGRES_DB} username: ${POSTGRES_USER} @@ -13,4 +16,7 @@ server: jwt: secret: Z29nb3Bvd2VycmFuZ2VydHVtYmF5YW1iZjMyNDIyMjh3aW5lcndpbmVy - expiration: 3600000 \ No newline at end of file + expiration: 3600000 + +nocopy-dashboard: + url: http://localhost:3001 \ No newline at end of file -- 2.54.0 From 67222ab6ba5d3f4319f18550fef81c1d09b13812 Mon Sep 17 00:00:00 2001 From: backdev-1 Date: Fri, 8 May 2026 17:19:19 +0700 Subject: [PATCH 07/47] add section admin permission --- src/main/resources/application.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/resources/application.yaml b/src/main/resources/application.yaml index 28764bf..498a17f 100644 --- a/src/main/resources/application.yaml +++ b/src/main/resources/application.yaml @@ -19,4 +19,4 @@ jwt: expiration: 3600000 nocopy-dashboard: - url: http://localhost:3001 \ No newline at end of file + url: http://app-backend-3001:8080 \ No newline at end of file -- 2.54.0 From 8dc2d69714a539e1ad0d94ac4ceb02845701a8e6 Mon Sep 17 00:00:00 2001 From: backdev-1 Date: Fri, 8 May 2026 17:22:35 +0700 Subject: [PATCH 08/47] add section admin permission --- src/main/resources/application.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/resources/application.yaml b/src/main/resources/application.yaml index 498a17f..e4e365d 100644 --- a/src/main/resources/application.yaml +++ b/src/main/resources/application.yaml @@ -19,4 +19,4 @@ jwt: expiration: 3600000 nocopy-dashboard: - url: http://app-backend-3001:8080 \ No newline at end of file + url: http://172.17.0.1:3001 \ No newline at end of file -- 2.54.0 From 01915e1a08b45c13f73d88d7951992952f3ca83b Mon Sep 17 00:00:00 2001 From: backdev-1 Date: Sat, 9 May 2026 11:30:20 +0700 Subject: [PATCH 09/47] add section admin permission --- .../adminpanel/entity/PermissionType.java | 14 +++++ .../adminpanel/handler/AdminUserHandler.java | 55 ++++++++++++++++++- .../AdminSectionPermissionService.java | 1 + 3 files changed, 68 insertions(+), 2 deletions(-) create mode 100644 src/main/java/ru/soune/nocopy/adminpanel/entity/PermissionType.java diff --git a/src/main/java/ru/soune/nocopy/adminpanel/entity/PermissionType.java b/src/main/java/ru/soune/nocopy/adminpanel/entity/PermissionType.java new file mode 100644 index 0000000..dd6b983 --- /dev/null +++ b/src/main/java/ru/soune/nocopy/adminpanel/entity/PermissionType.java @@ -0,0 +1,14 @@ +package ru.soune.nocopy.adminpanel.entity; + +import lombok.Getter; + +@Getter +public enum PermissionType { + READ(0b01), NONE(0b00), WRITE_AND_READ(0b11); + + private final Integer value; + + PermissionType(Integer value) { + this.value = value; + } +} diff --git a/src/main/java/ru/soune/nocopy/adminpanel/handler/AdminUserHandler.java b/src/main/java/ru/soune/nocopy/adminpanel/handler/AdminUserHandler.java index 2e84c40..7cfef37 100644 --- a/src/main/java/ru/soune/nocopy/adminpanel/handler/AdminUserHandler.java +++ b/src/main/java/ru/soune/nocopy/adminpanel/handler/AdminUserHandler.java @@ -7,6 +7,7 @@ import org.springframework.stereotype.Component; import ru.soune.nocopy.adminpanel.dto.*; import ru.soune.nocopy.adminpanel.entity.AdminSection; import ru.soune.nocopy.adminpanel.entity.AdminUser; +import ru.soune.nocopy.adminpanel.entity.PermissionType; import ru.soune.nocopy.adminpanel.exceptions.AdminUserNotFoundException; import ru.soune.nocopy.adminpanel.exceptions.EmailAlreadyExistsException; import ru.soune.nocopy.adminpanel.permission.AdminPermission; @@ -110,9 +111,41 @@ public class AdminUserHandler implements RequestHandler { adminRequest.getFullName(), adminRequest.getEmail(), adminRequest.getPassword(), - superAdmin - ); + superAdmin); + Map sectionPermissons = new HashMap<>(); + + if (superAdmin) { + sectionPermissons.put(AdminSection.DASH, PermissionType.WRITE_AND_READ.getValue()); + sectionPermissons.put(AdminSection.USERS, PermissionType.WRITE_AND_READ.getValue()); + sectionPermissons.put(AdminSection.STAFF, PermissionType.WRITE_AND_READ.getValue()); + sectionPermissons.put(AdminSection.SUBSCRIPTIONS, PermissionType.WRITE_AND_READ.getValue()); + sectionPermissons.put(AdminSection.TARIFFS, PermissionType.WRITE_AND_READ.getValue()); + sectionPermissons.put(AdminSection.CONTENT_MODERATION, PermissionType.WRITE_AND_READ.getValue()); + sectionPermissons.put(AdminSection.COMPLAINTS, PermissionType.WRITE_AND_READ.getValue()); + sectionPermissons.put(AdminSection.CLAIMS, PermissionType.WRITE_AND_READ.getValue()); + sectionPermissons.put(AdminSection.MAILINGS, PermissionType.WRITE_AND_READ.getValue()); + sectionPermissons.put(AdminSection.API, PermissionType.WRITE_AND_READ.getValue()); + sectionPermissons.put(AdminSection.MONEY, PermissionType.WRITE_AND_READ.getValue()); + sectionPermissons.put(AdminSection.KYC, PermissionType.WRITE_AND_READ.getValue()); + sectionPermissons.put(AdminSection.AGREEMENTS, PermissionType.WRITE_AND_READ.getValue()); + } else { + sectionPermissons.put(AdminSection.DASH, PermissionType.READ.getValue()); + sectionPermissons.put(AdminSection.USERS, PermissionType.READ.getValue()); + sectionPermissons.put(AdminSection.STAFF, PermissionType.READ.getValue()); + sectionPermissons.put(AdminSection.SUBSCRIPTIONS, PermissionType.READ.getValue()); + sectionPermissons.put(AdminSection.TARIFFS, PermissionType.READ.getValue()); + sectionPermissons.put(AdminSection.CONTENT_MODERATION, PermissionType.READ.getValue()); + sectionPermissons.put(AdminSection.COMPLAINTS, PermissionType.READ.getValue()); + sectionPermissons.put(AdminSection.CLAIMS, PermissionType.READ.getValue()); + sectionPermissons.put(AdminSection.MAILINGS, PermissionType.READ.getValue()); + sectionPermissons.put(AdminSection.API, PermissionType.READ.getValue()); + sectionPermissons.put(AdminSection.MONEY, PermissionType.READ.getValue()); + sectionPermissons.put(AdminSection.KYC, PermissionType.READ.getValue()); + sectionPermissons.put(AdminSection.AGREEMENTS, PermissionType.READ.getValue()); + } + permissionService.setAllPermissions(admin.getId(), sectionPermissons); + return BaseResponse.builder() .msgId(request.getMsgId()) .messageCode(MessageCode.SUCCESS.getCode()) @@ -193,6 +226,24 @@ public class AdminUserHandler implements RequestHandler { try { AdminUser admin = adminUserService.setSuperAdmin(adminRequest.getAdminId(), adminRequest.getIsSuperAdmin()); + Map sectionPermissons = new HashMap<>(); + + sectionPermissons.put(AdminSection.DASH, PermissionType.WRITE_AND_READ.getValue()); + sectionPermissons.put(AdminSection.USERS, PermissionType.WRITE_AND_READ.getValue()); + sectionPermissons.put(AdminSection.STAFF, PermissionType.WRITE_AND_READ.getValue()); + sectionPermissons.put(AdminSection.SUBSCRIPTIONS, PermissionType.WRITE_AND_READ.getValue()); + sectionPermissons.put(AdminSection.TARIFFS, PermissionType.WRITE_AND_READ.getValue()); + sectionPermissons.put(AdminSection.CONTENT_MODERATION, PermissionType.WRITE_AND_READ.getValue()); + sectionPermissons.put(AdminSection.COMPLAINTS, PermissionType.WRITE_AND_READ.getValue()); + sectionPermissons.put(AdminSection.CLAIMS, PermissionType.WRITE_AND_READ.getValue()); + sectionPermissons.put(AdminSection.MAILINGS, PermissionType.WRITE_AND_READ.getValue()); + sectionPermissons.put(AdminSection.API, PermissionType.WRITE_AND_READ.getValue()); + sectionPermissons.put(AdminSection.MONEY, PermissionType.WRITE_AND_READ.getValue()); + sectionPermissons.put(AdminSection.KYC, PermissionType.WRITE_AND_READ.getValue()); + sectionPermissons.put(AdminSection.AGREEMENTS, PermissionType.WRITE_AND_READ.getValue()); + + permissionService.setAllPermissions(admin.getId(), sectionPermissons); + return BaseResponse.builder() .msgId(request.getMsgId()) .messageCode(MessageCode.SUCCESS.getCode()) diff --git a/src/main/java/ru/soune/nocopy/adminpanel/service/AdminSectionPermissionService.java b/src/main/java/ru/soune/nocopy/adminpanel/service/AdminSectionPermissionService.java index 331b092..2d0ee24 100644 --- a/src/main/java/ru/soune/nocopy/adminpanel/service/AdminSectionPermissionService.java +++ b/src/main/java/ru/soune/nocopy/adminpanel/service/AdminSectionPermissionService.java @@ -50,6 +50,7 @@ public class AdminSectionPermissionService { public void setAllPermissions(Long userId, Map permissions) { AdminSectionPermission permission = getOrCreate(userId); permissions.forEach((section, value) -> setSectionValue(permission, section, value)); + repository.save(permission); } -- 2.54.0 From 3ccdac8ada7603b22a9d57a2f80d9e4062c48e8b Mon Sep 17 00:00:00 2001 From: backdev-1 Date: Sat, 9 May 2026 11:36:05 +0700 Subject: [PATCH 10/47] add section admin permission --- .../soune/nocopy/adminpanel/handler/AdminUserHandler.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/main/java/ru/soune/nocopy/adminpanel/handler/AdminUserHandler.java b/src/main/java/ru/soune/nocopy/adminpanel/handler/AdminUserHandler.java index 7cfef37..6489a68 100644 --- a/src/main/java/ru/soune/nocopy/adminpanel/handler/AdminUserHandler.java +++ b/src/main/java/ru/soune/nocopy/adminpanel/handler/AdminUserHandler.java @@ -459,6 +459,12 @@ public class AdminUserHandler implements RequestHandler { } private AdminUserResponse convertToResponse(AdminUser admin) { + Map sectionPermissions = permissionService.getAllPermissions(admin.getId()); + + Map permissionsMap = new HashMap<>(); + sectionPermissions.forEach((section, value) -> + permissionsMap.put(section.name().toLowerCase(), value)); + return AdminUserResponse.builder() .id(admin.getId()) .fullName(admin.getFullName()) @@ -466,6 +472,7 @@ public class AdminUserHandler implements RequestHandler { .isActive(admin.getIsActive()) .isSuperAdmin(AdminPermission.isSuperAdmin(admin.getPermissions())) .createdAt(admin.getCreatedAt().toString()) + .permissions(permissionsMap) .build(); } } -- 2.54.0 From c47c09bd8cd401f04373f6cc87b7ceb85af68243 Mon Sep 17 00:00:00 2001 From: backdev-1 Date: Sat, 9 May 2026 12:04:56 +0700 Subject: [PATCH 11/47] add section admin permission --- .env | 10 +++++----- docker-compose.yaml | 4 ++-- infrastrucure/deploy.groovy | 8 ++++---- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/.env b/.env index 07be7fb..b1dc353 100644 --- a/.env +++ b/.env @@ -1,8 +1,8 @@ -POSTGRES_DB=no_copy_ -POSTGRES_USER=ncp_db -POSTGRES_PASSWORD=ncpDbApp -POSTGRES_PORT=5432 -POSTGRES_HOST=postgres +POSTGRES_DB=admin_db +POSTGRES_USER=admin +POSTGRES_PASSWORD=adminDbApp +POSTGRES_PORT=5454 +POSTGRES_HOST=db REDIS_HOST=redis REDIS_PORT=6379 diff --git a/docker-compose.yaml b/docker-compose.yaml index 8160e9f..f53cde4 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -9,8 +9,8 @@ services: environment: SPRING_PROFILES_ACTIVE: prod POSTGRES_HOST: db - POSTGRES_PORT: 5432 - POSTGRES_DB: no_copy_ + POSTGRES_PORT: 5454 + POSTGRES_DB: admin_db POSTGRES_USER: ${POSTGRES_USER} POSTGRES_PASSWORD: ${POSTGRES_PASSWORD} networks: diff --git a/infrastrucure/deploy.groovy b/infrastrucure/deploy.groovy index 2584401..d0cef2b 100644 --- a/infrastrucure/deploy.groovy +++ b/infrastrucure/deploy.groovy @@ -116,10 +116,10 @@ pipeline { --network-alias admin-${params.PORT} \\ -p ${params.PORT}:${params.PORT} \\ -v uploads_data:/data/uploads:rw \\ - -e POSTGRES_DB=no_copy_ \\ - -e POSTGRES_USER=${DB_USER} \\ - -e POSTGRES_PASSWORD=${DB_PASSWORD} \\ - -e POSTGRES_PORT=5432 \\ + -e POSTGRES_DB=admin_db \\ + -e POSTGRES_USER=admin \\ + -e POSTGRES_PASSWORD=adminDbApp \\ + -e POSTGRES_PORT=5454 \\ -e POSTGRES_HOST=${params.DB_HOST} \\ -e SERVER_PORT=${params.PORT} \\ -e BUILD_TIME='${buildTime}' \\ -- 2.54.0 From 8f8ecc94b78d7e5fe0f60d4c5feee3b6c49722d5 Mon Sep 17 00:00:00 2001 From: backdev-1 Date: Sat, 9 May 2026 12:24:39 +0700 Subject: [PATCH 12/47] add section admin permission --- docker-compose.yaml | 3 ++- src/main/resources/application.yaml | 12 ++++++++---- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/docker-compose.yaml b/docker-compose.yaml index f53cde4..1a93418 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -5,12 +5,13 @@ services: build: . container_name: admin-backend ports: - - "8082:8080" + - "${SERVER_PORT:-8082}:${SERVER_PORT:-8082}" environment: SPRING_PROFILES_ACTIVE: prod POSTGRES_HOST: db POSTGRES_PORT: 5454 POSTGRES_DB: admin_db + SERVER_PORT: ${SERVER_PORT:-8082} POSTGRES_USER: ${POSTGRES_USER} POSTGRES_PASSWORD: ${POSTGRES_PASSWORD} networks: diff --git a/src/main/resources/application.yaml b/src/main/resources/application.yaml index e4e365d..0f00301 100644 --- a/src/main/resources/application.yaml +++ b/src/main/resources/application.yaml @@ -3,16 +3,20 @@ spring: compatibility-verifier: enabled: false datasource: - url: jdbc:postgresql://${POSTGRES_HOST}:${POSTGRES_PORT}/${POSTGRES_DB} - username: ${POSTGRES_USER} - password: ${POSTGRES_PASSWORD} + url: jdbc:postgresql://${POSTGRES_HOST:db}:${POSTGRES_PORT:5454}/${POSTGRES_DB:admin_db} + username: ${POSTGRES_USER:admin} + password: ${POSTGRES_PASSWORD:adminDbApp} jpa: hibernate: ddl-auto: update + properties: + hibernate: + dialect: org.hibernate.dialect.PostgreSQLDialect + format_sql: true server: - port: 8082 + port: ${SERVER_PORT:8082} jwt: secret: Z29nb3Bvd2VycmFuZ2VydHVtYmF5YW1iZjMyNDIyMjh3aW5lcndpbmVy -- 2.54.0 From be4073795f5a7c8e0486b4f8f5a577fe9abdd7b0 Mon Sep 17 00:00:00 2001 From: backdev-1 Date: Sat, 9 May 2026 12:35:54 +0700 Subject: [PATCH 13/47] add section admin permission --- docker-compose.yaml | 26 +++++++++++++++++++++++--- src/main/resources/application.yaml | 2 +- 2 files changed, 24 insertions(+), 4 deletions(-) diff --git a/docker-compose.yaml b/docker-compose.yaml index 1a93418..fa5b8b8 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -1,6 +1,21 @@ version: '3.9' services: + db: + image: postgres:17 + container_name: admin-db + environment: + POSTGRES_DB: admin_db + POSTGRES_USER: admin + POSTGRES_PASSWORD: adminDbApp + ports: + - "5454:5432" + volumes: + - postgres_data:/var/lib/postgresql/data + networks: + - app-network + restart: unless-stopped + admin: build: . container_name: admin-backend @@ -9,15 +24,20 @@ services: environment: SPRING_PROFILES_ACTIVE: prod POSTGRES_HOST: db - POSTGRES_PORT: 5454 + POSTGRES_PORT: 5432 POSTGRES_DB: admin_db + POSTGRES_USER: admin + POSTGRES_PASSWORD: adminDbApp SERVER_PORT: ${SERVER_PORT:-8082} - POSTGRES_USER: ${POSTGRES_USER} - POSTGRES_PASSWORD: ${POSTGRES_PASSWORD} + depends_on: + - db networks: - app-network restart: unless-stopped +volumes: + postgres_data: + networks: app-network: external: true \ No newline at end of file diff --git a/src/main/resources/application.yaml b/src/main/resources/application.yaml index 0f00301..2585e56 100644 --- a/src/main/resources/application.yaml +++ b/src/main/resources/application.yaml @@ -3,7 +3,7 @@ spring: compatibility-verifier: enabled: false datasource: - url: jdbc:postgresql://${POSTGRES_HOST:db}:${POSTGRES_PORT:5454}/${POSTGRES_DB:admin_db} + url: jdbc:postgresql://${POSTGRES_HOST:db}:${POSTGRES_PORT:5432}/${POSTGRES_DB:admin_db} username: ${POSTGRES_USER:admin} password: ${POSTGRES_PASSWORD:adminDbApp} -- 2.54.0 From 213ae881e6aba29121947c55183ba1e0e6612b00 Mon Sep 17 00:00:00 2001 From: backdev-1 Date: Sat, 9 May 2026 12:44:04 +0700 Subject: [PATCH 14/47] add section admin permission --- infrastrucure/deploy.groovy | 105 +++++++++++++++++++++--------------- 1 file changed, 61 insertions(+), 44 deletions(-) diff --git a/infrastrucure/deploy.groovy b/infrastrucure/deploy.groovy index d0cef2b..46850ae 100644 --- a/infrastrucure/deploy.groovy +++ b/infrastrucure/deploy.groovy @@ -23,9 +23,9 @@ pipeline { description: 'Имя сети (будет создана если не существует)' ) string( - name: 'DB_HOST', - defaultValue: 'db', - description: 'Хост базы данных' + name: 'DB_PORT', + defaultValue: '5454', + description: 'Порт для базы данных' ) } @@ -57,19 +57,14 @@ pipeline { ) ]) { sh """ - sshpass -p '${SSH_PASS}' ssh -o StrictHostKeyChecking=no ${SSH_USER}@${params.SERVER} " + sshpass -p '${SSH_PASS}' ssh -o StrictHostKeyChecking=no ${SSH_USER}@${params.SERVER} ' + mkdir -p /opt/deployments/admin-panel-${params.PORT} && rm -rf /opt/deployments/admin-panel-${params.PORT}/* - mkdir -p /opt/deployments/admin-panel-${params.PORT} - " + ' - sshpass -p '${SSH_PASS}' rsync -av --delete \\ - --exclude=.git \\ - --exclude=.gradle \\ - --exclude=build \\ - --exclude=**/build \\ - --exclude=.idea \\ - --exclude=out \\ - . ${SSH_USER}@${params.SERVER}:/opt/deployments/admin-panel-${params.PORT}/ + sshpass -p '${SSH_PASS}' scp -r -o StrictHostKeyChecking=no \ + . \ + ${SSH_USER}@${params.SERVER}:/opt/deployments/admin-panel-${params.PORT}/ """ } } @@ -85,9 +80,7 @@ pipeline { credentialsId: 'server-root-password', usernameVariable: 'SSH_USER', passwordVariable: 'SSH_PASS' - ), - string(credentialsId: 'DB_USER', variable: 'DB_USER'), - string(credentialsId: 'DB_PASSWORD', variable: 'DB_PASSWORD') + ) ]) { sh """ sshpass -p '${SSH_PASS}' ssh -o StrictHostKeyChecking=no ${SSH_USER}@${params.SERVER} " @@ -101,32 +94,56 @@ pipeline { echo 'Сеть ${params.NETWORK} уже существует' fi - echo '2. Останавливаем старый контейнер...' - docker stop admin-panel-${params.PORT} 2>/dev/null || echo 'Контейнер не найден' - docker rm admin-panel-${params.PORT} 2>/dev/null || echo 'Контейнер не найден' + echo '2. Останавливаем старые контейнеры...' + docker stop admin-panel-${params.PORT} 2>/dev/null || echo 'Контейнер приложения не найден' + docker rm admin-panel-${params.PORT} 2>/dev/null || echo 'Контейнер приложения не найден' + + docker stop admin-db-${params.PORT} 2>/dev/null || echo 'Контейнер БД не найден' + docker rm admin-db-${params.PORT} 2>/dev/null || echo 'Контейнер БД не найден' - echo '3. Собираем образ...' + echo '3. Запускаем базу данных...' + docker run -d \\ + --name admin-db-${params.PORT} \\ + --network ${params.NETWORK} \\ + --network-alias db \\ + -p ${params.DB_PORT}:5432 \\ + -v admin_db_data_${params.PORT}:/var/lib/postgresql/data \\ + -e POSTGRES_DB=admin_db \\ + -e POSTGRES_USER=admin \\ + -e POSTGRES_PASSWORD=adminDbApp \\ + --restart unless-stopped \\ + postgres:16 + + echo '4. Ждем готовности БД...' + sleep 5 + until docker exec admin-db-${params.PORT} pg_isready -U admin; do + echo 'Waiting for database...' + sleep 2 + done + echo 'База данных готова' + + echo '5. Собираем образ приложения...' docker build --no-cache -t admin-panel-${params.PORT}:latest . - echo '4. Запускаем контейнер...' + echo '6. Запускаем приложение...' docker run -d \\ - --name admin-panel-${params.PORT} \\ - --network ${params.NETWORK} \\ - --network-alias admin \\ - --network-alias admin-${params.PORT} \\ - -p ${params.PORT}:${params.PORT} \\ - -v uploads_data:/data/uploads:rw \\ - -e POSTGRES_DB=admin_db \\ - -e POSTGRES_USER=admin \\ - -e POSTGRES_PASSWORD=adminDbApp \\ - -e POSTGRES_PORT=5454 \\ - -e POSTGRES_HOST=${params.DB_HOST} \\ - -e SERVER_PORT=${params.PORT} \\ - -e BUILD_TIME='${buildTime}' \\ - --restart unless-stopped \\ - admin-panel-${params.PORT}:latest + --name admin-panel-${params.PORT} \\ + --network ${params.NETWORK} \\ + --network-alias admin \\ + --network-alias admin-${params.PORT} \\ + -p ${params.PORT}:${params.PORT} \\ + -v uploads_data:/data/uploads:rw \\ + -e POSTGRES_DB=admin_db \\ + -e POSTGRES_USER=admin \\ + -e POSTGRES_PASSWORD=adminDbApp \\ + -e POSTGRES_PORT=5432 \\ + -e POSTGRES_HOST=db \\ + -e SERVER_PORT=${params.PORT} \\ + -e BUILD_TIME='${buildTime}' \\ + --restart unless-stopped \\ + admin-panel-${params.PORT}:latest - echo '5. Проверка...' + echo '7. Проверка...' sleep 10 if curl -s -f http://localhost:${params.PORT}/actuator/health > /dev/null 2>&1; then @@ -134,7 +151,10 @@ pipeline { echo 'URL: http://${params.SERVER}:${params.PORT}' else echo 'Проверка health не удалась' - docker logs admin-panel-${params.PORT} --tail=20 + echo '=== Логи приложения: ===' + docker logs admin-panel-${params.PORT} --tail=30 + echo '=== Логи БД: ===' + docker logs admin-db-${params.PORT} --tail=10 fi " """ @@ -155,11 +175,8 @@ pipeline { ]) { sh """ sshpass -p '${SSH_PASS}' ssh -o StrictHostKeyChecking=no ${SSH_USER}@${params.SERVER} " - echo 'Проверяем подключение к сети ${params.NETWORK}' - docker network inspect ${params.NETWORK} --format='{{.Name}}: {{range .Containers}}{{.Name}} {{end}}' - - echo 'Проверяем алиас admin для контейнера admin-panel-${params.PORT}' - docker inspect admin-panel-${params.PORT} | grep -A 5 'Aliases' + echo '=== Контейнеры в сети ${params.NETWORK} ===' + docker network inspect ${params.NETWORK} --format='{{range .Containers}}{{.Name}} ({{.IPv4Address}}){{println}}{{end}}' " """ } -- 2.54.0 From d9989d3bfd2fe9885eaf805e074c802af25c4444 Mon Sep 17 00:00:00 2001 From: backdev-1 Date: Tue, 12 May 2026 12:24:39 +0700 Subject: [PATCH 15/47] add add change password update logic --- .../soune/nocopy/adminpanel/dto/AdminUserRequest.java | 6 ++++++ .../nocopy/adminpanel/exceptions/WrongPassword.java | 7 +++++++ .../nocopy/adminpanel/handler/AdminUserHandler.java | 11 +++++++++-- .../nocopy/adminpanel/service/AdminUserService.java | 11 ++++++++--- .../ru/soune/nocopy/adminpanel/util/MessageCode.java | 1 + 5 files changed, 31 insertions(+), 5 deletions(-) create mode 100644 src/main/java/ru/soune/nocopy/adminpanel/exceptions/WrongPassword.java diff --git a/src/main/java/ru/soune/nocopy/adminpanel/dto/AdminUserRequest.java b/src/main/java/ru/soune/nocopy/adminpanel/dto/AdminUserRequest.java index 698118a..bbca2a8 100644 --- a/src/main/java/ru/soune/nocopy/adminpanel/dto/AdminUserRequest.java +++ b/src/main/java/ru/soune/nocopy/adminpanel/dto/AdminUserRequest.java @@ -22,6 +22,12 @@ public class AdminUserRequest { @JsonProperty("password") private String password; + @JsonProperty("new_password") + private String newPassword; + + @JsonProperty("old_password") + private String oldPassword; + @JsonProperty("is_super_admin") private Boolean isSuperAdmin; diff --git a/src/main/java/ru/soune/nocopy/adminpanel/exceptions/WrongPassword.java b/src/main/java/ru/soune/nocopy/adminpanel/exceptions/WrongPassword.java new file mode 100644 index 0000000..f87bf33 --- /dev/null +++ b/src/main/java/ru/soune/nocopy/adminpanel/exceptions/WrongPassword.java @@ -0,0 +1,7 @@ +package ru.soune.nocopy.adminpanel.exceptions; + +public class WrongPassword extends RuntimeException { + public WrongPassword(String message) { + super(message); + } +} diff --git a/src/main/java/ru/soune/nocopy/adminpanel/handler/AdminUserHandler.java b/src/main/java/ru/soune/nocopy/adminpanel/handler/AdminUserHandler.java index 6489a68..fe744fa 100644 --- a/src/main/java/ru/soune/nocopy/adminpanel/handler/AdminUserHandler.java +++ b/src/main/java/ru/soune/nocopy/adminpanel/handler/AdminUserHandler.java @@ -10,6 +10,7 @@ import ru.soune.nocopy.adminpanel.entity.AdminUser; import ru.soune.nocopy.adminpanel.entity.PermissionType; import ru.soune.nocopy.adminpanel.exceptions.AdminUserNotFoundException; import ru.soune.nocopy.adminpanel.exceptions.EmailAlreadyExistsException; +import ru.soune.nocopy.adminpanel.exceptions.WrongPassword; import ru.soune.nocopy.adminpanel.permission.AdminPermission; import ru.soune.nocopy.adminpanel.service.AdminSectionPermissionService; import ru.soune.nocopy.adminpanel.service.AdminUserService; @@ -198,8 +199,8 @@ public class AdminUserHandler implements RequestHandler { adminRequest.getAdminId(), adminRequest.getFullName(), adminRequest.getEmail(), - adminRequest.getPassword() - ); + adminRequest.getOldPassword(), + adminRequest.getNewPassword()); return BaseResponse.builder() .msgId(request.getMsgId()) @@ -219,6 +220,12 @@ public class AdminUserHandler implements RequestHandler { .messageCode(MessageCode.EMAIL_ALREADY_EXISTS.getCode()) .messageDesc(MessageCode.EMAIL_ALREADY_EXISTS.getDescription()) .build(); + } catch (WrongPassword e) { + return BaseResponse.builder() + .msgId(request.getMsgId()) + .messageCode(MessageCode.WRONG_PASSWORD.getCode()) + .messageDesc(MessageCode.WRONG_PASSWORD.getDescription()) + .build(); } } diff --git a/src/main/java/ru/soune/nocopy/adminpanel/service/AdminUserService.java b/src/main/java/ru/soune/nocopy/adminpanel/service/AdminUserService.java index dbdcb6b..8330815 100644 --- a/src/main/java/ru/soune/nocopy/adminpanel/service/AdminUserService.java +++ b/src/main/java/ru/soune/nocopy/adminpanel/service/AdminUserService.java @@ -7,6 +7,7 @@ import org.springframework.transaction.annotation.Transactional; import ru.soune.nocopy.adminpanel.entity.AdminUser; import ru.soune.nocopy.adminpanel.exceptions.AdminUserNotFoundException; import ru.soune.nocopy.adminpanel.exceptions.EmailAlreadyExistsException; +import ru.soune.nocopy.adminpanel.exceptions.WrongPassword; import ru.soune.nocopy.adminpanel.permission.AdminPermission; import ru.soune.nocopy.adminpanel.repository.AdminUserRepository; @@ -52,7 +53,7 @@ public class AdminUserService { } @Transactional - public AdminUser update(Long id, String fullName, String email, String password) { + public AdminUser update(Long id, String fullName, String email, String oldPassword, String newPassword) { AdminUser admin = findById(id); if (fullName != null) admin.setFullName(fullName); @@ -64,8 +65,12 @@ public class AdminUserService { admin.setEmail(email); } - if (password != null && !password.isEmpty()) { - admin.setPassword(passwordEncoder.encode(password)); + if (newPassword != null && oldPassword != null) { + if (passwordEncoder.matches(oldPassword, admin.getPassword())) { + admin.setPassword(passwordEncoder.encode(newPassword)); + } else { + throw new WrongPassword("Old password not equal current"); + } } return adminUserRepository.save(admin); diff --git a/src/main/java/ru/soune/nocopy/adminpanel/util/MessageCode.java b/src/main/java/ru/soune/nocopy/adminpanel/util/MessageCode.java index b3e7ecf..05a0dc6 100644 --- a/src/main/java/ru/soune/nocopy/adminpanel/util/MessageCode.java +++ b/src/main/java/ru/soune/nocopy/adminpanel/util/MessageCode.java @@ -8,6 +8,7 @@ public enum MessageCode { INVALID_ACTION(2, "Invalid action"), ADMIN_NOT_FOUND(4, "Admin not found"), EMAIL_ALREADY_EXISTS(2, "Email already exists"), + WRONG_PASSWORD(2, "Wrong password"), INVALID_CREDENTIALS(2, "Invalid credentials"), PERMISSION_DENIED(2, "Permission denied"), ADMIN_INACTIVE(2, "Admin is inactive"); -- 2.54.0 From 69271594cd092942e37ad160f507992201b57cc5 Mon Sep 17 00:00:00 2001 From: backdev-1 Date: Thu, 14 May 2026 15:36:01 +0700 Subject: [PATCH 16/47] add add flag for active password --- .../java/ru/soune/nocopy/adminpanel/dto/AdminUserResponse.java | 3 +++ src/main/java/ru/soune/nocopy/adminpanel/entity/AdminUser.java | 3 +++ .../ru/soune/nocopy/adminpanel/handler/AdminUserHandler.java | 1 + .../ru/soune/nocopy/adminpanel/service/AdminUserService.java | 1 + 4 files changed, 8 insertions(+) diff --git a/src/main/java/ru/soune/nocopy/adminpanel/dto/AdminUserResponse.java b/src/main/java/ru/soune/nocopy/adminpanel/dto/AdminUserResponse.java index a155fa8..a0061d1 100644 --- a/src/main/java/ru/soune/nocopy/adminpanel/dto/AdminUserResponse.java +++ b/src/main/java/ru/soune/nocopy/adminpanel/dto/AdminUserResponse.java @@ -27,6 +27,9 @@ public class AdminUserResponse { @JsonProperty("created_at") private String createdAt; + @JsonProperty("active_password") + private Boolean activePassword; + private Map permissions; } diff --git a/src/main/java/ru/soune/nocopy/adminpanel/entity/AdminUser.java b/src/main/java/ru/soune/nocopy/adminpanel/entity/AdminUser.java index 0d99281..cde4803 100644 --- a/src/main/java/ru/soune/nocopy/adminpanel/entity/AdminUser.java +++ b/src/main/java/ru/soune/nocopy/adminpanel/entity/AdminUser.java @@ -53,6 +53,9 @@ public class AdminUser { @Column(name = "is_super_admin", nullable = false) private Boolean isSuperAdmin = false; + @Column(name = "active_password", nullable = false) + private Boolean isActivePassword = false; + @Column(name = "permissions", nullable = false) private Long permissions = AdminPermission.DEFAULT_PERMISSIONS; diff --git a/src/main/java/ru/soune/nocopy/adminpanel/handler/AdminUserHandler.java b/src/main/java/ru/soune/nocopy/adminpanel/handler/AdminUserHandler.java index fe744fa..2090d92 100644 --- a/src/main/java/ru/soune/nocopy/adminpanel/handler/AdminUserHandler.java +++ b/src/main/java/ru/soune/nocopy/adminpanel/handler/AdminUserHandler.java @@ -480,6 +480,7 @@ public class AdminUserHandler implements RequestHandler { .isSuperAdmin(AdminPermission.isSuperAdmin(admin.getPermissions())) .createdAt(admin.getCreatedAt().toString()) .permissions(permissionsMap) + .activePassword(admin.getIsActivePassword()) .build(); } } diff --git a/src/main/java/ru/soune/nocopy/adminpanel/service/AdminUserService.java b/src/main/java/ru/soune/nocopy/adminpanel/service/AdminUserService.java index 8330815..0bb0c90 100644 --- a/src/main/java/ru/soune/nocopy/adminpanel/service/AdminUserService.java +++ b/src/main/java/ru/soune/nocopy/adminpanel/service/AdminUserService.java @@ -33,6 +33,7 @@ public class AdminUserService { admin.setPassword(passwordEncoder.encode(password)); admin.setCreatedAt(LocalDateTime.now()); admin.setIsActive(true); + admin.setIsActivePassword(superAdmin); admin.setPermissions(superAdmin ? AdminPermission.SUPER_ADMIN_PERMISSIONS : AdminPermission.DEFAULT_PERMISSIONS); return adminUserRepository.save(admin); -- 2.54.0 From 8dc76a19776fab1acd0664ee1e91481c36cbd98c Mon Sep 17 00:00:00 2001 From: backdev-1 Date: Thu, 14 May 2026 15:48:43 +0700 Subject: [PATCH 17/47] add add flag for active password --- .../ru/soune/nocopy/adminpanel/service/AdminUserService.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/ru/soune/nocopy/adminpanel/service/AdminUserService.java b/src/main/java/ru/soune/nocopy/adminpanel/service/AdminUserService.java index 0bb0c90..6930f16 100644 --- a/src/main/java/ru/soune/nocopy/adminpanel/service/AdminUserService.java +++ b/src/main/java/ru/soune/nocopy/adminpanel/service/AdminUserService.java @@ -69,6 +69,7 @@ public class AdminUserService { if (newPassword != null && oldPassword != null) { if (passwordEncoder.matches(oldPassword, admin.getPassword())) { admin.setPassword(passwordEncoder.encode(newPassword)); + admin.setIsActivePassword(true); } else { throw new WrongPassword("Old password not equal current"); } -- 2.54.0 From 90cd1c4fa13304c27af6a6662ad4d535ed757f2f Mon Sep 17 00:00:00 2001 From: backdev-1 Date: Fri, 15 May 2026 12:08:52 +0700 Subject: [PATCH 18/47] add add flag for active password --- .../ru/soune/nocopy/adminpanel/controller/AdminController.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/ru/soune/nocopy/adminpanel/controller/AdminController.java b/src/main/java/ru/soune/nocopy/adminpanel/controller/AdminController.java index 9b079ed..6e5ce82 100644 --- a/src/main/java/ru/soune/nocopy/adminpanel/controller/AdminController.java +++ b/src/main/java/ru/soune/nocopy/adminpanel/controller/AdminController.java @@ -59,7 +59,7 @@ public class AdminController { } } - @PostMapping("/get-users") + @PostMapping("/info") public ResponseEntity handleUsers(@RequestBody BaseRequest request) { Map response = dashBoardAppClient.getUsersWithPagination(request); -- 2.54.0 From c8d2d519fcd45d678eb2ddd0762ec83eb6d01faf Mon Sep 17 00:00:00 2001 From: backdev-1 Date: Fri, 15 May 2026 16:55:48 +0700 Subject: [PATCH 19/47] add add flag for active password --- .../adminpanel/controller/AdminController.java | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/src/main/java/ru/soune/nocopy/adminpanel/controller/AdminController.java b/src/main/java/ru/soune/nocopy/adminpanel/controller/AdminController.java index 6e5ce82..1824006 100644 --- a/src/main/java/ru/soune/nocopy/adminpanel/controller/AdminController.java +++ b/src/main/java/ru/soune/nocopy/adminpanel/controller/AdminController.java @@ -60,7 +60,20 @@ public class AdminController { } @PostMapping("/info") - public ResponseEntity handleUsers(@RequestBody BaseRequest request) { + public ResponseEntity handleInfo(@RequestBody BaseRequest request) { + Map response = dashBoardAppClient.getUsersWithPagination(request); + + return ResponseEntity.ok( + BaseResponse.builder() + .msgId(request.getMsgId()) + .messageCode(MessageCode.SUCCESS.getCode()) + .messageDesc(MessageCode.SUCCESS.getDescription()) + .messageBody(response) + .build()); + } + + @PostMapping("/control") + public ResponseEntity handleControl(@RequestBody BaseRequest request) { Map response = dashBoardAppClient.getUsersWithPagination(request); return ResponseEntity.ok( -- 2.54.0 From db2a345efdd23aff6c150c887de8ed9f7125bda3 Mon Sep 17 00:00:00 2001 From: backdev-1 Date: Wed, 20 May 2026 12:09:58 +0700 Subject: [PATCH 20/47] add add flag for active password --- .../adminpanel/handler/AdminUserHandler.java | 20 +++++++------------ 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/src/main/java/ru/soune/nocopy/adminpanel/handler/AdminUserHandler.java b/src/main/java/ru/soune/nocopy/adminpanel/handler/AdminUserHandler.java index 2090d92..474e25b 100644 --- a/src/main/java/ru/soune/nocopy/adminpanel/handler/AdminUserHandler.java +++ b/src/main/java/ru/soune/nocopy/adminpanel/handler/AdminUserHandler.java @@ -113,6 +113,7 @@ public class AdminUserHandler implements RequestHandler { adminRequest.getEmail(), adminRequest.getPassword(), superAdmin); + Map permissions = adminRequest.getPermissions(); Map sectionPermissons = new HashMap<>(); if (superAdmin) { @@ -130,19 +131,12 @@ public class AdminUserHandler implements RequestHandler { sectionPermissons.put(AdminSection.KYC, PermissionType.WRITE_AND_READ.getValue()); sectionPermissons.put(AdminSection.AGREEMENTS, PermissionType.WRITE_AND_READ.getValue()); } else { - sectionPermissons.put(AdminSection.DASH, PermissionType.READ.getValue()); - sectionPermissons.put(AdminSection.USERS, PermissionType.READ.getValue()); - sectionPermissons.put(AdminSection.STAFF, PermissionType.READ.getValue()); - sectionPermissons.put(AdminSection.SUBSCRIPTIONS, PermissionType.READ.getValue()); - sectionPermissons.put(AdminSection.TARIFFS, PermissionType.READ.getValue()); - sectionPermissons.put(AdminSection.CONTENT_MODERATION, PermissionType.READ.getValue()); - sectionPermissons.put(AdminSection.COMPLAINTS, PermissionType.READ.getValue()); - sectionPermissons.put(AdminSection.CLAIMS, PermissionType.READ.getValue()); - sectionPermissons.put(AdminSection.MAILINGS, PermissionType.READ.getValue()); - sectionPermissons.put(AdminSection.API, PermissionType.READ.getValue()); - sectionPermissons.put(AdminSection.MONEY, PermissionType.READ.getValue()); - sectionPermissons.put(AdminSection.KYC, PermissionType.READ.getValue()); - sectionPermissons.put(AdminSection.AGREEMENTS, PermissionType.READ.getValue()); + for (Map.Entry entry: permissions.entrySet()) { + String name = entry.getKey(); + AdminSection adminSection = AdminSection.valueOf(name.toUpperCase()); + + sectionPermissons.put(adminSection, entry.getValue()); + } } permissionService.setAllPermissions(admin.getId(), sectionPermissons); -- 2.54.0 From ed52fe3c519c10844c1f82d8e1adbe0d70fd00bd Mon Sep 17 00:00:00 2001 From: backdev-1 Date: Wed, 20 May 2026 12:45:24 +0700 Subject: [PATCH 21/47] add add flag for active password --- .../ru/soune/nocopy/adminpanel/dto/AdminUserRequest.java | 3 +++ .../soune/nocopy/adminpanel/handler/AdminUserHandler.java | 6 +++++- .../soune/nocopy/adminpanel/service/AdminUserService.java | 4 ++-- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/src/main/java/ru/soune/nocopy/adminpanel/dto/AdminUserRequest.java b/src/main/java/ru/soune/nocopy/adminpanel/dto/AdminUserRequest.java index bbca2a8..dab02f1 100644 --- a/src/main/java/ru/soune/nocopy/adminpanel/dto/AdminUserRequest.java +++ b/src/main/java/ru/soune/nocopy/adminpanel/dto/AdminUserRequest.java @@ -34,6 +34,9 @@ public class AdminUserRequest { @JsonProperty("is_active") private Boolean isActive; + @JsonProperty("change_password") + private Boolean changePassword; + @JsonProperty("permissions") private Map permissions; diff --git a/src/main/java/ru/soune/nocopy/adminpanel/handler/AdminUserHandler.java b/src/main/java/ru/soune/nocopy/adminpanel/handler/AdminUserHandler.java index 474e25b..85acc93 100644 --- a/src/main/java/ru/soune/nocopy/adminpanel/handler/AdminUserHandler.java +++ b/src/main/java/ru/soune/nocopy/adminpanel/handler/AdminUserHandler.java @@ -108,11 +108,15 @@ public class AdminUserHandler implements RequestHandler { private BaseResponse handleCreate(BaseRequest request, AdminUserRequest adminRequest) { try { boolean superAdmin = adminRequest.getIsSuperAdmin() != null && adminRequest.getIsSuperAdmin(); + boolean changePassword = adminRequest.getChangePassword() != null ? adminRequest.getChangePassword(): + !superAdmin; + AdminUser admin = adminUserService.create( adminRequest.getFullName(), adminRequest.getEmail(), adminRequest.getPassword(), - superAdmin); + changePassword, superAdmin); + Map permissions = adminRequest.getPermissions(); Map sectionPermissons = new HashMap<>(); diff --git a/src/main/java/ru/soune/nocopy/adminpanel/service/AdminUserService.java b/src/main/java/ru/soune/nocopy/adminpanel/service/AdminUserService.java index 6930f16..c187fb3 100644 --- a/src/main/java/ru/soune/nocopy/adminpanel/service/AdminUserService.java +++ b/src/main/java/ru/soune/nocopy/adminpanel/service/AdminUserService.java @@ -22,7 +22,7 @@ public class AdminUserService { private final PasswordEncoder passwordEncoder; @Transactional - public AdminUser create(String fullName, String email, String password, boolean superAdmin) { + public AdminUser create(String fullName, String email, String password, boolean changePassword, boolean superAdmin) { if (adminUserRepository.existsByEmail(email)) { throw new EmailAlreadyExistsException("Email already exists: " + email); } @@ -33,7 +33,7 @@ public class AdminUserService { admin.setPassword(passwordEncoder.encode(password)); admin.setCreatedAt(LocalDateTime.now()); admin.setIsActive(true); - admin.setIsActivePassword(superAdmin); + admin.setIsActivePassword(changePassword); admin.setPermissions(superAdmin ? AdminPermission.SUPER_ADMIN_PERMISSIONS : AdminPermission.DEFAULT_PERMISSIONS); return adminUserRepository.save(admin); -- 2.54.0 From 245e524dd41b6db6bec4eb40551a8bd51cd3d5a9 Mon Sep 17 00:00:00 2001 From: backdev-1 Date: Wed, 20 May 2026 12:50:51 +0700 Subject: [PATCH 22/47] add add flag for active password --- .../ru/soune/nocopy/adminpanel/service/AdminUserService.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/ru/soune/nocopy/adminpanel/service/AdminUserService.java b/src/main/java/ru/soune/nocopy/adminpanel/service/AdminUserService.java index c187fb3..bb43bee 100644 --- a/src/main/java/ru/soune/nocopy/adminpanel/service/AdminUserService.java +++ b/src/main/java/ru/soune/nocopy/adminpanel/service/AdminUserService.java @@ -33,7 +33,7 @@ public class AdminUserService { admin.setPassword(passwordEncoder.encode(password)); admin.setCreatedAt(LocalDateTime.now()); admin.setIsActive(true); - admin.setIsActivePassword(changePassword); + admin.setIsActivePassword(!changePassword); admin.setPermissions(superAdmin ? AdminPermission.SUPER_ADMIN_PERMISSIONS : AdminPermission.DEFAULT_PERMISSIONS); return adminUserRepository.save(admin); -- 2.54.0 From 0d5d61b9bec1a8b0b47582a025bd03371e0ec68c Mon Sep 17 00:00:00 2001 From: backdev-1 Date: Wed, 20 May 2026 16:56:00 +0700 Subject: [PATCH 23/47] add entity and controller for templates admin create --- .../dto/AdminCreateTemplateRequest.java | 22 ++ .../dto/AdminCreateTemplateResponse.java | 18 ++ .../entity/AdminCreateTemplate.java | 24 +++ .../entity/AdminSectionPermission.java | 2 +- .../adminpanel/handler/AdminUserHandler.java | 2 +- .../handler/CreateAdminTemplateHandler.java | 194 ++++++++++++++++++ .../AdminCreateTemplateRepository.java | 11 + .../service/AdminCreateTemplateService.java | 60 ++++++ .../nocopy/adminpanel/util/MessageCode.java | 4 +- 9 files changed, 334 insertions(+), 3 deletions(-) create mode 100644 src/main/java/ru/soune/nocopy/adminpanel/dto/AdminCreateTemplateRequest.java create mode 100644 src/main/java/ru/soune/nocopy/adminpanel/dto/AdminCreateTemplateResponse.java create mode 100644 src/main/java/ru/soune/nocopy/adminpanel/entity/AdminCreateTemplate.java create mode 100644 src/main/java/ru/soune/nocopy/adminpanel/handler/CreateAdminTemplateHandler.java create mode 100644 src/main/java/ru/soune/nocopy/adminpanel/repository/AdminCreateTemplateRepository.java create mode 100644 src/main/java/ru/soune/nocopy/adminpanel/service/AdminCreateTemplateService.java diff --git a/src/main/java/ru/soune/nocopy/adminpanel/dto/AdminCreateTemplateRequest.java b/src/main/java/ru/soune/nocopy/adminpanel/dto/AdminCreateTemplateRequest.java new file mode 100644 index 0000000..141a2a7 --- /dev/null +++ b/src/main/java/ru/soune/nocopy/adminpanel/dto/AdminCreateTemplateRequest.java @@ -0,0 +1,22 @@ +package ru.soune.nocopy.adminpanel.dto; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Data; + +import java.util.Map; + +@Data +public class AdminCreateTemplateRequest { + + @JsonProperty("permissions") + private Map permissions; + + @JsonProperty("change_password") + private Boolean changePassword; + + @JsonProperty("action") + private String action; + + @JsonProperty("id") + private Long id; +} diff --git a/src/main/java/ru/soune/nocopy/adminpanel/dto/AdminCreateTemplateResponse.java b/src/main/java/ru/soune/nocopy/adminpanel/dto/AdminCreateTemplateResponse.java new file mode 100644 index 0000000..41a37a6 --- /dev/null +++ b/src/main/java/ru/soune/nocopy/adminpanel/dto/AdminCreateTemplateResponse.java @@ -0,0 +1,18 @@ +package ru.soune.nocopy.adminpanel.dto; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Builder; +import lombok.Data; + +@Data +@Builder +public class AdminCreateTemplateResponse { + @JsonProperty("id") + private Long id; + + @JsonProperty("permissions") + private String permissions; + + @JsonProperty("change_password") + private Boolean changePassword; +} diff --git a/src/main/java/ru/soune/nocopy/adminpanel/entity/AdminCreateTemplate.java b/src/main/java/ru/soune/nocopy/adminpanel/entity/AdminCreateTemplate.java new file mode 100644 index 0000000..8a405ab --- /dev/null +++ b/src/main/java/ru/soune/nocopy/adminpanel/entity/AdminCreateTemplate.java @@ -0,0 +1,24 @@ +package ru.soune.nocopy.adminpanel.entity; + +import jakarta.persistence.*; +import lombok.*; + +@Entity +@Table(name = "admin_create_template") +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class AdminCreateTemplate { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @Column(name = "permission", columnDefinition = "TEXT") + String permission; + + @Column(name = "change_password") + Boolean changePassword; +} diff --git a/src/main/java/ru/soune/nocopy/adminpanel/entity/AdminSectionPermission.java b/src/main/java/ru/soune/nocopy/adminpanel/entity/AdminSectionPermission.java index e1aeff9..0d661e3 100644 --- a/src/main/java/ru/soune/nocopy/adminpanel/entity/AdminSectionPermission.java +++ b/src/main/java/ru/soune/nocopy/adminpanel/entity/AdminSectionPermission.java @@ -66,7 +66,7 @@ public class AdminSectionPermission { @CreatedDate @Column(name = "created_at", updatable = false) - private LocalDateTime createdAt; + private LocalDateTime createdAt = LocalDateTime.now(); @LastModifiedDate @Column(name = "updated_at") diff --git a/src/main/java/ru/soune/nocopy/adminpanel/handler/AdminUserHandler.java b/src/main/java/ru/soune/nocopy/adminpanel/handler/AdminUserHandler.java index 85acc93..9b802c4 100644 --- a/src/main/java/ru/soune/nocopy/adminpanel/handler/AdminUserHandler.java +++ b/src/main/java/ru/soune/nocopy/adminpanel/handler/AdminUserHandler.java @@ -408,7 +408,7 @@ public class AdminUserHandler implements RequestHandler { if (permissionsMap == null || permissionsMap.isEmpty()) { return BaseResponse.builder() .msgId(request.getMsgId()) - .messageCode(MessageCode.INVALID_ACTION.getCode()) + .messageCode(MessageCode.PERMISSION_IS_EMPTY.getCode()) .messageDesc("Permissions map is required") .build(); } diff --git a/src/main/java/ru/soune/nocopy/adminpanel/handler/CreateAdminTemplateHandler.java b/src/main/java/ru/soune/nocopy/adminpanel/handler/CreateAdminTemplateHandler.java new file mode 100644 index 0000000..34b12c6 --- /dev/null +++ b/src/main/java/ru/soune/nocopy/adminpanel/handler/CreateAdminTemplateHandler.java @@ -0,0 +1,194 @@ +package ru.soune.nocopy.adminpanel.handler; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.ObjectNode; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; +import ru.soune.nocopy.adminpanel.dto.*; +import ru.soune.nocopy.adminpanel.entity.AdminCreateTemplate; +import ru.soune.nocopy.adminpanel.service.AdminCreateTemplateService; +import ru.soune.nocopy.adminpanel.util.MessageCode; + +import java.util.Arrays; +import java.util.List; +import java.util.Map; + +@Component +@RequiredArgsConstructor +@Slf4j +public class CreateAdminTemplateHandler implements RequestHandler { + + private final ObjectMapper objectMapper; + + private final AdminCreateTemplateService adminCreateTemplateService; + + @Override + public BaseResponse handle(BaseRequest request) { + AdminCreateTemplateRequest adminCreateTemplateRequest = objectMapper.convertValue(request.getMessageBody(), + AdminCreateTemplateRequest.class); + String action = adminCreateTemplateRequest.getAction(); + + return switch (action) { + case "create" -> handleCreate(request, adminCreateTemplateRequest); + case "update" -> handleUpdate(request, adminCreateTemplateRequest); + case "delete" -> handleDelete(request, adminCreateTemplateRequest); + case "get_all" -> handleGetAll(request); + case "get_by_id" -> handleGetById(request, adminCreateTemplateRequest); + default -> handleInvalidAction(request, action); + }; + } + + private BaseResponse handleDelete(BaseRequest request, AdminCreateTemplateRequest adminCreateTemplateRequest) { + Long adminCreateTemplateRequestId = adminCreateTemplateRequest.getId(); + + if (adminCreateTemplateRequestId == null || adminCreateTemplateService.existById(adminCreateTemplateRequestId)) { + return BaseResponse.builder() + .msgId(request.getMsgId()) + .messageCode(MessageCode.TEMPLATE_NOT_FOUND.getCode()) + .messageDesc(MessageCode.TEMPLATE_NOT_FOUND.getDescription()) + .messageBody(Map.of("id", adminCreateTemplateRequest.getId())) + .build(); + } + + adminCreateTemplateService.deleteTemplate(adminCreateTemplateRequestId); + + + return BaseResponse.builder() + .msgId(request.getMsgId()) + .messageCode(MessageCode.SUCCESS.getCode()) + .messageDesc(MessageCode.SUCCESS.getDescription()) + .messageBody(Map.of("id", adminCreateTemplateRequestId)) + .build(); + } + + private BaseResponse handleUpdate(BaseRequest request, AdminCreateTemplateRequest adminCreateTemplateRequest) { + Map permissionsMap = adminCreateTemplateRequest.getPermissions(); + + if (permissionsMap == null || permissionsMap.isEmpty()) { + return BaseResponse.builder() + .msgId(request.getMsgId()) + .messageCode(MessageCode.TEMPLATE_NOT_FOUND.getCode()) + .messageDesc(MessageCode.TEMPLATE_NOT_FOUND.getDescription()) + .messageBody(Map.of("id", adminCreateTemplateRequest.getId())) + .build(); + } + + ObjectNode node = objectMapper.createObjectNode(); + + for (Map.Entry entry: permissionsMap.entrySet()) { + node.put(entry.getKey(), entry.getValue()); + } + + Boolean changePassword = adminCreateTemplateRequest.getChangePassword(); + + AdminCreateTemplate adminTemplate = + adminCreateTemplateService.updateCreateTemplate(node.toString(), changePassword, + adminCreateTemplateRequest.getId()); + + if (adminTemplate == null) { + return BaseResponse.builder() + .msgId(request.getMsgId()) + .messageCode(MessageCode.TEMPLATE_NOT_FOUND.getCode()) + .messageDesc(MessageCode.TEMPLATE_NOT_FOUND.getDescription()) + .messageBody(Map.of("id", adminCreateTemplateRequest.getId())) + .build(); + } + + return BaseResponse.builder() + .msgId(request.getMsgId()) + .messageCode(MessageCode.SUCCESS.getCode()) + .messageDesc(MessageCode.SUCCESS.getDescription()) + .messageBody(convertToResponse(adminTemplate)) + .build(); + } + + private BaseResponse handleCreate(BaseRequest request, AdminCreateTemplateRequest adminCreateTemplateRequest) { + Map permissionsMap = adminCreateTemplateRequest.getPermissions(); + + if (permissionsMap == null || permissionsMap.isEmpty()) { + return BaseResponse.builder() + .msgId(request.getMsgId()) + .messageCode(MessageCode.PERMISSION_IS_EMPTY.getCode()) + .messageDesc("Permissions map is required") + .build(); + } + + ObjectNode node = objectMapper.createObjectNode(); + + for (Map.Entry entry: permissionsMap.entrySet()) { + node.put(entry.getKey(), entry.getValue()); + } + + Boolean changePassword = adminCreateTemplateRequest.getChangePassword(); + + AdminCreateTemplate adminTemplate = + adminCreateTemplateService.createAdminTemplate(node.toString(), changePassword); + + + return BaseResponse.builder() + .msgId(request.getMsgId()) + .messageCode(MessageCode.SUCCESS.getCode()) + .messageDesc(MessageCode.SUCCESS.getDescription()) + .messageBody(convertToResponse(adminTemplate)) + .build(); + } + + private BaseResponse handleGetAll(BaseRequest request) { + List templateResponses = adminCreateTemplateService.getAllTemplates() + .stream() + .map(this::convertToResponse) + .toList(); + + return BaseResponse.builder() + .msgId(request.getMsgId()) + .messageCode(MessageCode.SUCCESS.getCode()) + .messageDesc(MessageCode.SUCCESS.getDescription()) + .messageBody(templateResponses) + .build(); + } + + private BaseResponse handleGetById(BaseRequest request, AdminCreateTemplateRequest adminCreateTemplateRequest) { + Long id = adminCreateTemplateRequest.getId(); + + if (id == null || !adminCreateTemplateService.existById(id)) { + return BaseResponse.builder() + .msgId(request.getMsgId()) + .messageCode(MessageCode.TEMPLATE_NOT_FOUND.getCode()) + .messageDesc(MessageCode.TEMPLATE_NOT_FOUND.getDescription()) + .messageBody(Map.of("id", adminCreateTemplateRequest.getId())) + .build(); + } + + AdminCreateTemplate template = adminCreateTemplateService.getTemplateById(adminCreateTemplateRequest.getId()); + + return BaseResponse.builder() + .msgId(request.getMsgId()) + .messageCode(MessageCode.SUCCESS.getCode()) + .messageDesc(MessageCode.SUCCESS.getDescription()) + .messageBody(convertToResponse(template)) + .build(); + } + + private BaseResponse handleInvalidAction(BaseRequest request, String action) { + ActionResponse response = ActionResponse.builder() + .action(action) + .availableActions(Arrays.asList("create", "update", "delete")) + .build(); + + return BaseResponse.builder() + .msgId(request.getMsgId()) + .messageCode(MessageCode.INVALID_ACTION.getCode()) + .messageDesc(MessageCode.INVALID_ACTION.getDescription()) + .messageBody(response) + .build(); + } + + private AdminCreateTemplateResponse convertToResponse(AdminCreateTemplate adminTemplate) { + return AdminCreateTemplateResponse.builder() + .id(adminTemplate.getId()) + .changePassword(adminTemplate.getChangePassword()) + .permissions(adminTemplate.getPermission()) + .build(); + } +} diff --git a/src/main/java/ru/soune/nocopy/adminpanel/repository/AdminCreateTemplateRepository.java b/src/main/java/ru/soune/nocopy/adminpanel/repository/AdminCreateTemplateRepository.java new file mode 100644 index 0000000..91a5040 --- /dev/null +++ b/src/main/java/ru/soune/nocopy/adminpanel/repository/AdminCreateTemplateRepository.java @@ -0,0 +1,11 @@ +package ru.soune.nocopy.adminpanel.repository; + +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; +import ru.soune.nocopy.adminpanel.entity.AdminCreateTemplate; + +@Repository +public interface AdminCreateTemplateRepository extends JpaRepository { + + boolean existsById(Long id); +} diff --git a/src/main/java/ru/soune/nocopy/adminpanel/service/AdminCreateTemplateService.java b/src/main/java/ru/soune/nocopy/adminpanel/service/AdminCreateTemplateService.java new file mode 100644 index 0000000..2598335 --- /dev/null +++ b/src/main/java/ru/soune/nocopy/adminpanel/service/AdminCreateTemplateService.java @@ -0,0 +1,60 @@ +package ru.soune.nocopy.adminpanel.service; + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import ru.soune.nocopy.adminpanel.entity.AdminCreateTemplate; +import ru.soune.nocopy.adminpanel.repository.AdminCreateTemplateRepository; + +import java.util.List; + +@Service +@RequiredArgsConstructor +@Slf4j +public class AdminCreateTemplateService { + + private final AdminCreateTemplateRepository adminCreateTemplateRepository; + + public AdminCreateTemplate createAdminTemplate(String permissionsMap, Boolean changePassword) { + AdminCreateTemplate adminCreateTemplate = AdminCreateTemplate.builder() + .permission(permissionsMap) + .changePassword(changePassword) + .build(); + + return adminCreateTemplateRepository.save(adminCreateTemplate); + } + + public AdminCreateTemplate updateCreateTemplate(String permissionsMap, Boolean changePassword, Long id) { + AdminCreateTemplate adminCreateTemplate = adminCreateTemplateRepository.findById(id).orElse(null); + + if (adminCreateTemplate == null) { + return null; + } + + if (!permissionsMap.isEmpty()) { + adminCreateTemplate.setPermission(permissionsMap); + } + + if (changePassword != null) { + adminCreateTemplate.setChangePassword(changePassword); + } + + return adminCreateTemplateRepository.save(adminCreateTemplate); + } + + public void deleteTemplate(Long id) { + adminCreateTemplateRepository.deleteById(id); + } + + public boolean existById(Long id) { + return adminCreateTemplateRepository.existsById(id); + } + + public List getAllTemplates() { + return adminCreateTemplateRepository.findAll(); + } + + public AdminCreateTemplate getTemplateById(Long id) { + return adminCreateTemplateRepository.findById(id).orElse(null); + } +} diff --git a/src/main/java/ru/soune/nocopy/adminpanel/util/MessageCode.java b/src/main/java/ru/soune/nocopy/adminpanel/util/MessageCode.java index 05a0dc6..eee9f6b 100644 --- a/src/main/java/ru/soune/nocopy/adminpanel/util/MessageCode.java +++ b/src/main/java/ru/soune/nocopy/adminpanel/util/MessageCode.java @@ -7,11 +7,13 @@ public enum MessageCode { SUCCESS(0, "Success"), INVALID_ACTION(2, "Invalid action"), ADMIN_NOT_FOUND(4, "Admin not found"), + TEMPLATE_NOT_FOUND(4, "Template not found or id is null"), EMAIL_ALREADY_EXISTS(2, "Email already exists"), WRONG_PASSWORD(2, "Wrong password"), INVALID_CREDENTIALS(2, "Invalid credentials"), PERMISSION_DENIED(2, "Permission denied"), - ADMIN_INACTIVE(2, "Admin is inactive"); + ADMIN_INACTIVE(2, "Admin is inactive"), + PERMISSION_IS_EMPTY(2, "Permission is empty"); private final int code; private final String description; -- 2.54.0 From 4f80b990b64a3a86da382bbe4a0b9485a3f52626 Mon Sep 17 00:00:00 2001 From: backdev-1 Date: Wed, 20 May 2026 17:12:08 +0700 Subject: [PATCH 24/47] add entity and controller for templates admin create --- .../ru/soune/nocopy/adminpanel/config/AppConfig.java | 4 +++- .../adminpanel/dto/AdminCreateTemplateRequest.java | 3 +++ .../adminpanel/dto/AdminCreateTemplateResponse.java | 3 +++ .../nocopy/adminpanel/entity/AdminCreateTemplate.java | 3 +++ .../adminpanel/handler/CreateAdminTemplateHandler.java | 8 +++++--- .../adminpanel/service/AdminCreateTemplateService.java | 9 +++++++-- 6 files changed, 24 insertions(+), 6 deletions(-) diff --git a/src/main/java/ru/soune/nocopy/adminpanel/config/AppConfig.java b/src/main/java/ru/soune/nocopy/adminpanel/config/AppConfig.java index d369206..ae859c5 100644 --- a/src/main/java/ru/soune/nocopy/adminpanel/config/AppConfig.java +++ b/src/main/java/ru/soune/nocopy/adminpanel/config/AppConfig.java @@ -8,6 +8,7 @@ import org.springframework.web.cors.CorsConfiguration; import org.springframework.web.cors.UrlBasedCorsConfigurationSource; import org.springframework.web.filter.CorsFilter; import ru.soune.nocopy.adminpanel.handler.AdminUserHandler; +import ru.soune.nocopy.adminpanel.handler.CreateAdminTemplateHandler; import ru.soune.nocopy.adminpanel.handler.RequestHandler; import java.util.HashMap; @@ -34,9 +35,10 @@ public class AppConfig { } @Bean - public Map handlers(AdminUserHandler adminUserHandler) { + public Map handlers(AdminUserHandler adminUserHandler, CreateAdminTemplateHandler createAdminTemplateHandler) { Map map = new HashMap<>(); map.put(100, adminUserHandler); + map.put(200, createAdminTemplateHandler); return map; } diff --git a/src/main/java/ru/soune/nocopy/adminpanel/dto/AdminCreateTemplateRequest.java b/src/main/java/ru/soune/nocopy/adminpanel/dto/AdminCreateTemplateRequest.java index 141a2a7..d6cc955 100644 --- a/src/main/java/ru/soune/nocopy/adminpanel/dto/AdminCreateTemplateRequest.java +++ b/src/main/java/ru/soune/nocopy/adminpanel/dto/AdminCreateTemplateRequest.java @@ -19,4 +19,7 @@ public class AdminCreateTemplateRequest { @JsonProperty("id") private Long id; + + @JsonProperty("name") + private String name; } diff --git a/src/main/java/ru/soune/nocopy/adminpanel/dto/AdminCreateTemplateResponse.java b/src/main/java/ru/soune/nocopy/adminpanel/dto/AdminCreateTemplateResponse.java index 41a37a6..eae6e04 100644 --- a/src/main/java/ru/soune/nocopy/adminpanel/dto/AdminCreateTemplateResponse.java +++ b/src/main/java/ru/soune/nocopy/adminpanel/dto/AdminCreateTemplateResponse.java @@ -15,4 +15,7 @@ public class AdminCreateTemplateResponse { @JsonProperty("change_password") private Boolean changePassword; + + @JsonProperty("name") + private String name; } diff --git a/src/main/java/ru/soune/nocopy/adminpanel/entity/AdminCreateTemplate.java b/src/main/java/ru/soune/nocopy/adminpanel/entity/AdminCreateTemplate.java index 8a405ab..9cd5fe8 100644 --- a/src/main/java/ru/soune/nocopy/adminpanel/entity/AdminCreateTemplate.java +++ b/src/main/java/ru/soune/nocopy/adminpanel/entity/AdminCreateTemplate.java @@ -21,4 +21,7 @@ public class AdminCreateTemplate { @Column(name = "change_password") Boolean changePassword; + + @Column(name = "name") + String name; } diff --git a/src/main/java/ru/soune/nocopy/adminpanel/handler/CreateAdminTemplateHandler.java b/src/main/java/ru/soune/nocopy/adminpanel/handler/CreateAdminTemplateHandler.java index 34b12c6..0d3bf26 100644 --- a/src/main/java/ru/soune/nocopy/adminpanel/handler/CreateAdminTemplateHandler.java +++ b/src/main/java/ru/soune/nocopy/adminpanel/handler/CreateAdminTemplateHandler.java @@ -84,7 +84,7 @@ public class CreateAdminTemplateHandler implements RequestHandler { AdminCreateTemplate adminTemplate = adminCreateTemplateService.updateCreateTemplate(node.toString(), changePassword, - adminCreateTemplateRequest.getId()); + adminCreateTemplateRequest.getId(), adminCreateTemplateRequest.getName()); if (adminTemplate == null) { return BaseResponse.builder() @@ -123,7 +123,8 @@ public class CreateAdminTemplateHandler implements RequestHandler { Boolean changePassword = adminCreateTemplateRequest.getChangePassword(); AdminCreateTemplate adminTemplate = - adminCreateTemplateService.createAdminTemplate(node.toString(), changePassword); + adminCreateTemplateService.createAdminTemplate(node.toString(), changePassword, + adminCreateTemplateRequest.getName()); return BaseResponse.builder() @@ -173,7 +174,7 @@ public class CreateAdminTemplateHandler implements RequestHandler { private BaseResponse handleInvalidAction(BaseRequest request, String action) { ActionResponse response = ActionResponse.builder() .action(action) - .availableActions(Arrays.asList("create", "update", "delete")) + .availableActions(Arrays.asList("create", "update", "delete", "get_all", "get_by_id")) .build(); return BaseResponse.builder() @@ -189,6 +190,7 @@ public class CreateAdminTemplateHandler implements RequestHandler { .id(adminTemplate.getId()) .changePassword(adminTemplate.getChangePassword()) .permissions(adminTemplate.getPermission()) + .name(adminTemplate.getName()) .build(); } } diff --git a/src/main/java/ru/soune/nocopy/adminpanel/service/AdminCreateTemplateService.java b/src/main/java/ru/soune/nocopy/adminpanel/service/AdminCreateTemplateService.java index 2598335..c996aec 100644 --- a/src/main/java/ru/soune/nocopy/adminpanel/service/AdminCreateTemplateService.java +++ b/src/main/java/ru/soune/nocopy/adminpanel/service/AdminCreateTemplateService.java @@ -15,16 +15,17 @@ public class AdminCreateTemplateService { private final AdminCreateTemplateRepository adminCreateTemplateRepository; - public AdminCreateTemplate createAdminTemplate(String permissionsMap, Boolean changePassword) { + public AdminCreateTemplate createAdminTemplate(String permissionsMap, Boolean changePassword, String name) { AdminCreateTemplate adminCreateTemplate = AdminCreateTemplate.builder() .permission(permissionsMap) .changePassword(changePassword) + .name(name) .build(); return adminCreateTemplateRepository.save(adminCreateTemplate); } - public AdminCreateTemplate updateCreateTemplate(String permissionsMap, Boolean changePassword, Long id) { + public AdminCreateTemplate updateCreateTemplate(String permissionsMap, Boolean changePassword, Long id, String name) { AdminCreateTemplate adminCreateTemplate = adminCreateTemplateRepository.findById(id).orElse(null); if (adminCreateTemplate == null) { @@ -39,6 +40,10 @@ public class AdminCreateTemplateService { adminCreateTemplate.setChangePassword(changePassword); } + if (name != null) { + adminCreateTemplate.setName(name); + } + return adminCreateTemplateRepository.save(adminCreateTemplate); } -- 2.54.0 From ee30b90641b18fb69935819495593aad8a7e71e5 Mon Sep 17 00:00:00 2001 From: backdev-1 Date: Wed, 20 May 2026 17:20:35 +0700 Subject: [PATCH 25/47] add entity and controller for templates admin create --- .../adminpanel/dto/AdminCreateTemplateResponse.java | 4 +++- .../handler/CreateAdminTemplateHandler.java | 13 ++++++++++++- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/src/main/java/ru/soune/nocopy/adminpanel/dto/AdminCreateTemplateResponse.java b/src/main/java/ru/soune/nocopy/adminpanel/dto/AdminCreateTemplateResponse.java index eae6e04..1a1aaed 100644 --- a/src/main/java/ru/soune/nocopy/adminpanel/dto/AdminCreateTemplateResponse.java +++ b/src/main/java/ru/soune/nocopy/adminpanel/dto/AdminCreateTemplateResponse.java @@ -4,6 +4,8 @@ import com.fasterxml.jackson.annotation.JsonProperty; import lombok.Builder; import lombok.Data; +import java.util.Map; + @Data @Builder public class AdminCreateTemplateResponse { @@ -11,7 +13,7 @@ public class AdminCreateTemplateResponse { private Long id; @JsonProperty("permissions") - private String permissions; + private Map permissions; @JsonProperty("change_password") private Boolean changePassword; diff --git a/src/main/java/ru/soune/nocopy/adminpanel/handler/CreateAdminTemplateHandler.java b/src/main/java/ru/soune/nocopy/adminpanel/handler/CreateAdminTemplateHandler.java index 0d3bf26..25e3310 100644 --- a/src/main/java/ru/soune/nocopy/adminpanel/handler/CreateAdminTemplateHandler.java +++ b/src/main/java/ru/soune/nocopy/adminpanel/handler/CreateAdminTemplateHandler.java @@ -1,5 +1,6 @@ package ru.soune.nocopy.adminpanel.handler; +import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.node.ObjectNode; import lombok.RequiredArgsConstructor; @@ -186,10 +187,20 @@ public class CreateAdminTemplateHandler implements RequestHandler { } private AdminCreateTemplateResponse convertToResponse(AdminCreateTemplate adminTemplate) { + Map permissionsMap = null; + try { + permissionsMap = objectMapper.readValue( + adminTemplate.getPermission(), + new TypeReference>() {} + ); + } catch (Exception e) { + log.error("Failed to parse permissions", e); + } + return AdminCreateTemplateResponse.builder() .id(adminTemplate.getId()) .changePassword(adminTemplate.getChangePassword()) - .permissions(adminTemplate.getPermission()) + .permissions(permissionsMap) .name(adminTemplate.getName()) .build(); } -- 2.54.0 From a6a6c40b927f71e08fbe8d9689ec4f8f7f828f03 Mon Sep 17 00:00:00 2001 From: backdev-1 Date: Thu, 21 May 2026 16:21:15 +0700 Subject: [PATCH 26/47] add entity and controller for templates admin create --- .../nocopy/adminpanel/handler/CreateAdminTemplateHandler.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/ru/soune/nocopy/adminpanel/handler/CreateAdminTemplateHandler.java b/src/main/java/ru/soune/nocopy/adminpanel/handler/CreateAdminTemplateHandler.java index 25e3310..b24356a 100644 --- a/src/main/java/ru/soune/nocopy/adminpanel/handler/CreateAdminTemplateHandler.java +++ b/src/main/java/ru/soune/nocopy/adminpanel/handler/CreateAdminTemplateHandler.java @@ -43,7 +43,7 @@ public class CreateAdminTemplateHandler implements RequestHandler { private BaseResponse handleDelete(BaseRequest request, AdminCreateTemplateRequest adminCreateTemplateRequest) { Long adminCreateTemplateRequestId = adminCreateTemplateRequest.getId(); - if (adminCreateTemplateRequestId == null || adminCreateTemplateService.existById(adminCreateTemplateRequestId)) { + if (adminCreateTemplateRequestId == null || !adminCreateTemplateService.existById(adminCreateTemplateRequestId)) { return BaseResponse.builder() .msgId(request.getMsgId()) .messageCode(MessageCode.TEMPLATE_NOT_FOUND.getCode()) -- 2.54.0 From 4b281dccbdfd2b1133d0493c10eb0d68f7017c19 Mon Sep 17 00:00:00 2001 From: backdev-1 Date: Fri, 22 May 2026 13:39:13 +0700 Subject: [PATCH 27/47] add entity and controller for templates admin create --- .../adminpanel/handler/AdminUserHandler.java | 112 +++++++++++++++++- 1 file changed, 110 insertions(+), 2 deletions(-) diff --git a/src/main/java/ru/soune/nocopy/adminpanel/handler/AdminUserHandler.java b/src/main/java/ru/soune/nocopy/adminpanel/handler/AdminUserHandler.java index 9b802c4..68242c5 100644 --- a/src/main/java/ru/soune/nocopy/adminpanel/handler/AdminUserHandler.java +++ b/src/main/java/ru/soune/nocopy/adminpanel/handler/AdminUserHandler.java @@ -1,6 +1,7 @@ package ru.soune.nocopy.adminpanel.handler; import com.fasterxml.jackson.databind.ObjectMapper; +import jakarta.servlet.http.HttpServletRequest; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; @@ -36,15 +37,28 @@ public class AdminUserHandler implements RequestHandler { private final AdminSectionPermissionService permissionService; + private final HttpServletRequest httpServletRequest; + + private final AdminSectionPermissionService adminSectionPermissionService; + @Override public BaseResponse handle(BaseRequest request) throws Exception { AdminUserRequest adminRequest = objectMapper.convertValue(request.getMessageBody(), AdminUserRequest.class); String action = adminRequest.getAction(); + Long currentUserId = (Long) httpServletRequest.getAttribute("userId"); + + if (currentUserId == null) { + return BaseResponse.builder() + .msgId(request.getMsgId()) + .messageCode(MessageCode.INVALID_CREDENTIALS.getCode()) + .messageDesc(MessageCode.INVALID_CREDENTIALS.getDescription()) + .build(); + } return switch (action) { case "login" -> handleLogin(request, adminRequest); case "create" -> handleCreate(request, adminRequest); - case "get_all" -> handleGetAll(request); + case "get_all" -> handleGetAll(request, adminRequest); case "get_by_id" -> handleGetById(request, adminRequest); case "update" -> handleUpdate(request, adminRequest); case "set_super_admin" -> handleSetSuperAdmin(request, adminRequest); @@ -107,6 +121,17 @@ public class AdminUserHandler implements RequestHandler { private BaseResponse handleCreate(BaseRequest request, AdminUserRequest adminRequest) { try { + Long currentUserId = (Long) httpServletRequest.getAttribute("userId"); + + if (!adminSectionPermissionService.canWrite(currentUserId, + AdminSection.USERS)) { + return BaseResponse.builder() + .msgId(request.getMsgId()) + .messageCode(MessageCode.PERMISSION_DENIED.getCode()) + .messageDesc("You can't create profile") + .build(); + } + boolean superAdmin = adminRequest.getIsSuperAdmin() != null && adminRequest.getIsSuperAdmin(); boolean changePassword = adminRequest.getChangePassword() != null ? adminRequest.getChangePassword(): !superAdmin; @@ -160,7 +185,18 @@ public class AdminUserHandler implements RequestHandler { } } - private BaseResponse handleGetAll(BaseRequest request) { + private BaseResponse handleGetAll(BaseRequest request, AdminUserRequest adminRequest) { + Long currentUserId = (Long) httpServletRequest.getAttribute("userId"); + + if (!adminSectionPermissionService.canRead(currentUserId, + AdminSection.USERS)) { + return BaseResponse.builder() + .msgId(request.getMsgId()) + .messageCode(MessageCode.PERMISSION_DENIED.getCode()) + .messageDesc("You can't update profile") + .build(); + } + List admins = adminUserService.findAll().stream() .map(this::convertToResponse) .collect(Collectors.toList()); @@ -176,6 +212,19 @@ public class AdminUserHandler implements RequestHandler { private BaseResponse handleGetById(BaseRequest request, AdminUserRequest adminRequest) { try { AdminUser admin = adminUserService.findById(adminRequest.getAdminId()); + Long currentUserId = (Long) httpServletRequest.getAttribute("userId"); + + if (!currentUserId.equals(adminRequest.getAdminId())) { + if (!adminSectionPermissionService.canRead(currentUserId, + AdminSection.USERS)) { + return BaseResponse.builder() + .msgId(request.getMsgId()) + .messageCode(MessageCode.PERMISSION_DENIED.getCode()) + .messageDesc("You can't update profile") + .build(); + } + } + return BaseResponse.builder() .msgId(request.getMsgId()) .messageCode(MessageCode.SUCCESS.getCode()) @@ -193,6 +242,19 @@ public class AdminUserHandler implements RequestHandler { private BaseResponse handleUpdate(BaseRequest request, AdminUserRequest adminRequest) { try { + Long currentUserId = (Long) httpServletRequest.getAttribute("userId"); + + if (!currentUserId.equals(adminRequest.getAdminId())) { + if (!adminSectionPermissionService.canWrite(currentUserId, + AdminSection.USERS)) { + return BaseResponse.builder() + .msgId(request.getMsgId()) + .messageCode(MessageCode.PERMISSION_DENIED.getCode()) + .messageDesc("You can't update profile") + .build(); + } + } + AdminUser admin = adminUserService.update( adminRequest.getAdminId(), adminRequest.getFullName(), @@ -229,6 +291,17 @@ public class AdminUserHandler implements RequestHandler { private BaseResponse handleSetSuperAdmin(BaseRequest request, AdminUserRequest adminRequest) { try { + Long currentUserId = (Long) httpServletRequest.getAttribute("userId"); + + if (!adminSectionPermissionService.canWrite(currentUserId, + AdminSection.USERS)) { + return BaseResponse.builder() + .msgId(request.getMsgId()) + .messageCode(MessageCode.PERMISSION_DENIED.getCode()) + .messageDesc("You can't create profile") + .build(); + } + AdminUser admin = adminUserService.setSuperAdmin(adminRequest.getAdminId(), adminRequest.getIsSuperAdmin()); Map sectionPermissons = new HashMap<>(); @@ -266,6 +339,19 @@ public class AdminUserHandler implements RequestHandler { private BaseResponse handleToggleActive(BaseRequest request, AdminUserRequest adminRequest) { try { + Long currentUserId = (Long) httpServletRequest.getAttribute("userId"); + + if (!currentUserId.equals(adminRequest.getAdminId())) { + if (!adminSectionPermissionService.canWrite(currentUserId, + AdminSection.USERS)) { + return BaseResponse.builder() + .msgId(request.getMsgId()) + .messageCode(MessageCode.PERMISSION_DENIED.getCode()) + .messageDesc("You can't update profile") + .build(); + } + } + adminUserService.toggleActive(adminRequest.getAdminId(), adminRequest.getIsActive()); AdminUser admin = adminUserService.findById(adminRequest.getAdminId()); @@ -286,6 +372,17 @@ public class AdminUserHandler implements RequestHandler { private BaseResponse handleDelete(BaseRequest request, AdminUserRequest adminRequest) { try { + Long currentUserId = (Long) httpServletRequest.getAttribute("userId"); + + if (!adminSectionPermissionService.canWrite(currentUserId, + AdminSection.USERS)) { + return BaseResponse.builder() + .msgId(request.getMsgId()) + .messageCode(MessageCode.PERMISSION_DENIED.getCode()) + .messageDesc("You can't create profile") + .build(); + } + adminUserService.delete(adminRequest.getAdminId()); return BaseResponse.builder() @@ -402,6 +499,17 @@ public class AdminUserHandler implements RequestHandler { private BaseResponse handleUpdatePermissions(BaseRequest request, AdminUserRequest adminRequest) { try { + Long currentUserId = (Long) httpServletRequest.getAttribute("userId"); + + if (!adminSectionPermissionService.canWrite(currentUserId, + AdminSection.USERS)) { + return BaseResponse.builder() + .msgId(request.getMsgId()) + .messageCode(MessageCode.PERMISSION_DENIED.getCode()) + .messageDesc("You can't create profile") + .build(); + } + Long userId = adminRequest.getAdminId(); Map permissionsMap = adminRequest.getPermissions(); -- 2.54.0 From 8a986ea2a0cc5922a97cf8a8e8f940bd3b2802fc Mon Sep 17 00:00:00 2001 From: backdev-1 Date: Fri, 22 May 2026 13:49:04 +0700 Subject: [PATCH 28/47] add entity and controller for templates admin create --- .../nocopy/adminpanel/handler/AdminUserHandler.java | 9 --------- 1 file changed, 9 deletions(-) diff --git a/src/main/java/ru/soune/nocopy/adminpanel/handler/AdminUserHandler.java b/src/main/java/ru/soune/nocopy/adminpanel/handler/AdminUserHandler.java index 68242c5..7ab2268 100644 --- a/src/main/java/ru/soune/nocopy/adminpanel/handler/AdminUserHandler.java +++ b/src/main/java/ru/soune/nocopy/adminpanel/handler/AdminUserHandler.java @@ -45,15 +45,6 @@ public class AdminUserHandler implements RequestHandler { public BaseResponse handle(BaseRequest request) throws Exception { AdminUserRequest adminRequest = objectMapper.convertValue(request.getMessageBody(), AdminUserRequest.class); String action = adminRequest.getAction(); - Long currentUserId = (Long) httpServletRequest.getAttribute("userId"); - - if (currentUserId == null) { - return BaseResponse.builder() - .msgId(request.getMsgId()) - .messageCode(MessageCode.INVALID_CREDENTIALS.getCode()) - .messageDesc(MessageCode.INVALID_CREDENTIALS.getDescription()) - .build(); - } return switch (action) { case "login" -> handleLogin(request, adminRequest); -- 2.54.0 From bfeea41ee19743f2ff65a368d65c737083ead27a Mon Sep 17 00:00:00 2001 From: backdev-1 Date: Fri, 22 May 2026 13:59:55 +0700 Subject: [PATCH 29/47] add entity and controller for templates admin create --- .../adminpanel/handler/AdminUserHandler.java | 40 +++++++++++++++---- 1 file changed, 33 insertions(+), 7 deletions(-) diff --git a/src/main/java/ru/soune/nocopy/adminpanel/handler/AdminUserHandler.java b/src/main/java/ru/soune/nocopy/adminpanel/handler/AdminUserHandler.java index 7ab2268..5f0f639 100644 --- a/src/main/java/ru/soune/nocopy/adminpanel/handler/AdminUserHandler.java +++ b/src/main/java/ru/soune/nocopy/adminpanel/handler/AdminUserHandler.java @@ -56,7 +56,7 @@ public class AdminUserHandler implements RequestHandler { case "toggle_active" -> handleToggleActive(request, adminRequest); case "delete" -> handleDelete(request, adminRequest); case "get_permissions_by_id" -> handleGetPermissionsById(request, adminRequest); - case "get_permissions_by_token" -> handleGetPermissionsByToken(request); + case "get_permissions_by_token" -> handleGetPermissionsByToken(request, adminRequest); case "update_permissions" -> handleUpdatePermissions(request, adminRequest); default -> handleInvalidAction(request, action); }; @@ -184,7 +184,7 @@ public class AdminUserHandler implements RequestHandler { return BaseResponse.builder() .msgId(request.getMsgId()) .messageCode(MessageCode.PERMISSION_DENIED.getCode()) - .messageDesc("You can't update profile") + .messageDesc("You can't reads") .build(); } @@ -211,7 +211,7 @@ public class AdminUserHandler implements RequestHandler { return BaseResponse.builder() .msgId(request.getMsgId()) .messageCode(MessageCode.PERMISSION_DENIED.getCode()) - .messageDesc("You can't update profile") + .messageDesc("You can't read") .build(); } } @@ -289,7 +289,7 @@ public class AdminUserHandler implements RequestHandler { return BaseResponse.builder() .msgId(request.getMsgId()) .messageCode(MessageCode.PERMISSION_DENIED.getCode()) - .messageDesc("You can't create profile") + .messageDesc("You can't update profile") .build(); } @@ -370,7 +370,7 @@ public class AdminUserHandler implements RequestHandler { return BaseResponse.builder() .msgId(request.getMsgId()) .messageCode(MessageCode.PERMISSION_DENIED.getCode()) - .messageDesc("You can't create profile") + .messageDesc("You can't delete profile") .build(); } @@ -410,6 +410,19 @@ public class AdminUserHandler implements RequestHandler { private BaseResponse handleGetPermissionsById(BaseRequest request, AdminUserRequest adminRequest) { try { + Long currentUserId = (Long) httpServletRequest.getAttribute("userId"); + + if (!currentUserId.equals(adminRequest.getAdminId())) { + if (!adminSectionPermissionService.canRead(currentUserId, + AdminSection.USERS)) { + return BaseResponse.builder() + .msgId(request.getMsgId()) + .messageCode(MessageCode.PERMISSION_DENIED.getCode()) + .messageDesc("You can't update profile") + .build(); + } + } + Long userId = adminRequest.getAdminId(); AdminUser admin = adminUserService.findById(userId); @@ -444,8 +457,21 @@ public class AdminUserHandler implements RequestHandler { } } - private BaseResponse handleGetPermissionsByToken(BaseRequest request) { + private BaseResponse handleGetPermissionsByToken(BaseRequest request, AdminUserRequest adminRequest) { try { + Long currentUserId = (Long) httpServletRequest.getAttribute("userId"); + + if (!currentUserId.equals(adminRequest.getAdminId())) { + if (!adminSectionPermissionService.canRead(currentUserId, + AdminSection.USERS)) { + return BaseResponse.builder() + .msgId(request.getMsgId()) + .messageCode(MessageCode.PERMISSION_DENIED.getCode()) + .messageDesc("You can't update profile") + .build(); + } + } + String token = request.getToken(); if (token == null || token.isEmpty()) { return BaseResponse.builder() @@ -497,7 +523,7 @@ public class AdminUserHandler implements RequestHandler { return BaseResponse.builder() .msgId(request.getMsgId()) .messageCode(MessageCode.PERMISSION_DENIED.getCode()) - .messageDesc("You can't create profile") + .messageDesc("You can't update profile") .build(); } -- 2.54.0 From b7dd9ab95ab3653acd3f78faeaa82ad0f4fafa74 Mon Sep 17 00:00:00 2001 From: backdev-1 Date: Fri, 22 May 2026 14:15:26 +0700 Subject: [PATCH 30/47] add entity and controller for templates admin create --- .../controller/AdminController.java | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/src/main/java/ru/soune/nocopy/adminpanel/controller/AdminController.java b/src/main/java/ru/soune/nocopy/adminpanel/controller/AdminController.java index 1824006..e98789d 100644 --- a/src/main/java/ru/soune/nocopy/adminpanel/controller/AdminController.java +++ b/src/main/java/ru/soune/nocopy/adminpanel/controller/AdminController.java @@ -1,5 +1,6 @@ package ru.soune.nocopy.adminpanel.controller; +import jakarta.servlet.http.HttpServletRequest; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.http.ResponseEntity; @@ -10,7 +11,9 @@ import org.springframework.web.bind.annotation.RestController; import ru.soune.nocopy.adminpanel.client.DashBoardAppClient; import ru.soune.nocopy.adminpanel.dto.BaseRequest; import ru.soune.nocopy.adminpanel.dto.BaseResponse; +import ru.soune.nocopy.adminpanel.entity.AdminSection; import ru.soune.nocopy.adminpanel.handler.RequestHandler; +import ru.soune.nocopy.adminpanel.service.AdminSectionPermissionService; import ru.soune.nocopy.adminpanel.util.MessageCode; import java.util.Map; @@ -25,6 +28,10 @@ public class AdminController { private final DashBoardAppClient dashBoardAppClient; + private final AdminSectionPermissionService adminSectionPermissionService; + + private final HttpServletRequest httpServletRequest; + @PostMapping public ResponseEntity handleRequest(@RequestBody BaseRequest request) { log.info("Received request: msg_id={}, version={}", request.getMsgId(), request.getVersion()); @@ -61,6 +68,17 @@ public class AdminController { @PostMapping("/info") public ResponseEntity handleInfo(@RequestBody BaseRequest request) { + Long currentUserId = (Long) httpServletRequest.getAttribute("userId"); + + if (!adminSectionPermissionService.canRead(currentUserId, + AdminSection.USERS)) { + return ResponseEntity.ok(BaseResponse.builder() + .msgId(request.getMsgId()) + .messageCode(MessageCode.PERMISSION_DENIED.getCode()) + .messageDesc("You can't reads") + .build()); + } + Map response = dashBoardAppClient.getUsersWithPagination(request); return ResponseEntity.ok( @@ -74,6 +92,17 @@ public class AdminController { @PostMapping("/control") public ResponseEntity handleControl(@RequestBody BaseRequest request) { + Long currentUserId = (Long) httpServletRequest.getAttribute("userId"); + + if (!adminSectionPermissionService.canWrite(currentUserId, + AdminSection.USERS)) { + return ResponseEntity.ok(BaseResponse.builder() + .msgId(request.getMsgId()) + .messageCode(MessageCode.PERMISSION_DENIED.getCode()) + .messageDesc("You can't control") + .build()); + } + Map response = dashBoardAppClient.getUsersWithPagination(request); return ResponseEntity.ok( -- 2.54.0 From 95825dc7fcbef3c135f7e87912d1e682a384bc9a Mon Sep 17 00:00:00 2001 From: backdev-1 Date: Mon, 25 May 2026 13:46:14 +0700 Subject: [PATCH 31/47] add internal feign key --- .../adminpanel/client/DashBoardAppClient.java | 3 +++ .../nocopy/adminpanel/config/FeignConfig.java | 20 ++++++++++++++++ .../controller/AdminController.java | 24 +++++++++++++++++++ src/main/resources/application.yaml | 3 +++ 4 files changed, 50 insertions(+) create mode 100644 src/main/java/ru/soune/nocopy/adminpanel/config/FeignConfig.java diff --git a/src/main/java/ru/soune/nocopy/adminpanel/client/DashBoardAppClient.java b/src/main/java/ru/soune/nocopy/adminpanel/client/DashBoardAppClient.java index 795e39c..2935a9c 100644 --- a/src/main/java/ru/soune/nocopy/adminpanel/client/DashBoardAppClient.java +++ b/src/main/java/ru/soune/nocopy/adminpanel/client/DashBoardAppClient.java @@ -12,4 +12,7 @@ public interface DashBoardAppClient { @PostMapping("/api/v1/data") Map getUsersWithPagination(@RequestBody BaseRequest request); + + @PostMapping("api/internal/data") + Map internalData(@RequestBody BaseRequest request); } diff --git a/src/main/java/ru/soune/nocopy/adminpanel/config/FeignConfig.java b/src/main/java/ru/soune/nocopy/adminpanel/config/FeignConfig.java new file mode 100644 index 0000000..74d0512 --- /dev/null +++ b/src/main/java/ru/soune/nocopy/adminpanel/config/FeignConfig.java @@ -0,0 +1,20 @@ +package ru.soune.nocopy.adminpanel.config; + +import feign.RequestInterceptor; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class FeignConfig { + + @Value("${app.internal-api-key}") + private String internalApiKey; + + @Bean + public RequestInterceptor internalKeyInterceptor() { + return requestTemplate -> { + requestTemplate.header("X-Internal-Key", internalApiKey); + }; + } +} diff --git a/src/main/java/ru/soune/nocopy/adminpanel/controller/AdminController.java b/src/main/java/ru/soune/nocopy/adminpanel/controller/AdminController.java index e98789d..ac6465d 100644 --- a/src/main/java/ru/soune/nocopy/adminpanel/controller/AdminController.java +++ b/src/main/java/ru/soune/nocopy/adminpanel/controller/AdminController.java @@ -90,6 +90,30 @@ public class AdminController { .build()); } + @PostMapping("/internal-info") + public ResponseEntity handleInternalInfo(@RequestBody BaseRequest request) { + Long currentUserId = (Long) httpServletRequest.getAttribute("userId"); + + if (!adminSectionPermissionService.canRead(currentUserId, + AdminSection.USERS)) { + return ResponseEntity.ok(BaseResponse.builder() + .msgId(request.getMsgId()) + .messageCode(MessageCode.PERMISSION_DENIED.getCode()) + .messageDesc("You can't reads") + .build()); + } + + Map response = dashBoardAppClient.internalData(request); + + return ResponseEntity.ok( + BaseResponse.builder() + .msgId(request.getMsgId()) + .messageCode(MessageCode.SUCCESS.getCode()) + .messageDesc(MessageCode.SUCCESS.getDescription()) + .messageBody(response) + .build()); + } + @PostMapping("/control") public ResponseEntity handleControl(@RequestBody BaseRequest request) { Long currentUserId = (Long) httpServletRequest.getAttribute("userId"); diff --git a/src/main/resources/application.yaml b/src/main/resources/application.yaml index 2585e56..a8ecf31 100644 --- a/src/main/resources/application.yaml +++ b/src/main/resources/application.yaml @@ -18,6 +18,9 @@ spring: server: port: ${SERVER_PORT:8082} +app: + internal-api-key: "tljzkXiEYF1klSHuG2hPZKjx6EsBX8RQP6UrzMdQanSKbRYuHuOBwrXejZkn7V4FICvIahoDmYD2hjNBPw61NFbGIt4scOzwZpyCiXEa1YKLAeJSPso4S43LIZlKjO4S" + jwt: secret: Z29nb3Bvd2VycmFuZ2VydHVtYmF5YW1iZjMyNDIyMjh3aW5lcndpbmVy expiration: 3600000 -- 2.54.0 From 73030fdf562e10ba3bbff7d7b6a70120474e5e3c Mon Sep 17 00:00:00 2001 From: backdev-1 Date: Mon, 25 May 2026 14:37:01 +0700 Subject: [PATCH 32/47] add internal feign key --- .../controller/AdminController.java | 24 ------------------- 1 file changed, 24 deletions(-) diff --git a/src/main/java/ru/soune/nocopy/adminpanel/controller/AdminController.java b/src/main/java/ru/soune/nocopy/adminpanel/controller/AdminController.java index ac6465d..6243091 100644 --- a/src/main/java/ru/soune/nocopy/adminpanel/controller/AdminController.java +++ b/src/main/java/ru/soune/nocopy/adminpanel/controller/AdminController.java @@ -79,30 +79,6 @@ public class AdminController { .build()); } - Map response = dashBoardAppClient.getUsersWithPagination(request); - - return ResponseEntity.ok( - BaseResponse.builder() - .msgId(request.getMsgId()) - .messageCode(MessageCode.SUCCESS.getCode()) - .messageDesc(MessageCode.SUCCESS.getDescription()) - .messageBody(response) - .build()); - } - - @PostMapping("/internal-info") - public ResponseEntity handleInternalInfo(@RequestBody BaseRequest request) { - Long currentUserId = (Long) httpServletRequest.getAttribute("userId"); - - if (!adminSectionPermissionService.canRead(currentUserId, - AdminSection.USERS)) { - return ResponseEntity.ok(BaseResponse.builder() - .msgId(request.getMsgId()) - .messageCode(MessageCode.PERMISSION_DENIED.getCode()) - .messageDesc("You can't reads") - .build()); - } - Map response = dashBoardAppClient.internalData(request); return ResponseEntity.ok( -- 2.54.0 From 57e4818b0a3d05d12e6bbb145e5c3fad018cf087 Mon Sep 17 00:00:00 2001 From: backdev-1 Date: Mon, 25 May 2026 19:08:49 +0700 Subject: [PATCH 33/47] add internal feign key --- .../soune/nocopy/adminpanel/client/DashBoardAppClient.java | 7 +++++-- .../nocopy/adminpanel/controller/AdminController.java | 6 +++--- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/src/main/java/ru/soune/nocopy/adminpanel/client/DashBoardAppClient.java b/src/main/java/ru/soune/nocopy/adminpanel/client/DashBoardAppClient.java index 2935a9c..ffad958 100644 --- a/src/main/java/ru/soune/nocopy/adminpanel/client/DashBoardAppClient.java +++ b/src/main/java/ru/soune/nocopy/adminpanel/client/DashBoardAppClient.java @@ -13,6 +13,9 @@ public interface DashBoardAppClient { @PostMapping("/api/v1/data") Map getUsersWithPagination(@RequestBody BaseRequest request); - @PostMapping("api/internal/data") - Map internalData(@RequestBody BaseRequest request); + @PostMapping("api/internal/data-info") + Map internalDataInfo(@RequestBody BaseRequest request); + + @PostMapping("api/internal/data-control") + Map internalDataControl(@RequestBody BaseRequest request); } diff --git a/src/main/java/ru/soune/nocopy/adminpanel/controller/AdminController.java b/src/main/java/ru/soune/nocopy/adminpanel/controller/AdminController.java index 6243091..975c8a0 100644 --- a/src/main/java/ru/soune/nocopy/adminpanel/controller/AdminController.java +++ b/src/main/java/ru/soune/nocopy/adminpanel/controller/AdminController.java @@ -79,7 +79,7 @@ public class AdminController { .build()); } - Map response = dashBoardAppClient.internalData(request); + Map response = dashBoardAppClient.internalDataInfo(request); return ResponseEntity.ok( BaseResponse.builder() @@ -94,7 +94,7 @@ public class AdminController { public ResponseEntity handleControl(@RequestBody BaseRequest request) { Long currentUserId = (Long) httpServletRequest.getAttribute("userId"); - if (!adminSectionPermissionService.canWrite(currentUserId, + if (!adminSectionPermissionService.canRead(currentUserId, AdminSection.USERS)) { return ResponseEntity.ok(BaseResponse.builder() .msgId(request.getMsgId()) @@ -103,7 +103,7 @@ public class AdminController { .build()); } - Map response = dashBoardAppClient.getUsersWithPagination(request); + Map response = dashBoardAppClient.internalDataControl(request); return ResponseEntity.ok( BaseResponse.builder() -- 2.54.0 From 3f38adfa7b35ff566f09530557ff53815de90b52 Mon Sep 17 00:00:00 2001 From: backdev-1 Date: Tue, 26 May 2026 14:55:57 +0700 Subject: [PATCH 34/47] add internal feign key --- .../soune/nocopy/adminpanel/controller/AdminController.java | 4 ++++ src/main/java/ru/soune/nocopy/adminpanel/dto/BaseRequest.java | 3 +++ 2 files changed, 7 insertions(+) diff --git a/src/main/java/ru/soune/nocopy/adminpanel/controller/AdminController.java b/src/main/java/ru/soune/nocopy/adminpanel/controller/AdminController.java index 975c8a0..5914ba7 100644 --- a/src/main/java/ru/soune/nocopy/adminpanel/controller/AdminController.java +++ b/src/main/java/ru/soune/nocopy/adminpanel/controller/AdminController.java @@ -79,6 +79,8 @@ public class AdminController { .build()); } + request.setAdminId(currentUserId); + Map response = dashBoardAppClient.internalDataInfo(request); return ResponseEntity.ok( @@ -103,6 +105,8 @@ public class AdminController { .build()); } + request.setAdminId(currentUserId); + Map response = dashBoardAppClient.internalDataControl(request); return ResponseEntity.ok( diff --git a/src/main/java/ru/soune/nocopy/adminpanel/dto/BaseRequest.java b/src/main/java/ru/soune/nocopy/adminpanel/dto/BaseRequest.java index d960005..207ec47 100644 --- a/src/main/java/ru/soune/nocopy/adminpanel/dto/BaseRequest.java +++ b/src/main/java/ru/soune/nocopy/adminpanel/dto/BaseRequest.java @@ -18,4 +18,7 @@ public class BaseRequest { @JsonProperty("message_body") Object messageBody; + + @JsonProperty(value = "admin_id", required = false) + Long adminId; } -- 2.54.0 From 0a053a565754512356ca7365d0d656a4a0444fdc Mon Sep 17 00:00:00 2001 From: backdev-1 Date: Thu, 28 May 2026 12:19:05 +0700 Subject: [PATCH 35/47] add internal feign key --- .../adminpanel/client/DashBoardAppClient.java | 7 +++++++ .../controller/AdminController.java | 21 +++++++++++++++---- 2 files changed, 24 insertions(+), 4 deletions(-) diff --git a/src/main/java/ru/soune/nocopy/adminpanel/client/DashBoardAppClient.java b/src/main/java/ru/soune/nocopy/adminpanel/client/DashBoardAppClient.java index ffad958..40a4118 100644 --- a/src/main/java/ru/soune/nocopy/adminpanel/client/DashBoardAppClient.java +++ b/src/main/java/ru/soune/nocopy/adminpanel/client/DashBoardAppClient.java @@ -1,8 +1,12 @@ package ru.soune.nocopy.adminpanel.client; import org.springframework.cloud.openfeign.FeignClient; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.servlet.mvc.method.annotation.StreamingResponseBody; import ru.soune.nocopy.adminpanel.dto.BaseRequest; import java.util.Map; @@ -18,4 +22,7 @@ public interface DashBoardAppClient { @PostMapping("api/internal/data-control") Map internalDataControl(@RequestBody BaseRequest request); + + @GetMapping("api/internal/data-download/{fileId}") + public ResponseEntity download(@PathVariable String fileId); } diff --git a/src/main/java/ru/soune/nocopy/adminpanel/controller/AdminController.java b/src/main/java/ru/soune/nocopy/adminpanel/controller/AdminController.java index 5914ba7..ed92236 100644 --- a/src/main/java/ru/soune/nocopy/adminpanel/controller/AdminController.java +++ b/src/main/java/ru/soune/nocopy/adminpanel/controller/AdminController.java @@ -4,10 +4,7 @@ import jakarta.servlet.http.HttpServletRequest; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.bind.annotation.*; import ru.soune.nocopy.adminpanel.client.DashBoardAppClient; import ru.soune.nocopy.adminpanel.dto.BaseRequest; import ru.soune.nocopy.adminpanel.dto.BaseResponse; @@ -117,4 +114,20 @@ public class AdminController { .messageBody(response) .build()); } + + @GetMapping("/download/{fileId}") + public ResponseEntity downloadFile(@PathVariable String fileId) { + Long currentUserId = (Long) httpServletRequest.getAttribute("userId"); + + if (!adminSectionPermissionService.canRead(currentUserId, + AdminSection.USERS)) { + return ResponseEntity.ok(BaseResponse.builder() + .msgId(0) + .messageCode(MessageCode.PERMISSION_DENIED.getCode()) + .messageDesc("You can't control") + .build()); + } + + return dashBoardAppClient.download(fileId); + } } -- 2.54.0 From 7c4843a081d1d10d839c196f0746d6c71bf577fd Mon Sep 17 00:00:00 2001 From: backdev-1 Date: Thu, 28 May 2026 12:44:41 +0700 Subject: [PATCH 36/47] add internal feign key --- .../nocopy/adminpanel/client/DashBoardAppClient.java | 5 +++-- .../nocopy/adminpanel/controller/AdminController.java | 8 +++++++- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/src/main/java/ru/soune/nocopy/adminpanel/client/DashBoardAppClient.java b/src/main/java/ru/soune/nocopy/adminpanel/client/DashBoardAppClient.java index 40a4118..caf5d03 100644 --- a/src/main/java/ru/soune/nocopy/adminpanel/client/DashBoardAppClient.java +++ b/src/main/java/ru/soune/nocopy/adminpanel/client/DashBoardAppClient.java @@ -1,6 +1,7 @@ package ru.soune.nocopy.adminpanel.client; import org.springframework.cloud.openfeign.FeignClient; +import org.springframework.core.io.Resource; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; @@ -23,6 +24,6 @@ public interface DashBoardAppClient { @PostMapping("api/internal/data-control") Map internalDataControl(@RequestBody BaseRequest request); - @GetMapping("api/internal/data-download/{fileId}") - public ResponseEntity download(@PathVariable String fileId); + @GetMapping("/internal/data-download/{fileId}") + ResponseEntity download(@PathVariable String fileId); } diff --git a/src/main/java/ru/soune/nocopy/adminpanel/controller/AdminController.java b/src/main/java/ru/soune/nocopy/adminpanel/controller/AdminController.java index ed92236..d8eb31f 100644 --- a/src/main/java/ru/soune/nocopy/adminpanel/controller/AdminController.java +++ b/src/main/java/ru/soune/nocopy/adminpanel/controller/AdminController.java @@ -1,8 +1,10 @@ package ru.soune.nocopy.adminpanel.controller; +import feign.FeignException; import jakarta.servlet.http.HttpServletRequest; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; import ru.soune.nocopy.adminpanel.client.DashBoardAppClient; @@ -128,6 +130,10 @@ public class AdminController { .build()); } - return dashBoardAppClient.download(fileId); + try { + return dashBoardAppClient.download(fileId); + } catch (FeignException.NotFound e) { + return ResponseEntity.notFound().build(); + } } } -- 2.54.0 From f88c8fe500753f754ade7030298400a3bca7e00a Mon Sep 17 00:00:00 2001 From: backdev-1 Date: Thu, 28 May 2026 12:57:18 +0700 Subject: [PATCH 37/47] add internal feign key --- .../ru/soune/nocopy/adminpanel/client/DashBoardAppClient.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/ru/soune/nocopy/adminpanel/client/DashBoardAppClient.java b/src/main/java/ru/soune/nocopy/adminpanel/client/DashBoardAppClient.java index caf5d03..de50731 100644 --- a/src/main/java/ru/soune/nocopy/adminpanel/client/DashBoardAppClient.java +++ b/src/main/java/ru/soune/nocopy/adminpanel/client/DashBoardAppClient.java @@ -24,6 +24,6 @@ public interface DashBoardAppClient { @PostMapping("api/internal/data-control") Map internalDataControl(@RequestBody BaseRequest request); - @GetMapping("/internal/data-download/{fileId}") + @GetMapping("api/internal/data-download/{fileId}") ResponseEntity download(@PathVariable String fileId); } -- 2.54.0 From a4feb5277a4093adbf491d5056ae11029b9aa046 Mon Sep 17 00:00:00 2001 From: backdev-1 Date: Thu, 28 May 2026 13:06:58 +0700 Subject: [PATCH 38/47] add internal feign key --- .../adminpanel/client/DashBoardAppClient.java | 2 +- .../controller/AdminController.java | 22 +++++++++++++++++-- 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/src/main/java/ru/soune/nocopy/adminpanel/client/DashBoardAppClient.java b/src/main/java/ru/soune/nocopy/adminpanel/client/DashBoardAppClient.java index de50731..1dbab82 100644 --- a/src/main/java/ru/soune/nocopy/adminpanel/client/DashBoardAppClient.java +++ b/src/main/java/ru/soune/nocopy/adminpanel/client/DashBoardAppClient.java @@ -25,5 +25,5 @@ public interface DashBoardAppClient { Map internalDataControl(@RequestBody BaseRequest request); @GetMapping("api/internal/data-download/{fileId}") - ResponseEntity download(@PathVariable String fileId); + ResponseEntity download(@PathVariable String fileId); } diff --git a/src/main/java/ru/soune/nocopy/adminpanel/controller/AdminController.java b/src/main/java/ru/soune/nocopy/adminpanel/controller/AdminController.java index d8eb31f..0683c6c 100644 --- a/src/main/java/ru/soune/nocopy/adminpanel/controller/AdminController.java +++ b/src/main/java/ru/soune/nocopy/adminpanel/controller/AdminController.java @@ -4,9 +4,11 @@ import feign.FeignException; import jakarta.servlet.http.HttpServletRequest; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; +import org.springframework.web.servlet.mvc.method.annotation.StreamingResponseBody; import ru.soune.nocopy.adminpanel.client.DashBoardAppClient; import ru.soune.nocopy.adminpanel.dto.BaseRequest; import ru.soune.nocopy.adminpanel.dto.BaseResponse; @@ -129,11 +131,27 @@ public class AdminController { .messageDesc("You can't control") .build()); } - try { - return dashBoardAppClient.download(fileId); + ResponseEntity response = dashBoardAppClient.download(fileId); + + StreamingResponseBody stream = outputStream -> { + outputStream.write(response.getBody()); + outputStream.flush(); + }; + + return ResponseEntity.ok() + .contentType(response.getHeaders().getContentType()) + .header(HttpHeaders.CONTENT_DISPOSITION, + response.getHeaders().getFirst(HttpHeaders.CONTENT_DISPOSITION)) + .header(HttpHeaders.CACHE_CONTROL, + response.getHeaders().getFirst(HttpHeaders.CACHE_CONTROL)) + .body(stream); } catch (FeignException.NotFound e) { return ResponseEntity.notFound().build(); + } catch (FeignException e) { + log.error("Error downloading file: {}", fileId, e); + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build(); } + } } -- 2.54.0 From 15e2617ce9f6343664c4333c4a340280c0f67cd4 Mon Sep 17 00:00:00 2001 From: backdev-1 Date: Thu, 28 May 2026 13:32:19 +0700 Subject: [PATCH 39/47] add internal feign key --- .../adminpanel/controller/AdminController.java | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/main/java/ru/soune/nocopy/adminpanel/controller/AdminController.java b/src/main/java/ru/soune/nocopy/adminpanel/controller/AdminController.java index 0683c6c..67e1d77 100644 --- a/src/main/java/ru/soune/nocopy/adminpanel/controller/AdminController.java +++ b/src/main/java/ru/soune/nocopy/adminpanel/controller/AdminController.java @@ -17,6 +17,8 @@ import ru.soune.nocopy.adminpanel.handler.RequestHandler; import ru.soune.nocopy.adminpanel.service.AdminSectionPermissionService; import ru.soune.nocopy.adminpanel.util.MessageCode; +import java.io.IOException; +import java.io.OutputStream; import java.util.Map; @RestController @@ -134,9 +136,12 @@ public class AdminController { try { ResponseEntity response = dashBoardAppClient.download(fileId); - StreamingResponseBody stream = outputStream -> { - outputStream.write(response.getBody()); - outputStream.flush(); + StreamingResponseBody streamBody = new StreamingResponseBody() { + @Override + public void writeTo(OutputStream outputStream) throws IOException { + outputStream.write(response.getBody()); + outputStream.flush(); + } }; return ResponseEntity.ok() @@ -145,7 +150,7 @@ public class AdminController { response.getHeaders().getFirst(HttpHeaders.CONTENT_DISPOSITION)) .header(HttpHeaders.CACHE_CONTROL, response.getHeaders().getFirst(HttpHeaders.CACHE_CONTROL)) - .body(stream); + .body(streamBody); } catch (FeignException.NotFound e) { return ResponseEntity.notFound().build(); } catch (FeignException e) { -- 2.54.0 From d23932b2ec2966464e4ee3164df8d131d126fd41 Mon Sep 17 00:00:00 2001 From: backdev-1 Date: Thu, 28 May 2026 13:38:25 +0700 Subject: [PATCH 40/47] add internal feign key --- .../controller/AdminController.java | 32 +++---------------- 1 file changed, 5 insertions(+), 27 deletions(-) diff --git a/src/main/java/ru/soune/nocopy/adminpanel/controller/AdminController.java b/src/main/java/ru/soune/nocopy/adminpanel/controller/AdminController.java index 67e1d77..865d6cd 100644 --- a/src/main/java/ru/soune/nocopy/adminpanel/controller/AdminController.java +++ b/src/main/java/ru/soune/nocopy/adminpanel/controller/AdminController.java @@ -122,41 +122,19 @@ public class AdminController { } @GetMapping("/download/{fileId}") - public ResponseEntity downloadFile(@PathVariable String fileId) { + public ResponseEntity downloadFile(@PathVariable String fileId) { Long currentUserId = (Long) httpServletRequest.getAttribute("userId"); - if (!adminSectionPermissionService.canRead(currentUserId, - AdminSection.USERS)) { - return ResponseEntity.ok(BaseResponse.builder() - .msgId(0) - .messageCode(MessageCode.PERMISSION_DENIED.getCode()) - .messageDesc("You can't control") - .build()); + if (!adminSectionPermissionService.canRead(currentUserId, AdminSection.USERS)) { + return ResponseEntity.status(HttpStatus.FORBIDDEN).build(); } + try { - ResponseEntity response = dashBoardAppClient.download(fileId); - - StreamingResponseBody streamBody = new StreamingResponseBody() { - @Override - public void writeTo(OutputStream outputStream) throws IOException { - outputStream.write(response.getBody()); - outputStream.flush(); - } - }; - - return ResponseEntity.ok() - .contentType(response.getHeaders().getContentType()) - .header(HttpHeaders.CONTENT_DISPOSITION, - response.getHeaders().getFirst(HttpHeaders.CONTENT_DISPOSITION)) - .header(HttpHeaders.CACHE_CONTROL, - response.getHeaders().getFirst(HttpHeaders.CACHE_CONTROL)) - .body(streamBody); + return dashBoardAppClient.download(fileId); } catch (FeignException.NotFound e) { return ResponseEntity.notFound().build(); } catch (FeignException e) { - log.error("Error downloading file: {}", fileId, e); return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build(); } - } } -- 2.54.0 From 1a7b4ce6c36d363a19b600f2300caafb1788c88b Mon Sep 17 00:00:00 2001 From: backdev-1 Date: Thu, 28 May 2026 14:26:35 +0700 Subject: [PATCH 41/47] add internal feign key --- .../soune/nocopy/adminpanel/controller/AdminController.java | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/main/java/ru/soune/nocopy/adminpanel/controller/AdminController.java b/src/main/java/ru/soune/nocopy/adminpanel/controller/AdminController.java index 865d6cd..65d4efe 100644 --- a/src/main/java/ru/soune/nocopy/adminpanel/controller/AdminController.java +++ b/src/main/java/ru/soune/nocopy/adminpanel/controller/AdminController.java @@ -4,11 +4,9 @@ import feign.FeignException; import jakarta.servlet.http.HttpServletRequest; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; -import org.springframework.web.servlet.mvc.method.annotation.StreamingResponseBody; import ru.soune.nocopy.adminpanel.client.DashBoardAppClient; import ru.soune.nocopy.adminpanel.dto.BaseRequest; import ru.soune.nocopy.adminpanel.dto.BaseResponse; @@ -17,8 +15,6 @@ import ru.soune.nocopy.adminpanel.handler.RequestHandler; import ru.soune.nocopy.adminpanel.service.AdminSectionPermissionService; import ru.soune.nocopy.adminpanel.util.MessageCode; -import java.io.IOException; -import java.io.OutputStream; import java.util.Map; @RestController @@ -125,7 +121,7 @@ public class AdminController { public ResponseEntity downloadFile(@PathVariable String fileId) { Long currentUserId = (Long) httpServletRequest.getAttribute("userId"); - if (!adminSectionPermissionService.canRead(currentUserId, AdminSection.USERS)) { + if (!adminSectionPermissionService.canRead(currentUserId, AdminSection.CONTENT_MODERATION)) { return ResponseEntity.status(HttpStatus.FORBIDDEN).build(); } -- 2.54.0 From 690bc0fcf061f941cc60acf38d6d04546f598e12 Mon Sep 17 00:00:00 2001 From: backdev-1 Date: Fri, 5 Jun 2026 22:06:28 +0700 Subject: [PATCH 42/47] add internal feign key --- build.gradle | 3 + .../adminpanel/config/SecurityConfig.java | 34 +++++++++++ .../nocopy/adminpanel/dto/BaseRequest.java | 3 - .../adminpanel/handler/AdminUserHandler.java | 60 +------------------ 4 files changed, 38 insertions(+), 62 deletions(-) create mode 100644 src/main/java/ru/soune/nocopy/adminpanel/config/SecurityConfig.java diff --git a/build.gradle b/build.gradle index 4411033..cbeb567 100644 --- a/build.gradle +++ b/build.gradle @@ -47,5 +47,8 @@ dependencies { testImplementation 'org.springframework.boot:spring-boot-starter-webmvc-test' testRuntimeOnly 'org.junit.platform:junit-platform-launcher' implementation 'org.springframework.cloud:spring-cloud-starter-openfeign:4.1.0' + //security + implementation 'org.springframework.boot:spring-boot-starter-security' + implementation("io.jsonwebtoken:jjwt:0.13.0") } diff --git a/src/main/java/ru/soune/nocopy/adminpanel/config/SecurityConfig.java b/src/main/java/ru/soune/nocopy/adminpanel/config/SecurityConfig.java new file mode 100644 index 0000000..e410b56 --- /dev/null +++ b/src/main/java/ru/soune/nocopy/adminpanel/config/SecurityConfig.java @@ -0,0 +1,34 @@ +package ru.soune.nocopy.adminpanel.config; + +import lombok.RequiredArgsConstructor; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; +import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer; +import org.springframework.security.config.http.SessionCreationPolicy; +import org.springframework.security.web.SecurityFilterChain; +import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; +import ru.soune.nocopy.adminpanel.util.JwtAuthFilter; + +@Configuration +@EnableWebSecurity +@RequiredArgsConstructor +public class SecurityConfig { + + private final JwtAuthFilter jwtAuthFilter; + + @Bean + public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { + http + .csrf(AbstractHttpConfigurer::disable) + .sessionManagement(session -> + session.sessionCreationPolicy(SessionCreationPolicy.STATELESS)) + .authorizeHttpRequests(auth -> auth + .anyRequest().authenticated() + ) + .addFilterBefore(jwtAuthFilter, UsernamePasswordAuthenticationFilter.class); + + return http.build(); + } +} \ No newline at end of file diff --git a/src/main/java/ru/soune/nocopy/adminpanel/dto/BaseRequest.java b/src/main/java/ru/soune/nocopy/adminpanel/dto/BaseRequest.java index 207ec47..baae892 100644 --- a/src/main/java/ru/soune/nocopy/adminpanel/dto/BaseRequest.java +++ b/src/main/java/ru/soune/nocopy/adminpanel/dto/BaseRequest.java @@ -13,9 +13,6 @@ public class BaseRequest { @JsonProperty("msg_id") Integer msgId; - @JsonProperty("token") - String token; - @JsonProperty("message_body") Object messageBody; diff --git a/src/main/java/ru/soune/nocopy/adminpanel/handler/AdminUserHandler.java b/src/main/java/ru/soune/nocopy/adminpanel/handler/AdminUserHandler.java index 5f0f639..3e8420b 100644 --- a/src/main/java/ru/soune/nocopy/adminpanel/handler/AdminUserHandler.java +++ b/src/main/java/ru/soune/nocopy/adminpanel/handler/AdminUserHandler.java @@ -56,7 +56,6 @@ public class AdminUserHandler implements RequestHandler { case "toggle_active" -> handleToggleActive(request, adminRequest); case "delete" -> handleDelete(request, adminRequest); case "get_permissions_by_id" -> handleGetPermissionsById(request, adminRequest); - case "get_permissions_by_token" -> handleGetPermissionsByToken(request, adminRequest); case "update_permissions" -> handleUpdatePermissions(request, adminRequest); default -> handleInvalidAction(request, action); }; @@ -397,7 +396,7 @@ public class AdminUserHandler implements RequestHandler { .availableActions(Arrays.asList( "login", "create", "get_all", "get_by_id", "update", "set_super_admin", "toggle_active", "delete", - "get_permissions", "update_permissions")) + "get_permissions_by_id", "update_permissions")) .build(); return BaseResponse.builder() @@ -457,63 +456,6 @@ public class AdminUserHandler implements RequestHandler { } } - private BaseResponse handleGetPermissionsByToken(BaseRequest request, AdminUserRequest adminRequest) { - try { - Long currentUserId = (Long) httpServletRequest.getAttribute("userId"); - - if (!currentUserId.equals(adminRequest.getAdminId())) { - if (!adminSectionPermissionService.canRead(currentUserId, - AdminSection.USERS)) { - return BaseResponse.builder() - .msgId(request.getMsgId()) - .messageCode(MessageCode.PERMISSION_DENIED.getCode()) - .messageDesc("You can't update profile") - .build(); - } - } - - String token = request.getToken(); - if (token == null || token.isEmpty()) { - return BaseResponse.builder() - .msgId(request.getMsgId()) - .messageCode(MessageCode.INVALID_CREDENTIALS.getCode()) - .messageDesc("Token is required") - .build(); - } - - String email = jwtUtil.extractEmail(token); - AdminUser admin = adminUserService.findByEmail(email); - Map sectionPermissions = permissionService.getAllPermissions(admin.getId()); - - Map permissionsMap = new HashMap<>(); - sectionPermissions.forEach((section, value) -> - permissionsMap.put(section.name().toLowerCase(), value)); - - AdminUserResponse response = AdminUserResponse.builder() - .id(admin.getId()) - .fullName(admin.getFullName()) - .email(admin.getEmail()) - .isActive(admin.getIsActive()) - .isSuperAdmin(AdminPermission.isSuperAdmin(admin.getPermissions())) - .createdAt(admin.getCreatedAt().toString()) - .permissions(permissionsMap) - .build(); - - return BaseResponse.builder() - .msgId(request.getMsgId()) - .messageCode(MessageCode.SUCCESS.getCode()) - .messageDesc(MessageCode.SUCCESS.getDescription()) - .messageBody(response) - .build(); - } catch (AdminUserNotFoundException e) { - return BaseResponse.builder() - .msgId(request.getMsgId()) - .messageCode(MessageCode.ADMIN_NOT_FOUND.getCode()) - .messageDesc(MessageCode.ADMIN_NOT_FOUND.getDescription()) - .build(); - } - } - private BaseResponse handleUpdatePermissions(BaseRequest request, AdminUserRequest adminRequest) { try { Long currentUserId = (Long) httpServletRequest.getAttribute("userId"); -- 2.54.0 From 9b028237a4d02920a444588bf9010c20d948c775 Mon Sep 17 00:00:00 2001 From: backdev-1 Date: Fri, 5 Jun 2026 22:23:49 +0700 Subject: [PATCH 43/47] add internal feign key --- .../nocopy/adminpanel/config/AppConfig.java | 9 ++ .../adminpanel/config/SecurityConfig.java | 2 + .../controller/AdminController.java | 37 +++++ .../adminpanel/handler/AdminUserHandler.java | 53 +------- .../adminpanel/handler/LoginHandler.java | 127 ++++++++++++++++++ 5 files changed, 176 insertions(+), 52 deletions(-) create mode 100644 src/main/java/ru/soune/nocopy/adminpanel/handler/LoginHandler.java diff --git a/src/main/java/ru/soune/nocopy/adminpanel/config/AppConfig.java b/src/main/java/ru/soune/nocopy/adminpanel/config/AppConfig.java index ae859c5..2c6be73 100644 --- a/src/main/java/ru/soune/nocopy/adminpanel/config/AppConfig.java +++ b/src/main/java/ru/soune/nocopy/adminpanel/config/AppConfig.java @@ -9,6 +9,7 @@ import org.springframework.web.cors.UrlBasedCorsConfigurationSource; import org.springframework.web.filter.CorsFilter; import ru.soune.nocopy.adminpanel.handler.AdminUserHandler; import ru.soune.nocopy.adminpanel.handler.CreateAdminTemplateHandler; +import ru.soune.nocopy.adminpanel.handler.LoginHandler; import ru.soune.nocopy.adminpanel.handler.RequestHandler; import java.util.HashMap; @@ -43,4 +44,12 @@ public class AppConfig { return map; } + @Bean + public Map loginHandlers(LoginHandler loginHandler) { + Map map = new HashMap<>(); + map.put(101, loginHandler); + + return map; + } + } diff --git a/src/main/java/ru/soune/nocopy/adminpanel/config/SecurityConfig.java b/src/main/java/ru/soune/nocopy/adminpanel/config/SecurityConfig.java index e410b56..6742bb4 100644 --- a/src/main/java/ru/soune/nocopy/adminpanel/config/SecurityConfig.java +++ b/src/main/java/ru/soune/nocopy/adminpanel/config/SecurityConfig.java @@ -25,6 +25,8 @@ public class SecurityConfig { .sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS)) .authorizeHttpRequests(auth -> auth + .requestMatchers("/api/admin/login").permitAll() + .requestMatchers("/api/admin").permitAll() .anyRequest().authenticated() ) .addFilterBefore(jwtAuthFilter, UsernamePasswordAuthenticationFilter.class); diff --git a/src/main/java/ru/soune/nocopy/adminpanel/controller/AdminController.java b/src/main/java/ru/soune/nocopy/adminpanel/controller/AdminController.java index 65d4efe..810aeb2 100644 --- a/src/main/java/ru/soune/nocopy/adminpanel/controller/AdminController.java +++ b/src/main/java/ru/soune/nocopy/adminpanel/controller/AdminController.java @@ -25,6 +25,8 @@ public class AdminController { private final Map handlers; + private final Map loginHandlers; + private final DashBoardAppClient dashBoardAppClient; private final AdminSectionPermissionService adminSectionPermissionService; @@ -65,6 +67,41 @@ public class AdminController { } } + + @PostMapping("/login") + public ResponseEntity handleLoginRequest(@RequestBody BaseRequest request) { + log.info("Received request: msg_id={}, version={}", request.getMsgId(), request.getVersion()); + + try { + RequestHandler handler = loginHandlers.get(request.getMsgId()); + + if (handler == null) { + log.warn("No handler found for msg_id: {}", request.getMsgId()); + return ResponseEntity.ok( + BaseResponse.builder() + .msgId(request.getMsgId()) + .messageCode(MessageCode.INVALID_ACTION.getCode()) + .messageDesc("No handler for msg_id: " + request.getMsgId()) + .build() + ); + } + + BaseResponse response = handler.handle(request); + log.info("Request processed successfully: msg_id={}", request.getMsgId()); + return ResponseEntity.ok(response); + + } catch (Exception e) { + log.error("Error processing request: msg_id={}", request.getMsgId(), e); + return ResponseEntity.ok( + BaseResponse.builder() + .msgId(request.getMsgId()) + .messageCode(MessageCode.INVALID_ACTION.getCode()) + .messageDesc("Internal server error: " + e.getMessage()) + .build() + ); + } + } + @PostMapping("/info") public ResponseEntity handleInfo(@RequestBody BaseRequest request) { Long currentUserId = (Long) httpServletRequest.getAttribute("userId"); diff --git a/src/main/java/ru/soune/nocopy/adminpanel/handler/AdminUserHandler.java b/src/main/java/ru/soune/nocopy/adminpanel/handler/AdminUserHandler.java index 3e8420b..2b6c5a7 100644 --- a/src/main/java/ru/soune/nocopy/adminpanel/handler/AdminUserHandler.java +++ b/src/main/java/ru/soune/nocopy/adminpanel/handler/AdminUserHandler.java @@ -33,8 +33,6 @@ public class AdminUserHandler implements RequestHandler { private final AdminUserService adminUserService; - private final JwtUtil jwtUtil; - private final AdminSectionPermissionService permissionService; private final HttpServletRequest httpServletRequest; @@ -47,7 +45,6 @@ public class AdminUserHandler implements RequestHandler { String action = adminRequest.getAction(); return switch (action) { - case "login" -> handleLogin(request, adminRequest); case "create" -> handleCreate(request, adminRequest); case "get_all" -> handleGetAll(request, adminRequest); case "get_by_id" -> handleGetById(request, adminRequest); @@ -61,60 +58,12 @@ public class AdminUserHandler implements RequestHandler { }; } - private BaseResponse handleLogin(BaseRequest request, AdminUserRequest adminRequest) { - String email = adminRequest.getEmail(); - String password = adminRequest.getPassword(); - - boolean authenticated = adminUserService.authenticate(email, password); - - if (!authenticated) { - return BaseResponse.builder() - .msgId(request.getMsgId()) - .messageCode(MessageCode.INVALID_CREDENTIALS.getCode()) - .messageDesc(MessageCode.INVALID_CREDENTIALS.getDescription()) - .build(); - } - - try { - AdminUser admin = adminUserService.findByEmail(email); - - if (!admin.getIsActive()) { - return BaseResponse.builder() - .msgId(request.getMsgId()) - .messageCode(MessageCode.ADMIN_INACTIVE.getCode()) - .messageDesc(MessageCode.ADMIN_INACTIVE.getDescription()) - .build(); - } - - String token = jwtUtil.generateToken(admin.getEmail(), admin.getId()); - - LoginResponse loginResponse = LoginResponse.builder() - .success(true) - .token(token) - .admin(convertToResponse(admin)) - .build(); - - return BaseResponse.builder() - .msgId(request.getMsgId()) - .messageCode(MessageCode.SUCCESS.getCode()) - .messageDesc(MessageCode.SUCCESS.getDescription()) - .messageBody(loginResponse) - .build(); - } catch (AdminUserNotFoundException e) { - return BaseResponse.builder() - .msgId(request.getMsgId()) - .messageCode(MessageCode.ADMIN_NOT_FOUND.getCode()) - .messageDesc(MessageCode.ADMIN_NOT_FOUND.getDescription()) - .build(); - } - } - private BaseResponse handleCreate(BaseRequest request, AdminUserRequest adminRequest) { try { Long currentUserId = (Long) httpServletRequest.getAttribute("userId"); if (!adminSectionPermissionService.canWrite(currentUserId, - AdminSection.USERS)) { + AdminSection.STAFF)) { return BaseResponse.builder() .msgId(request.getMsgId()) .messageCode(MessageCode.PERMISSION_DENIED.getCode()) diff --git a/src/main/java/ru/soune/nocopy/adminpanel/handler/LoginHandler.java b/src/main/java/ru/soune/nocopy/adminpanel/handler/LoginHandler.java new file mode 100644 index 0000000..26a2ffa --- /dev/null +++ b/src/main/java/ru/soune/nocopy/adminpanel/handler/LoginHandler.java @@ -0,0 +1,127 @@ +package ru.soune.nocopy.adminpanel.handler; + +import com.fasterxml.jackson.databind.ObjectMapper; +import jakarta.servlet.http.HttpServletRequest; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; +import ru.soune.nocopy.adminpanel.dto.*; +import ru.soune.nocopy.adminpanel.entity.AdminSection; +import ru.soune.nocopy.adminpanel.entity.AdminUser; +import ru.soune.nocopy.adminpanel.exceptions.AdminUserNotFoundException; +import ru.soune.nocopy.adminpanel.permission.AdminPermission; +import ru.soune.nocopy.adminpanel.service.AdminSectionPermissionService; +import ru.soune.nocopy.adminpanel.service.AdminUserService; +import ru.soune.nocopy.adminpanel.util.JwtUtil; +import ru.soune.nocopy.adminpanel.util.MessageCode; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; + +@Component +@Slf4j +@RequiredArgsConstructor +public class LoginHandler implements RequestHandler { + private final ObjectMapper objectMapper; + + private final AdminUserService adminUserService; + + private final JwtUtil jwtUtil; + + private final AdminSectionPermissionService permissionService; + + @Override + public BaseResponse handle(BaseRequest request) { + AdminUserRequest adminRequest = objectMapper.convertValue(request.getMessageBody(), AdminUserRequest.class); + String action = adminRequest.getAction(); + + return switch (action) { + case "login" -> handleLogin(request, adminRequest); + default -> handleInvalidAction(request, action); + }; + } + + private BaseResponse handleLogin(BaseRequest request, AdminUserRequest adminRequest) { + String email = adminRequest.getEmail(); + String password = adminRequest.getPassword(); + + boolean authenticated = adminUserService.authenticate(email, password); + + if (!authenticated) { + return BaseResponse.builder() + .msgId(request.getMsgId()) + .messageCode(MessageCode.INVALID_CREDENTIALS.getCode()) + .messageDesc(MessageCode.INVALID_CREDENTIALS.getDescription()) + .build(); + } + + try { + AdminUser admin = adminUserService.findByEmail(email); + + if (!admin.getIsActive()) { + return BaseResponse.builder() + .msgId(request.getMsgId()) + .messageCode(MessageCode.ADMIN_INACTIVE.getCode()) + .messageDesc(MessageCode.ADMIN_INACTIVE.getDescription()) + .build(); + } + + String token = jwtUtil.generateToken(admin.getEmail(), admin.getId()); + + LoginResponse loginResponse = LoginResponse.builder() + .success(true) + .token(token) + .admin(convertToResponse(admin)) + .build(); + + return BaseResponse.builder() + .msgId(request.getMsgId()) + .messageCode(MessageCode.SUCCESS.getCode()) + .messageDesc(MessageCode.SUCCESS.getDescription()) + .messageBody(loginResponse) + .build(); + } catch (AdminUserNotFoundException e) { + return BaseResponse.builder() + .msgId(request.getMsgId()) + .messageCode(MessageCode.ADMIN_NOT_FOUND.getCode()) + .messageDesc(MessageCode.ADMIN_NOT_FOUND.getDescription()) + .build(); + } + } + + private AdminUserResponse convertToResponse(AdminUser admin) { + Map sectionPermissions = permissionService.getAllPermissions(admin.getId()); + + Map permissionsMap = new HashMap<>(); + sectionPermissions.forEach((section, value) -> + permissionsMap.put(section.name().toLowerCase(), value)); + + return AdminUserResponse.builder() + .id(admin.getId()) + .fullName(admin.getFullName()) + .email(admin.getEmail()) + .isActive(admin.getIsActive()) + .isSuperAdmin(AdminPermission.isSuperAdmin(admin.getPermissions())) + .createdAt(admin.getCreatedAt().toString()) + .permissions(permissionsMap) + .activePassword(admin.getIsActivePassword()) + .build(); + } + + private BaseResponse handleInvalidAction(BaseRequest request, String action) { + ActionResponse response = ActionResponse.builder() + .action(action) + .availableActions(Arrays.asList( + "login")) + .build(); + + return BaseResponse.builder() + .msgId(request.getMsgId()) + .messageCode(MessageCode.INVALID_ACTION.getCode()) + .messageDesc(MessageCode.INVALID_ACTION.getDescription()) + .messageBody(response) + .build(); + } + +} -- 2.54.0 From c537de7fe6a2045d5f3ff76430a2807c3a68b1b9 Mon Sep 17 00:00:00 2001 From: backdev-1 Date: Fri, 5 Jun 2026 22:29:55 +0700 Subject: [PATCH 44/47] add internal feign key --- .../adminpanel/handler/AdminUserHandler.java | 51 +++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/src/main/java/ru/soune/nocopy/adminpanel/handler/AdminUserHandler.java b/src/main/java/ru/soune/nocopy/adminpanel/handler/AdminUserHandler.java index 2b6c5a7..9fda54c 100644 --- a/src/main/java/ru/soune/nocopy/adminpanel/handler/AdminUserHandler.java +++ b/src/main/java/ru/soune/nocopy/adminpanel/handler/AdminUserHandler.java @@ -33,6 +33,8 @@ public class AdminUserHandler implements RequestHandler { private final AdminUserService adminUserService; + private final JwtUtil jwtUtil; + private final AdminSectionPermissionService permissionService; private final HttpServletRequest httpServletRequest; @@ -45,6 +47,7 @@ public class AdminUserHandler implements RequestHandler { String action = adminRequest.getAction(); return switch (action) { + case "login" -> handleLogin(request, adminRequest); case "create" -> handleCreate(request, adminRequest); case "get_all" -> handleGetAll(request, adminRequest); case "get_by_id" -> handleGetById(request, adminRequest); @@ -58,6 +61,54 @@ public class AdminUserHandler implements RequestHandler { }; } + private BaseResponse handleLogin(BaseRequest request, AdminUserRequest adminRequest) { + String email = adminRequest.getEmail(); + String password = adminRequest.getPassword(); + + boolean authenticated = adminUserService.authenticate(email, password); + + if (!authenticated) { + return BaseResponse.builder() + .msgId(request.getMsgId()) + .messageCode(MessageCode.INVALID_CREDENTIALS.getCode()) + .messageDesc(MessageCode.INVALID_CREDENTIALS.getDescription()) + .build(); + } + + try { + AdminUser admin = adminUserService.findByEmail(email); + + if (!admin.getIsActive()) { + return BaseResponse.builder() + .msgId(request.getMsgId()) + .messageCode(MessageCode.ADMIN_INACTIVE.getCode()) + .messageDesc(MessageCode.ADMIN_INACTIVE.getDescription()) + .build(); + } + + String token = jwtUtil.generateToken(admin.getEmail(), admin.getId()); + + LoginResponse loginResponse = LoginResponse.builder() + .success(true) + .token(token) + .admin(convertToResponse(admin)) + .build(); + + return BaseResponse.builder() + .msgId(request.getMsgId()) + .messageCode(MessageCode.SUCCESS.getCode()) + .messageDesc(MessageCode.SUCCESS.getDescription()) + .messageBody(loginResponse) + .build(); + } catch (AdminUserNotFoundException e) { + return BaseResponse.builder() + .msgId(request.getMsgId()) + .messageCode(MessageCode.ADMIN_NOT_FOUND.getCode()) + .messageDesc(MessageCode.ADMIN_NOT_FOUND.getDescription()) + .build(); + } + } + private BaseResponse handleCreate(BaseRequest request, AdminUserRequest adminRequest) { try { Long currentUserId = (Long) httpServletRequest.getAttribute("userId"); -- 2.54.0 From 0c432b5aa7a234f35ff5f2b524f07c2d3d8fcdb1 Mon Sep 17 00:00:00 2001 From: backdev-1 Date: Fri, 5 Jun 2026 22:57:17 +0700 Subject: [PATCH 45/47] add internal feign key --- .../ru/soune/nocopy/adminpanel/util/JwtAuthFilter.java | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/main/java/ru/soune/nocopy/adminpanel/util/JwtAuthFilter.java b/src/main/java/ru/soune/nocopy/adminpanel/util/JwtAuthFilter.java index 31304a2..5b78e9b 100644 --- a/src/main/java/ru/soune/nocopy/adminpanel/util/JwtAuthFilter.java +++ b/src/main/java/ru/soune/nocopy/adminpanel/util/JwtAuthFilter.java @@ -6,17 +6,22 @@ import jakarta.servlet.ServletException; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import lombok.RequiredArgsConstructor; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.authority.SimpleGrantedAuthority; +import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.stereotype.Component; import org.springframework.web.filter.OncePerRequestFilter; import ru.soune.nocopy.adminpanel.dto.BaseResponse; import java.io.IOException; +import java.util.List; @Component @RequiredArgsConstructor public class JwtAuthFilter extends OncePerRequestFilter { private final JwtUtil jwtUtil; + private final ObjectMapper objectMapper; @Override @@ -46,6 +51,11 @@ public class JwtAuthFilter extends OncePerRequestFilter { return; } + UsernamePasswordAuthenticationToken authentication = + new UsernamePasswordAuthenticationToken(jwtUtil.extractEmail(token), null, + List.of(new SimpleGrantedAuthority("ROLE_ADMIN"))); + SecurityContextHolder.getContext().setAuthentication(authentication); + request.setAttribute("userId", jwtUtil.extractUserId(token)); request.setAttribute("email", jwtUtil.extractEmail(token)); -- 2.54.0 From bb54e6802bdf4744cbc24c1867be57ad7867fef0 Mon Sep 17 00:00:00 2001 From: backdev-1 Date: Sat, 6 Jun 2026 10:24:13 +0700 Subject: [PATCH 46/47] add internal feign key --- .../java/ru/soune/nocopy/adminpanel/config/SecurityConfig.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/ru/soune/nocopy/adminpanel/config/SecurityConfig.java b/src/main/java/ru/soune/nocopy/adminpanel/config/SecurityConfig.java index 6742bb4..24f7a59 100644 --- a/src/main/java/ru/soune/nocopy/adminpanel/config/SecurityConfig.java +++ b/src/main/java/ru/soune/nocopy/adminpanel/config/SecurityConfig.java @@ -26,7 +26,7 @@ public class SecurityConfig { session.sessionCreationPolicy(SessionCreationPolicy.STATELESS)) .authorizeHttpRequests(auth -> auth .requestMatchers("/api/admin/login").permitAll() - .requestMatchers("/api/admin").permitAll() +// .requestMatchers("/api/admin").permitAll() .anyRequest().authenticated() ) .addFilterBefore(jwtAuthFilter, UsernamePasswordAuthenticationFilter.class); -- 2.54.0 From 88e50bbedf3725a4d808f9ed69ca357114b3507c Mon Sep 17 00:00:00 2001 From: backdev-1 Date: Thu, 18 Jun 2026 11:55:25 +0700 Subject: [PATCH 47/47] add permissons for update and create template --- .../handler/CreateAdminTemplateHandler.java | 71 +++++++++++++++++++ 1 file changed, 71 insertions(+) diff --git a/src/main/java/ru/soune/nocopy/adminpanel/handler/CreateAdminTemplateHandler.java b/src/main/java/ru/soune/nocopy/adminpanel/handler/CreateAdminTemplateHandler.java index b24356a..e8839ec 100644 --- a/src/main/java/ru/soune/nocopy/adminpanel/handler/CreateAdminTemplateHandler.java +++ b/src/main/java/ru/soune/nocopy/adminpanel/handler/CreateAdminTemplateHandler.java @@ -3,12 +3,16 @@ package ru.soune.nocopy.adminpanel.handler; import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.node.ObjectNode; +import jakarta.servlet.http.HttpServletRequest; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Component; import ru.soune.nocopy.adminpanel.dto.*; import ru.soune.nocopy.adminpanel.entity.AdminCreateTemplate; +import ru.soune.nocopy.adminpanel.entity.AdminSection; import ru.soune.nocopy.adminpanel.service.AdminCreateTemplateService; +import ru.soune.nocopy.adminpanel.service.AdminSectionPermissionService; import ru.soune.nocopy.adminpanel.util.MessageCode; import java.util.Arrays; @@ -24,6 +28,10 @@ public class CreateAdminTemplateHandler implements RequestHandler { private final AdminCreateTemplateService adminCreateTemplateService; + private final AdminSectionPermissionService adminSectionPermissionService; + + private final HttpServletRequest httpServletRequest; + @Override public BaseResponse handle(BaseRequest request) { AdminCreateTemplateRequest adminCreateTemplateRequest = objectMapper.convertValue(request.getMessageBody(), @@ -42,6 +50,7 @@ public class CreateAdminTemplateHandler implements RequestHandler { private BaseResponse handleDelete(BaseRequest request, AdminCreateTemplateRequest adminCreateTemplateRequest) { Long adminCreateTemplateRequestId = adminCreateTemplateRequest.getId(); + Long currentUserId = (Long) httpServletRequest.getAttribute("userId"); if (adminCreateTemplateRequestId == null || !adminCreateTemplateService.existById(adminCreateTemplateRequestId)) { return BaseResponse.builder() @@ -52,6 +61,17 @@ public class CreateAdminTemplateHandler implements RequestHandler { .build(); } + if (!adminSectionPermissionService.canWrite(currentUserId, + AdminSection.STAFF)) { + + return BaseResponse.builder() + .msgId(request.getMsgId()) + .messageCode(MessageCode.PERMISSION_DENIED.getCode()) + .messageDesc(MessageCode.PERMISSION_DENIED.getDescription()) + .messageBody(Map.of("currentUserId", currentUserId)) + .build(); + } + adminCreateTemplateService.deleteTemplate(adminCreateTemplateRequestId); @@ -65,6 +85,7 @@ public class CreateAdminTemplateHandler implements RequestHandler { private BaseResponse handleUpdate(BaseRequest request, AdminCreateTemplateRequest adminCreateTemplateRequest) { Map permissionsMap = adminCreateTemplateRequest.getPermissions(); + Long currentUserId = (Long) httpServletRequest.getAttribute("userId"); if (permissionsMap == null || permissionsMap.isEmpty()) { return BaseResponse.builder() @@ -75,6 +96,17 @@ public class CreateAdminTemplateHandler implements RequestHandler { .build(); } + if (!adminSectionPermissionService.canWrite(currentUserId, + AdminSection.STAFF)) { + + return BaseResponse.builder() + .msgId(request.getMsgId()) + .messageCode(MessageCode.PERMISSION_DENIED.getCode()) + .messageDesc(MessageCode.PERMISSION_DENIED.getDescription()) + .messageBody(Map.of("currentUserId", currentUserId)) + .build(); + } + ObjectNode node = objectMapper.createObjectNode(); for (Map.Entry entry: permissionsMap.entrySet()) { @@ -106,6 +138,7 @@ public class CreateAdminTemplateHandler implements RequestHandler { private BaseResponse handleCreate(BaseRequest request, AdminCreateTemplateRequest adminCreateTemplateRequest) { Map permissionsMap = adminCreateTemplateRequest.getPermissions(); + Long currentUserId = (Long) httpServletRequest.getAttribute("userId"); if (permissionsMap == null || permissionsMap.isEmpty()) { return BaseResponse.builder() @@ -115,6 +148,18 @@ public class CreateAdminTemplateHandler implements RequestHandler { .build(); } + + if (!adminSectionPermissionService.canWrite(currentUserId, + AdminSection.STAFF)) { + + return BaseResponse.builder() + .msgId(request.getMsgId()) + .messageCode(MessageCode.PERMISSION_DENIED.getCode()) + .messageDesc(MessageCode.PERMISSION_DENIED.getDescription()) + .messageBody(Map.of("currentUserId", currentUserId)) + .build(); + } + ObjectNode node = objectMapper.createObjectNode(); for (Map.Entry entry: permissionsMap.entrySet()) { @@ -137,11 +182,25 @@ public class CreateAdminTemplateHandler implements RequestHandler { } private BaseResponse handleGetAll(BaseRequest request) { + Long currentUserId = (Long) httpServletRequest.getAttribute("userId"); + + if (!adminSectionPermissionService.canRead(currentUserId, + AdminSection.STAFF)) { + + return BaseResponse.builder() + .msgId(request.getMsgId()) + .messageCode(MessageCode.PERMISSION_DENIED.getCode()) + .messageDesc(MessageCode.PERMISSION_DENIED.getDescription()) + .messageBody(Map.of("currentUserId", currentUserId)) + .build(); + } + List templateResponses = adminCreateTemplateService.getAllTemplates() .stream() .map(this::convertToResponse) .toList(); + return BaseResponse.builder() .msgId(request.getMsgId()) .messageCode(MessageCode.SUCCESS.getCode()) @@ -152,6 +211,7 @@ public class CreateAdminTemplateHandler implements RequestHandler { private BaseResponse handleGetById(BaseRequest request, AdminCreateTemplateRequest adminCreateTemplateRequest) { Long id = adminCreateTemplateRequest.getId(); + Long currentUserId = (Long) httpServletRequest.getAttribute("userId"); if (id == null || !adminCreateTemplateService.existById(id)) { return BaseResponse.builder() @@ -162,6 +222,17 @@ public class CreateAdminTemplateHandler implements RequestHandler { .build(); } + if (!adminSectionPermissionService.canRead(currentUserId, + AdminSection.STAFF)) { + + return BaseResponse.builder() + .msgId(request.getMsgId()) + .messageCode(MessageCode.PERMISSION_DENIED.getCode()) + .messageDesc(MessageCode.PERMISSION_DENIED.getDescription()) + .messageBody(Map.of("currentUserId", currentUserId)) + .build(); + } + AdminCreateTemplate template = adminCreateTemplateService.getTemplateById(adminCreateTemplateRequest.getId()); return BaseResponse.builder() -- 2.54.0