SUPPORT-8971: move validation to backend

This commit is contained in:
Emir Suleimanov 2025-03-11 18:36:33 +03:00
parent 8ff8302c67
commit f9ec8a77cd
12 changed files with 207 additions and 51 deletions

View file

@ -0,0 +1,14 @@
package ru.micord.ervu.account_applications.component.exception;
/**
* @author Emir Suleimanov
*/
public class IdmValidatorException extends RuntimeException {
public IdmValidatorException(String message) {
super(message);
}
public IdmValidatorException(String message, Throwable cause) {
super(message, cause);
}
}

View file

@ -0,0 +1,22 @@
package ru.micord.ervu.account_applications.component.model.dto;
import java.util.List;
import java.util.Map;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
/**
* @author Emir Suleimanov
*/
@JsonIgnoreProperties(ignoreUnknown = true)
public class IdmPersonsResponse {
private List<Map<String, Object>> records;
public List<Map<String, Object>> getRecords() {
return records;
}
public void setRecords(List<Map<String, Object>> records) {
this.records = records;
}
}

View file

@ -0,0 +1,22 @@
package ru.micord.ervu.account_applications.component.rpc;
import ru.micord.ervu.account_applications.component.service.IdmValidatorService;
import ru.cg.webbpm.modules.standard_annotations.validation.NotNull;
import ru.cg.webbpm.modules.webkit.annotations.RpcCall;
import ru.cg.webbpm.modules.webkit.annotations.RpcService;
import ru.cg.webbpm.modules.webkit.beans.Behavior;
/**
* @author Emir Suleimanov
*/
@RpcService
public class IdmValidatorRpcService extends Behavior {
@NotNull
public IdmValidatorService validatorService;
@RpcCall
public boolean valueExists(String login) {
return validatorService.valueExists(login);
}
}

View file

@ -0,0 +1,41 @@
package ru.micord.ervu.account_applications.component.service;
import java.util.List;
import java.util.Map;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
import ru.micord.ervu.account_applications.component.exception.IdmValidatorException;
/**
* @author Emir Suleimanov
*/
@Service
public class IdmLoginValidatorService implements IdmValidatorService{
private final RestTemplate restTemplate;
@Value("${ervu.url}")
private String ervuUrl;
public IdmLoginValidatorService(RestTemplate restTemplate) {
this.restTemplate = restTemplate;
}
public boolean valueExists(String login) {
String url = String.format("%s/service/idm/credentials/login/%s", ervuUrl, login);
try {
ResponseEntity<List<Map<String, Object>>> response = restTemplate.exchange(
url, HttpMethod.GET, null, new ParameterizedTypeReference<>() {}
);
return response.getBody() != null &&
response.getBody().stream()
.anyMatch(user -> login.equals(user.get("userName")));
} catch (Exception e) {
throw new IdmValidatorException("Ошибка при проверке логина: " + login, e);
}
}
}

View file

@ -0,0 +1,46 @@
package ru.micord.ervu.account_applications.component.service;
import java.util.Objects;
import java.util.Optional;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
import ru.micord.ervu.account_applications.component.exception.IdmValidatorException;
import ru.micord.ervu.account_applications.component.model.dto.IdmPersonsResponse;
/**
* @author Emir Suleimanov
*/
@Service
public class IdmSnilsValidatorService implements IdmValidatorService {
private final RestTemplate restTemplate;
@Value("${ervu.url}")
private String ervuUrl;
public IdmSnilsValidatorService(RestTemplate restTemplate) {
this.restTemplate = restTemplate;
}
public boolean valueExists(String snils) {
String url = String.format("%s/service/idm/persons?query=snils==\"%s\"", ervuUrl, snils);
try {
ResponseEntity<IdmPersonsResponse> response = restTemplate.exchange(
url, HttpMethod.GET, null, new ParameterizedTypeReference<>() {}
);
IdmPersonsResponse records = response.getBody();
if (Objects.nonNull(records)) {
return Optional.ofNullable(records.getRecords())
.map(record -> record.stream().anyMatch(value -> snils.equals(value.get("snils"))))
.orElse(false);
}
return false;
} catch (Exception e) {
throw new IdmValidatorException("Ошибка при проверке СНИЛС: " + snils, e);
}
}
}

View file

@ -0,0 +1,8 @@
package ru.micord.ervu.account_applications.component.service;
/**
* @author Emir Suleimanov
*/
public interface IdmValidatorService {
boolean valueExists(String value);
}

View file

@ -16,6 +16,5 @@
"password_pattern": "^((?=(.*\\d){1,})(?=.*[a-zа-яё])(?=.*[A-ZА-ЯЁ]).{8,})$",
"password_pattern_error": "Пароль должен содержать заглавные или прописные буквы и как минимум 1 цифру",
"show.client.errors": false,
"available_task.single_fetch": true,
"ervu_url": "https://ervu-dev.pgs.rtlabs.ru/service"
"available_task.single_fetch": true
}

View file

@ -1,36 +0,0 @@
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import {Observable, throwError} from 'rxjs';
import {catchError, map} from "rxjs/operators";
import {AppConfigService} from "@webbpm/base-package";
@Injectable({
providedIn: 'root'
})
export class IdmService {
private ervuUrl: string;
constructor(private http: HttpClient, appConfigService: AppConfigService) {
this.ervuUrl = appConfigService.getParamValue("ervu_url");
}
checkLoginExists(login: string): Observable<boolean> {
const url = `${this.ervuUrl}/idm/credentials/login/${login}`;
return this.http.get<any[]>(url).pipe(
map(response =>
response.length > 0 && response.some(user => user.userName === login)
),
catchError(error => throwError(error))
);
}
checkSnilsExists(snils: string): Observable<boolean> {
const url = `${this.ervuUrl}/idm/persons?query=snils%3D%3D%22${snils}%22`;
return this.http.get<{ records: any[] }>(url).pipe(
map(response =>
response.records.length > 0 && response.records.some(person => person.snils === snils)
),
catchError(error => throwError(error))
);
}
}

View file

@ -1,19 +1,22 @@
import {SimpleValidator, TextField} from "@webbpm/base-package";
import {Observable} from "rxjs";
import {IdmService} from "../IdmService";
import {
IdmValidatorRpcService
} from "../../../generated/ru/micord/ervu/account_applications/component/rpc/IdmValidatorRpcService";
import {first} from "rxjs/operators";
export abstract class AbstractIdmValidator extends SimpleValidator {
protected abstract ERROR_MESSAGE: string;
protected abstract checkValueExists(value: string): Observable<boolean>;
protected textField: TextField;
protected idmService: IdmService;
protected rpcService: IdmValidatorRpcService;
protected textInput: HTMLInputElement;
initialize(): void {
super.initialize();
this.textField = this.getScript(TextField);
this.idmService = this.injector.get(IdmService);
this.rpcService = this.getScript(IdmValidatorRpcService);
this.textInput = this.textField.getEl().nativeElement.querySelector('input');
this.textInput.addEventListener('blur', this.onBlurHandler.bind(this));
}
@ -25,17 +28,16 @@ export abstract class AbstractIdmValidator extends SimpleValidator {
const cleanedValue = this.cleanValue(inputValue);
if (!this.isPatternValid(cleanedValue)) return Promise.resolve(false);
return this.checkValueExists(cleanedValue).toPromise().then(
(exists) => {
return this.checkValueExists(cleanedValue).pipe(first()).toPromise()
.then(exists => {
this.pushError(!exists, this.ERROR_MESSAGE);
return !exists;
},
(err) => {
})
.catch(err => {
const fieldName = this.textField.getObjectName();
console.error(`Ошибка проверки ${fieldName}: ${err.message}`);
return false;
}
);
});
}
private async onBlurHandler(event: FocusEvent): Promise<void> {

View file

@ -1,11 +1,11 @@
import {Observable} from "rxjs";
import {from, Observable} from "rxjs";
import {AbstractIdmValidator} from "./AbstractIdmValidator";
export class IdmLoginValidator extends AbstractIdmValidator {
protected ERROR_MESSAGE = "Пользователь с указанным логином уже существует";
protected checkValueExists(value: string): Observable<boolean> {
return this.idmService.checkLoginExists(value);
return from(this.rpcService.valueExists(value));
}
protected isPatternValid(value: string): boolean {

View file

@ -1,11 +1,11 @@
import {Observable} from "rxjs";
import {from, Observable} from "rxjs";
import {AbstractIdmValidator} from "./AbstractIdmValidator";
export class IdmSnilsValidator extends AbstractIdmValidator {
protected ERROR_MESSAGE = "Пользователь с указанным СНИЛС уже существует";
protected checkValueExists(value: string): Observable<boolean> {
return this.idmService.checkSnilsExists(value);
return from(this.rpcService.valueExists(value));
}
protected cleanValue(value: string): string {

View file

@ -2033,6 +2033,25 @@
<enabled>true</enabled>
<expanded>true</expanded>
</scripts>
<scripts id="d70e3509-97f9-4a71-bc3c-46f316373662">
<classRef type="JAVA">
<className>IdmValidatorRpcService</className>
<packageName>ru.micord.ervu.account_applications.component.rpc</packageName>
</classRef>
<enabled>true</enabled>
<expanded>true</expanded>
<properties>
<entry>
<key>validatorService</key>
<value>
<implRef type="JAVA">
<className>IdmLoginValidatorService</className>
<packageName>ru.micord.ervu.account_applications.component.service</packageName>
</implRef>
</value>
</entry>
</properties>
</scripts>
</children>
<children id="d260fc10-b0a6-4aff-92cc-6da81ddbedc0">
<prototypeId>b310f98a-69c6-4e7b-8cdb-f1ab9f9c0d94</prototypeId>
@ -2185,6 +2204,25 @@
<enabled>true</enabled>
<expanded>true</expanded>
</scripts>
<scripts id="cbeb2f00-ea44-4d3a-803c-8f995cafcb75">
<classRef type="JAVA">
<className>IdmValidatorRpcService</className>
<packageName>ru.micord.ervu.account_applications.component.rpc</packageName>
</classRef>
<enabled>true</enabled>
<expanded>true</expanded>
<properties>
<entry>
<key>validatorService</key>
<value>
<implRef type="JAVA">
<className>IdmSnilsValidatorService</className>
<packageName>ru.micord.ervu.account_applications.component.service</packageName>
</implRef>
</value>
</entry>
</properties>
</scripts>
</children>
<children id="dd4cd434-7c4a-46d6-85dc-ef991a460d8f">
<prototypeId>d7d54cfb-26b5-4dba-b56f-b6247183c24d</prototypeId>