SUPPORT-9416: fix

This commit is contained in:
adel.ka 2025-09-18 17:36:02 +03:00
parent 38a95b7ec0
commit dc9eec7fda
6 changed files with 66 additions and 36 deletions

View file

@ -6,6 +6,8 @@ import java.util.Set;
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.Autowired;
import ru.micord.ervu.account_applications.security.context.SecurityContext;
import ru.micord.ervu.account_applications.security.model.UserSession;
import ru.micord.ervu.account_applications.service.AccountFetchService; import ru.micord.ervu.account_applications.service.AccountFetchService;
import ru.micord.ervu.account_applications.service.UserApplicationListService; import ru.micord.ervu.account_applications.service.UserApplicationListService;
@ -24,16 +26,14 @@ public class UserApplicationListRpcService extends Behavior {
private UserApplicationListService applicationListService; private UserApplicationListService applicationListService;
@Autowired @Autowired
private AccountFetchService accountService; private AccountFetchService accountService;
@Autowired
private SecurityContext securityContext;
@RpcCall @RpcCall
public void saveError(long appNumber, String errorMsg) { public void saveError(long appNumber, String errorMsg) {
UserSession userSession = securityContext.getUserSession();
LOGGER.error("error for application = {}, message: {}", appNumber, errorMsg); LOGGER.error("error for application = {}, message: {}", appNumber, errorMsg);
applicationListService.saveError(appNumber, errorMsg); applicationListService.saveError(appNumber, errorMsg, userSession.name(), userSession.userId());
}
@RpcCall
public void saveAcceptedStatus(long appNumber) {
applicationListService.saveAcceptedStatus(appNumber);
} }
@RpcCall @RpcCall

View file

@ -5,10 +5,13 @@ import com.fasterxml.jackson.databind.ObjectMapper;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.kafka.annotation.KafkaListener; import org.springframework.kafka.annotation.KafkaListener;
import org.springframework.messaging.handler.annotation.Header;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
import ru.micord.ervu.account_applications.kafka.model.ApplicationStatus; import ru.micord.ervu.account_applications.kafka.model.ApplicationStatus;
import ru.micord.ervu.account_applications.security.model.jwt.UserClaims;
import ru.micord.ervu.account_applications.security.service.EncryptionService; import ru.micord.ervu.account_applications.security.service.EncryptionService;
import ru.micord.ervu.account_applications.security.service.JwtTokenService;
import ru.micord.ervu.account_applications.service.UserApplicationListService; import ru.micord.ervu.account_applications.service.UserApplicationListService;
/** /**
@ -20,17 +23,26 @@ public class ApplicationStatusListener {
private final ObjectMapper mapper; private final ObjectMapper mapper;
private final UserApplicationListService applicationService; private final UserApplicationListService applicationService;
private final EncryptionService encryptionService; private final EncryptionService encryptionService;
private final JwtTokenService jwtTokenService;
public ApplicationStatusListener(ObjectMapper mapper, public ApplicationStatusListener(ObjectMapper mapper,
UserApplicationListService applicationService, EncryptionService encryptionService) { UserApplicationListService applicationService, EncryptionService encryptionService,
JwtTokenService jwtTokenService) {
this.mapper = mapper; this.mapper = mapper;
this.applicationService = applicationService; this.applicationService = applicationService;
this.encryptionService = encryptionService; this.encryptionService = encryptionService;
this.jwtTokenService = jwtTokenService;
} }
@KafkaListener(id = "${kafka.application.status.group.id}", topics = "${kafka.application.status}") @KafkaListener(id = "${kafka.application.status.group.id}",
public void listenKafkaDomain(String kafkaMessage) { topics = "${kafka.application.status}")
public void listenKafkaDomain(String kafkaMessage, @Header("authorization") String authHeader) {
try { try {
String token = authHeader.replace("Bearer ", "");
UserClaims userClaims = jwtTokenService.getUserClaims(token);
String name = userClaims.name();
String userId = userClaims.userId();
ApplicationStatus applicationStatus = mapper.readValue(kafkaMessage, ApplicationStatus.class); ApplicationStatus applicationStatus = mapper.readValue(kafkaMessage, ApplicationStatus.class);
Long applicationNumber = applicationStatus.applicationNumber(); Long applicationNumber = applicationStatus.applicationNumber();
if (applicationStatus.status()) { if (applicationStatus.status()) {
@ -38,16 +50,16 @@ public class ApplicationStatusListener {
String tempPass = applicationStatus.password(); String tempPass = applicationStatus.password();
if (StringUtils.hasText(tempPass)) { if (StringUtils.hasText(tempPass)) {
String encryptedPassword = encryptionService.encrypt(tempPass); String encryptedPassword = encryptionService.encrypt(tempPass);
applicationService.savePassword(applicationNumber, encryptedPassword); applicationService.savePassword(applicationNumber, encryptedPassword, name, userId);
} }
else { else {
applicationService.saveAcceptedStatus(applicationNumber); applicationService.saveAcceptedStatus(applicationNumber, name, userId);
} }
} }
else { else {
String errorMsg = applicationStatus.errorMsg(); String errorMsg = applicationStatus.errorMsg();
LOGGER.error("error by appNumber = {}, message: {}", applicationNumber, errorMsg); LOGGER.error("error by appNumber = {}, message: {}", applicationNumber, errorMsg);
applicationService.saveError(applicationNumber, errorMsg); applicationService.saveError(applicationNumber, errorMsg, name, userId);
} }
} }
catch (JsonProcessingException e) { catch (JsonProcessingException e) {

View file

@ -8,8 +8,6 @@ import java.util.Map;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import ru.micord.ervu.account_applications.component.dao.AuditDao; import ru.micord.ervu.account_applications.component.dao.AuditDao;
import ru.micord.ervu.account_applications.dao.UserApplicationListDao; import ru.micord.ervu.account_applications.dao.UserApplicationListDao;
import ru.micord.ervu.account_applications.security.context.SecurityContext;
import ru.micord.ervu.account_applications.security.model.UserSession;
import utils.DateTimeUtil; import utils.DateTimeUtil;
import static ru.micord.ervu.account_applications.enums.ApplicationStatus.ACCEPTED; import static ru.micord.ervu.account_applications.enums.ApplicationStatus.ACCEPTED;
@ -23,42 +21,37 @@ public class UserApplicationListService {
private final UserApplicationListDao dao; private final UserApplicationListDao dao;
private final AuditDao auditDao; private final AuditDao auditDao;
private final SecurityContext securityContext;
public UserApplicationListService(UserApplicationListDao dao, AuditDao auditDao, SecurityContext securityContext) { public UserApplicationListService(UserApplicationListDao dao, AuditDao auditDao) {
this.dao = dao; this.dao = dao;
this.auditDao = auditDao; this.auditDao = auditDao;
this.securityContext = securityContext;
} }
public Map<Long, String> getStatusesBatch(List<Long> appNumbers) { public Map<Long, String> getStatusesBatch(List<Long> appNumbers) {
return dao.getStatusesBatch(appNumbers); return dao.getStatusesBatch(appNumbers);
} }
public void savePassword(Long appNumber, String encodedPass) { public void savePassword(Long appNumber, String encodedPass, String name, String userId) {
dao.savePassword(appNumber, encodedPass); dao.savePassword(appNumber, encodedPass);
saveAuditStatusByAppNumber(appNumber, ACCEPTED.name()); saveAuditStatusByAppNumber(appNumber, ACCEPTED.name(), name, userId);
} }
public boolean userExists(String login){ public boolean userExists(String login){
return dao.userExists(login); return dao.userExists(login);
} }
public void saveAcceptedStatus(long appNumber) { public void saveAcceptedStatus(long appNumber, String name, String userId) {
dao.saveAcceptedStatus(appNumber); dao.saveAcceptedStatus(appNumber);
saveAuditStatusByAppNumber(appNumber, ACCEPTED.name()); saveAuditStatusByAppNumber(appNumber, ACCEPTED.name(), name, userId);
} }
public void saveError(long appNumber, String errorMsg) { public void saveError(long appNumber, String errorMsg, String name, String userId) {
dao.saveError(appNumber, errorMsg); dao.saveError(appNumber, errorMsg);
saveAuditStatusByAppNumber(appNumber, AGREED.name()); saveAuditStatusByAppNumber(appNumber, AGREED.name(), name, userId);
} }
private void saveAuditStatusByAppNumber(long appNumber, String status) { private void saveAuditStatusByAppNumber(long appNumber, String status, String name, String userId) {
List<Long> appIds = auditDao.selectAppListIdsByAppNumber(appNumber); List<Long> appIds = auditDao.selectAppListIdsByAppNumber(appNumber);
UserSession userSession = securityContext.getUserSession();
String name = userSession.name();
String userId = userSession.userId();
appIds.forEach(id -> { appIds.forEach(id -> {
auditDao.insert(id, name, userId, status, Timestamp.valueOf( auditDao.insert(id, name, userId, status, Timestamp.valueOf(
DateTimeUtil.dateToLocalDateTimeUtc(new Date()))); DateTimeUtil.dateToLocalDateTimeUtc(new Date())));

View file

@ -7,7 +7,7 @@ import {
TextField, TextField,
Visible Visible
} from "@webbpm/base-package"; } from "@webbpm/base-package";
import {HttpClient, HttpErrorResponse, HttpResponse} from "@angular/common/http"; import {HttpClient} from "@angular/common/http";
import {FormField} from "../field/FormField"; import {FormField} from "../field/FormField";
import {AuthorizationService} from "../../../modules/app/service/authorization.service"; import {AuthorizationService} from "../../../modules/app/service/authorization.service";
import {ApplicationKind} from "../enum/ApplicationKind"; import {ApplicationKind} from "../enum/ApplicationKind";

View file

@ -1,4 +1,4 @@
import {Injectable, OnDestroy} from "@angular/core"; import {Injectable} from "@angular/core";
import {Subject} from "rxjs"; import {Subject} from "rxjs";
import {HttpClient} from "@angular/common/http"; import {HttpClient} from "@angular/common/http";

View file

@ -20,23 +20,30 @@ export class StatusUpdateService {
} }
public statusMessage = new BehaviorSubject<any>(null); public statusMessage = new BehaviorSubject<any>(null);
private pendingApplications = new Set<number>(); private pendingApplications = new Map<number, number>();
private pollingInterval: any; private pollingInterval: any;
private readonly MAX_ATTEMPTS = 12;
public trackApplication(appNumber: number): void { public trackApplication(appNumber: number): void {
this.pendingApplications.add(appNumber); if (!this.pendingApplications.has(appNumber)) {
this.startPolling(); this.pendingApplications.set(appNumber, 0);
this.startPolling();
}
} }
public publishStatus(appNumber: number, accepted: boolean) { public publishStatus(appNumber: number, accepted: boolean) {
this.statusMessage.next({ this.statusMessage.next({
appNumber: appNumber, appNumber: appNumber,
status: accepted ? ApplicationStatus.ACCEPTED : ApplicationStatus.AGREED status: accepted
? ApplicationStatus.ACCEPTED
: ApplicationStatus.AGREED
}); });
} }
private startPolling(): void { private startPolling(): void {
if (this.pendingApplications.size === 0 || this.pollingInterval) return; if (this.pendingApplications.size === 0 || this.pollingInterval) {
return;
}
this.pollingInterval = setInterval(() => { this.pollingInterval = setInterval(() => {
this.checkPendingStatuses(); this.checkPendingStatuses();
@ -51,7 +58,7 @@ export class StatusUpdateService {
} }
private checkPendingStatuses(): void { private checkPendingStatuses(): void {
const appNumbers = Array.from(this.pendingApplications); const appNumbers = Array.from(this.pendingApplications.keys());
if (appNumbers.length === 0) { if (appNumbers.length === 0) {
this.stopPolling(); this.stopPolling();
return; return;
@ -61,16 +68,34 @@ export class StatusUpdateService {
.toPromise() .toPromise()
.then(responses => { .then(responses => {
responses.forEach(response => { responses.forEach(response => {
const attemptCount = (this.pendingApplications.get(response.appNumber) || 0) + 1;
this.pendingApplications.set(response.appNumber, attemptCount);
if (response.status !== 'SENT') { if (response.status !== 'SENT') {
this.pendingApplications.delete(response.appNumber); this.pendingApplications.delete(response.appNumber);
this.publishStatus(response.appNumber, response.status === 'ACCEPTED'); this.publishStatus(response.appNumber, response.status === 'ACCEPTED');
} }
else if (attemptCount >= this.MAX_ATTEMPTS) {
this.pendingApplications.delete(response.appNumber);
console.warn(`Max attempts exceeded for application ${response.appNumber}`);
}
}); });
if (this.pendingApplications.size === 0) { if (this.pendingApplications.size === 0) {
this.stopPolling(); this.stopPolling();
} }
}) })
.catch(err => console.error('Failed to check statuses', err)); .catch(err => {
console.error('Failed to check statuses', err);
appNumbers.forEach(appNumber => {
const attemptCount = (this.pendingApplications.get(appNumber) || 0) + 1;
this.pendingApplications.set(appNumber, attemptCount);
if (attemptCount >= this.MAX_ATTEMPTS) {
this.pendingApplications.delete(appNumber);
console.warn(`Max attempts exceeded for application ${appNumber} due to errors`);
}
});
});
} }
} }