Merge branch 'hotfix/1.9.5'

# Conflicts:
#	backend/pom.xml
#	distribution/pom.xml
#	frontend/pom.xml
#	pom.xml
#	resources/pom.xml
This commit is contained in:
Zaripov Emil 2025-02-07 10:07:24 +03:00
commit 1911e67f8c
10 changed files with 61 additions and 37 deletions

View file

@ -5,7 +5,7 @@
<parent> <parent>
<groupId>ru.micord.ervu.lkrp</groupId> <groupId>ru.micord.ervu.lkrp</groupId>
<artifactId>ul</artifactId> <artifactId>ul</artifactId>
<version>1.9.4</version> <version>1.9.5</version>
</parent> </parent>
<groupId>ru.micord.ervu.lkrp.ul</groupId> <groupId>ru.micord.ervu.lkrp.ul</groupId>
<artifactId>backend</artifactId> <artifactId>backend</artifactId>

View file

@ -11,6 +11,7 @@ import java.net.http.HttpClient;
import java.net.http.HttpRequest; import java.net.http.HttpRequest;
import java.net.http.HttpResponse; import java.net.http.HttpResponse;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.time.Duration;
import java.time.ZonedDateTime; import java.time.ZonedDateTime;
import java.util.Arrays; import java.util.Arrays;
import java.util.Comparator; import java.util.Comparator;
@ -34,6 +35,7 @@ import ervu.model.webdav.Server;
import org.apache.http.client.ClientProtocolException; import org.apache.http.client.ClientProtocolException;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.InputStreamResource; import org.springframework.core.io.InputStreamResource;
import org.springframework.core.io.Resource; import org.springframework.core.io.Resource;
@ -44,6 +46,7 @@ import org.springframework.retry.annotation.Backoff;
import org.springframework.retry.annotation.Retryable; import org.springframework.retry.annotation.Retryable;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartFile;
import ru.micord.ervu.security.esia.config.EsiaConfig;
/** /**
* @author Alexandr Shalaginov * @author Alexandr Shalaginov
@ -60,6 +63,10 @@ public class WebDavClient {
private String password; private String password;
@Value("${webdav.bad_servers.cache.expire.seconds:120}") @Value("${webdav.bad_servers.cache.expire.seconds:120}")
private long cacheExpireSec; private long cacheExpireSec;
@Value("${request.timeout:20}")
private long requestTimeout;
@Value("${connection.timeout:10}")
private long connectionTimeout;
private List<Server> servers; private List<Server> servers;
private LoadingCache<String, String> badServersCache; private LoadingCache<String, String> badServersCache;
@ -167,10 +174,14 @@ public class WebDavClient {
protected PasswordAuthentication getPasswordAuthentication() { protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication(username, password.toCharArray()); return new PasswordAuthentication(username, password.toCharArray());
} }
}).build(); })
.connectTimeout(Duration.ofSeconds(connectionTimeout))
.build();
HttpRequest httpRequest = HttpRequest.newBuilder().uri(URI.create(url)) HttpRequest httpRequest = HttpRequest.newBuilder().uri(URI.create(url))
.GET().build(); .GET()
.timeout(Duration.ofSeconds(requestTimeout))
.build();
HttpResponse<InputStream> response = httpClient.send(httpRequest, HttpResponse<InputStream> response = httpClient.send(httpRequest,
HttpResponse.BodyHandlers.ofInputStream() HttpResponse.BodyHandlers.ofInputStream()

View file

@ -1,11 +1,14 @@
package ru.micord.ervu.kafka.service.impl; package ru.micord.ervu.kafka.service.impl;
import java.lang.invoke.MethodHandles;
import java.util.Optional; import java.util.Optional;
import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutionException;
import org.apache.kafka.clients.consumer.ConsumerRecord; import org.apache.kafka.clients.consumer.ConsumerRecord;
import org.apache.kafka.clients.producer.ProducerRecord; import org.apache.kafka.clients.producer.ProducerRecord;
import org.apache.kafka.common.header.internals.RecordHeader; import org.apache.kafka.common.header.internals.RecordHeader;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.kafka.requestreply.ReplyingKafkaTemplate; import org.springframework.kafka.requestreply.ReplyingKafkaTemplate;
import org.springframework.kafka.requestreply.RequestReplyFuture; import org.springframework.kafka.requestreply.RequestReplyFuture;
import org.springframework.kafka.support.KafkaHeaders; import org.springframework.kafka.support.KafkaHeaders;
@ -17,7 +20,7 @@ import ru.micord.ervu.kafka.service.ReplyingKafkaService;
*/ */
@Service @Service
public class BaseReplyingKafkaServiceImpl implements ReplyingKafkaService { public class BaseReplyingKafkaServiceImpl implements ReplyingKafkaService {
private static final Logger LOGGER = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
private final ReplyingKafkaTemplate<String, String, String> replyingKafkaTemplate; private final ReplyingKafkaTemplate<String, String, String> replyingKafkaTemplate;
public BaseReplyingKafkaServiceImpl( public BaseReplyingKafkaServiceImpl(
@ -28,16 +31,22 @@ public class BaseReplyingKafkaServiceImpl implements ReplyingKafkaService {
public String sendMessageAndGetReply(String requestTopic, public String sendMessageAndGetReply(String requestTopic,
String replyTopic, String replyTopic,
String requestMessage) { String requestMessage) {
long startTime = System.currentTimeMillis();
ProducerRecord<String, String> record = new ProducerRecord<>(requestTopic, requestMessage); ProducerRecord<String, String> record = new ProducerRecord<>(requestTopic, requestMessage);
record.headers().add(new RecordHeader(KafkaHeaders.REPLY_TOPIC, replyTopic.getBytes())); record.headers().add(new RecordHeader(KafkaHeaders.REPLY_TOPIC, replyTopic.getBytes()));
RequestReplyFuture<String, String, String> replyFuture = replyingKafkaTemplate.sendAndReceive(record); RequestReplyFuture<String, String, String> replyFuture = replyingKafkaTemplate.sendAndReceive(record);
try { try {
return Optional.ofNullable(replyFuture.get()) String result = Optional.ofNullable(replyFuture.get())
.map(ConsumerRecord::value) .map(ConsumerRecord::value)
.orElseThrow(() -> new RuntimeException("Kafka return result is null.")); .orElseThrow(() -> new RuntimeException("Kafka return result is null."));
LOGGER.info("Thread {} - KafkaSendMessageAndGetReply: {} ms",
Thread.currentThread().getId(), System.currentTimeMillis() - startTime);
return result;
} }
catch (InterruptedException | ExecutionException e) { catch (InterruptedException | ExecutionException e) {
LOGGER.error("Thread {} - KafkaSendMessageAndGetReply: {} ms",
Thread.currentThread().getId(), System.currentTimeMillis() - startTime);
throw new RuntimeException("Failed to get kafka response.", e); throw new RuntimeException("Failed to get kafka response.", e);
} }
} }

View file

@ -38,10 +38,10 @@ public class EsiaConfig {
@Value("${esia.client.cert.hash}") @Value("${esia.client.cert.hash}")
private String clientCertHash; private String clientCertHash;
@Value("${esia.request.timeout:60}") @Value("${request.timeout:20}")
private long requestTimeout; private long requestTimeout;
@Value("${esia.connection.timeout:30}") @Value("${connection.timeout:10}")
private long connectionTimeout; private long connectionTimeout;
@Value("${esia.logout.url:idp/ext/Logout}") @Value("${esia.logout.url:idp/ext/Logout}")

View file

@ -19,6 +19,7 @@ import java.util.UUID;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import ervu.service.okopf.OkopfService; import ervu.service.okopf.OkopfService;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
@ -241,12 +242,14 @@ public class EsiaAuthService {
throw new EsiaException(e); throw new EsiaException(e);
} }
finally { finally {
LOGGER.info("Thread {}: SignSecret: {}ms RequestAccessToken: {}ms VerifySecret: {}ms", LOGGER.info("Thread {} - SignSecret: {} ms RequestAccessToken: {} ms VerifySecret: {} ms",
Thread.currentThread().getId(), timeSignSecret, timeRequestAccessToken, timeVerifySecret); Thread.currentThread().getId(), timeSignSecret, timeRequestAccessToken, timeVerifySecret);
} }
OrgInfo orgInfo = null;
try { try {
orgInfo = getOrgInfo(esiaAccessTokenStr);
hasRole = ulDataService.checkRole(esiaAccessTokenStr); hasRole = ulDataService.checkRole(esiaAccessTokenStr);
String ervuId = getErvuId(esiaAccessTokenStr, prnOid); String ervuId = getErvuId(prnOid, orgInfo);
createTokenAndAddCookie(response, prnOid, ervuId, hasRole, expiresIn); createTokenAndAddCookie(response, prnOid, ervuId, hasRole, expiresIn);
if (!hasRole) { if (!hasRole) {
LOGGER.error("The user with id = " + prnOid + " does not have the required role"); LOGGER.error("The user with id = " + prnOid + " does not have the required role");
@ -333,7 +336,8 @@ public class EsiaAuthService {
Long expiresIn = tokenResponse.getExpires_in(); Long expiresIn = tokenResponse.getExpires_in();
EsiaTokensStore.addAccessToken(prnOid, esiaAccessTokenStr, expiresIn); EsiaTokensStore.addAccessToken(prnOid, esiaAccessTokenStr, expiresIn);
EsiaTokensStore.addRefreshToken(prnOid, esiaNewRefreshToken, expiresIn); EsiaTokensStore.addRefreshToken(prnOid, esiaNewRefreshToken, expiresIn);
String ervuId = getErvuId(esiaAccessTokenStr, prnOid); OrgInfo orgInfo = getOrgInfo(esiaAccessTokenStr);
String ervuId = getErvuId(prnOid, orgInfo);
createTokenAndAddCookie(response, esiaAccessToken.getSbj_id(), ervuId, true, expiresIn); createTokenAndAddCookie(response, esiaAccessToken.getSbj_id(), ervuId, true, expiresIn);
} }
catch (Exception e) { catch (Exception e) {
@ -353,6 +357,7 @@ public class EsiaAuthService {
.uri(URI.create(esiaConfig.getSignUrl())) .uri(URI.create(esiaConfig.getSignUrl()))
.header("Content-Type", "text/plain") .header("Content-Type", "text/plain")
.POST(HttpRequest.BodyPublishers.ofString(requestBody, StandardCharsets.UTF_8)) .POST(HttpRequest.BodyPublishers.ofString(requestBody, StandardCharsets.UTF_8))
.timeout(Duration.ofSeconds(esiaConfig.getRequestTimeout()))
.build(); .build();
HttpResponse<String> response = HttpClient.newBuilder() HttpResponse<String> response = HttpClient.newBuilder()
.connectTimeout(Duration.ofSeconds(esiaConfig.getConnectionTimeout())) .connectTimeout(Duration.ofSeconds(esiaConfig.getConnectionTimeout()))
@ -392,10 +397,23 @@ public class EsiaAuthService {
} }
} }
public String getErvuId(String accessToken, String prnOid) { public String getErvuId(String prnOid, OrgInfo orgInfo) throws JsonProcessingException {
long timeRequestPersonDataOrg = 0, timeRequestPersonDataEmployee = 0, timeRequestPersonDataChief = 0, timeRequestIdERVU = 0; orgInfo.setOrgTypeName(okopfService.findTitleByLeg(orgInfo.getOrgTypeLeg()));
String kafkaResponse = replyingKafkaService.sendMessageAndGetReply(requestTopic,
requestReplyTopic, objectMapper.writeValueAsString(orgInfo)
);
ErvuOrgResponse ervuOrgResponse = objectMapper.readValue(kafkaResponse, ErvuOrgResponse.class);
String ervuId = ervuOrgResponse.getData().getErvuId();
if (!StringUtils.hasText(ervuId)) {
throw new EsiaException("No ervuId for prnOid = " + prnOid);
}
return ervuId;
}
private OrgInfo getOrgInfo(String accessToken) {
long startTime = System.currentTimeMillis();
long timeRequestPersonDataOrg = 0, timeRequestPersonDataEmployee = 0, timeRequestPersonDataChief = 0;
try { try {
long startTime = System.currentTimeMillis();
OrganizationModel organizationModel = ulDataService.getOrganizationModel(accessToken); OrganizationModel organizationModel = ulDataService.getOrganizationModel(accessToken);
timeRequestPersonDataOrg = System.currentTimeMillis() - startTime; timeRequestPersonDataOrg = System.currentTimeMillis() - startTime;
startTime = System.currentTimeMillis(); startTime = System.currentTimeMillis();
@ -404,27 +422,12 @@ public class EsiaAuthService {
startTime = System.currentTimeMillis(); startTime = System.currentTimeMillis();
EmployeeModel chiefModel = ulDataService.getChiefEmployeeModel(accessToken); EmployeeModel chiefModel = ulDataService.getChiefEmployeeModel(accessToken);
timeRequestPersonDataChief = System.currentTimeMillis() - startTime; timeRequestPersonDataChief = System.currentTimeMillis() - startTime;
OrgInfo orgInfo = copyToOrgInfo(organizationModel, employeeModel, chiefModel); return copyToOrgInfo(organizationModel, employeeModel, chiefModel);
orgInfo.setOrgTypeName(okopfService.findTitleByLeg(orgInfo.getOrgTypeLeg()));
startTime = System.currentTimeMillis();
String kafkaResponse = replyingKafkaService.sendMessageAndGetReply(requestTopic,
requestReplyTopic, objectMapper.writeValueAsString(orgInfo)
);
timeRequestIdERVU = System.currentTimeMillis() - startTime;
ErvuOrgResponse ervuOrgResponse = objectMapper.readValue(kafkaResponse, ErvuOrgResponse.class);
String ervuId = ervuOrgResponse.getData().getErvuId();
if (!StringUtils.hasText(ervuId)) {
throw new EsiaException("No ervuId for prnOid = " + prnOid);
}
return ervuId;
}
catch (Exception e) {
throw new EsiaException(e);
} }
finally { finally {
LOGGER.info("Thread {}: RequestPersonDataOrg: {}ms RequestPersonDataEmployee: {}ms RequestPersonDataChief: {}ms RequestIdERVU: {}ms", LOGGER.info("Thread {} - RequestPersonDataOrg: {} ms RequestPersonDataEmployee: {} ms RequestPersonDataChief: {} ms",
Thread.currentThread().getId(), timeRequestPersonDataOrg, timeRequestPersonDataEmployee, timeRequestPersonDataChief, timeRequestIdERVU); Thread.currentThread().getId(), timeRequestPersonDataOrg, timeRequestPersonDataEmployee, timeRequestPersonDataChief
);
} }
} }
@ -546,6 +549,7 @@ public class EsiaAuthService {
.uri(URI.create(esiaConfig.getSignVerifyUrl())) .uri(URI.create(esiaConfig.getSignVerifyUrl()))
.header("Content-Type", "text/plain") .header("Content-Type", "text/plain")
.POST(HttpRequest.BodyPublishers.ofString(accessToken, StandardCharsets.UTF_8)) .POST(HttpRequest.BodyPublishers.ofString(accessToken, StandardCharsets.UTF_8))
.timeout(Duration.ofSeconds(esiaConfig.getRequestTimeout()))
.build(); .build();
return HttpClient.newBuilder() return HttpClient.newBuilder()
.connectTimeout(Duration.ofSeconds(esiaConfig.getConnectionTimeout())) .connectTimeout(Duration.ofSeconds(esiaConfig.getConnectionTimeout()))

View file

@ -4,7 +4,7 @@
<parent> <parent>
<groupId>ru.micord.ervu.lkrp</groupId> <groupId>ru.micord.ervu.lkrp</groupId>
<artifactId>ul</artifactId> <artifactId>ul</artifactId>
<version>1.9.4</version> <version>1.9.5</version>
</parent> </parent>
<groupId>ru.micord.ervu.lkrp.ul</groupId> <groupId>ru.micord.ervu.lkrp.ul</groupId>

View file

@ -4,7 +4,7 @@
<parent> <parent>
<groupId>ru.micord.ervu.lkrp</groupId> <groupId>ru.micord.ervu.lkrp</groupId>
<artifactId>ul</artifactId> <artifactId>ul</artifactId>
<version>1.9.4</version> <version>1.9.5</version>
</parent> </parent>
<groupId>ru.micord.ervu.lkrp.ul</groupId> <groupId>ru.micord.ervu.lkrp.ul</groupId>

View file

@ -1,7 +1,7 @@
<nav class="header" id="webbpm-header" [ngClass]="{'header-landing': isLanding}"> <nav class="header" id="webbpm-header" [ngClass]="{'header-landing': isLanding}">
<div *ngIf="isLanding"> <div *ngIf="isLanding">
<div class="header-logo"></div> <div class="header-logo"></div>
<div class="header-title">Реестр повесток юридических лиц</div> <div class="header-title">Личный кабинет для юридических лиц</div>
</div> </div>
<div *ngIf="!isLanding" class="header-logo"> <div *ngIf="!isLanding" class="header-logo">
<div class="logo"><a routerLink="/"></a></div> <div class="logo"><a routerLink="/"></a></div>

View file

@ -4,7 +4,7 @@
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<groupId>ru.micord.ervu.lkrp</groupId> <groupId>ru.micord.ervu.lkrp</groupId>
<artifactId>ul</artifactId> <artifactId>ul</artifactId>
<version>1.9.4</version> <version>1.9.5</version>
<packaging>pom</packaging> <packaging>pom</packaging>
<modules> <modules>
<module>backend</module> <module>backend</module>

View file

@ -4,7 +4,7 @@
<parent> <parent>
<groupId>ru.micord.ervu.lkrp</groupId> <groupId>ru.micord.ervu.lkrp</groupId>
<artifactId>ul</artifactId> <artifactId>ul</artifactId>
<version>1.9.4</version> <version>1.9.5</version>
</parent> </parent>
<groupId>ru.micord.ervu.lkrp.ul</groupId> <groupId>ru.micord.ervu.lkrp.ul</groupId>