Commit c8b67725 authored by Bazarbay Tulenov's avatar Bazarbay Tulenov

Merge branch 'master' of http://gitlab.lan.arta.kz/Bazarbay/templateservice...

Merge branch 'master' of http://gitlab.lan.arta.kz/Bazarbay/templateservice into b.tulenov/add_consumer

 Conflicts:
	src/main/java/kz/project/printedFormsService/controller/DocumentsController.java
	src/main/java/kz/project/printedFormsService/service/impl/TemplateServiceImpl.java
	src/main/resources/application.yml
parents 6dd750a8 523acd85
Pipeline #377 failed with stage
...@@ -4,6 +4,7 @@ build/ ...@@ -4,6 +4,7 @@ build/
!gradle/wrapper/gradle-wrapper.jar !gradle/wrapper/gradle-wrapper.jar
!**/src/main/**/build/ !**/src/main/**/build/
!**/src/test/**/build/ !**/src/test/**/build/
*.log
### STS ### ### STS ###
.apt_generated .apt_generated
......
...@@ -31,6 +31,7 @@ dependencies { ...@@ -31,6 +31,7 @@ dependencies {
implementation "org.springframework.boot:spring-boot-starter-actuator" implementation "org.springframework.boot:spring-boot-starter-actuator"
implementation 'org.springframework.boot:spring-boot-starter-security' implementation 'org.springframework.boot:spring-boot-starter-security'
implementation 'org.springframework.boot:spring-boot-starter-oauth2-resource-server' implementation 'org.springframework.boot:spring-boot-starter-oauth2-resource-server'
implementation 'org.springframework.boot:spring-boot-starter-webflux'
implementation 'org.springframework.cloud:spring-cloud-starter-feign:1.4.7.RELEASE' implementation 'org.springframework.cloud:spring-cloud-starter-feign:1.4.7.RELEASE'
implementation 'org.springframework.boot:spring-boot-starter-amqp:3.2.0' implementation 'org.springframework.boot:spring-boot-starter-amqp:3.2.0'
runtimeOnly 'org.postgresql:postgresql:42.6.0' runtimeOnly 'org.postgresql:postgresql:42.6.0'
...@@ -48,7 +49,7 @@ dependencies { ...@@ -48,7 +49,7 @@ dependencies {
testImplementation 'org.junit.jupiter:junit-jupiter-api:5.8.2' testImplementation 'org.junit.jupiter:junit-jupiter-api:5.8.2'
testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.8.2' testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.8.2'
implementation 'org.modelmapper:modelmapper:3.2.0' implementation 'org.modelmapper:modelmapper:3.2.0'
implementation 'commons-fileupload:commons-fileupload:1.4' //implementation 'commons-fileupload:commons-fileupload:1.4'
implementation 'commons-codec:commons-codec:1.16.0' implementation 'commons-codec:commons-codec:1.16.0'
implementation group: 'javax.validation', name: 'validation-api', version: '2.0.1.Final' implementation group: 'javax.validation', name: 'validation-api', version: '2.0.1.Final'
implementation 'org.jetbrains:annotations:24.0.1' implementation 'org.jetbrains:annotations:24.0.1'
......
...@@ -29,8 +29,10 @@ services: ...@@ -29,8 +29,10 @@ services:
- SPRING_DATASOURCE_URL=jdbc:postgresql://postgres:5432/template_db - SPRING_DATASOURCE_URL=jdbc:postgresql://postgres:5432/template_db
- KEYCLOAK_URI=https://idp.applatform.qaztech.gov.kz - KEYCLOAK_URI=https://idp.applatform.qaztech.gov.kz
- KEYCLOAK_CLIENT_SECRET=1NYLMNlWXpPDW3QKeZ4VjlY76DuzNtaB - KEYCLOAK_CLIENT_SECRET=1NYLMNlWXpPDW3QKeZ4VjlY76DuzNtaB
- GITLAB_BASE_PATH=http://gitlab.lan.arta.kz
- GITLAB_TOKEN=zif-LhgdzuLtpNW7uxYs
networks: networks:
printform: printform:
external: true external: true
name: printform name: printform
\ No newline at end of file
...@@ -3,6 +3,7 @@ package kz.project.printedFormsService.config; ...@@ -3,6 +3,7 @@ package kz.project.printedFormsService.config;
import kz.project.printedFormsService.controller.DTemplateTypeController; import kz.project.printedFormsService.controller.DTemplateTypeController;
import kz.project.printedFormsService.controller.DocumentsController; import kz.project.printedFormsService.controller.DocumentsController;
import kz.project.printedFormsService.controller.GitlabTemplateController;
import kz.project.printedFormsService.controller.TemplateController; import kz.project.printedFormsService.controller.TemplateController;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
...@@ -46,6 +47,7 @@ public class SecurityConfiguration { ...@@ -46,6 +47,7 @@ public class SecurityConfiguration {
http.sessionManagement(sm -> sm.sessionCreationPolicy(SessionCreationPolicy.STATELESS)); http.sessionManagement(sm -> sm.sessionCreationPolicy(SessionCreationPolicy.STATELESS));
http.csrf(AbstractHttpConfigurer::disable); http.csrf(AbstractHttpConfigurer::disable);
http.anonymous(AbstractHttpConfigurer::disable);
http.exceptionHandling(eh -> eh.authenticationEntryPoint((request, response, authException) -> { http.exceptionHandling(eh -> eh.authenticationEntryPoint((request, response, authException) -> {
response.addHeader(HttpHeaders.WWW_AUTHENTICATE, "Bearer realm=\"Restricted Content\""); response.addHeader(HttpHeaders.WWW_AUTHENTICATE, "Bearer realm=\"Restricted Content\"");
...@@ -56,9 +58,7 @@ public class SecurityConfiguration { ...@@ -56,9 +58,7 @@ public class SecurityConfiguration {
.requestMatchers("/actuator/health/readiness", .requestMatchers("/actuator/health/readiness",
"/actuator/health/liveness", "/actuator/health/liveness",
"/api-docs/**", "/api-docs/**",
"/swagger-ui/**", "/swagger-ui/**"
BASE_PATH + TemplateController.GET_TEMPLATE,
DTemplateTypeController.BASE_PATH+DTemplateTypeController.GET_ALL
) )
.permitAll() .permitAll()
...@@ -86,7 +86,19 @@ public class SecurityConfiguration { ...@@ -86,7 +86,19 @@ public class SecurityConfiguration {
.requestMatchers(DocumentsController.BY_TEMPLATE) .requestMatchers(DocumentsController.BY_TEMPLATE)
.hasAnyRole(CREATOR, EDITOR, DELETE, ADMIN) .hasAnyRole(CREATOR, EDITOR, DELETE, ADMIN)
.anyRequest().authenticated() .requestMatchers(GitlabTemplateController.SAVE)
.hasAnyRole(CREATOR, ADMIN)
.requestMatchers(GitlabTemplateController.EDIT)
.hasAnyRole(EDITOR, ADMIN)
.requestMatchers(
BASE_PATH + TemplateController.GET_TEMPLATE,
DTemplateTypeController.BASE_PATH + DTemplateTypeController.GET_ALL)
.permitAll()
.anyRequest().fullyAuthenticated()
); );
......
package kz.project.printedFormsService.config; package kz.project.printedFormsService.config;
import kz.project.printedFormsService.exception.AccessDeniedException;
import lombok.experimental.UtilityClass; import lombok.experimental.UtilityClass;
import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.core.context.SecurityContextHolder;
...@@ -25,6 +26,13 @@ public class SecurityContextUtils { ...@@ -25,6 +26,13 @@ public class SecurityContextUtils {
} }
public static String getUsername() {
return SecurityContextHolder
.getContext()
.getAuthentication()
.getName();
}
public static Map<String, List<String>> getProjectRoleMap() { public static Map<String, List<String>> getProjectRoleMap() {
return SecurityContextHolder return SecurityContextHolder
...@@ -35,6 +43,7 @@ public class SecurityContextUtils { ...@@ -35,6 +43,7 @@ public class SecurityContextUtils {
.map(GrantedAuthority::getAuthority) .map(GrantedAuthority::getAuthority)
.map(role -> role.replace("ROLE_", "")) .map(role -> role.replace("ROLE_", ""))
.filter(role -> role.contains(PROJECT_ROLE_SPLITTER)) .filter(role -> role.contains(PROJECT_ROLE_SPLITTER))
.filter(role -> !role.contains("gitlab_"))
.collect(Collectors.toMap( .collect(Collectors.toMap(
role -> role.split(PROJECT_ROLE_SPLITTER)[0], role -> role.split(PROJECT_ROLE_SPLITTER)[0],
role -> new ArrayList<>(List.of(role.split(PROJECT_ROLE_SPLITTER)[1])), role -> new ArrayList<>(List.of(role.split(PROJECT_ROLE_SPLITTER)[1])),
...@@ -45,4 +54,18 @@ public class SecurityContextUtils { ...@@ -45,4 +54,18 @@ public class SecurityContextUtils {
) )
); );
} }
public static String getGitlabProjectBranchFromRole() {
return SecurityContextHolder
.getContext()
.getAuthentication()
.getAuthorities()
.stream()
.map(GrantedAuthority::getAuthority)
.filter(role -> role.contains("gitlab"))
.map(role -> role.replace("ROLE_gitlab_", ""))
.findFirst()
.orElseThrow(() -> new AccessDeniedException("Не указана роль для доступа к gitlab"));
}
} }
...@@ -3,9 +3,14 @@ package kz.project.printedFormsService.controller; ...@@ -3,9 +3,14 @@ package kz.project.printedFormsService.controller;
import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag; import io.swagger.v3.oas.annotations.tags.Tag;
import kz.project.printedFormsService.data.dto.DTemplateTypeDto; import kz.project.printedFormsService.data.dto.DTemplateTypeDto;
import kz.project.printedFormsService.logging.ProcessLogger;
import kz.project.printedFormsService.service.DTemplateTypeService; import kz.project.printedFormsService.service.DTemplateTypeService;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
...@@ -16,18 +21,31 @@ import static kz.project.printedFormsService.controller.DTemplateTypeController. ...@@ -16,18 +21,31 @@ import static kz.project.printedFormsService.controller.DTemplateTypeController.
@RestController @RestController
@RequestMapping(BASE_PATH) @RequestMapping(BASE_PATH)
@RequiredArgsConstructor
@Slf4j @Slf4j
@Tag(name = "DTemplate Controller", description = "API TemplateService") @Tag(name = "DTemplate Controller", description = "API TemplateService")
public class DTemplateTypeController { public class DTemplateTypeController {
private static final Logger LOGGER = LoggerFactory.getLogger(DTemplateTypeController.class);
public final static String BASE_PATH = "/api/dict"; public final static String BASE_PATH = "/api/dict";
public final static String GET_ALL = "/get/all"; public final static String GET_ALL = "/get/all";
private final DTemplateTypeService service; private final DTemplateTypeService service;
private ProcessLogger processLogger;
@GetMapping("get/all") public DTemplateTypeController(DTemplateTypeService service, ProcessLogger processLogger) {
this.service = service;
this.processLogger = processLogger;
}
@GetMapping("get/all")
@Operation(description = "Метод для получения шаблона по идентификатору") @Operation(description = "Метод для получения шаблона по идентификатору")
public List<DTemplateTypeDto> getDict() { public ResponseEntity getDict() {
return service.getAllTemplateType(); try {
List<DTemplateTypeDto> dtoList = service.getAllTemplateType();
return ResponseEntity.ok(dtoList);
} catch (Exception e){
LOGGER.error(e.getMessage(), e);
processLogger.error(TemplateController.class, new Throwable().getStackTrace()[0].getMethodName(), "Получение типов шаблонов");
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(e.getMessage());
}
} }
} }
...@@ -12,9 +12,13 @@ import kz.project.printedFormsService.data.dto.DocumentByDateDto; ...@@ -12,9 +12,13 @@ import kz.project.printedFormsService.data.dto.DocumentByDateDto;
import kz.project.printedFormsService.data.dto.DocumentByTemplateDto; import kz.project.printedFormsService.data.dto.DocumentByTemplateDto;
import kz.project.printedFormsService.data.dto.TemplateDto; import kz.project.printedFormsService.data.dto.TemplateDto;
import kz.project.printedFormsService.exception.ValidationException; import kz.project.printedFormsService.exception.ValidationException;
import kz.project.printedFormsService.logging.ProcessLogger;
import kz.project.printedFormsService.service.DocumentsService; import kz.project.printedFormsService.service.DocumentsService;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.aspectj.apache.bcel.generic.LocalVariableGen;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.format.annotation.DateTimeFormat; import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
...@@ -27,17 +31,23 @@ import java.util.List; ...@@ -27,17 +31,23 @@ import java.util.List;
import java.util.Map; import java.util.Map;
@RestController @RestController
@RequiredArgsConstructor
@Slf4j @Slf4j
@Tag(name = "Documents Controller", description = "API DocumentsService") @Tag(name = "Documents Controller", description = "API DocumentsService")
public class DocumentsController { public class DocumentsController {
private static final Logger LOGGER = LoggerFactory.getLogger(DocumentsController.class);
private final DocumentsService documentsService; private final DocumentsService documentsService;
public static final String BASE_PATH = "/api/documents"; public static final String BASE_PATH = "/api/documents";
public static final String BY_DAY = BASE_PATH + "/by-day"; public static final String BY_DAY = BASE_PATH + "/by-day";
public static final String BY_TEMPLATE = BASE_PATH + "/by-template"; public static final String BY_TEMPLATE = BASE_PATH + "/by-template";
private static final String UPDATE_DOCUMENT = BASE_PATH+"/saveDocument"; private static final String UPDATE_DOCUMENT = BASE_PATH+"/saveDocument";
private ProcessLogger processLogger;
public DocumentsController(DocumentsService documentsService,
ProcessLogger processLogger) {
this.documentsService = documentsService;
this.processLogger = processLogger;
}
@GetMapping(BY_DAY) @GetMapping(BY_DAY)
@Operation(description = "Метод для получения данных по общему количеству генерации по всем доступным пользователю шаблонам") @Operation(description = "Метод для получения данных по общему количеству генерации по всем доступным пользователю шаблонам")
...@@ -64,18 +74,24 @@ public class DocumentsController { ...@@ -64,18 +74,24 @@ public class DocumentsController {
}) })
}) })
public ResponseEntity<DocumentByDateDto> getDocumentsCountByDay( public ResponseEntity getDocumentsCountByDay(
@RequestParam("startDate") @RequestParam("startDate")
@DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate startDate, @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate startDate,
@RequestParam("endDate") @RequestParam("endDate")
@DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate endDate) { @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate endDate) {
Map<String, List<String>> projectRoleMap = SecurityContextUtils.getProjectRoleMap(); try {
DocumentByDateDto documentsByDate = documentsService.getDocumentCountsByDate(startDate, endDate, projectRoleMap.keySet()); processLogger.start(TemplateController.class, new Throwable().getStackTrace()[0].getMethodName(), "Получение данных генераций всех отчётов за диапазон времени");
return ResponseEntity.ok(documentsByDate); Map<String, List<String>> projectRoleMap = SecurityContextUtils.getProjectRoleMap();
DocumentByDateDto documentsByDate = documentsService.getDocumentCountsByDate(startDate, endDate, projectRoleMap.keySet());
processLogger.finish(TemplateController.class, new Throwable().getStackTrace()[0].getMethodName(), "Получение данных генераций всех отчётов за диапазон времени");
return ResponseEntity.ok(documentsByDate);
} catch (Exception e){
LOGGER.error(e.getMessage(), e);
processLogger.start(TemplateController.class, new Throwable().getStackTrace()[0].getMethodName(), "Получение данных генераций всех отчётов за диапазон времени");
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(e.getMessage());
}
} }
@GetMapping(BY_TEMPLATE) @GetMapping(BY_TEMPLATE)
@Operation(description = "Метод для получения данных по общему количеству генерации по каждому доступному пользователю шаблонам") @Operation(description = "Метод для получения данных по общему количеству генерации по каждому доступному пользователю шаблонам")
@ApiResponses(value = { @ApiResponses(value = {
...@@ -88,8 +104,6 @@ public class DocumentsController { ...@@ -88,8 +104,6 @@ public class DocumentsController {
schema = @Schema(implementation = DocumentByTemplateDto.class)) schema = @Schema(implementation = DocumentByTemplateDto.class))
}), }),
@ApiResponse( @ApiResponse(
responseCode = "400", responseCode = "400",
description = "Ошибка валидации параметров запроса", description = "Ошибка валидации параметров запроса",
...@@ -101,13 +115,21 @@ public class DocumentsController { ...@@ -101,13 +115,21 @@ public class DocumentsController {
}) })
}) })
public ResponseEntity<DocumentByTemplateDto> getDocumentsCountByTemplate( public ResponseEntity getDocumentsCountByTemplate(
@RequestParam("startDate") @RequestParam("startDate")
@DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate startDate, @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate startDate,
@RequestParam("endDate") @RequestParam("endDate")
@DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate endDate) { @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate endDate) {
Map<String, List<String>> projectRoleMap = SecurityContextUtils.getProjectRoleMap(); try {
DocumentByTemplateDto documentCountsByTemplate = documentsService.getDocumentCountsByTemplate(startDate, endDate, projectRoleMap.keySet()); processLogger.start(TemplateController.class, new Throwable().getStackTrace()[0].getMethodName(), "Получение данных генераций по шаблону за диапазон времени");
return ResponseEntity.ok(documentCountsByTemplate); Map<String, List<String>> projectRoleMap = SecurityContextUtils.getProjectRoleMap();
DocumentByTemplateDto documentCountsByTemplate = documentsService.getDocumentCountsByTemplate(startDate, endDate, projectRoleMap.keySet());
processLogger.start(TemplateController.class, new Throwable().getStackTrace()[0].getMethodName(), "Получение данных генераций по шаблону за диапазон времени");
return ResponseEntity.ok(documentCountsByTemplate);
} catch (Exception e){
LOGGER.error(e.getMessage(), e);
processLogger.start(TemplateController.class, new Throwable().getStackTrace()[0].getMethodName(), "Получение данных генераций по шаблону за диапазон времени");
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(e.getMessage());
}
} }
} }
package kz.project.printedFormsService.controller;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import io.swagger.v3.oas.annotations.tags.Tag;
import kz.project.printedFormsService.data.dto.GitlabUploadRequest;
import kz.project.printedFormsService.data.dto.TemplateDto;
import kz.project.printedFormsService.data.dto.TemplateResponseDto;
import kz.project.printedFormsService.exception.ValidationException;
import kz.project.printedFormsService.service.GitlabTemplateService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequiredArgsConstructor
@Slf4j
@Tag(name = "Gitlab Template Controller", description = "API GitlabTemplateService")
public class GitlabTemplateController {
public static final String BASE_PATH = "/api/gitlabTemplate";
public static final String SAVE = BASE_PATH + "/save";
public static final String EDIT = BASE_PATH + "/edit";
private final GitlabTemplateService gitlabTemplateService;
@PostMapping(SAVE)
@Operation(description = "Метод сохранения шаблона")
@ApiResponses(value = {
@ApiResponse(
responseCode = "200",
description = "Данные получены успешно",
content = {
@Content(
mediaType = "application/json",
schema = @Schema(implementation = TemplateDto.class))
}),
@ApiResponse(
responseCode = "400",
description = "Ошибка сервиса",
content = {
@Content(
mediaType = "application/json",
schema = @Schema(implementation = ValidationException.class))
})
})
public ResponseEntity<TemplateDto> saveTemplate(
@RequestBody @Validated GitlabUploadRequest request
) {
return ResponseEntity.ok(gitlabTemplateService.saveFromGitlab(request));
}
@PutMapping(EDIT)
@Operation(description = "Метод редактирования шаблона")
@ApiResponses(value = {
@ApiResponse(
responseCode = "200",
description = "Данные получены успешно",
content = {
@Content(
mediaType = "application/json",
schema = @Schema(implementation = TemplateDto.class))
}),
@ApiResponse(
responseCode = "400",
description = "Ошибка сервиса",
content = {
@Content(
mediaType = "application/json",
schema = @Schema(implementation = ValidationException.class))
})
})
public ResponseEntity<TemplateResponseDto> editTemplate(
@RequestBody @Validated GitlabUploadRequest request
) {
return ResponseEntity.ok(gitlabTemplateService.updateFromGitlab(request));
}
}
package kz.project.printedFormsService.controller; package kz.project.printedFormsService.controller;
;
import kz.project.printedFormsService.exception.ValidationException;
import kz.project.printedFormsService.data.dto.ResponseErrorDto; import kz.project.printedFormsService.data.dto.ResponseErrorDto;
import kz.project.printedFormsService.exception.AccessDeniedException;
import kz.project.printedFormsService.exception.ValidationException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ControllerAdvice; import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler; import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler;
;
@ControllerAdvice @ControllerAdvice
@Slf4j
public class RestErrorController extends ResponseEntityExceptionHandler { public class RestErrorController extends ResponseEntityExceptionHandler {
@ExceptionHandler(ValidationException.class) @ExceptionHandler(ValidationException.class)
//@ResponseStatus(code = HttpStatus.BAD_REQUEST, reason = "Remote service response") //@ResponseStatus(code = HttpStatus.BAD_REQUEST, reason = "Remote service response")
protected ResponseEntity<ResponseErrorDto> handleThereIsNoSuchUserException(ValidationException err) { protected ResponseEntity<ResponseErrorDto> handleThereIsNoSuchUserException(ValidationException err) {
err.printStackTrace(); err.printStackTrace();
return new ResponseEntity<>(new ResponseErrorDto(err.getMessage(),err.getCode()),HttpStatus.BAD_REQUEST); return new ResponseEntity<>(new ResponseErrorDto(err.getMessage(), err.getCode()), HttpStatus.BAD_REQUEST);
}
@ExceptionHandler(AccessDeniedException.class)
protected ResponseEntity<ResponseErrorDto> handleAccessDeniedException(AccessDeniedException err) {
log.warn("Access denied", err);
return new ResponseEntity<>(new ResponseErrorDto(err.getMessage(), HttpStatus.FORBIDDEN.value()), HttpStatus.FORBIDDEN);
} }
} }
...@@ -3,6 +3,8 @@ package kz.project.printedFormsService.converter; ...@@ -3,6 +3,8 @@ package kz.project.printedFormsService.converter;
import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import com.jayway.jsonpath.JsonPath; import com.jayway.jsonpath.JsonPath;
import com.nimbusds.jwt.JWT;
import com.nimbusds.jwt.JWTParser;
import org.springframework.core.convert.converter.Converter; import org.springframework.core.convert.converter.Converter;
import org.springframework.security.authentication.AbstractAuthenticationToken; import org.springframework.security.authentication.AbstractAuthenticationToken;
import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.GrantedAuthority;
...@@ -11,10 +13,21 @@ import org.springframework.security.oauth2.jwt.Jwt; ...@@ -11,10 +13,21 @@ import org.springframework.security.oauth2.jwt.Jwt;
import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationToken; import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationToken;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import java.text.ParseException;
import java.util.*; import java.util.*;
@Component @Component
public class JwtAuthConverter implements Converter<Jwt, AbstractAuthenticationToken> { public class JwtAuthConverter implements Converter<Jwt, AbstractAuthenticationToken> {
public static Map<String, Object> getTokenClaims(String token) throws ParseException {
JWT parsedJwt = JWTParser.parse(token);
return parsedJwt.getJWTClaimsSet().getClaims();
}
public static String getUsername(String token) throws ParseException {
Map<String, Object> claims = getTokenClaims(token);
if (claims == null) return null;
return (String) claims.get("preferred_username");
}
@Override @Override
public AbstractAuthenticationToken convert(Jwt jwt) { public AbstractAuthenticationToken convert(Jwt jwt) {
...@@ -26,15 +39,20 @@ public class JwtAuthConverter implements Converter<Jwt, AbstractAuthenticationTo ...@@ -26,15 +39,20 @@ public class JwtAuthConverter implements Converter<Jwt, AbstractAuthenticationTo
private Collection<GrantedAuthority> extractAuthorities(Jwt jwt) { private Collection<GrantedAuthority> extractAuthorities(Jwt jwt) {
if (jwt.getClaim("resource_access") != null) { if (jwt.getClaim("resource_access") != null) {
Map<String, Map<String,Object>> resourceAccess = jwt.getClaim("resource_access"); Map<String, Map<String, Object>> resourceAccess = jwt.getClaim("resource_access");
if (resourceAccess.containsKey("print_form")){ if (resourceAccess.containsKey("print_form")) {
ObjectMapper mapper = new ObjectMapper(); ObjectMapper mapper = new ObjectMapper();
List<String> roles = mapper.convertValue(resourceAccess.get("print_form").get("roles"), new TypeReference<>() { List<String> roles = mapper.convertValue(resourceAccess.get("print_form").get("roles"), new TypeReference<>() {
}); });
Set<GrantedAuthority> authorities = new HashSet<>(); Set<GrantedAuthority> authorities = new HashSet<>();
for (String role : roles) { for (String role : roles) {
authorities.add(new SimpleGrantedAuthority("ROLE_" + role.substring(role.lastIndexOf('_')+1))); if (role.contains("gitlab")) {
authorities.add(new SimpleGrantedAuthority("ROLE_" + role));
} else {
authorities.add(new SimpleGrantedAuthority("ROLE_" + role));
authorities.add(new SimpleGrantedAuthority("ROLE_" + role.substring(role.lastIndexOf('_') + 1)));
}
} }
return authorities; return authorities;
......
package kz.project.printedFormsService.data.dto;
import lombok.Data;
import lombok.RequiredArgsConstructor;
import org.jetbrains.annotations.NotNull;
import org.springframework.web.multipart.MultipartFile;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.InputStream;
@Data
@RequiredArgsConstructor
public class GitlabMultipartFile implements MultipartFile {
private final String name;
private final String originalFilename;
private final String contentType;
private final byte[] bytes;
@Override
public @NotNull String getName() {
return name;
}
@Override
public String getOriginalFilename() {
return originalFilename;
}
@Override
public String getContentType() {
return contentType;
}
@Override
public boolean isEmpty() {
return bytes.length == 0;
}
@Override
public long getSize() {
return bytes.length;
}
@Override
public byte @NotNull [] getBytes() {
return bytes;
}
@Override
public @NotNull InputStream getInputStream() {
return new ByteArrayInputStream(bytes);
}
@Override
public void transferTo(File dest) {
}
}
package kz.project.printedFormsService.data.dto;
import jakarta.validation.constraints.NotBlank;
import lombok.Data;
@Data
public class GitlabUploadRequest {
@NotBlank
private String repository;
@NotBlank
private String fileDataPath;
private String fileHeaderPath;
@NotBlank
private String fileDtoPath;
}
...@@ -3,6 +3,7 @@ package kz.project.printedFormsService.data.dto; ...@@ -3,6 +3,7 @@ package kz.project.printedFormsService.data.dto;
import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotBlank;
import kz.project.printedFormsService.data.entity.TemplateEntity; import kz.project.printedFormsService.data.entity.TemplateEntity;
import kz.project.printedFormsService.data.entity.TemplateEntityVersion;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Builder; import lombok.Builder;
import lombok.Data; import lombok.Data;
...@@ -57,7 +58,7 @@ public class TemplateDto { ...@@ -57,7 +58,7 @@ public class TemplateDto {
.code(te.getCode()) .code(te.getCode())
.status(te.getStatus()) .status(te.getStatus())
.templateFile(new TemplateFileDataDto(te.getTemplate().getId(),te.getTemplate().getName(), te.getTemplate().getData())) .templateFile(new TemplateFileDataDto(te.getTemplate().getId(),te.getTemplate().getName(), te.getTemplate().getData()))
.headerFile(te.getTempleateHeader()!=null?new TemplateFileDataDto(te.getTempleateHeader().getId(),te.getTempleateHeader().getName(), te.getTempleateHeader().getData()):null) .headerFile(te.getTemplateHeader()!=null?new TemplateFileDataDto(te.getTemplateHeader().getId(),te.getTemplateHeader().getName(), te.getTemplateHeader().getData()):null)
.type(te.getType().getCode()) .type(te.getType().getCode())
.project(te.getProject()) .project(te.getProject())
.version(te.getVersion()) .version(te.getVersion())
...@@ -72,7 +73,7 @@ public class TemplateDto { ...@@ -72,7 +73,7 @@ public class TemplateDto {
.status(te.getStatus()) .status(te.getStatus())
.project(te.getProject()) .project(te.getProject())
.templateFile(new TemplateFileDataDto(te.getTemplate().getId(),te.getTemplate().getName(), te.getTemplate().getData())) .templateFile(new TemplateFileDataDto(te.getTemplate().getId(),te.getTemplate().getName(), te.getTemplate().getData()))
.headerFile(te.getTempleateHeader()!=null?new TemplateFileDataDto(te.getTempleateHeader().getId(),te.getTempleateHeader().getName(), te.getTempleateHeader().getData()):null) .headerFile(te.getTemplateHeader()!=null?new TemplateFileDataDto(te.getTemplateHeader().getId(),te.getTemplateHeader().getName(), te.getTemplateHeader().getData()):null)
.type(te.getType().getCode()) .type(te.getType().getCode())
.version(te.getVersion()) .version(te.getVersion())
.build(); .build();
...@@ -99,6 +100,24 @@ public class TemplateDto { ...@@ -99,6 +100,24 @@ public class TemplateDto {
return new PageImpl<>(dtos, PageRequest.of(all.getNumber(),all.getSize()),all.getTotalElements()); return new PageImpl<>(dtos, PageRequest.of(all.getNumber(),all.getSize()),all.getTotalElements());
} }
public static Page<TemplateDto> toDtoList(Page<TemplateEntity> all, Page<TemplateEntityVersion> versions){
if(all.getContent() == null && versions.getContent() == null) return null;
List<TemplateDto> dtos = new ArrayList<>();
if (all.getContent() != null){
for (TemplateEntity te:all.getContent()) {
dtos.add(TemplateDto.toDtoAll(te));
}
}
if (versions.getContent() != null){
for (TemplateEntityVersion ver:versions.getContent()) {
dtos.add(TemplateDto.toDtoAll(new TemplateEntity(ver)));
}
}
return new PageImpl<>(dtos, PageRequest.of(all.getNumber(),all.getSize()),all.getTotalElements());
}
@Data @Data
@AllArgsConstructor @AllArgsConstructor
@NoArgsConstructor @NoArgsConstructor
......
...@@ -46,7 +46,7 @@ public class TemplateResponseDto { ...@@ -46,7 +46,7 @@ public class TemplateResponseDto {
.status(te.getStatus()) .status(te.getStatus())
.project(te.getProject()) .project(te.getProject())
.templateFile(new TemplateDto.TemplateFileDataDto(te.getTemplate().getId(), te.getTemplate().getName(), te.getTemplate().getData())) .templateFile(new TemplateDto.TemplateFileDataDto(te.getTemplate().getId(), te.getTemplate().getName(), te.getTemplate().getData()))
.headerFile(te.getTempleateHeader() != null ? new TemplateDto.TemplateFileDataDto(te.getTempleateHeader().getId(), te.getTempleateHeader().getName(), te.getTempleateHeader().getData()) : null) .headerFile(te.getTemplateHeader() != null ? new TemplateDto.TemplateFileDataDto(te.getTemplateHeader().getId(), te.getTemplateHeader().getName(), te.getTemplateHeader().getData()) : null)
.type(te.getType().getCode()) .type(te.getType().getCode())
.version(te.getVersion()) .version(te.getVersion())
.build(); .build();
......
...@@ -2,11 +2,9 @@ package kz.project.printedFormsService.data.entity; ...@@ -2,11 +2,9 @@ package kz.project.printedFormsService.data.entity;
import jakarta.persistence.*; import jakarta.persistence.*;
import kz.project.printedFormsService.data.entity.dict.DTemplateType; import kz.project.printedFormsService.data.entity.dict.DTemplateType;
import lombok.Data;
@Entity @Entity
@Table(name = "template", schema = "template_schema") @Table(name = "template", schema = "template_schema")
@Data
public class TemplateEntity { public class TemplateEntity {
@Id @Id
@GeneratedValue(strategy = GenerationType.IDENTITY) @GeneratedValue(strategy = GenerationType.IDENTITY)
...@@ -19,9 +17,130 @@ public class TemplateEntity { ...@@ -19,9 +17,130 @@ public class TemplateEntity {
@ManyToOne @ManyToOne
private DTemplateType type; private DTemplateType type;
@OneToOne @OneToOne
private TemplateFileInfoEntity template; private TemplateFileInfoEntity template;
@OneToOne @OneToOne
private TemplateFileInfoEntity templeateHeader; private TemplateFileInfoEntity templateHeader;
public TemplateEntity() {}
public TemplateEntity(TemplateEntityVersion version){
this.id = version.getId();
this.code = version.getCode();
this.name = version.getName();
this.status = version.getStatus();
this.project = version.getProject();
this.version = version.getVersion();
this.type = version.getType();
this.template = version.getTemplate();
this.templateHeader = version.getTemplateHeader();
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Boolean getStatus() {
return status;
}
public void setStatus(Boolean status) {
this.status = status;
}
public String getProject() {
return project;
}
public void setProject(String project) {
this.project = project;
}
public Integer getVersion() {
return version;
}
public void setVersion(Integer version) {
this.version = version;
}
public DTemplateType getType() {
return type;
}
public void setType(DTemplateType type) {
this.type = type;
}
public TemplateFileInfoEntity getTemplate() {
return template;
}
public void setTemplate(TemplateFileInfoEntity template) {
this.template = template;
}
public TemplateFileInfoEntity getTemplateHeader() {
return templateHeader;
}
public void setTemplateHeader(TemplateFileInfoEntity templateHeader) {
this.templateHeader = templateHeader;
}
@Override
public boolean equals(Object o){
if (this == o) return true;
if (o == null || !(o instanceof TemplateEntity)) return false;
TemplateEntity other = (TemplateEntity) o;
/* Примитивы */
boolean isCodeEqual = this.code == other.getCode() || (this.code != null && this.code.equals(other.getCode()));
boolean isNameEqual = this.name == other.getName() || (this.name != null && this.name.equals(other.getName()));
boolean isStatusEqual = this.status == other.getStatus() || (this.status != null && this.status.equals(other.getStatus()));
boolean isProjectEqual = this.project == other.getProject() || (this.project != null && this.project.equals(other.getProject()));
/* Сложные типы */
boolean isTypeEqual = this.type == other.getType() || (this.type != null && this.type.equals(other.getType()));
boolean isTemplateEqual = this.template == other.getTemplate() || (this.template != null && this.template.equals(other.getTemplate()));
boolean isHeaderEqual = this.templateHeader == other.getTemplateHeader() || (this.templateHeader != null && this.templateHeader.equals(other.getTemplateHeader()));
return isCodeEqual && isNameEqual && isStatusEqual && isProjectEqual && isTypeEqual && isTemplateEqual && isHeaderEqual;
}
@Override
public int hashCode(){
int hash = 17;
if (code != null) hash = 31 * hash * code.hashCode();
if (name != null) hash = 31 * hash * name.hashCode();
if (status != null) hash = 31 * hash * status.hashCode();
if (project != null) hash = 31 * hash * project.hashCode();
if (type != null) hash = 31 * hash * type.hashCode();
if (template != null) hash = 31 * hash * template.hashCode();
if (templateHeader != null) hash = 31 * hash * templateHeader.hashCode();
return hash;
}
} }
package kz.project.printedFormsService.data.entity;
import jakarta.persistence.*;
import kz.project.printedFormsService.data.entity.dict.DTemplateType;
@Entity
@Table(name = "template_version", schema = "template_schema")
public class TemplateEntityVersion {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String code;
private String name;
private Boolean status;
private String project;
private Integer version;
@ManyToOne
private DTemplateType type;
@OneToOne
private TemplateFileInfoEntity template;
@OneToOne
private TemplateFileInfoEntity templateHeader;
public TemplateEntityVersion() {}
public TemplateEntityVersion(TemplateEntity entity) {
this.code = entity.getCode();
this.name = entity.getName();
this.status = entity.getStatus();
this.project = entity.getProject();
this.version = entity.getVersion();
this.type = entity.getType();
this.template = entity.getTemplate();
this.templateHeader = entity.getTemplateHeader();
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Boolean getStatus() {
return status;
}
public void setStatus(Boolean status) {
this.status = status;
}
public String getProject() {
return project;
}
public void setProject(String project) {
this.project = project;
}
public Integer getVersion() {
return version;
}
public void setVersion(Integer version) {
this.version = version;
}
public DTemplateType getType() {
return type;
}
public void setType(DTemplateType type) {
this.type = type;
}
public TemplateFileInfoEntity getTemplate() {
return template;
}
public void setTemplate(TemplateFileInfoEntity template) {
this.template = template;
}
public TemplateFileInfoEntity getTemplateHeader() {
return templateHeader;
}
public void setTemplateHeader(TemplateFileInfoEntity templateHeader) {
this.templateHeader = templateHeader;
}
@Override
public boolean equals(Object o){
if (this == o) return true;
if (o == null || !(o instanceof TemplateEntity)) return false;
TemplateEntity other = (TemplateEntity) o;
/* Примитивы */
boolean isCodeEqual = this.code == other.getCode() || (this.code != null && this.code.equals(other.getCode()));
boolean isNameEqual = this.name == other.getName() || (this.name != null && this.name.equals(other.getName()));
boolean isStatusEqual = this.status == other.getStatus() || (this.status != null && this.status.equals(other.getStatus()));
boolean isProjectEqual = this.project == other.getProject() || (this.project != null && this.project.equals(other.getProject()));
/* Сложные типы */
boolean isTypeEqual = this.type == other.getType() || (this.type != null && this.type.equals(other.getType()));
boolean isTemplateEqual = this.template == other.getTemplate() || (this.template != null && this.template.equals(other.getTemplate()));
boolean isHeaderEqual = this.templateHeader == other.getTemplateHeader() || (this.templateHeader != null && this.templateHeader.equals(other.getTemplateHeader()));
return isCodeEqual && isNameEqual && isStatusEqual && isProjectEqual && isTypeEqual && isTemplateEqual && isHeaderEqual;
}
@Override
public int hashCode(){
int hash = 17;
if (code != null) hash = 31 * hash * code.hashCode();
if (name != null) hash = 31 * hash * name.hashCode();
if (status != null) hash = 31 * hash * status.hashCode();
if (project != null) hash = 31 * hash * project.hashCode();
if (type != null) hash = 31 * hash * type.hashCode();
if (template != null) hash = 31 * hash * template.hashCode();
if (templateHeader != null) hash = 31 * hash * templateHeader.hashCode();
return hash;
}
}
...@@ -21,4 +21,34 @@ public class TemplateFileInfoEntity { ...@@ -21,4 +21,34 @@ public class TemplateFileInfoEntity {
private String path; private String path;
private Integer hash; private Integer hash;
private byte[] data; private byte[] data;
@Override
public boolean equals(Object o){
if (this == o) return true;
if (o == null || !(o instanceof TemplateFileInfoEntity)) return false;
TemplateFileInfoEntity other = (TemplateFileInfoEntity) o;
boolean isNameEqual = this.name == other.getName() || (this.name != null && this.name.equals(other.getName()));
boolean isHeaderEqual = this.isHeader == other.getIsHeader() || (this.isHeader != null && this.isHeader.equals(other.getIsHeader()));
boolean isPathEqual = this.path == other.getPath() || (this.path != null && this.path.equals(other.getPath()));
boolean isHashEqual = this.hash == other.getHash() || (this.hash != null && this.hash.equals(other.getHash()));
boolean isDataEqual = this.data == other.getData() || (this.data != null && this.data.equals(other.getData()));
return isNameEqual && isHeaderEqual && isPathEqual && isHashEqual && isDataEqual;
}
@Override
public int hashCode(){
int hashResult = 17;
if (name != null) hashResult = 31 * hashResult * name.hashCode();
if (isHeader != null) hashResult = 31 * hashResult * isHeader.hashCode();
if (path != null) hashResult = 31 * hashResult * path.hashCode();
if (hash != null) hashResult = 31 * hashResult * hash.hashCode();
if (data != null) hashResult = 31 * hashResult * data.hashCode();
return hashResult;
}
} }
...@@ -35,7 +35,7 @@ public class DocumentJdbcRepository { ...@@ -35,7 +35,7 @@ public class DocumentJdbcRepository {
WHERE WHERE
DATE_TRUNC('day',created_at) >= :startDate DATE_TRUNC('day',created_at) >= :startDate
AND DATE_TRUNC('day',created_at) <= :endDate AND DATE_TRUNC('day',created_at) <= :endDate
--AND project in(:projects) AND project in(:projects)
GROUP BY GROUP BY
date date
ORDER BY ORDER BY
...@@ -63,11 +63,11 @@ public class DocumentJdbcRepository { ...@@ -63,11 +63,11 @@ public class DocumentJdbcRepository {
COUNT(1) as count COUNT(1) as count
FROM FROM
template_schema.document d template_schema.document d
inner join template_schema.template t on t.template_id = d.template_id inner join template_schema.template t on t.id = d.template_id
WHERE WHERE
DATE_TRUNC('day',created_at) >= :startDate DATE_TRUNC('day',created_at) >= :startDate
AND DATE_TRUNC('day',created_at) <= :endDate AND DATE_TRUNC('day',created_at) <= :endDate
--AND d.project in(:projects) AND d.project in(:projects)
GROUP BY GROUP BY
d.template_id, t.name d.template_id, t.name
ORDER BY ORDER BY
......
package kz.project.printedFormsService.data.repository;
import kz.project.printedFormsService.data.entity.TemplateEntity;
import kz.project.printedFormsService.data.entity.TemplateEntityVersion;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
@Repository
public interface TemplateVersionRepository extends JpaRepository<TemplateEntityVersion, Long> {
Page<TemplateEntityVersion> findAllByCode(Pageable pageable, String code);
}
package kz.project.printedFormsService.exception;
import lombok.Data;
@Data
public class AccessDeniedException extends RuntimeException {
public AccessDeniedException(String message) {
super(message);
}
}
package kz.project.printedFormsService.logging;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.format.datetime.DateFormatter;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.time.ZoneId;
import java.util.Locale;
@Configuration
public class LoggingConfig {
private static final String DEFAULT_LOCALE = "ru_RU";
private static final String DEFAULT_DATE_FORMAT = "dd:MM:yyyy hh:mm:ss";
@Value("${process-logger.date-format}")
private String dateFormatString;
@Value("${process-logger.locale}")
private String localeString;
@Bean
public DateFormatter dateFormatter(){
return new DateFormatter(dateFormatString != null ? dateFormatString : DEFAULT_DATE_FORMAT);
}
@Bean
public Locale locale(){
return parseLocale(localeString != null ? localeString : DEFAULT_LOCALE);
}
@Bean
public ZoneId zoneId(){
return ZoneId.systemDefault();
}
private Locale parseLocale(String localeString){
String[] localeParts = localeString.split("_");
if (localeParts.length == 1) localeParts[1] = "";
return new Locale(localeParts[0], localeParts[1]);
}
}
package kz.project.printedFormsService.logging;
import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.servlet.http.HttpServletRequest;
import kz.project.printedFormsService.converter.JwtAuthConverter;
import org.apache.tomcat.util.http.fileupload.FileUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.format.datetime.DateFormatter;
import org.springframework.http.HttpHeaders;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileWriter;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.nio.file.attribute.PosixFilePermission;
import java.text.ParseException;
import java.time.Instant;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.util.*;
import java.util.stream.Collectors;
/* Класс для логгирования старта и завершения процессов в формате SIEM и на естественном языке */
@Component
public class ProcessLogger {
private static final Logger LOGGER = LoggerFactory.getLogger(ProcessLogger.class);
private static final String DEFAULT_FILENAME = "siem-processes.log";
private static final int DEFAULT_FILE_SIZE = 100;
private static final String DEFAULT_DELIMITER = " ";
private static final String DEFAULT_START_PREFIX = "Process start: ";
private static final String DEFAULT_FINISH_PREFIX = "Process finish: ";
private static final String DEFAULT_ERROR_PREFIX = "Process error: ";
@Value("${process-logger.file-name}")
private String logFileName;
@Value("${process-logger.file-max-size-mb}")
private int logFileSize;
@Value("${process-logger.delimiter}")
private String delimiter;
@Value("${spring.application.name}")
private String serviceName;
@Value("${process-logger.start-prefix}")
private String startPrefix;
@Value("${process-logger.finish-prefix}")
private String finishPrefix;
@Value("${process-logger.error-prefix}")
private String errorPrefix;
private DateFormatter dateFormatter;
private Locale locale;
private ZoneId zoneId;
public ProcessLogger(DateFormatter dateFormatter, Locale locale, ZoneId zoneId) {
this.dateFormatter = dateFormatter;
this.locale = locale;
this.zoneId = zoneId;
}
public void start(Class javaClass, String processName, String description){
write(javaClass, processName, startPrefix != null ? startPrefix : DEFAULT_START_PREFIX, description);
}
public void finish(Class javaClass, String processName, String description){
write(javaClass, processName, finishPrefix != null ? finishPrefix : DEFAULT_FINISH_PREFIX, description);
}
public void error(Class javaClass, String processName, String description){
write(javaClass, processName, errorPrefix != null ? errorPrefix : DEFAULT_ERROR_PREFIX, description);
}
public void write(Class javaClass, String processName, String descriptionPrefix, String description){
String fileName = this.logFileName != null ? this.logFileName : DEFAULT_FILENAME;
try {
HttpServletRequest request = getRequest();
String logRow = getLogRow(request, javaClass.getSimpleName(), processName, descriptionPrefix, description, fileName);
File file = new File(fileName);
controlFileSize(file);
boolean isCreated = file.createNewFile();
if (!isValidFile(file)) return;
if (isUnixSystem()){
setFilePermissions(file);
}
FileWriter writer = new FileWriter(fileName, true);
writer.append(logRow).append(System.lineSeparator());
writer.close();
} catch (FileNotFoundException fnfe){
LOGGER.error("Ошибка чтения/записи файла {}. Недостаточно прав.", fileName);
} catch (Exception e){
LOGGER.error(e.getMessage(), e);
}
}
private String getLogRow(HttpServletRequest request, String className, String processName, String descriptionPrefix, String description, String fileName){
String delimiter = this.delimiter != null ? this.delimiter : DEFAULT_DELIMITER;
try {
String ip = request.getRemoteAddr();
String userName = getUserName(request);
return String.format(
"%s%s%s.%s%s%s%s%s%s%s%s%s%s",
serviceName,
delimiter,
className,
processName,
delimiter,
getTodayDateTimeString(),
delimiter,
userName != null ? userName : "system-request",
delimiter,
ip,
delimiter,
descriptionPrefix,
description
);
} catch (Exception e){
LOGGER.error(e.getMessage(), e);
return "";
}
}
private String getUserName(HttpServletRequest request) throws ParseException {
String authHeader = request.getHeader(HttpHeaders.AUTHORIZATION);
String userName = null;
if (authHeader != null){
userName = JwtAuthConverter.getUsername(authHeader.substring(7));
} else {
authHeader = request.getHeader("X-API-Key");
if (authHeader != null) userName = authHeader.substring(9);
}
return userName;
}
private boolean isValidFile(File file){
boolean isValid = file.isFile();
if (!isValid) LOGGER.warn("{} не является файлом. Проверьте конфигурацию.", file.getName());
return isValid;
}
private boolean isOverwhelmed(File file){
int maxSizeMegabytes = logFileSize > 0 ? logFileSize : DEFAULT_FILE_SIZE;
long fileSizeMegabytes = file.length() / (1024*1024);
return fileSizeMegabytes >= maxSizeMegabytes;
}
private boolean isUnixSystem(){
String osName = System.getProperty("os.name").toLowerCase();
return osName.contains("nix") || osName.contains("nux");
}
private void copyFile(File file) throws IOException {
String filePath = this.logFileName != null ? this.logFileName : DEFAULT_FILENAME;
String todayString = getTodayDateTimeString();
String copyFilePath = String.format("%s%s", filePath, todayString.replace(" ", "").replace(".", "").replace(":", ""));
Path copyPath = Paths.get(copyFilePath);
Path originalPath = file.toPath();
Files.copy(originalPath, copyPath, StandardCopyOption.REPLACE_EXISTING);
LOGGER.info("Файл лога {} превысил допустимый размер, и был скопирован в {}", filePath, copyFilePath);
}
private void controlFileSize(File file) throws IOException {
if (isOverwhelmed(file)){
copyFile(file);
file.delete();
}
}
private void setFilePermissions(File file) throws IOException {
Set<PosixFilePermission> permissions = Arrays.stream(PosixFilePermission.values()).collect(Collectors.toSet());
Files.setPosixFilePermissions(file.toPath(), permissions);
}
private String getTodayDateTimeString(){
Instant instant = new Date().toInstant();
ZonedDateTime zonedDateTime = instant.atZone(this.zoneId);
Date today = Date.from(zonedDateTime.toInstant());
return dateFormatter.print(today, locale);
}
private HttpServletRequest getRequest(){
return ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
}
}
package kz.project.printedFormsService.service;
import org.springframework.web.multipart.MultipartFile;
import reactor.core.publisher.Mono;
public interface GitlabClient {
Mono<byte[]> downloadFileFromGitLab(String projectName, String filePath, String branch);
Mono<String> downloadFileContentAsString(String projectName, String filePath, String branch);
MultipartFile downloadFileAsMultipartFile(String projectName, String filePath, String branch);
}
package kz.project.printedFormsService.service;
import kz.project.printedFormsService.data.dto.GitlabUploadRequest;
import kz.project.printedFormsService.data.dto.TemplateDto;
import kz.project.printedFormsService.data.dto.TemplateResponseDto;
import lombok.SneakyThrows;
public interface GitlabTemplateService {
@SneakyThrows
TemplateDto saveFromGitlab(GitlabUploadRequest gitlabUploadRequest);
@SneakyThrows
TemplateResponseDto updateFromGitlab(GitlabUploadRequest gitlabUploadRequest);
}
package kz.project.printedFormsService.service; package kz.project.printedFormsService.service;
import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.core.JsonProcessingException;
import kz.project.printedFormsService.data.dto.TemplateDto;
import kz.project.printedFormsService.data.dto.TemplateResponseDto; import kz.project.printedFormsService.data.dto.TemplateResponseDto;
import kz.project.printedFormsService.data.dto.TemplateShortDto; import kz.project.printedFormsService.data.dto.TemplateShortDto;
import kz.project.printedFormsService.data.entity.TemplateEntity; import kz.project.printedFormsService.data.entity.TemplateEntity;
import kz.project.printedFormsService.exception.ValidationException; import kz.project.printedFormsService.exception.ValidationException;
import kz.project.printedFormsService.data.dto.TemplateDto;
import org.springframework.data.domain.Page; import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Pageable;
import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartFile;
......
package kz.project.printedFormsService.service.impl; package kz.project.printedFormsService.service.impl;
import kz.project.printedFormsService.controller.TemplateController;
import kz.project.printedFormsService.data.dto.DTemplateTypeDto; import kz.project.printedFormsService.data.dto.DTemplateTypeDto;
import kz.project.printedFormsService.data.entity.dict.DTemplateType; import kz.project.printedFormsService.data.entity.dict.DTemplateType;
import kz.project.printedFormsService.data.repository.DTemplateTypeRepository; import kz.project.printedFormsService.data.repository.DTemplateTypeRepository;
import kz.project.printedFormsService.logging.ProcessLogger;
import kz.project.printedFormsService.service.DTemplateTypeService; import kz.project.printedFormsService.service.DTemplateTypeService;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
...@@ -10,12 +12,19 @@ import org.springframework.stereotype.Service; ...@@ -10,12 +12,19 @@ import org.springframework.stereotype.Service;
import java.util.List; import java.util.List;
@Service @Service
@RequiredArgsConstructor
public class DTemplateTypeServiceImpl implements DTemplateTypeService { public class DTemplateTypeServiceImpl implements DTemplateTypeService {
private final DTemplateTypeRepository repository; private final DTemplateTypeRepository repository;
private ProcessLogger processLogger;
public DTemplateTypeServiceImpl(DTemplateTypeRepository repository, ProcessLogger processLogger) {
this.repository = repository;
this.processLogger = processLogger;
}
public List<DTemplateTypeDto> getAllTemplateType(){ public List<DTemplateTypeDto> getAllTemplateType(){
processLogger.start(TemplateController.class, new Throwable().getStackTrace()[0].getMethodName(), "Получение типов шаблонов");
List<DTemplateType> all = repository.findAll(); List<DTemplateType> all = repository.findAll();
processLogger.finish(TemplateController.class, new Throwable().getStackTrace()[0].getMethodName(), "Получение типов шаблонов");
return DTemplateTypeDto.toDtoList(all); return DTemplateTypeDto.toDtoList(all);
} }
} }
package kz.project.printedFormsService.service.impl;
import kz.project.printedFormsService.data.dto.GitlabMultipartFile;
import kz.project.printedFormsService.service.GitlabClient;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.reactive.function.client.WebClient;
import reactor.core.publisher.Mono;
import java.io.File;
@Service
@Slf4j
public class GitlabClientImpl implements GitlabClient {
private final WebClient webClient;
public GitlabClientImpl(@Value("${gitlab.base-url}") String baseUrl, @Value("${gitlab.token}") String token) {
this.webClient = WebClient.builder()
.baseUrl(baseUrl)
.defaultHeader("PRIVATE-TOKEN", token)
.build();
}
@Override
public Mono<byte[]> downloadFileFromGitLab(String projectName, String filePath, String branch) {
String urlPath = String.format("/api/v4/projects/%s/repository/files/%s/raw", projectName, filePath);
return webClient.get()
.uri(uriBuilder -> uriBuilder
.path(urlPath)
.queryParam("ref", branch) // or the branch you want to fetch from
.build())
.retrieve()
.bodyToMono(byte[].class)
.doOnError(error -> log.error("Error downloading file: {}", error.getMessage()));
}
@Override
public Mono<String> downloadFileContentAsString(String projectName, String filePath, String branch) {
String urlPath = String.format("/api/v4/projects/%s/repository/files/%s/raw", projectName, filePath);
return webClient.get()
.uri(uriBuilder -> uriBuilder
.path(urlPath)
.queryParam("ref", branch) // or the branch you want to fetch from
.build())
.retrieve()
.bodyToMono(String.class)
.doOnError(error -> log.error("Error downloading file: {}", error.getMessage()));
}
@Override
public MultipartFile downloadFileAsMultipartFile(String projectName, String filePath, String branch) {
String urlPath = String.format("/api/v4/projects/%s/repository/files/%s/raw", projectName, filePath);
return webClient.get()
.uri(uriBuilder -> uriBuilder
.path(urlPath)
.queryParam("ref", branch) // or the branch you want to fetch from
.build())
.retrieve()
.bodyToMono(byte[].class)
.map(bytes -> {
File file = new File(filePath);
return new GitlabMultipartFile(file.getName(), file.getName(), null, bytes);
})
.doOnError(error -> log.error("Error downloading file: {}", error.getMessage()))
.block();
}
}
package kz.project.printedFormsService.service.impl;
import com.fasterxml.jackson.databind.ObjectMapper;
import kz.project.printedFormsService.config.SecurityContextUtils;
import kz.project.printedFormsService.data.dto.GitlabUploadRequest;
import kz.project.printedFormsService.data.dto.TemplateDto;
import kz.project.printedFormsService.data.dto.TemplateResponseDto;
import kz.project.printedFormsService.service.GitlabClient;
import kz.project.printedFormsService.service.TemplateService;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import java.util.ArrayList;
import java.util.List;
@Service
@RequiredArgsConstructor
public class GitlabTemplateServiceImpl implements kz.project.printedFormsService.service.GitlabTemplateService {
private final GitlabClient gitlabClient;
private final TemplateService templateService;
private final ObjectMapper objectMapper;
@SneakyThrows
@Override
public TemplateDto saveFromGitlab(GitlabUploadRequest gitlabUploadRequest) {
String gitlabBranch = SecurityContextUtils.getGitlabProjectBranchFromRole();
List<MultipartFile> filesToSave = new ArrayList<>();
filesToSave.add(gitlabClient.downloadFileAsMultipartFile(
gitlabUploadRequest.getRepository(),
gitlabUploadRequest.getFileDataPath(),
gitlabBranch
));
String dtoString = gitlabClient.downloadFileContentAsString(
gitlabUploadRequest.getRepository(),
gitlabUploadRequest.getFileDtoPath(),
gitlabBranch
)
.blockOptional()
.orElseThrow();
TemplateDto templateDto = objectMapper.readValue(dtoString, TemplateDto.class);
if (gitlabUploadRequest.getFileHeaderPath() != null) {
filesToSave.add(
gitlabClient.downloadFileAsMultipartFile(
gitlabUploadRequest.getRepository(),
gitlabUploadRequest.getFileHeaderPath(),
gitlabBranch
)
);
}
return templateService.save(templateDto, filesToSave);
}
@SneakyThrows
@Override
public TemplateResponseDto updateFromGitlab(GitlabUploadRequest gitlabUploadRequest) {
String gitlabBranch = SecurityContextUtils.getGitlabProjectBranchFromRole();
List<MultipartFile> filesToSave = new ArrayList<>();
filesToSave.add(gitlabClient.downloadFileAsMultipartFile(
gitlabUploadRequest.getRepository(),
gitlabUploadRequest.getFileDataPath(),
gitlabBranch
));
String dtoString = gitlabClient.downloadFileContentAsString(
gitlabUploadRequest.getRepository(),
gitlabUploadRequest.getFileDtoPath(),
gitlabBranch
)
.blockOptional()
.orElseThrow();
TemplateDto templateDto = objectMapper.readValue(dtoString, TemplateDto.class);
if (gitlabUploadRequest.getFileHeaderPath() != null) {
filesToSave.add(
gitlabClient.downloadFileAsMultipartFile(
gitlabUploadRequest.getRepository(),
gitlabUploadRequest.getFileHeaderPath(),
gitlabBranch
)
);
}
return templateService.edit(templateDto, filesToSave);
}
}
...@@ -6,20 +6,20 @@ spring: ...@@ -6,20 +6,20 @@ spring:
oauth2: oauth2:
resourceserver: resourceserver:
jwt: jwt:
jwk-set-uri: ${KEYCLOAK_URI:http://94.247.129.11:8080}/realms/${KEYCLOAK_REALM:}/protocol/openid-connect/certs jwk-set-uri: ${KEYCLOAK_URI:http://94.247.129.11:8080}/realms/${KEYCLOAK_REALM:selfserviceportal}/protocol/openid-connect/certs
client: client:
registration: registration:
keycloak: keycloak:
client-id: print_form client-id: print_form
client-secret: ${KEYCLOAK_CLIENT_SECRET:PCFdHvlgAZTjqoieXvHN3z8zZENrbfKJ} client-secret: ${KEYCLOAK_CLIENT_SECRET:MAJ7LHWtuZYpUI4wqdol6uKoyINj2OeE}
client-name: Keycloak client-name: Keycloak
provider: keycloak provider: keycloak
scope: openid scope: openid
authorization-grant-type: authorization_code authorization-grant-type: authorization_code
provider: provider:
keycloak: keycloak:
jwk-set-uri: ${KEYCLOAK_URI:http://94.247.129.11:8080}/realms/${KEYCLOAK_REALM}/protocol/openid-connect/certs jwk-set-uri: ${KEYCLOAK_URI:http://94.247.129.11:8080}/realms/${KEYCLOAK_REALM:selfserviceportal}/protocol/openid-connect/certs
issuer-uri: ${KEYCLOAK_URI:http://94.247.129.11:8080}/realms/${KEYCLOAK_REALM} issuer-uri: ${KEYCLOAK_URI:http://94.247.129.11:8080}/realms/${KEYCLOAK_REALM:selfserviceportal}
jpa: jpa:
hibernate: hibernate:
...@@ -79,4 +79,19 @@ management: ...@@ -79,4 +79,19 @@ management:
liquibase: liquibase:
enabled: false enabled: false
beans: beans:
enabled: false enabled: false
\ No newline at end of file
process-logger:
file-name: templateService.log
file-max-size-mb: 100
delimiter: " "
date-format: "dd.MM.yyyy HH:mm:ss"
locale: kk_KZ
start-prefix: "Начало процесса: "
finish-prefix: "Конец процесса: "
error-prefix: "Неуспешный процесс: "
gitlab:
base-url: ${GITLAB_BASE_PATH:http://gitlab.lan.arta.kz}
token: ${GITLAB_TOKEN:zif-LhgdzuLtpNW7uxYs}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment