LP: added package validation

This commit is contained in:
Mikhail Trofimov 2026-06-30 12:56:53 +03:00
parent 50b8eeee89
commit 15c651debd
7 changed files with 86 additions and 20 deletions

View file

@ -1,7 +1,7 @@
package ru.nbch.credit_tracker.component; package ru.nbch.credit_tracker.component;
import java.util.concurrent.atomic.AtomicBoolean;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartFile;
import ru.nbch.credit_tracker.config.settings.CreditTrackerSettings; import ru.nbch.credit_tracker.config.settings.CreditTrackerSettings;
@ -11,8 +11,8 @@ import ru.nbch.credit_tracker.enums.XmlErrorFormat;
import ru.nbch.credit_tracker.exceptions.SignalException; import ru.nbch.credit_tracker.exceptions.SignalException;
import ru.nbch.credit_tracker.model.MonitoringValidationError; import ru.nbch.credit_tracker.model.MonitoringValidationError;
import ru.nbch.credit_tracker.model.ValidationResult; import ru.nbch.credit_tracker.model.ValidationResult;
import ru.nbch.credit_tracker.service.xml.stax.StaxXmlProcessor;
import ru.nbch.credit_tracker.service.ValidationService; import ru.nbch.credit_tracker.service.ValidationService;
import ru.nbch.credit_tracker.service.xml.stax.StaxXmlProcessor;
import ru.nbch.credit_tracker.utils.ZipUtils; import ru.nbch.credit_tracker.utils.ZipUtils;
import java.io.BufferedInputStream; import java.io.BufferedInputStream;
@ -20,6 +20,7 @@ import java.io.IOException;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
import java.util.Optional; import java.util.Optional;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.zip.ZipEntry; import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream; import java.util.zip.ZipInputStream;
@ -85,6 +86,11 @@ public class MonitoringRequestValidator {
if (request.getPassword() != null && validationResult.getPassword() == null) { if (request.getPassword() != null && validationResult.getPassword() == null) {
validationResult.setPassword(request.getPassword()); validationResult.setPassword(request.getPassword());
} }
if (StringUtils.isBlank(request.getSubjectType()) && validationResult.getSubjectType() == null) {
validationResult.setSubjectType(1);
} else if (StringUtils.isNotBlank(request.getSubjectType()) && validationResult.getSubjectType() == null) {
validationResult.setSubjectType(2);
}
if (request.getSignalTypes() != null && !request.getSignalTypes().isEmpty() if (request.getSignalTypes() != null && !request.getSignalTypes().isEmpty()
&& validationResult.getSignalTypes().isEmpty()) { && validationResult.getSignalTypes().isEmpty()) {
validationResult.setSignalTypes(request.getSignalTypes()); validationResult.setSignalTypes(request.getSignalTypes());

View file

@ -1,16 +1,13 @@
package ru.nbch.credit_tracker.entities.user_request.monitoring_request; package ru.nbch.credit_tracker.entities.user_request.monitoring_request;
import jakarta.xml.bind.annotation.XmlAccessType; import jakarta.xml.bind.annotation.*;
import jakarta.xml.bind.annotation.XmlAccessorType;
import jakarta.xml.bind.annotation.XmlElement;
import jakarta.xml.bind.annotation.XmlRootElement;
import jakarta.xml.bind.annotation.XmlType;
import java.util.ArrayList;
import java.util.List;
import lombok.Getter; import lombok.Getter;
import lombok.Setter; import lombok.Setter;
import java.util.ArrayList;
import java.util.List;
@Setter @Setter
@Getter @Getter
@ -19,6 +16,7 @@ import lombok.Setter;
"userId", "userId",
"password", "password",
"packageName", "packageName",
"subjectType",
"subjects" "subjects"
}) })
@XmlRootElement(name = "MonitoringRequest") @XmlRootElement(name = "MonitoringRequest")
@ -30,6 +28,8 @@ public class MonitoringRequest {
protected String password; protected String password;
@XmlElement(name = "PackageName", required = true) @XmlElement(name = "PackageName", required = true)
protected String packageName; protected String packageName;
@XmlElement(name = "SubjectType", required = false)
protected String subjectType;
@XmlElement(name = "Subjects", required = true) @XmlElement(name = "Subjects", required = true)
protected Subjects subjects; protected Subjects subjects;
protected List<Integer> signalTypes = null; protected List<Integer> signalTypes = null;

View file

@ -14,7 +14,9 @@ import lombok.Setter;
@XmlAccessorType(XmlAccessType.FIELD) @XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "SubjectType", propOrder = { @XmlType(name = "SubjectType", propOrder = {
"id", "id",
"clientId" "clientId",
"inn",
"regNum"
}) })
public class Subject { public class Subject {
@ -24,5 +26,10 @@ public class Subject {
@XmlElement(name = "ClientId", required = true) @XmlElement(name = "ClientId", required = true)
protected String clientId; protected String clientId;
@XmlElement(name = "Inn", required = true)
protected String inn;
@XmlElement(name = "RegNum", required = true)
protected String regNum;
} }

View file

@ -28,6 +28,9 @@ public enum SignalError implements IEnumKeyCode {
ERROR_026("026", "Пакет {} обновляется. Удаление невозможно. Дождитесь завершения обновления и повторите попытку."), ERROR_026("026", "Пакет {} обновляется. Удаление невозможно. Дождитесь завершения обновления и повторите попытку."),
ERROR_027("027", "Недопустимое значение в элементе SignalTypes"), ERROR_027("027", "Недопустимое значение в элементе SignalTypes"),
ERROR_028("028", "Некорректный формат запроса: в теле ожидается ZIP-архив"), ERROR_028("028", "Некорректный формат запроса: в теле ожидается ZIP-архив"),
ERROR_029("029", "Элемент Inn не соответствует формату XXXXXXXXX. Id: {}"),
ERROR_030("030", "Элемент RegNum не соответствует формату XXXXXXXXXXXXX. Id: {}"),
ERROR_031("031", "Состав Subject не соответствует типу пакета"),
; ;

View file

@ -7,6 +7,7 @@ public class ValidationResult {
private String packageName; private String packageName;
private String userId; private String userId;
private String password; private String password;
private Integer subjectType;
private List<Integer> signalTypes = new ArrayList<>(); private List<Integer> signalTypes = new ArrayList<>();
private List<MonitoringValidationError> validationErrors = new ArrayList<>(); private List<MonitoringValidationError> validationErrors = new ArrayList<>();
@ -41,6 +42,14 @@ public class ValidationResult {
this.password = password; this.password = password;
} }
public Integer getSubjectType() {
return subjectType;
}
public void setSubjectType(Integer subjectType) {
this.subjectType = subjectType;
}
public List<Integer> getSignalTypes() { public List<Integer> getSignalTypes() {
return signalTypes; return signalTypes;
} }

View file

@ -1,8 +1,7 @@
package ru.nbch.credit_tracker.service; package ru.nbch.credit_tracker.service;
import java.util.List;
import java.util.regex.Pattern;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import ru.nbch.credit_tracker.config.mdc.SetAndClearMdc; import ru.nbch.credit_tracker.config.mdc.SetAndClearMdc;
import ru.nbch.credit_tracker.entities.user_request.monitoring_request.MonitoringRequest; import ru.nbch.credit_tracker.entities.user_request.monitoring_request.MonitoringRequest;
@ -10,6 +9,10 @@ import ru.nbch.credit_tracker.entities.user_request.monitoring_request.Subject;
import ru.nbch.credit_tracker.enums.SignalError; import ru.nbch.credit_tracker.enums.SignalError;
import ru.nbch.credit_tracker.enums.XmlErrorFormat; import ru.nbch.credit_tracker.enums.XmlErrorFormat;
import ru.nbch.credit_tracker.exceptions.SignalClientException; import ru.nbch.credit_tracker.exceptions.SignalClientException;
import java.util.List;
import java.util.regex.Pattern;
import static ru.nbch.credit_tracker.utils.error.ExceptionUtils.clientExcp; import static ru.nbch.credit_tracker.utils.error.ExceptionUtils.clientExcp;
@Slf4j @Slf4j
@ -17,6 +20,8 @@ import static ru.nbch.credit_tracker.utils.error.ExceptionUtils.clientExcp;
public class ValidationService { public class ValidationService {
private static final String phoneRegex = "^\\d{9}$"; private static final String phoneRegex = "^\\d{9}$";
private static final String innRegex = "^\\d{10}$";
private static final String regNumRegex = "^\\d{13}$";
private static final String packageNameRegex = "^[A-Z0-9_]{1,22}$"; private static final String packageNameRegex = "^[A-Z0-9_]{1,22}$";
private static final String npIdRegex = "^\\S{1,36}$"; private static final String npIdRegex = "^\\S{1,36}$";
@ -44,6 +49,10 @@ public class ValidationService {
throw clientExcp(SignalError.ERROR_002, packageName, XmlErrorFormat.MonitoringError, "Password"); throw clientExcp(SignalError.ERROR_002, packageName, XmlErrorFormat.MonitoringError, "Password");
} }
if (StringUtils.isNotBlank(request.getSubjectType()) && !request.getSubjectType().equalsIgnoreCase("LEGAL")) {
throw clientExcp(SignalError.ERROR_031, XmlErrorFormat.MonitoringError);
}
if (request.getSubjects() == null) { if (request.getSubjects() == null) {
throw clientExcp(SignalError.ERROR_002, packageName, XmlErrorFormat.MonitoringError, "Subjects"); throw clientExcp(SignalError.ERROR_002, packageName, XmlErrorFormat.MonitoringError, "Subjects");
} }
@ -54,20 +63,34 @@ public class ValidationService {
List<Integer> signalTypes = request.getSignalTypes(); List<Integer> signalTypes = request.getSignalTypes();
if (signalTypes != null) { if (signalTypes != null) {
boolean validValues = !signalTypes.isEmpty() && signalTypes.stream().allMatch(integer -> integer == 1 || integer == 2); boolean validValues = !signalTypes.isEmpty() && signalTypes.stream().allMatch(integer -> integer == 1 || integer == 2 || integer == 3);
if (!validValues) { if (!validValues) {
throw clientExcp(SignalError.ERROR_027, packageName, XmlErrorFormat.MonitoringError); throw clientExcp(SignalError.ERROR_027, packageName, XmlErrorFormat.MonitoringError);
} }
} }
if (StringUtils.isBlank(request.getSubjectType())) {
for (Subject subject : request.getSubjects().getSubject()) { for (Subject subject : request.getSubjects().getSubject()) {
if (!validateNPId(subject.getId())) { if (!validateId(subject.getId())) {
throw clientExcp(SignalError.ERROR_010, packageName, XmlErrorFormat.MonitoringError, subject.getId()); throw clientExcp(SignalError.ERROR_010, packageName, XmlErrorFormat.MonitoringError, subject.getId());
} }
if (!validatePhone(subject.getClientId())) { if (!validatePhone(subject.getClientId())) {
throw clientExcp(SignalError.ERROR_003, packageName, XmlErrorFormat.MonitoringError, subject.getId()); throw clientExcp(SignalError.ERROR_003, packageName, XmlErrorFormat.MonitoringError, subject.getId());
} }
} }
} else {
for (Subject subject : request.getSubjects().getSubject()) {
if (!validateId(subject.getId())) {
throw clientExcp(SignalError.ERROR_010, packageName, XmlErrorFormat.MonitoringError, subject.getId());
}
if (!validateInn(subject.getInn())) {
throw clientExcp(SignalError.ERROR_029, packageName, XmlErrorFormat.MonitoringError, subject.getId());
}
if (!validateRegNum(subject.getRegNum())) {
throw clientExcp(SignalError.ERROR_030, packageName, XmlErrorFormat.MonitoringError, subject.getId());
}
}
}
} }
private static boolean validatePhone(String input) { private static boolean validatePhone(String input) {
@ -77,6 +100,20 @@ public class ValidationService {
return Pattern.matches(phoneRegex, input); return Pattern.matches(phoneRegex, input);
} }
private static boolean validateInn(String input) {
if (input == null) {
return false;
}
return Pattern.matches(innRegex, input);
}
private static boolean validateRegNum(String input) {
if (input == null) {
return false;
}
return Pattern.matches(regNumRegex, input);
}
private static boolean validatePackageName(String input) { private static boolean validatePackageName(String input) {
if (input == null) { if (input == null) {
return false; return false;
@ -84,7 +121,7 @@ public class ValidationService {
return Pattern.matches(packageNameRegex, input); return Pattern.matches(packageNameRegex, input);
} }
private static boolean validateNPId(String input) { private static boolean validateId(String input) {
if (input == null) { if (input == null) {
return false; return false;
} }

View file

@ -1,8 +1,9 @@
package ru.nbch.credit_tracker.service.xml.stax; package ru.nbch.credit_tracker.service.xml.stax;
import ru.nbch.credit_tracker.entities.user_request.monitoring_request.MonitoringRequest;
import javax.xml.stream.XMLStreamException; import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader; import javax.xml.stream.XMLStreamReader;
import ru.nbch.credit_tracker.entities.user_request.monitoring_request.MonitoringRequest;
public class MonitoringRequestStaxReader extends BaseStaxReader<MonitoringRequest> { public class MonitoringRequestStaxReader extends BaseStaxReader<MonitoringRequest> {
@ -24,12 +25,15 @@ public class MonitoringRequestStaxReader extends BaseStaxReader<MonitoringReques
case "/MonitoringRequest/UserId" -> obj.setUserId(text); case "/MonitoringRequest/UserId" -> obj.setUserId(text);
case "/MonitoringRequest/Password" -> obj.setPassword(text); case "/MonitoringRequest/Password" -> obj.setPassword(text);
case "/MonitoringRequest/PackageName" -> obj.setPackageName(text); case "/MonitoringRequest/PackageName" -> obj.setPackageName(text);
case "/MonitoringRequest/SubjectType" -> obj.setSubjectType(text);
case "/MonitoringRequest/SignalTypes/SignalType" -> { case "/MonitoringRequest/SignalTypes/SignalType" -> {
if (!text.isEmpty()) obj.getSignalTypes().add(Integer.parseInt(text)); if (!text.isEmpty()) obj.getSignalTypes().add(Integer.parseInt(text));
} }
case "/MonitoringRequest/Subjects/Subject" -> obj.finalizeSubject(); case "/MonitoringRequest/Subjects/Subject" -> obj.finalizeSubject();
case "/MonitoringRequest/Subjects/Subject/Id" -> obj.getCurrentSubject().setId(text); case "/MonitoringRequest/Subjects/Subject/Id" -> obj.getCurrentSubject().setId(text);
case "/MonitoringRequest/Subjects/Subject/ClientId" -> obj.getCurrentSubject().setClientId(text); case "/MonitoringRequest/Subjects/Subject/ClientId" -> obj.getCurrentSubject().setClientId(text);
case "/MonitoringRequest/Subjects/Subject/Inn" -> obj.getCurrentSubject().setInn(text);
case "/MonitoringRequest/Subjects/Subject/RegNum" -> obj.getCurrentSubject().setRegNum(text);
} }
return false; return false;
} }