Merge branch 'hotfix/1.9.9' into feature/SUPPORT-8643_error_code
# Conflicts: # frontend/src/ts/modules/security/guard/auth.guard.ts
This commit is contained in:
commit
89ff7b8747
169 changed files with 1561 additions and 375 deletions
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ru.micord.ervu.lkrp</groupId>
|
||||
<artifactId>fl</artifactId>
|
||||
<version>1.9.8-SNAPSHOT</version>
|
||||
<version>1.9.9-SNAPSHOT</version>
|
||||
</parent>
|
||||
<groupId>ru.micord.ervu.lkrp.fl</groupId>
|
||||
<artifactId>backend</artifactId>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,88 @@
|
|||
package ru.micord.ervu.audit.config;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.kafka.clients.CommonClientConfigs;
|
||||
import org.apache.kafka.clients.admin.AdminClientConfig;
|
||||
import org.apache.kafka.clients.admin.NewTopic;
|
||||
import org.apache.kafka.clients.producer.ProducerConfig;
|
||||
import org.apache.kafka.common.config.SaslConfigs;
|
||||
import org.apache.kafka.common.serialization.StringSerializer;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.kafka.config.TopicBuilder;
|
||||
import org.springframework.kafka.core.DefaultKafkaProducerFactory;
|
||||
import org.springframework.kafka.core.KafkaAdmin;
|
||||
import org.springframework.kafka.core.KafkaTemplate;
|
||||
import org.springframework.kafka.core.ProducerFactory;
|
||||
|
||||
/**
|
||||
* @author Adel Kalimullin
|
||||
*/
|
||||
@Configuration
|
||||
public class AuditKafkaConfig {
|
||||
@Value("${audit.kafka.bootstrap.servers}")
|
||||
private String bootstrapServers;
|
||||
@Value("${audit.kafka.security.protocol}")
|
||||
private String securityProtocol;
|
||||
@Value("${audit.kafka.login.module:org.apache.kafka.common.security.scram.ScramLoginModule}")
|
||||
private String loginModule;
|
||||
@Value("${audit.kafka.username}")
|
||||
private String username;
|
||||
@Value("${audit.kafka.password}")
|
||||
private String password;
|
||||
@Value("${audit.kafka.sasl.mechanism}")
|
||||
private String saslMechanism;
|
||||
@Value("${audit.kafka.authorization.topic}")
|
||||
private String authorizationTopic;
|
||||
@Value("${audit.kafka.action.topic}")
|
||||
private String actionTopic;
|
||||
@Value("${audit.kafka.file.download.topic}")
|
||||
private String fileDownloadTopic;
|
||||
|
||||
@Bean("auditProducerFactory")
|
||||
public ProducerFactory<String, String> producerFactory() {
|
||||
Map<String, Object> configProps = new HashMap<>();
|
||||
configProps.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, bootstrapServers);
|
||||
configProps.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, StringSerializer.class);
|
||||
configProps.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, StringSerializer.class);
|
||||
configProps.put(CommonClientConfigs.SECURITY_PROTOCOL_CONFIG, securityProtocol);
|
||||
configProps.put(SaslConfigs.SASL_JAAS_CONFIG, loginModule + " required username=\""
|
||||
+ username + "\" password=\"" + password + "\";");
|
||||
configProps.put(SaslConfigs.SASL_MECHANISM, saslMechanism);
|
||||
return new DefaultKafkaProducerFactory<>(configProps);
|
||||
}
|
||||
|
||||
@Bean("auditTemplate")
|
||||
public KafkaTemplate<String, String> kafkaTemplate() {
|
||||
return new KafkaTemplate<>(producerFactory());
|
||||
}
|
||||
|
||||
@Bean
|
||||
public KafkaAdmin auditKafkaAdmin() {
|
||||
Map<String, Object> configs = new HashMap<>();
|
||||
configs.put(AdminClientConfig.BOOTSTRAP_SERVERS_CONFIG, bootstrapServers);
|
||||
configs.put(AdminClientConfig.SECURITY_PROTOCOL_CONFIG, securityProtocol);
|
||||
configs.put(SaslConfigs.SASL_JAAS_CONFIG, loginModule + " required username=\""
|
||||
+ username + "\" password=\"" + password + "\";");
|
||||
configs.put(SaslConfigs.SASL_MECHANISM, saslMechanism);
|
||||
return new KafkaAdmin(configs);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public NewTopic auditAuthTopic() {
|
||||
return TopicBuilder.name(authorizationTopic).build();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public NewTopic auditActionTopic() {
|
||||
return TopicBuilder.name(actionTopic).build();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public NewTopic auditDownloadTopic() {
|
||||
return TopicBuilder.name(fileDownloadTopic).build();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
package ru.micord.ervu.audit.constants;
|
||||
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* @author Adel Kalimullin
|
||||
*/
|
||||
public final class AuditConstants {
|
||||
public static final String SUBSYSTEM_TYPE = "FL";
|
||||
public static final String LOGOUT_EVENT_TYPE = "logout";
|
||||
public static final String LOGIN_EVENT_TYPE = "login";
|
||||
public static final String SUCCESS_STATUS = "success";
|
||||
public static final String FAILURE_STATUS = "failure";
|
||||
|
||||
private static final Map<String, String> routeDescriptions = Map.of(
|
||||
"/", "Главная",
|
||||
"/mydata", "Мои данные",
|
||||
"/subpoena", "Повестки",
|
||||
"/restriction", "Временные меры"
|
||||
);
|
||||
|
||||
private static final Map<String, String> downloadTypes = Map.of(
|
||||
"1", "Выписка из реестра воинского учета ФЛ",
|
||||
"2", "Выписка из реестра повесток ФЛ"
|
||||
);
|
||||
|
||||
public static String getRouteDescription(String route) {
|
||||
return Optional.ofNullable(routeDescriptions.get(route))
|
||||
.orElseThrow(() -> new IllegalArgumentException("Invalid route :" + route));
|
||||
}
|
||||
|
||||
public static String getDownloadType(String formatRegistry) {
|
||||
return Optional.ofNullable(downloadTypes.get(formatRegistry))
|
||||
.orElseThrow(
|
||||
() -> new IllegalArgumentException("Invalid formatRegistry :" + formatRegistry));
|
||||
}
|
||||
|
||||
private AuditConstants() {
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
package ru.micord.ervu.audit.controller;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import ru.micord.ervu.audit.model.AuditActionRequest;
|
||||
import ru.micord.ervu.audit.service.AuditService;
|
||||
|
||||
/**
|
||||
* @author Adel Kalimullin
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/audit")
|
||||
public class AuditController {
|
||||
private final AuditService auditService;
|
||||
|
||||
public AuditController(AuditService auditService) {
|
||||
this.auditService = auditService;
|
||||
}
|
||||
|
||||
@PostMapping("/action")
|
||||
public ResponseEntity<Void> auditAction(HttpServletRequest request,
|
||||
@RequestBody AuditActionRequest actionEvent) {
|
||||
auditService.processActionEvent(request, actionEvent);
|
||||
return ResponseEntity.ok().build();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,53 @@
|
|||
package ru.micord.ervu.audit.model;
|
||||
|
||||
/**
|
||||
* @author Adel Kalimullin
|
||||
*/
|
||||
public class AuditActionEvent extends AuditEvent {
|
||||
private String eventType;
|
||||
private String description;
|
||||
private String sourceUrl;
|
||||
private String fileName;
|
||||
|
||||
public AuditActionEvent(
|
||||
String esiaPersonId, String eventTime, String eventType,
|
||||
String description, String sourceUrl, String fileName) {
|
||||
super(esiaPersonId, eventTime);
|
||||
this.eventType = eventType;
|
||||
this.description = description;
|
||||
this.sourceUrl = sourceUrl;
|
||||
this.fileName = fileName;
|
||||
}
|
||||
|
||||
public String getFileName() {
|
||||
return fileName;
|
||||
}
|
||||
|
||||
public void setFileName(String fileName) {
|
||||
this.fileName = fileName;
|
||||
}
|
||||
|
||||
public String getEventType() {
|
||||
return eventType;
|
||||
}
|
||||
|
||||
public void setEventType(String eventType) {
|
||||
this.eventType = eventType;
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
public void setDescription(String description) {
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
public String getSourceUrl() {
|
||||
return sourceUrl;
|
||||
}
|
||||
|
||||
public void setSourceUrl(String sourceUrl) {
|
||||
this.sourceUrl = sourceUrl;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
package ru.micord.ervu.audit.model;
|
||||
|
||||
/**
|
||||
* @author Adel Kalimullin
|
||||
*/
|
||||
public class AuditActionRequest {
|
||||
private String route;
|
||||
private String sourceUrl;
|
||||
private String eventType;
|
||||
private String fileName;
|
||||
|
||||
public String getFileName() {
|
||||
return fileName;
|
||||
}
|
||||
|
||||
public void setFileName(String fileName) {
|
||||
this.fileName = fileName;
|
||||
}
|
||||
|
||||
public String getRoute() {
|
||||
return route;
|
||||
}
|
||||
|
||||
public void setRoute(String route) {
|
||||
this.route = route;
|
||||
}
|
||||
|
||||
public String getSourceUrl() {
|
||||
return sourceUrl;
|
||||
}
|
||||
|
||||
public void setSourceUrl(String sourceUrl) {
|
||||
this.sourceUrl = sourceUrl;
|
||||
}
|
||||
|
||||
public String getEventType() {
|
||||
return eventType;
|
||||
}
|
||||
|
||||
public void setEventType(String eventType) {
|
||||
this.eventType = eventType;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,113 @@
|
|||
package ru.micord.ervu.audit.model;
|
||||
|
||||
|
||||
public class AuditAuthorizationEvent extends AuditEvent {
|
||||
private String status;
|
||||
private String eventType;
|
||||
private String firstName;
|
||||
private String lastName;
|
||||
private String middleName;
|
||||
private String snils;
|
||||
private String serverIp;
|
||||
private String serverHostName;
|
||||
private String clientIp;
|
||||
private String clientHostName;
|
||||
|
||||
public AuditAuthorizationEvent(
|
||||
String esiaPersonId, String eventTime, String firstName,
|
||||
String lastName, String middleName, String snils,
|
||||
String status, String eventType, String serverIp,
|
||||
String serverHostName, String clientIp, String clientHostName) {
|
||||
super(esiaPersonId, eventTime);
|
||||
this.status = status;
|
||||
this.firstName = firstName;
|
||||
this.lastName = lastName;
|
||||
this.middleName = middleName;
|
||||
this.snils = snils;
|
||||
this.eventType = eventType;
|
||||
this.serverIp = serverIp;
|
||||
this.serverHostName = serverHostName;
|
||||
this.clientIp = clientIp;
|
||||
this.clientHostName = clientHostName;
|
||||
}
|
||||
|
||||
public String getFirstName() {
|
||||
return firstName;
|
||||
}
|
||||
|
||||
public void setFirstName(String firstName) {
|
||||
this.firstName = firstName;
|
||||
}
|
||||
|
||||
public String getLastName() {
|
||||
return lastName;
|
||||
}
|
||||
|
||||
public void setLastName(String lastName) {
|
||||
this.lastName = lastName;
|
||||
}
|
||||
|
||||
public String getMiddleName() {
|
||||
return middleName;
|
||||
}
|
||||
|
||||
public void setMiddleName(String middleName) {
|
||||
this.middleName = middleName;
|
||||
}
|
||||
|
||||
public String getSnils() {
|
||||
return snils;
|
||||
}
|
||||
|
||||
public void setSnils(String snils) {
|
||||
this.snils = snils;
|
||||
}
|
||||
|
||||
public String getStatus() {
|
||||
return status;
|
||||
}
|
||||
|
||||
public void setStatus(String status) {
|
||||
this.status = status;
|
||||
}
|
||||
|
||||
public String getEventType() {
|
||||
return eventType;
|
||||
}
|
||||
|
||||
public void setEventType(String eventType) {
|
||||
this.eventType = eventType;
|
||||
}
|
||||
|
||||
public String getServerIp() {
|
||||
return serverIp;
|
||||
}
|
||||
|
||||
public void setServerIp(String serverIp) {
|
||||
this.serverIp = serverIp;
|
||||
}
|
||||
|
||||
public String getServerHostName() {
|
||||
return serverHostName;
|
||||
}
|
||||
|
||||
public void setServerHostName(String serverHostName) {
|
||||
this.serverHostName = serverHostName;
|
||||
}
|
||||
|
||||
public String getClientIp() {
|
||||
return clientIp;
|
||||
}
|
||||
|
||||
public void setClientIp(String clientIp) {
|
||||
this.clientIp = clientIp;
|
||||
}
|
||||
|
||||
public String getClientHostName() {
|
||||
return clientHostName;
|
||||
}
|
||||
|
||||
public void setClientHostName(String clientHostName) {
|
||||
this.clientHostName = clientHostName;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,65 @@
|
|||
package ru.micord.ervu.audit.model;
|
||||
|
||||
|
||||
/**
|
||||
* @author Adel Kalimullin
|
||||
*/
|
||||
public class AuditDownloadEvent extends AuditEvent {
|
||||
private String downloadType;
|
||||
private String fileName;
|
||||
private String s3FileUrl;
|
||||
private String fileSize;
|
||||
private String status;
|
||||
|
||||
public AuditDownloadEvent(
|
||||
String esiaPersonId, String eventTime, String downloadType,
|
||||
String fileName, String s3FileUrl, String fileSize,
|
||||
String status) {
|
||||
super(esiaPersonId, eventTime);
|
||||
this.downloadType = downloadType;
|
||||
this.fileName = fileName;
|
||||
this.s3FileUrl = s3FileUrl;
|
||||
this.fileSize = fileSize;
|
||||
this.status = status;
|
||||
}
|
||||
|
||||
public String getS3FileUrl() {
|
||||
return s3FileUrl;
|
||||
}
|
||||
|
||||
public void setS3FileUrl(String s3FileUrl) {
|
||||
this.s3FileUrl = s3FileUrl;
|
||||
}
|
||||
|
||||
public String getDownloadType() {
|
||||
return downloadType;
|
||||
}
|
||||
|
||||
public void setDownloadType(String downloadType) {
|
||||
this.downloadType = downloadType;
|
||||
}
|
||||
|
||||
public String getFileName() {
|
||||
return fileName;
|
||||
}
|
||||
|
||||
public void setFileName(String fileName) {
|
||||
this.fileName = fileName;
|
||||
}
|
||||
|
||||
public String getFileSize() {
|
||||
return fileSize;
|
||||
}
|
||||
|
||||
public void setFileSize(String fileSize) {
|
||||
this.fileSize = fileSize;
|
||||
}
|
||||
|
||||
public String getStatus() {
|
||||
return status;
|
||||
}
|
||||
|
||||
public void setStatus(String status) {
|
||||
this.status = status;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
package ru.micord.ervu.audit.model;
|
||||
|
||||
import ru.micord.ervu.audit.constants.AuditConstants;
|
||||
|
||||
/**
|
||||
* @author Adel Kalimullin
|
||||
*/
|
||||
|
||||
public abstract class AuditEvent {
|
||||
protected final String subsystem = AuditConstants.SUBSYSTEM_TYPE;
|
||||
protected String esiaPersonId;
|
||||
protected String eventTime;
|
||||
|
||||
protected AuditEvent(String esiaPersonId, String eventTime) {
|
||||
this.esiaPersonId = esiaPersonId;
|
||||
this.eventTime = eventTime;
|
||||
}
|
||||
|
||||
public String getEsiaPersonId() {
|
||||
return esiaPersonId;
|
||||
}
|
||||
|
||||
public void setEsiaPersonId(String esiaPersonId) {
|
||||
this.esiaPersonId = esiaPersonId;
|
||||
}
|
||||
|
||||
public String getSubsystem() {
|
||||
return subsystem;
|
||||
}
|
||||
|
||||
public String getEventTime() {
|
||||
return eventTime;
|
||||
}
|
||||
|
||||
public void setEventTime(String eventTime) {
|
||||
this.eventTime = eventTime;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
package ru.micord.ervu.audit.service;
|
||||
|
||||
/**
|
||||
* @author Adel Kalimullin
|
||||
*/
|
||||
public interface AuditKafkaPublisher {
|
||||
void publishEvent(String topicName, String message);
|
||||
}
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
package ru.micord.ervu.audit.service;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import ru.micord.ervu.audit.model.AuditActionRequest;
|
||||
import ru.micord.ervu.security.esia.model.PersonModel;
|
||||
|
||||
/**
|
||||
* @author Adel Kalimullin
|
||||
*/
|
||||
public interface AuditService {
|
||||
void processActionEvent(HttpServletRequest request, AuditActionRequest auditActionRequest);
|
||||
|
||||
void processAuthEvent(HttpServletRequest request, PersonModel personModel, String status,
|
||||
String eventType);
|
||||
|
||||
void processDownloadEvent(HttpServletRequest request, int fileSize, String fileName,
|
||||
String formatRegistry, String status);
|
||||
}
|
||||
|
|
@ -0,0 +1,42 @@
|
|||
package ru.micord.ervu.audit.service.impl;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.kafka.core.KafkaTemplate;
|
||||
import org.springframework.stereotype.Service;
|
||||
import ru.micord.ervu.audit.service.AuditKafkaPublisher;
|
||||
|
||||
/**
|
||||
* @author Adel Kalimullin
|
||||
*/
|
||||
@Service
|
||||
public class BaseAuditKafkaPublisher implements AuditKafkaPublisher {
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(BaseAuditKafkaPublisher.class);
|
||||
private final KafkaTemplate<String, String> kafkaTemplate;
|
||||
@Value("${audit.kafka.enabled}")
|
||||
private boolean auditEnabled;
|
||||
|
||||
public BaseAuditKafkaPublisher(
|
||||
@Qualifier("auditTemplate") KafkaTemplate<String, String> kafkaTemplate) {
|
||||
this.kafkaTemplate = kafkaTemplate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void publishEvent(String topic, String message) {
|
||||
if (auditEnabled) {
|
||||
kafkaTemplate.send(topic, message)
|
||||
.addCallback(
|
||||
result -> {
|
||||
},
|
||||
ex -> LOGGER.error("Failed to send message to topic {}: {}", topic, ex.getMessage(),
|
||||
ex
|
||||
)
|
||||
);
|
||||
}
|
||||
else {
|
||||
LOGGER.info("Audit is disabled. Event not published.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,114 @@
|
|||
package ru.micord.ervu.audit.service.impl;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Service;
|
||||
import ru.micord.ervu.audit.constants.AuditConstants;
|
||||
import ru.micord.ervu.audit.model.AuditActionEvent;
|
||||
import ru.micord.ervu.audit.model.AuditActionRequest;
|
||||
import ru.micord.ervu.audit.model.AuditAuthorizationEvent;
|
||||
import ru.micord.ervu.audit.model.AuditDownloadEvent;
|
||||
import ru.micord.ervu.audit.service.AuditKafkaPublisher;
|
||||
import ru.micord.ervu.audit.service.AuditService;
|
||||
import ru.micord.ervu.security.esia.model.PersonModel;
|
||||
import ru.micord.ervu.security.webbpm.jwt.service.JwtTokenService;
|
||||
import ru.micord.ervu.util.DateUtils;
|
||||
import ru.micord.ervu.util.NetworkUtils;
|
||||
|
||||
/**
|
||||
* @author Adel Kalimullin
|
||||
*/
|
||||
@Service
|
||||
public class BaseAuditService implements AuditService {
|
||||
private final AuditKafkaPublisher auditPublisher;
|
||||
private final JwtTokenService jwtTokenService;
|
||||
private final ObjectMapper objectMapper;
|
||||
@Value("${audit.kafka.authorization.topic}")
|
||||
private String authorizationTopic;
|
||||
@Value("${audit.kafka.action.topic}")
|
||||
private String actionTopic;
|
||||
@Value("${audit.kafka.file.download.topic}")
|
||||
private String fileDownloadTopic;
|
||||
|
||||
public BaseAuditService(AuditKafkaPublisher auditPublisher, JwtTokenService jwtTokenService,
|
||||
ObjectMapper objectMapper) {
|
||||
this.auditPublisher = auditPublisher;
|
||||
this.jwtTokenService = jwtTokenService;
|
||||
this.objectMapper = objectMapper;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void processActionEvent(
|
||||
HttpServletRequest request, AuditActionRequest auditActionRequest) {
|
||||
String userAccountId = jwtTokenService.getUserAccountId(request);
|
||||
String description = AuditConstants.getRouteDescription(auditActionRequest.getRoute());
|
||||
|
||||
AuditActionEvent event = new AuditActionEvent(
|
||||
userAccountId,
|
||||
DateUtils.getClientTimeFromRequest(request),
|
||||
auditActionRequest.getEventType(),
|
||||
description,
|
||||
auditActionRequest.getSourceUrl(),
|
||||
auditActionRequest.getFileName()
|
||||
);
|
||||
String message = convertToMessage(event);
|
||||
auditPublisher.publishEvent(actionTopic, message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void processAuthEvent(HttpServletRequest request, PersonModel personModel, String status,
|
||||
String eventType) {
|
||||
String serverIp = NetworkUtils.getServerIp();
|
||||
String clientIp = NetworkUtils.getClientIp(request);
|
||||
String serverHostName = NetworkUtils.getHostName(serverIp);
|
||||
String clientHostName = NetworkUtils.getHostName(clientIp);
|
||||
|
||||
AuditAuthorizationEvent event = new AuditAuthorizationEvent(
|
||||
personModel.getPrnsId(),
|
||||
DateUtils.getClientTimeFromRequest(request),
|
||||
personModel.getFirstName(),
|
||||
personModel.getLastName(),
|
||||
personModel.getMiddleName(),
|
||||
personModel.getSnils(),
|
||||
status,
|
||||
eventType,
|
||||
serverIp,
|
||||
serverHostName,
|
||||
clientIp,
|
||||
clientHostName
|
||||
);
|
||||
String message = convertToMessage(event);
|
||||
auditPublisher.publishEvent(authorizationTopic, message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void processDownloadEvent(
|
||||
HttpServletRequest request, int fileSize, String fileName, String formatRegistry,
|
||||
String status) {
|
||||
String userAccountId = jwtTokenService.getUserAccountId(request);
|
||||
|
||||
AuditDownloadEvent event = new AuditDownloadEvent(
|
||||
userAccountId,
|
||||
DateUtils.getClientTimeFromRequest(request),
|
||||
AuditConstants.getDownloadType(formatRegistry),
|
||||
fileName,
|
||||
null,
|
||||
String.valueOf(fileSize),
|
||||
status
|
||||
);
|
||||
String message = convertToMessage(event);
|
||||
auditPublisher.publishEvent(fileDownloadTopic, message);
|
||||
}
|
||||
|
||||
private String convertToMessage(Object event) {
|
||||
try {
|
||||
return objectMapper.writeValueAsString(event);
|
||||
}
|
||||
catch (JsonProcessingException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -4,6 +4,7 @@ import java.net.URLEncoder;
|
|||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Arrays;
|
||||
|
||||
import com.google.protobuf.ByteString;
|
||||
import com.google.protobuf.InvalidProtocolBufferException;
|
||||
import org.apache.kafka.clients.consumer.ConsumerRecord;
|
||||
import org.apache.kafka.common.utils.Bytes;
|
||||
|
|
@ -16,6 +17,8 @@ import org.springframework.http.ResponseEntity;
|
|||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import ru.micord.ervu.audit.constants.AuditConstants;
|
||||
import ru.micord.ervu.audit.service.AuditService;
|
||||
import ru.micord.ervu.dto.ExtractEmptyRequestDto;
|
||||
import ru.micord.ervu.dto.ExtractRequestDto;
|
||||
import ru.micord.ervu.kafka.dto.EmptyExtract;
|
||||
|
|
@ -28,6 +31,8 @@ import ru.micord.ervu.security.esia.token.EsiaTokensStore;
|
|||
import ru.micord.ervu.security.webbpm.jwt.UserIdsPair;
|
||||
import ru.micord.ervu.security.webbpm.jwt.util.SecurityUtil;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
/**
|
||||
* @author gulnaz
|
||||
*/
|
||||
|
|
@ -35,6 +40,7 @@ import ru.micord.ervu.security.webbpm.jwt.util.SecurityUtil;
|
|||
public class ExtractController {
|
||||
private final PersonalDataService personalDataService;
|
||||
private final ReplyingKafkaService<Object, Bytes> replyingKafkaService;
|
||||
private final AuditService auditService;
|
||||
|
||||
@Value("${ervu.kafka.registry.extract.empty.request.topic}")
|
||||
private String registryExtractEmptyRequestTopic;
|
||||
|
|
@ -45,13 +51,18 @@ public class ExtractController {
|
|||
@Value("${ervu.kafka.registry.extract.type.header:empty}")
|
||||
private String registryExtractTypeHeader;
|
||||
|
||||
public ExtractController(PersonalDataService personalDataService, ReplyingKafkaService<Object, Bytes> replyingKafkaService) {
|
||||
public ExtractController(
|
||||
PersonalDataService personalDataService,
|
||||
ReplyingKafkaService<Object, Bytes> replyingKafkaService,
|
||||
AuditService auditService
|
||||
) {
|
||||
this.personalDataService = personalDataService;
|
||||
this.replyingKafkaService = replyingKafkaService;
|
||||
this.auditService = auditService;
|
||||
}
|
||||
|
||||
@GetMapping(value = "/extract/{formatRegistry}")
|
||||
public ResponseEntity<Resource> getExtract(@PathVariable String formatRegistry) {
|
||||
public ResponseEntity<Resource> getExtract(HttpServletRequest servletRequest, @PathVariable String formatRegistry) {
|
||||
UserIdsPair userIdsPair = SecurityUtil.getUserIdsPair();
|
||||
String ervuId = userIdsPair.getErvuId();
|
||||
ConsumerRecord<String, Bytes> record;
|
||||
|
|
@ -81,17 +92,28 @@ public class ExtractController {
|
|||
registryExtractReplyTopic, emptyRequest);
|
||||
}
|
||||
byte[] bytes = record.value().get();
|
||||
String fileName = null;
|
||||
int size = 0;
|
||||
|
||||
try {
|
||||
Extract extract = ervuId == null || isEmpty ? new EmptyExtract(bytes) : new FullExtract(bytes);
|
||||
String encodedFilename = URLEncoder.encode(extract.getFileName(), StandardCharsets.UTF_8);
|
||||
InputStreamResource resource = new InputStreamResource(extract.getFile().newInput());
|
||||
fileName = extract.getFileName();
|
||||
String encodedFilename = URLEncoder.encode(fileName, StandardCharsets.UTF_8);
|
||||
ByteString file = extract.getFile();
|
||||
InputStreamResource resource = new InputStreamResource(file.newInput());
|
||||
size = file.size();
|
||||
auditService.processDownloadEvent(servletRequest, size, fileName, formatRegistry,
|
||||
AuditConstants.SUCCESS_STATUS
|
||||
);
|
||||
return ResponseEntity.ok()
|
||||
.header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename*=UTF-8''" + encodedFilename)
|
||||
.contentType(MediaType.APPLICATION_OCTET_STREAM)
|
||||
.body(resource);
|
||||
}
|
||||
catch (InvalidProtocolBufferException e) {
|
||||
auditService.processDownloadEvent(servletRequest, size, fileName, formatRegistry,
|
||||
AuditConstants.FAILURE_STATUS
|
||||
);
|
||||
throw new RuntimeException("Failed to parse data", e);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,15 +10,14 @@ import proto.ervu.rp.summons.RecruitmentInfo;
|
|||
import ru.micord.ervu.dto.Restriction;
|
||||
import ru.micord.ervu.dto.SubpoenaResponseDto;
|
||||
import org.springframework.stereotype.Component;
|
||||
import proto.ervu.rp.summons.MeasuresTemporary;
|
||||
import proto.ervu.rp.summons.ResponseDataAddress;
|
||||
import proto.ervu.rp.summons.SummonsInfo;
|
||||
import proto.ervu.rp.summons.SummonsResponseData;
|
||||
|
||||
import static ru.micord.ervu.util.DateUtil.convertToLocalDate;
|
||||
import static ru.micord.ervu.util.DateUtils.convertToLocalDate;
|
||||
import static java.util.Objects.requireNonNull;
|
||||
import static ru.micord.ervu.util.DateUtil.convertToString;
|
||||
import static ru.micord.ervu.util.DateUtil.getDaysTill;
|
||||
import static ru.micord.ervu.util.DateUtils.convertToString;
|
||||
import static ru.micord.ervu.util.DateUtils.getDaysTill;
|
||||
|
||||
/**
|
||||
* @author gulnaz
|
||||
|
|
|
|||
|
|
@ -4,8 +4,8 @@ import java.util.ArrayList;
|
|||
import java.util.List;
|
||||
|
||||
import static org.springframework.util.StringUtils.hasText;
|
||||
import static ru.micord.ervu.util.DateUtil.convertToLocalDate;
|
||||
import static ru.micord.ervu.util.DateUtil.convertToString;
|
||||
import static ru.micord.ervu.util.DateUtils.convertToLocalDate;
|
||||
import static ru.micord.ervu.util.DateUtils.convertToString;
|
||||
|
||||
/**
|
||||
* @author gulnaz
|
||||
|
|
|
|||
|
|
@ -26,6 +26,8 @@ import org.springframework.beans.factory.annotation.Qualifier;
|
|||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.context.support.MessageSourceAccessor;
|
||||
import org.springframework.security.core.context.SecurityContext;
|
||||
import ru.micord.ervu.audit.constants.AuditConstants;
|
||||
import ru.micord.ervu.audit.service.AuditService;
|
||||
import ru.micord.ervu.kafka.model.Document;
|
||||
import ru.micord.ervu.kafka.model.Person;
|
||||
import ru.micord.ervu.kafka.model.Response;
|
||||
|
|
@ -75,6 +77,9 @@ public class EsiaAuthService {
|
|||
@Autowired
|
||||
private PersonalDataService personalDataService;
|
||||
|
||||
@Autowired
|
||||
private AuditService auditService;
|
||||
|
||||
@Autowired
|
||||
private SecurityHelper securityHelper;
|
||||
|
||||
|
|
@ -233,16 +238,25 @@ public class EsiaAuthService {
|
|||
Thread.currentThread().getId(), signSecret, requestAccessToken, verifySecret);
|
||||
}
|
||||
PersonModel personModel = null;
|
||||
String ervuId = null;
|
||||
String ervuId = null, status = null;
|
||||
try {
|
||||
personModel = personalDataService.getPersonModel(esiaAccessTokenStr);
|
||||
Response ervuIdResponse = getErvuIdResponse(personModel);
|
||||
ervuId = ervuIdResponse.getErvuId();
|
||||
status = AuditConstants.SUCCESS_STATUS;
|
||||
}
|
||||
catch (EsiaException | JsonProcessingException e) {
|
||||
throw new EsiaException(e);
|
||||
catch (Exception e) {
|
||||
status = AuditConstants.FAILURE_STATUS;
|
||||
if (e instanceof EsiaException || e instanceof JsonProcessingException) {
|
||||
throw new EsiaException(e);
|
||||
}
|
||||
}
|
||||
finally {
|
||||
if (personModel != null) {
|
||||
auditService.processAuthEvent(
|
||||
request, personModel, status, AuditConstants.LOGIN_EVENT_TYPE
|
||||
);
|
||||
}
|
||||
createTokenAndAddCookie(response, prnOid, ervuId, expiresIn);
|
||||
}
|
||||
}
|
||||
|
|
@ -349,9 +363,12 @@ public class EsiaAuthService {
|
|||
}
|
||||
|
||||
public String logout(HttpServletRequest request, HttpServletResponse response) {
|
||||
PersonModel personModel = null;
|
||||
try {
|
||||
securityHelper.clearAccessCookies(response);
|
||||
String userId = jwtTokenService.getUserAccountId(request);
|
||||
String accessToken = EsiaTokensStore.getAccessToken(userId);
|
||||
personModel = personalDataService.getPersonModel(accessToken);
|
||||
securityHelper.clearAccessCookies(response);
|
||||
EsiaTokensStore.removeAccessToken(userId);
|
||||
EsiaTokensStore.removeRefreshToken(userId);
|
||||
String logoutUrl = esiaConfig.getEsiaBaseUri() + esiaConfig.getEsiaLogoutUrl();
|
||||
|
|
@ -359,10 +376,19 @@ public class EsiaAuthService {
|
|||
URL url = new URL(logoutUrl);
|
||||
Map<String, String> params = mapOf(
|
||||
"client_id", esiaConfig.getClientId(),
|
||||
"redirect_url", redirectUrl);
|
||||
"redirect_url", redirectUrl
|
||||
);
|
||||
auditService.processAuthEvent(
|
||||
request, personModel, AuditConstants.SUCCESS_STATUS, AuditConstants.LOGOUT_EVENT_TYPE
|
||||
);
|
||||
return buildUrl(url, params);
|
||||
}
|
||||
catch (Exception e) {
|
||||
if (personModel != null){
|
||||
auditService.processAuthEvent(
|
||||
request, personModel, AuditConstants.FAILURE_STATUS, AuditConstants.LOGOUT_EVENT_TYPE
|
||||
);
|
||||
}
|
||||
throw new EsiaException(e);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,19 +1,39 @@
|
|||
package ru.micord.ervu.util;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.time.ZoneId;
|
||||
import java.time.ZonedDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
/**
|
||||
* @author gulnaz
|
||||
*/
|
||||
public final class DateUtil {
|
||||
public final class DateUtils {
|
||||
|
||||
public static final DateTimeFormatter DEFAULT_FORMATTER = DateTimeFormatter.ofPattern("dd.MM.yyyy");
|
||||
|
||||
private DateUtil() {}
|
||||
private static final DateTimeFormatter DATE_TIME_WITH_TIMEZONE_FORMATTER =
|
||||
DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSX");
|
||||
|
||||
private DateUtils() {
|
||||
}
|
||||
|
||||
public static String getClientTimeFromRequest(HttpServletRequest request) {
|
||||
String clientTimeZone = request.getHeader("Client-Time-Zone");
|
||||
ZoneId zoneId;
|
||||
try {
|
||||
zoneId = ZoneId.of(clientTimeZone);
|
||||
}
|
||||
catch (Exception e) {
|
||||
zoneId = ZoneId.systemDefault();
|
||||
}
|
||||
return ZonedDateTime.now(zoneId).format(DATE_TIME_WITH_TIMEZONE_FORMATTER);
|
||||
}
|
||||
|
||||
public static LocalDate convertToLocalDate(String date) {
|
||||
return StringUtils.hasText(date)
|
||||
53
backend/src/main/java/ru/micord/ervu/util/NetworkUtils.java
Normal file
53
backend/src/main/java/ru/micord/ervu/util/NetworkUtils.java
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
package ru.micord.ervu.util;
|
||||
|
||||
import java.net.InetAddress;
|
||||
import java.net.UnknownHostException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* @author Adel Kalimullin
|
||||
*/
|
||||
public final class NetworkUtils {
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(NetworkUtils.class);
|
||||
private static final String IP_HEADER = "X-Forwarded-For";
|
||||
private static final String UNKNOWN = "unknown";
|
||||
|
||||
private NetworkUtils() {
|
||||
}
|
||||
|
||||
public static String getServerIp() {
|
||||
try {
|
||||
InetAddress inetAddress = InetAddress.getLocalHost();
|
||||
return inetAddress.getHostAddress();
|
||||
}
|
||||
catch (UnknownHostException e) {
|
||||
LOGGER.error("Failed to get local IP address", e);
|
||||
return UNKNOWN;
|
||||
}
|
||||
}
|
||||
|
||||
public static String getClientIp(HttpServletRequest request) {
|
||||
String ip = request.getHeader(IP_HEADER);
|
||||
if (StringUtils.hasText(ip) && !ip.equalsIgnoreCase(UNKNOWN)) {
|
||||
return ip.split(",")[0].trim();
|
||||
}
|
||||
else {
|
||||
return request.getRemoteAddr();
|
||||
}
|
||||
}
|
||||
|
||||
public static String getHostName(String ip) {
|
||||
try {
|
||||
InetAddress inetAddress = InetAddress.getByName(ip);
|
||||
return inetAddress.getHostName();
|
||||
}
|
||||
catch (UnknownHostException e) {
|
||||
LOGGER.error("Unknown host for IP {}", ip, e);
|
||||
return UNKNOWN;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1 +1 @@
|
|||
error.unknown=The system is temporarily unavailable. Please try again later.
|
||||
error.unknown=The system is temporarily unavailable. Please try again later.
|
||||
10
config.md
10
config.md
|
|
@ -788,6 +788,16 @@ JBPM использует 3 корневых категории логирова
|
|||
- `ERVU_KAFKA_REGISTRY_EXTRACT_REQUEST_TOPIC` - топик для отправки запроса на получение выписки из Реестра воинского учета при наличии ErvuId
|
||||
- `ERVU_KAFKA_REGISTRY_EXTRACT_REPLY_TOPIC` - топик для получения выписки из Реестра воинского учета
|
||||
- `ERVU_KAFKA_EXTRACT_HEADER_CLASS` - класс для идентификации в заголовке запроса на получение выписки из Реестра повесток/Реестра воинского учета
|
||||
- `AUDIT_KAFKA_AUTHORIZATION_TOPIC` - топик для отправки аудита в журнал авторизации
|
||||
- `AUDIT_KAFKA_ACTION_TOPIC` - топик для отправки аудита в журнал действий пользователя
|
||||
- `AUDIT_KAFKA_FILE_DOWNLOAD_TOPIC` - топик для отправки аудита в журнал загрузки ЮЛ и ФЛ
|
||||
- `AUDIT_KAFKA_BOOTSTRAP_SERVERS` - список пар хост:порт, использующихся для установки первоначального соединения с кластером Kafka
|
||||
- `AUDIT_KAFKA_SECURITY_PROTOCOL` - протокол, используемый для взаимодействия с брокерами
|
||||
- `AUDIT_KAFKA_DOC_LOGIN_MODULE` - имя класса для входа в систему для SASL-соединений в формате, используемом конфигурационными файлами JAAS
|
||||
- `AUDIT_KAFKA_USERNAME` - пользователь для подключения к Kafka
|
||||
- `AUDIT_KAFKA_PASSWORD` - пароль для подключения к Kafka
|
||||
- `AUDIT_KAFKA_SASL_MECHANISM` - механизм SASL, используемый для клиентских подключений
|
||||
- `AUDIT_KAFKA_ENABLED` - флажок для включения записи аудита в кафку
|
||||
|
||||
# Прочее
|
||||
|
||||
|
|
|
|||
|
|
@ -33,6 +33,16 @@ ERVU_KAFKA_REGISTRY_EXTRACT_REQUEST_TOPIC=ervu.extract.info.request
|
|||
ERVU_KAFKA_REGISTRY_EXTRACT_REPLY_TOPIC=ervu.extract.info.response
|
||||
ERVU_KAFKA_EXTRACT_HEADER_CLASS=request@urn://rostelekom.ru/ERVU-extractFromRegistryTR/1.0.3
|
||||
ERVU_KAFKA_DOC_LOGIN_MODULE=org.apache.kafka.common.security.scram.ScramLoginModule
|
||||
AUDIT_KAFKA_AUTHORIZATION_TOPIC=ervu.lkrp.auth.events
|
||||
AUDIT_KAFKA_ACTION_TOPIC=ervu.lkrp.action.events
|
||||
AUDIT_KAFKA_FILE_DOWNLOAD_TOPIC=ervu.lkrp.import.file
|
||||
AUDIT_KAFKA_BOOTSTRAP_SERVERS=
|
||||
AUDIT_KAFKA_SECURITY_PROTOCOL=
|
||||
AUDIT_KAFKA_DOC_LOGIN_MODULE=
|
||||
AUDIT_KAFKA_USERNAME=
|
||||
AUDIT_KAFKA_PASSWORD=
|
||||
AUDIT_KAFKA_SASL_MECHANISM=
|
||||
AUDIT_KAFKA_ENABLED=false
|
||||
|
||||
ESIA_TOKEN_CLEAR_CRON=0 0 */1 * * *
|
||||
COOKIE_PATH=/fl
|
||||
|
|
|
|||
|
|
@ -80,6 +80,16 @@
|
|||
<property name="ervu.kafka.registry.extract.reply.topic" value="ervu.extract.info.response"/>
|
||||
<property name="ervu.kafka.extract.header.class" value="request@urn://rostelekom.ru/ERVU-extractFromRegistryTR/1.0.3"/>
|
||||
<property name="esia.token.clear.cron" value="0 0 */1 * * *"/>
|
||||
<property name="audit.kafka.bootstrap.servers" value="localhost:9092"/>
|
||||
<property name="audit.kafka.authorization.topic" value="ervu.lkrp.auth.events"/>
|
||||
<property name="audit.kafka.file.download.topic" value="ervu.lkrp.import.file"/>
|
||||
<property name="audit.kafka.action.topic" value="ervu.lkrp.action.events"/>
|
||||
<property name="audit.kafka.security.protocol" value="SASL_PLAINTEXT"/>
|
||||
<property name="audit.kafka.doc.login.module" value="org.apache.kafka.common.security.scram.ScramLoginModule"/>
|
||||
<property name="audit.kafka.sasl.mechanism" value="SCRAM-SHA-256"/>
|
||||
<property name="audit.kafka.username" value="user1"/>
|
||||
<property name="audit.kafka.password" value="Blfi9d2OFG"/>
|
||||
<property name="audit.kafka.enabled" value="false"/>
|
||||
</system-properties>
|
||||
<management>
|
||||
<audit-log>
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
<parent>
|
||||
<groupId>ru.micord.ervu.lkrp</groupId>
|
||||
<artifactId>fl</artifactId>
|
||||
<version>1.9.8-SNAPSHOT</version>
|
||||
<version>1.9.9-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<groupId>ru.micord.ervu.lkrp.fl</groupId>
|
||||
|
|
|
|||
6
frontend/package-lock.json
generated
6
frontend/package-lock.json
generated
|
|
@ -1748,9 +1748,9 @@
|
|||
}
|
||||
},
|
||||
"@webbpm/base-package": {
|
||||
"version": "3.187.2",
|
||||
"resolved": "https://repo.micord.ru/repository/npm-all/@webbpm/base-package/-/base-package-3.187.2.tgz",
|
||||
"integrity": "sha512-qDW+Yjm/gyTIM/4N7uQasQR1zk2tGGAF6rJFpSUSb1A7PYreXPqSAShzWJJJ1YZ9CCz2dAXSQzm6JjUJKu2VUg==",
|
||||
"version": "3.187.3",
|
||||
"resolved": "https://repo.micord.ru/repository/npm-all/@webbpm/base-package/-/base-package-3.187.3.tgz",
|
||||
"integrity": "sha512-uhESrMdBnxeWXX5LNENvzzq0k0t4jHcuD1JmRAF0WIFfKqhZNMsmd0xxf2CYMUSJrWESyjX2wiqpKFhDHd0+/A==",
|
||||
"requires": {
|
||||
"tslib": "^1.9.0"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@
|
|||
"@angular/platform-browser-dynamic": "7.2.15",
|
||||
"@angular/router": "7.2.15",
|
||||
"@ng-bootstrap/ng-bootstrap": "4.2.2-micord.1",
|
||||
"@webbpm/base-package": "3.187.2",
|
||||
"@webbpm/base-package": "3.187.3",
|
||||
"ag-grid-angular": "29.0.0-micord.4",
|
||||
"ag-grid-community": "29.0.0-micord.4",
|
||||
"angular-calendar": "0.28.28",
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
<parent>
|
||||
<groupId>ru.micord.ervu.lkrp</groupId>
|
||||
<artifactId>fl</artifactId>
|
||||
<version>1.9.8-SNAPSHOT</version>
|
||||
<version>1.9.9-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<groupId>ru.micord.ervu.lkrp.fl</groupId>
|
||||
|
|
|
|||
|
|
@ -17,5 +17,6 @@
|
|||
"password_pattern_error": "Пароль должен содержать заглавные или прописные буквы и как минимум 1 цифру",
|
||||
"show.client.errors": false,
|
||||
"available_task.single_fetch": true,
|
||||
"cert_check_url": "https://lkrp-dev2.micord.ru"
|
||||
"cert_check_url": "https://lkrp-dev2.micord.ru",
|
||||
"unknown.error.msg": "Система временно недоступна. Пожалуйста, повторите попытку позже."
|
||||
}
|
||||
|
|
|
|||
42
frontend/src/ts/ervu/LinkClickHandler.ts
Normal file
42
frontend/src/ts/ervu/LinkClickHandler.ts
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
import {AnalyticalScope, Behavior, Control, NotNull} from "@webbpm/base-package";
|
||||
import {ElementRef} from "@angular/core";
|
||||
import {AuditService} from "./service/AuditService";
|
||||
import {LinkEventTypeEnum} from "./component/enum/LinkEventTypeEnum";
|
||||
|
||||
@AnalyticalScope(Control)
|
||||
export class LinkClickHandler extends Behavior {
|
||||
@NotNull()
|
||||
public eventType: LinkEventTypeEnum;
|
||||
private control: Control;
|
||||
private auditService: AuditService;
|
||||
private el: ElementRef;
|
||||
|
||||
initialize() {
|
||||
this.control = this.getScript(Control);
|
||||
this.el = this.control.getEl();
|
||||
super.initialize();
|
||||
}
|
||||
|
||||
bindEvents() {
|
||||
super.bindEvents();
|
||||
if (this.el) {
|
||||
this.el.nativeElement.addEventListener('click',
|
||||
(event: MouseEvent) => this.onClickFunction(event));
|
||||
}
|
||||
}
|
||||
|
||||
unbindEvents() {
|
||||
super.unbindEvents()
|
||||
if (this.el) {
|
||||
this.el.nativeElement.removeEventListener('click',
|
||||
(event: MouseEvent) => this.onClickFunction(event));
|
||||
}
|
||||
}
|
||||
|
||||
private onClickFunction(event: MouseEvent) {
|
||||
const target = event.target as HTMLElement;
|
||||
if (target.tagName === 'A') {
|
||||
this.auditService.logActionAudit(this.eventType);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -29,8 +29,12 @@ export class ExtractLoadService extends Behavior {
|
|||
this.errorEvent.subscribe(() => console.log("error event occurred", this.errorEvent));
|
||||
this.onClickFunction = () => {
|
||||
console.log("click event occurred");
|
||||
const timeZone = Intl.DateTimeFormat().resolvedOptions().timeZone;
|
||||
this.httpClient.get('extract/' + this.formatRegistry, {
|
||||
responseType: 'blob',
|
||||
headers: {
|
||||
"Client-Time-Zone": timeZone,
|
||||
},
|
||||
observe: 'response'
|
||||
}).toPromise()
|
||||
.then((response) => {
|
||||
|
|
|
|||
5
frontend/src/ts/ervu/component/enum/LinkEventTypeEnum.ts
Normal file
5
frontend/src/ts/ervu/component/enum/LinkEventTypeEnum.ts
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
export enum LinkEventTypeEnum {
|
||||
NAVIGATION_TO_SOURCE = "Переход на другие источники",
|
||||
DOWNLOAD_TEMPLATE = "Скачивание шаблона",
|
||||
DOWNLOAD_EXAMPLE = "Скачивание примера заполнения формы"
|
||||
}
|
||||
43
frontend/src/ts/ervu/service/AuditService.ts
Normal file
43
frontend/src/ts/ervu/service/AuditService.ts
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
import {Injectable} from "@angular/core";
|
||||
import {HttpClient} from "@angular/common/http";
|
||||
import {Router} from "@angular/router";
|
||||
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class AuditService {
|
||||
|
||||
constructor(private httpClient: HttpClient, private router: Router) {
|
||||
}
|
||||
|
||||
public logActionAudit(eventType: string, fileName?: string): void {
|
||||
const currentRoute = this.router.url;
|
||||
const sourceUrl = window.location.href;
|
||||
const timeZone = Intl.DateTimeFormat().resolvedOptions().timeZone;
|
||||
|
||||
const data: AuditAction = {
|
||||
eventType: eventType,
|
||||
sourceUrl: sourceUrl,
|
||||
route: currentRoute,
|
||||
fileName: fileName
|
||||
};
|
||||
|
||||
this.httpClient.post("audit/action", data, {
|
||||
headers: {
|
||||
"Client-Time-Zone": timeZone,
|
||||
}
|
||||
}).toPromise();
|
||||
}
|
||||
}
|
||||
|
||||
export interface AuditAction {
|
||||
eventType: string;
|
||||
sourceUrl: string;
|
||||
route: string;
|
||||
fileName?: string;
|
||||
}
|
||||
|
||||
export class AuditConstants {
|
||||
public static readonly OPEN_PAGE_EVENT = "Открытие страницы";
|
||||
}
|
||||
|
|
@ -24,6 +24,7 @@ import {LogOutComponent} from "./component/logout.component";
|
|||
import {LoadForm} from "../../ervu/component/container/LoadForm";
|
||||
import {InMemoryStaticGrid} from "../../ervu/component/grid/InMemoryStaticGrid";
|
||||
import {AuthenticationService} from "../security/authentication.service";
|
||||
import {AuditService} from "../../ervu/service/AuditService";
|
||||
import {HomeLandingComponent} from "./component/home-landing.component";
|
||||
|
||||
registerLocaleData(localeRu);
|
||||
|
|
@ -64,7 +65,7 @@ export function checkAuthentication(authService: AuthenticationService): () => P
|
|||
DIRECTIVES
|
||||
],
|
||||
providers: [
|
||||
AuthenticationService,
|
||||
AuthenticationService, AuditService,
|
||||
{
|
||||
provide: APP_INITIALIZER,
|
||||
useFactory: checkAuthentication,
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ import {Injectable} from '@angular/core';
|
|||
import {HttpClient} from '@angular/common/http';
|
||||
import {CookieService} from "ngx-cookie";
|
||||
import {AppConfigService} from "@webbpm/base-package";
|
||||
import {map, tap} from "rxjs/operators";
|
||||
|
||||
@Injectable({providedIn: 'root'})
|
||||
export class AuthenticationService {
|
||||
|
|
@ -22,4 +23,13 @@ export class AuthenticationService {
|
|||
public isAuthenticated(): boolean {
|
||||
return this.cookieService.get('webbpm.ervu-lkrp-fl') != null;
|
||||
}
|
||||
|
||||
public redirectToEsia() {
|
||||
return this.http.get<string>("esia/url").pipe(
|
||||
tap(url => {
|
||||
window.open(url, "_self");
|
||||
}),
|
||||
map(() => true)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ export abstract class AuthGuard implements CanActivate {
|
|||
}
|
||||
if (error) {
|
||||
let errorMessage =
|
||||
'Произошла неизвестная ошибка. Обратитесь к системному администратору';
|
||||
this.messageService.getUnknowErrorMessage();
|
||||
let errorCode = this.extractCode(errorDescription);
|
||||
if (errorCode) {
|
||||
errorMessage = EsiaErrorDetail.getDescription(errorCode);
|
||||
|
|
@ -57,15 +57,10 @@ export abstract class AuthGuard implements CanActivate {
|
|||
return false;
|
||||
}
|
||||
else {
|
||||
return this.httpClient.get<string>("esia/url")
|
||||
.toPromise()
|
||||
.then(url => {
|
||||
window.open(url, "_self");
|
||||
return true;
|
||||
}).catch((reason)=> {
|
||||
console.error(reason);
|
||||
return false;
|
||||
});
|
||||
return this.authenticationService.redirectToEsia().toPromise().catch((reason) => {
|
||||
console.error(reason);
|
||||
return false;
|
||||
});
|
||||
}
|
||||
}).catch((reason) => {
|
||||
console.error(reason);
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ import {
|
|||
Router
|
||||
} from "@angular/router";
|
||||
import {ProgressIndicationService} from "@webbpm/base-package";
|
||||
import {AuditConstants, AuditService} from "../../../ervu/service/AuditService";
|
||||
|
||||
@Component({
|
||||
moduleId: module.id,
|
||||
|
|
@ -21,7 +22,8 @@ export class WebbpmComponent {
|
|||
|
||||
constructor(private router: Router,
|
||||
private progressIndicationService: ProgressIndicationService,
|
||||
private cd: ChangeDetectorRef) {
|
||||
private cd: ChangeDetectorRef,
|
||||
private auditService: AuditService) {
|
||||
router.events.subscribe((event: Event) => {
|
||||
if (event instanceof NavigationStart) {
|
||||
progressIndicationService.showProgressBar();
|
||||
|
|
@ -29,9 +31,15 @@ export class WebbpmComponent {
|
|||
this.cd.markForCheck();
|
||||
}
|
||||
else if (event instanceof NavigationEnd
|
||||
|| event instanceof NavigationError
|
||||
|| event instanceof NavigationCancel) {
|
||||
|| event instanceof NavigationError
|
||||
|| event instanceof NavigationCancel) {
|
||||
progressIndicationService.hideProgressBar();
|
||||
|
||||
if (event instanceof NavigationEnd
|
||||
&& event.url != '/home'
|
||||
&& event.url != '/access-denied') {
|
||||
this.auditService.logActionAudit(AuditConstants.OPEN_PAGE_EVENT);
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,14 +1,14 @@
|
|||
import {HTTP_INTERCEPTORS} from "@angular/common/http";
|
||||
import {
|
||||
FormDirtyInterceptor,
|
||||
HttpSecurityErrorInterceptor,
|
||||
HttpSecurityInterceptor
|
||||
} from "@webbpm/base-package";
|
||||
import {AbsoluteUrlCsrfInterceptor} from "./absolute-url-csrf.interceptor";
|
||||
import {ErvuHttpSecurityErrorInterceptor} from "./ervu-http-security-error-interceptor";
|
||||
|
||||
export const DEFAULT_HTTP_INTERCEPTOR_PROVIDERS = [
|
||||
{provide: HTTP_INTERCEPTORS, useClass: HttpSecurityInterceptor, multi: true},
|
||||
{provide: HTTP_INTERCEPTORS, useClass: HttpSecurityErrorInterceptor, multi: true},
|
||||
{provide: HTTP_INTERCEPTORS, useClass: ErvuHttpSecurityErrorInterceptor, multi: true},
|
||||
{provide: HTTP_INTERCEPTORS, useClass: FormDirtyInterceptor, multi: true},
|
||||
{provide: HTTP_INTERCEPTORS, useClass: AbsoluteUrlCsrfInterceptor, multi: true}
|
||||
];
|
||||
|
|
|
|||
|
|
@ -2,10 +2,11 @@ import {HTTP_INTERCEPTORS} from "@angular/common/http";
|
|||
import {FormDirtyInterceptor, HttpSecurityInterceptor} from "@webbpm/base-package";
|
||||
import {DevHttpSecurityErrorInterceptor} from "./http-security-error-interceptor.dev";
|
||||
import {AbsoluteUrlCsrfInterceptor} from "./absolute-url-csrf.interceptor";
|
||||
import {ErvuHttpSecurityErrorInterceptor} from "./ervu-http-security-error-interceptor";
|
||||
|
||||
export const DEFAULT_HTTP_INTERCEPTOR_PROVIDERS = [
|
||||
{provide: HTTP_INTERCEPTORS, useClass: HttpSecurityInterceptor, multi: true},
|
||||
{provide: HTTP_INTERCEPTORS, useClass: DevHttpSecurityErrorInterceptor, multi: true},
|
||||
{provide: HTTP_INTERCEPTORS, useClass: ErvuHttpSecurityErrorInterceptor, multi: true},
|
||||
{provide: HTTP_INTERCEPTORS, useClass: FormDirtyInterceptor, multi: true},
|
||||
{provide: HTTP_INTERCEPTORS, useClass: AbsoluteUrlCsrfInterceptor, multi: true},
|
||||
];
|
||||
|
|
|
|||
|
|
@ -0,0 +1,43 @@
|
|||
import {
|
||||
HttpEvent,
|
||||
HttpHandler,
|
||||
HttpInterceptor,
|
||||
HttpRequest, HttpResponse
|
||||
} from "@angular/common/http";
|
||||
import {
|
||||
HttpSecurityErrorInterceptor,
|
||||
MessagesService,
|
||||
UserService
|
||||
} from "@webbpm/base-package";
|
||||
import {Injectable} from "@angular/core";
|
||||
import {Router} from "@angular/router";
|
||||
import {from, Observable} from "rxjs";
|
||||
import {catchError, map} from "rxjs/operators";
|
||||
import {AuthenticationService} from "../../security/authentication.service";
|
||||
|
||||
@Injectable()
|
||||
export class ErvuHttpSecurityErrorInterceptor extends HttpSecurityErrorInterceptor
|
||||
implements HttpInterceptor {
|
||||
private authService: AuthenticationService;
|
||||
|
||||
constructor(router: Router, messagesService: MessagesService, userService: UserService,
|
||||
authService: AuthenticationService) {
|
||||
super(router, messagesService, userService);
|
||||
this.authService = authService;
|
||||
}
|
||||
|
||||
protected processAuthError(req: HttpRequest<any>, next: HttpHandler,
|
||||
error: any): Observable<HttpEvent<any>> {
|
||||
if (this.authService.isAuthenticated()) {
|
||||
return super.processAuthError(req, next, error);
|
||||
}
|
||||
else {
|
||||
return from(this.authService.redirectToEsia()).pipe(
|
||||
map(() => new HttpResponse<any>()),
|
||||
catchError((err) => {
|
||||
throw err;
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,19 +1,20 @@
|
|||
import {HttpEvent, HttpHandler, HttpInterceptor, HttpRequest} from "@angular/common/http";
|
||||
import {HttpSecurityErrorInterceptor, MessagesService, UserService} from "@webbpm/base-package";
|
||||
import {MessagesService, UserService} from "@webbpm/base-package";
|
||||
import {Injectable} from "@angular/core";
|
||||
import {Router} from "@angular/router";
|
||||
import {EMPTY, Observable} from "rxjs";
|
||||
import {catchError} from "rxjs/operators";
|
||||
import {ErvuHttpSecurityErrorInterceptor} from "./ervu-http-security-error-interceptor";
|
||||
import {AuthenticationService} from "../../security/authentication.service";
|
||||
|
||||
@Injectable()
|
||||
export class DevHttpSecurityErrorInterceptor extends HttpSecurityErrorInterceptor
|
||||
export class DevHttpSecurityErrorInterceptor extends ErvuHttpSecurityErrorInterceptor
|
||||
implements HttpInterceptor {
|
||||
private router: Router;
|
||||
|
||||
|
||||
constructor(router: Router, messagesService: MessagesService, userService: UserService) {
|
||||
super(router, messagesService, userService);
|
||||
this.router = router;
|
||||
constructor(router: Router, messagesService: MessagesService, userService: UserService,
|
||||
authService: AuthenticationService) {
|
||||
super(router, messagesService, userService, authService);
|
||||
}
|
||||
|
||||
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>ru.cg.webbpm.packages.base</groupId>
|
||||
<artifactId>resources</artifactId>
|
||||
<version>3.187.2</version>
|
||||
<version>3.187.3</version>
|
||||
<organization>
|
||||
<name>Micord</name>
|
||||
</organization>
|
||||
|
|
@ -28,13 +28,13 @@
|
|||
<jooq.version>3.19.3</jooq.version>
|
||||
<jupiter.version>5.10.2</jupiter.version>
|
||||
<enforcer.manageVersions>true</enforcer.manageVersions>
|
||||
<webbpm-platform.version>3.187.2</webbpm-platform.version>
|
||||
<webbpm-platform.version>3.187.3</webbpm-platform.version>
|
||||
<h2.version>1.4.200</h2.version>
|
||||
<build.timestamp>0115092226</build.timestamp>
|
||||
<build.timestamp>0224072420</build.timestamp>
|
||||
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
|
||||
<junit.platform.version>1.10.0</junit.platform.version>
|
||||
<enforcer.manageExclusions>true</enforcer.manageExclusions>
|
||||
<revision>3.187.2</revision>
|
||||
<revision>3.187.3</revision>
|
||||
<metadata.ts.filename>typescript.metadata.json</metadata.ts.filename>
|
||||
<package.repository.url>https://repo.micord.ru</package.repository.url>
|
||||
<maven.build.timestamp.format>MMddHHmmss</maven.build.timestamp.format>
|
||||
|
|
@ -47,19 +47,19 @@
|
|||
<dependency>
|
||||
<groupId>ru.cg.webbpm.packages.base</groupId>
|
||||
<artifactId>converters</artifactId>
|
||||
<version>3.187.2</version>
|
||||
<version>3.187.3</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ru.cg.webbpm.packages.base</groupId>
|
||||
<artifactId>backend</artifactId>
|
||||
<version>3.187.2</version>
|
||||
<version>3.187.3</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ru.cg.webbpm.packages.base</groupId>
|
||||
<artifactId>frontend</artifactId>
|
||||
<version>3.187.2</version>
|
||||
<version>3.187.3</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
|
|
|||
|
|
@ -60,7 +60,7 @@
|
|||
<ul>
|
||||
|
||||
<li>Образец внешней ссылки: <code>https://www.wildberries.ru/catalog/${sku}/detail.aspx</code></li>
|
||||
<li>Образец внутренней ссылки: <code>products/ru.cg.webbpm.packages.base:resources:jar:3.187.2</code></li>
|
||||
<li>Образец внутренней ссылки: <code>products/ru.cg.webbpm.packages.base:resources:jar:3.187.3</code></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>
|
||||
|
|
|
|||
|
|
@ -4,17 +4,17 @@
|
|||
<description>Base webbpm package</description>
|
||||
<groupId>ru.cg.webbpm.packages.base</groupId>
|
||||
<artifactId>resources</artifactId>
|
||||
<version>3.187.2</version>
|
||||
<studioVersion>3.187.2</studioVersion>
|
||||
<version>3.187.3</version>
|
||||
<studioVersion>3.187.3</studioVersion>
|
||||
|
||||
<backendModule>
|
||||
<groupId>ru.cg.webbpm.packages.base</groupId>
|
||||
<artifactId>backend</artifactId>
|
||||
<version>3.187.2</version>
|
||||
<version>3.187.3</version>
|
||||
</backendModule>
|
||||
<frontendModule>
|
||||
<packageName>@webbpm/base-package</packageName>
|
||||
<version>3.187.2</version>
|
||||
<version>3.187.3</version>
|
||||
</frontendModule>
|
||||
</packageInfo>
|
||||
|
||||
|
|
|
|||
|
|
@ -8,11 +8,11 @@
|
|||
<documentation>component/buttons/Кнопка.html</documentation>
|
||||
<internal>false</internal>
|
||||
<versions>
|
||||
<studioVersion>3.187.2</studioVersion>
|
||||
<studioVersion>3.187.3</studioVersion>
|
||||
<packageVersions>
|
||||
<entry>
|
||||
<key>ru.cg.webbpm.packages.base.resources</key>
|
||||
<value>3.187.2</value>
|
||||
<value>3.187.3</value>
|
||||
</entry>
|
||||
</packageVersions>
|
||||
</versions>
|
||||
|
|
|
|||
|
|
@ -8,11 +8,11 @@
|
|||
<documentation>component/buttons/Кнопка_отмены.html</documentation>
|
||||
<internal>false</internal>
|
||||
<versions>
|
||||
<studioVersion>3.187.2</studioVersion>
|
||||
<studioVersion>3.187.3</studioVersion>
|
||||
<packageVersions>
|
||||
<entry>
|
||||
<key>ru.cg.webbpm.packages.base.resources</key>
|
||||
<value>3.187.2</value>
|
||||
<value>3.187.3</value>
|
||||
</entry>
|
||||
</packageVersions>
|
||||
</versions>
|
||||
|
|
|
|||
|
|
@ -8,11 +8,11 @@
|
|||
<documentation>component/buttons/Кнопка_очистки_фильтра.html</documentation>
|
||||
<internal>false</internal>
|
||||
<versions>
|
||||
<studioVersion>3.187.2</studioVersion>
|
||||
<studioVersion>3.187.3</studioVersion>
|
||||
<packageVersions>
|
||||
<entry>
|
||||
<key>ru.cg.webbpm.packages.base.resources</key>
|
||||
<value>3.187.2</value>
|
||||
<value>3.187.3</value>
|
||||
</entry>
|
||||
</packageVersions>
|
||||
</versions>
|
||||
|
|
|
|||
|
|
@ -8,11 +8,11 @@
|
|||
<documentation>component/buttons/Кнопка_удаления.html</documentation>
|
||||
<internal>false</internal>
|
||||
<versions>
|
||||
<studioVersion>3.187.2</studioVersion>
|
||||
<studioVersion>3.187.3</studioVersion>
|
||||
<packageVersions>
|
||||
<entry>
|
||||
<key>ru.cg.webbpm.packages.base.resources</key>
|
||||
<value>3.187.2</value>
|
||||
<value>3.187.3</value>
|
||||
</entry>
|
||||
</packageVersions>
|
||||
</versions>
|
||||
|
|
|
|||
|
|
@ -8,11 +8,11 @@
|
|||
<documentation>component/buttons/Кнопка_загрузки.html</documentation>
|
||||
<internal>false</internal>
|
||||
<versions>
|
||||
<studioVersion>3.187.2</studioVersion>
|
||||
<studioVersion>3.187.3</studioVersion>
|
||||
<packageVersions>
|
||||
<entry>
|
||||
<key>ru.cg.webbpm.packages.base.resources</key>
|
||||
<value>3.187.2</value>
|
||||
<value>3.187.3</value>
|
||||
</entry>
|
||||
</packageVersions>
|
||||
</versions>
|
||||
|
|
|
|||
|
|
@ -8,11 +8,11 @@
|
|||
<documentation>component/buttons/Кнопка_вызова_ошибки.html</documentation>
|
||||
<internal>false</internal>
|
||||
<versions>
|
||||
<studioVersion>3.187.2</studioVersion>
|
||||
<studioVersion>3.187.3</studioVersion>
|
||||
<packageVersions>
|
||||
<entry>
|
||||
<key>ru.cg.webbpm.packages.base.resources</key>
|
||||
<value>3.187.2</value>
|
||||
<value>3.187.3</value>
|
||||
</entry>
|
||||
</packageVersions>
|
||||
</versions>
|
||||
|
|
|
|||
|
|
@ -7,11 +7,11 @@
|
|||
<documentation>component/buttons/Кнопка_выполнения_бизнес-процесса.html</documentation>
|
||||
<internal>false</internal>
|
||||
<versions>
|
||||
<studioVersion>3.187.2</studioVersion>
|
||||
<studioVersion>3.187.3</studioVersion>
|
||||
<packageVersions>
|
||||
<entry>
|
||||
<key>ru.cg.webbpm.packages.base.resources</key>
|
||||
<value>3.187.2</value>
|
||||
<value>3.187.3</value>
|
||||
</entry>
|
||||
</packageVersions>
|
||||
</versions>
|
||||
|
|
|
|||
|
|
@ -8,11 +8,11 @@
|
|||
<documentation>component/buttons/Кнопка_выполнения_SQL.html</documentation>
|
||||
<internal>false</internal>
|
||||
<versions>
|
||||
<studioVersion>3.187.2</studioVersion>
|
||||
<studioVersion>3.187.3</studioVersion>
|
||||
<packageVersions>
|
||||
<entry>
|
||||
<key>ru.cg.webbpm.packages.base.resources</key>
|
||||
<value>3.187.2</value>
|
||||
<value>3.187.3</value>
|
||||
</entry>
|
||||
</packageVersions>
|
||||
</versions>
|
||||
|
|
|
|||
|
|
@ -8,11 +8,11 @@
|
|||
<documentation>component/buttons/Кнопка_для_фильтрации.html</documentation>
|
||||
<internal>false</internal>
|
||||
<versions>
|
||||
<studioVersion>3.187.2</studioVersion>
|
||||
<studioVersion>3.187.3</studioVersion>
|
||||
<packageVersions>
|
||||
<entry>
|
||||
<key>ru.cg.webbpm.packages.base.resources</key>
|
||||
<value>3.187.2</value>
|
||||
<value>3.187.3</value>
|
||||
</entry>
|
||||
</packageVersions>
|
||||
</versions>
|
||||
|
|
|
|||
|
|
@ -8,11 +8,11 @@
|
|||
<documentation>component/buttons/Кнопка_навигации.html</documentation>
|
||||
<internal>false</internal>
|
||||
<versions>
|
||||
<studioVersion>3.187.2</studioVersion>
|
||||
<studioVersion>3.187.3</studioVersion>
|
||||
<packageVersions>
|
||||
<entry>
|
||||
<key>ru.cg.webbpm.packages.base.resources</key>
|
||||
<value>3.187.2</value>
|
||||
<value>3.187.3</value>
|
||||
</entry>
|
||||
</packageVersions>
|
||||
</versions>
|
||||
|
|
|
|||
|
|
@ -8,11 +8,11 @@
|
|||
<documentation>component/buttons/Кнопка_сохранения.html</documentation>
|
||||
<internal>false</internal>
|
||||
<versions>
|
||||
<studioVersion>3.187.2</studioVersion>
|
||||
<studioVersion>3.187.3</studioVersion>
|
||||
<packageVersions>
|
||||
<entry>
|
||||
<key>ru.cg.webbpm.packages.base.resources</key>
|
||||
<value>3.187.2</value>
|
||||
<value>3.187.3</value>
|
||||
</entry>
|
||||
</packageVersions>
|
||||
</versions>
|
||||
|
|
|
|||
|
|
@ -8,11 +8,11 @@
|
|||
<documentation>component/buttons/Кнопка_выбора.html</documentation>
|
||||
<internal>false</internal>
|
||||
<versions>
|
||||
<studioVersion>3.187.2</studioVersion>
|
||||
<studioVersion>3.187.3</studioVersion>
|
||||
<packageVersions>
|
||||
<entry>
|
||||
<key>ru.cg.webbpm.packages.base.resources</key>
|
||||
<value>3.187.2</value>
|
||||
<value>3.187.3</value>
|
||||
</entry>
|
||||
</packageVersions>
|
||||
</versions>
|
||||
|
|
|
|||
|
|
@ -8,11 +8,11 @@
|
|||
<documentation>component/buttons/Кнопка_подписи.html</documentation>
|
||||
<internal>false</internal>
|
||||
<versions>
|
||||
<studioVersion>3.187.2</studioVersion>
|
||||
<studioVersion>3.187.3</studioVersion>
|
||||
<packageVersions>
|
||||
<entry>
|
||||
<key>ru.cg.webbpm.packages.base.resources</key>
|
||||
<value>3.187.2</value>
|
||||
<value>3.187.3</value>
|
||||
</entry>
|
||||
</packageVersions>
|
||||
</versions>
|
||||
|
|
|
|||
|
|
@ -8,11 +8,11 @@
|
|||
<documentation>component/buttons/Кнопка_запуска_бизнес-процесса.html</documentation>
|
||||
<internal>false</internal>
|
||||
<versions>
|
||||
<studioVersion>3.187.2</studioVersion>
|
||||
<studioVersion>3.187.3</studioVersion>
|
||||
<packageVersions>
|
||||
<entry>
|
||||
<key>ru.cg.webbpm.packages.base.resources</key>
|
||||
<value>3.187.2</value>
|
||||
<value>3.187.3</value>
|
||||
</entry>
|
||||
</packageVersions>
|
||||
</versions>
|
||||
|
|
|
|||
|
|
@ -8,11 +8,11 @@
|
|||
<documentation>component/buttons/reporting/Кнопка_печати_из_графа_сущности.html</documentation>
|
||||
<internal>false</internal>
|
||||
<versions>
|
||||
<studioVersion>3.187.2</studioVersion>
|
||||
<studioVersion>3.187.3</studioVersion>
|
||||
<packageVersions>
|
||||
<entry>
|
||||
<key>ru.cg.webbpm.packages.base.resources</key>
|
||||
<value>3.187.2</value>
|
||||
<value>3.187.3</value>
|
||||
</entry>
|
||||
</packageVersions>
|
||||
</versions>
|
||||
|
|
|
|||
|
|
@ -8,11 +8,11 @@
|
|||
<documentation>component/buttons/reporting/Кнопка_печати_отчета_из_формы.html</documentation>
|
||||
<internal>false</internal>
|
||||
<versions>
|
||||
<studioVersion>3.187.2</studioVersion>
|
||||
<studioVersion>3.187.3</studioVersion>
|
||||
<packageVersions>
|
||||
<entry>
|
||||
<key>ru.cg.webbpm.packages.base.resources</key>
|
||||
<value>3.187.2</value>
|
||||
<value>3.187.3</value>
|
||||
</entry>
|
||||
</packageVersions>
|
||||
</versions>
|
||||
|
|
|
|||
|
|
@ -8,11 +8,11 @@
|
|||
<documentation>component/containers/Сворачиваемая_панель.html</documentation>
|
||||
<internal>false</internal>
|
||||
<versions>
|
||||
<studioVersion>3.187.2</studioVersion>
|
||||
<studioVersion>3.187.3</studioVersion>
|
||||
<packageVersions>
|
||||
<entry>
|
||||
<key>ru.cg.webbpm.packages.base.resources</key>
|
||||
<value>3.187.2</value>
|
||||
<value>3.187.3</value>
|
||||
</entry>
|
||||
</packageVersions>
|
||||
</versions>
|
||||
|
|
|
|||
|
|
@ -8,11 +8,11 @@
|
|||
<documentation>component/containers/Диалог.html</documentation>
|
||||
<internal>false</internal>
|
||||
<versions>
|
||||
<studioVersion>3.187.2</studioVersion>
|
||||
<studioVersion>3.187.3</studioVersion>
|
||||
<packageVersions>
|
||||
<entry>
|
||||
<key>ru.cg.webbpm.packages.base.resources</key>
|
||||
<value>3.187.2</value>
|
||||
<value>3.187.3</value>
|
||||
</entry>
|
||||
</packageVersions>
|
||||
</versions>
|
||||
|
|
|
|||
|
|
@ -8,11 +8,11 @@
|
|||
<documentation>component/containers/Контейнер_с_кнопками.html</documentation>
|
||||
<internal>false</internal>
|
||||
<versions>
|
||||
<studioVersion>3.187.2</studioVersion>
|
||||
<studioVersion>3.187.3</studioVersion>
|
||||
<packageVersions>
|
||||
<entry>
|
||||
<key>ru.cg.webbpm.packages.base.resources</key>
|
||||
<value>3.187.2</value>
|
||||
<value>3.187.3</value>
|
||||
</entry>
|
||||
</packageVersions>
|
||||
</versions>
|
||||
|
|
|
|||
|
|
@ -8,11 +8,11 @@
|
|||
<documentation>component/containers/Группа_полей.html</documentation>
|
||||
<internal>false</internal>
|
||||
<versions>
|
||||
<studioVersion>3.187.2</studioVersion>
|
||||
<studioVersion>3.187.3</studioVersion>
|
||||
<packageVersions>
|
||||
<entry>
|
||||
<key>ru.cg.webbpm.packages.base.resources</key>
|
||||
<value>3.187.2</value>
|
||||
<value>3.187.3</value>
|
||||
</entry>
|
||||
</packageVersions>
|
||||
</versions>
|
||||
|
|
|
|||
|
|
@ -8,11 +8,11 @@
|
|||
<documentation>component/containers/Набор_фильтров.html</documentation>
|
||||
<internal>false</internal>
|
||||
<versions>
|
||||
<studioVersion>3.187.2</studioVersion>
|
||||
<studioVersion>3.187.3</studioVersion>
|
||||
<packageVersions>
|
||||
<entry>
|
||||
<key>ru.cg.webbpm.packages.base.resources</key>
|
||||
<value>3.187.2</value>
|
||||
<value>3.187.3</value>
|
||||
</entry>
|
||||
</packageVersions>
|
||||
</versions>
|
||||
|
|
|
|||
|
|
@ -8,11 +8,11 @@
|
|||
<documentation>component/containers/Форма.html</documentation>
|
||||
<internal>false</internal>
|
||||
<versions>
|
||||
<studioVersion>3.187.2</studioVersion>
|
||||
<studioVersion>3.187.3</studioVersion>
|
||||
<packageVersions>
|
||||
<entry>
|
||||
<key>ru.cg.webbpm.packages.base.resources</key>
|
||||
<value>3.187.2</value>
|
||||
<value>3.187.3</value>
|
||||
</entry>
|
||||
</packageVersions>
|
||||
</versions>
|
||||
|
|
|
|||
|
|
@ -8,11 +8,11 @@
|
|||
<documentation>component/containers/Горизонтальный_контейнер.html</documentation>
|
||||
<internal>false</internal>
|
||||
<versions>
|
||||
<studioVersion>3.187.2</studioVersion>
|
||||
<studioVersion>3.187.3</studioVersion>
|
||||
<packageVersions>
|
||||
<entry>
|
||||
<key>ru.cg.webbpm.packages.base.resources</key>
|
||||
<value>3.187.2</value>
|
||||
<value>3.187.3</value>
|
||||
</entry>
|
||||
</packageVersions>
|
||||
</versions>
|
||||
|
|
|
|||
|
|
@ -8,11 +8,11 @@
|
|||
<documentation>component/containers/Контейнер_вкладок.html</documentation>
|
||||
<internal>false</internal>
|
||||
<versions>
|
||||
<studioVersion>3.187.2</studioVersion>
|
||||
<studioVersion>3.187.3</studioVersion>
|
||||
<packageVersions>
|
||||
<entry>
|
||||
<key>ru.cg.webbpm.packages.base.resources</key>
|
||||
<value>3.187.2</value>
|
||||
<value>3.187.3</value>
|
||||
</entry>
|
||||
</packageVersions>
|
||||
</versions>
|
||||
|
|
|
|||
|
|
@ -8,11 +8,11 @@
|
|||
<documentation>component/containers/Вкладка.html</documentation>
|
||||
<internal>false</internal>
|
||||
<versions>
|
||||
<studioVersion>3.187.2</studioVersion>
|
||||
<studioVersion>3.187.3</studioVersion>
|
||||
<packageVersions>
|
||||
<entry>
|
||||
<key>ru.cg.webbpm.packages.base.resources</key>
|
||||
<value>3.187.2</value>
|
||||
<value>3.187.3</value>
|
||||
</entry>
|
||||
</packageVersions>
|
||||
</versions>
|
||||
|
|
|
|||
|
|
@ -8,11 +8,11 @@
|
|||
<documentation>component/containers/Вертикальный_контейнер.html</documentation>
|
||||
<internal>false</internal>
|
||||
<versions>
|
||||
<studioVersion>3.187.2</studioVersion>
|
||||
<studioVersion>3.187.3</studioVersion>
|
||||
<packageVersions>
|
||||
<entry>
|
||||
<key>ru.cg.webbpm.packages.base.resources</key>
|
||||
<value>3.187.2</value>
|
||||
<value>3.187.3</value>
|
||||
</entry>
|
||||
</packageVersions>
|
||||
</versions>
|
||||
|
|
|
|||
|
|
@ -8,11 +8,11 @@
|
|||
<documentation>component/containers/Окно.html</documentation>
|
||||
<internal>false</internal>
|
||||
<versions>
|
||||
<studioVersion>3.187.2</studioVersion>
|
||||
<studioVersion>3.187.3</studioVersion>
|
||||
<packageVersions>
|
||||
<entry>
|
||||
<key>ru.cg.webbpm.packages.base.resources</key>
|
||||
<value>3.187.2</value>
|
||||
<value>3.187.3</value>
|
||||
</entry>
|
||||
</packageVersions>
|
||||
</versions>
|
||||
|
|
|
|||
|
|
@ -8,11 +8,11 @@
|
|||
<documentation>component/editable-grids/EditableGrid.html</documentation>
|
||||
<internal>false</internal>
|
||||
<versions>
|
||||
<studioVersion>3.187.2</studioVersion>
|
||||
<studioVersion>3.187.3</studioVersion>
|
||||
<packageVersions>
|
||||
<entry>
|
||||
<key>ru.cg.webbpm.packages.base.resources</key>
|
||||
<value>3.187.2</value>
|
||||
<value>3.187.3</value>
|
||||
</entry>
|
||||
</packageVersions>
|
||||
</versions>
|
||||
|
|
|
|||
|
|
@ -7,11 +7,11 @@
|
|||
<localization>META-INF/components/localization/editable-grids/autocomplete</localization>
|
||||
<internal>false</internal>
|
||||
<versions>
|
||||
<studioVersion>3.187.2</studioVersion>
|
||||
<studioVersion>3.187.3</studioVersion>
|
||||
<packageVersions>
|
||||
<entry>
|
||||
<key>ru.cg.webbpm.packages.base.resources</key>
|
||||
<value>3.187.2</value>
|
||||
<value>3.187.3</value>
|
||||
</entry>
|
||||
</packageVersions>
|
||||
</versions>
|
||||
|
|
|
|||
|
|
@ -7,11 +7,11 @@
|
|||
<localization>META-INF/components/localization/editable-grids/check-box</localization>
|
||||
<internal>false</internal>
|
||||
<versions>
|
||||
<studioVersion>3.187.2</studioVersion>
|
||||
<studioVersion>3.187.3</studioVersion>
|
||||
<packageVersions>
|
||||
<entry>
|
||||
<key>ru.cg.webbpm.packages.base.resources</key>
|
||||
<value>3.187.2</value>
|
||||
<value>3.187.3</value>
|
||||
</entry>
|
||||
</packageVersions>
|
||||
</versions>
|
||||
|
|
|
|||
|
|
@ -7,11 +7,11 @@
|
|||
<localization>META-INF/components/localization/editable-grids/combo-box</localization>
|
||||
<internal>false</internal>
|
||||
<versions>
|
||||
<studioVersion>3.187.2</studioVersion>
|
||||
<studioVersion>3.187.3</studioVersion>
|
||||
<packageVersions>
|
||||
<entry>
|
||||
<key>ru.cg.webbpm.packages.base.resources</key>
|
||||
<value>3.187.2</value>
|
||||
<value>3.187.3</value>
|
||||
</entry>
|
||||
</packageVersions>
|
||||
</versions>
|
||||
|
|
|
|||
|
|
@ -7,11 +7,11 @@
|
|||
<localization>META-INF/components/localization/editable-grids/date-time-picker</localization>
|
||||
<internal>false</internal>
|
||||
<versions>
|
||||
<studioVersion>3.187.2</studioVersion>
|
||||
<studioVersion>3.187.3</studioVersion>
|
||||
<packageVersions>
|
||||
<entry>
|
||||
<key>ru.cg.webbpm.packages.base.resources</key>
|
||||
<value>3.187.2</value>
|
||||
<value>3.187.3</value>
|
||||
</entry>
|
||||
</packageVersions>
|
||||
</versions>
|
||||
|
|
|
|||
|
|
@ -7,11 +7,11 @@
|
|||
<localization>META-INF/components/localization/editable-grids/money-field</localization>
|
||||
<internal>true</internal>
|
||||
<versions>
|
||||
<studioVersion>3.187.2</studioVersion>
|
||||
<studioVersion>3.187.3</studioVersion>
|
||||
<packageVersions>
|
||||
<entry>
|
||||
<key>ru.cg.webbpm.packages.base.resources</key>
|
||||
<value>3.187.2</value>
|
||||
<value>3.187.3</value>
|
||||
</entry>
|
||||
</packageVersions>
|
||||
</versions>
|
||||
|
|
|
|||
|
|
@ -7,11 +7,11 @@
|
|||
<localization>META-INF/components/localization/editable-grids/number-field</localization>
|
||||
<internal>false</internal>
|
||||
<versions>
|
||||
<studioVersion>3.187.2</studioVersion>
|
||||
<studioVersion>3.187.3</studioVersion>
|
||||
<packageVersions>
|
||||
<entry>
|
||||
<key>ru.cg.webbpm.packages.base.resources</key>
|
||||
<value>3.187.2</value>
|
||||
<value>3.187.3</value>
|
||||
</entry>
|
||||
</packageVersions>
|
||||
</versions>
|
||||
|
|
|
|||
|
|
@ -7,11 +7,11 @@
|
|||
<localization>META-INF/components/localization/editable-grids/one-to-many</localization>
|
||||
<internal>true</internal>
|
||||
<versions>
|
||||
<studioVersion>3.187.2</studioVersion>
|
||||
<studioVersion>3.187.3</studioVersion>
|
||||
<packageVersions>
|
||||
<entry>
|
||||
<key>ru.cg.webbpm.packages.base.resources</key>
|
||||
<value>3.187.2</value>
|
||||
<value>3.187.3</value>
|
||||
</entry>
|
||||
</packageVersions>
|
||||
</versions>
|
||||
|
|
|
|||
|
|
@ -7,11 +7,11 @@
|
|||
<localization>META-INF/components/localization/editable-grids/one-to-many</localization>
|
||||
<internal>false</internal>
|
||||
<versions>
|
||||
<studioVersion>3.187.2</studioVersion>
|
||||
<studioVersion>3.187.3</studioVersion>
|
||||
<packageVersions>
|
||||
<entry>
|
||||
<key>ru.cg.webbpm.packages.base.resources</key>
|
||||
<value>3.187.2</value>
|
||||
<value>3.187.3</value>
|
||||
</entry>
|
||||
</packageVersions>
|
||||
</versions>
|
||||
|
|
|
|||
|
|
@ -6,11 +6,11 @@
|
|||
<localization>META-INF/components/localization/editable-grids/read-only</localization>
|
||||
<internal>true</internal>
|
||||
<versions>
|
||||
<studioVersion>3.187.2</studioVersion>
|
||||
<studioVersion>3.187.3</studioVersion>
|
||||
<packageVersions>
|
||||
<entry>
|
||||
<key>ru.cg.webbpm.packages.base.resources</key>
|
||||
<value>3.187.2</value>
|
||||
<value>3.187.3</value>
|
||||
</entry>
|
||||
</packageVersions>
|
||||
</versions>
|
||||
|
|
|
|||
|
|
@ -5,11 +5,11 @@
|
|||
<category>editable-grids</category>
|
||||
<internal>true</internal>
|
||||
<versions>
|
||||
<studioVersion>3.187.2</studioVersion>
|
||||
<studioVersion>3.187.3</studioVersion>
|
||||
<packageVersions>
|
||||
<entry>
|
||||
<key>ru.cg.webbpm.packages.base.resources</key>
|
||||
<value>3.187.2</value>
|
||||
<value>3.187.3</value>
|
||||
</entry>
|
||||
</packageVersions>
|
||||
</versions>
|
||||
|
|
|
|||
|
|
@ -8,11 +8,11 @@
|
|||
<documentation>Статичный_выпадающий_список_колонки_таблицы.html</documentation>
|
||||
<internal>false</internal>
|
||||
<versions>
|
||||
<studioVersion>3.187.2</studioVersion>
|
||||
<studioVersion>3.187.3</studioVersion>
|
||||
<packageVersions>
|
||||
<entry>
|
||||
<key>ru.cg.webbpm.packages.base.resources</key>
|
||||
<value>3.187.2</value>
|
||||
<value>3.187.3</value>
|
||||
</entry>
|
||||
</packageVersions>
|
||||
</versions>
|
||||
|
|
|
|||
|
|
@ -7,11 +7,11 @@
|
|||
<localization>META-INF/components/localization/editable-grids/text-area</localization>
|
||||
<internal>false</internal>
|
||||
<versions>
|
||||
<studioVersion>3.187.2</studioVersion>
|
||||
<studioVersion>3.187.3</studioVersion>
|
||||
<packageVersions>
|
||||
<entry>
|
||||
<key>ru.cg.webbpm.packages.base.resources</key>
|
||||
<value>3.187.2</value>
|
||||
<value>3.187.3</value>
|
||||
</entry>
|
||||
</packageVersions>
|
||||
</versions>
|
||||
|
|
|
|||
|
|
@ -7,11 +7,11 @@
|
|||
<localization>META-INF/components/localization/editable-grids/text-field</localization>
|
||||
<internal>false</internal>
|
||||
<versions>
|
||||
<studioVersion>3.187.2</studioVersion>
|
||||
<studioVersion>3.187.3</studioVersion>
|
||||
<packageVersions>
|
||||
<entry>
|
||||
<key>ru.cg.webbpm.packages.base.resources</key>
|
||||
<value>3.187.2</value>
|
||||
<value>3.187.3</value>
|
||||
</entry>
|
||||
</packageVersions>
|
||||
</versions>
|
||||
|
|
|
|||
|
|
@ -7,11 +7,11 @@
|
|||
<localization>META-INF/components/localization/editable-grids/time-picker</localization>
|
||||
<internal>false</internal>
|
||||
<versions>
|
||||
<studioVersion>3.187.2</studioVersion>
|
||||
<studioVersion>3.187.3</studioVersion>
|
||||
<packageVersions>
|
||||
<entry>
|
||||
<key>ru.cg.webbpm.packages.base.resources</key>
|
||||
<value>3.187.2</value>
|
||||
<value>3.187.3</value>
|
||||
</entry>
|
||||
</packageVersions>
|
||||
</versions>
|
||||
|
|
|
|||
|
|
@ -8,11 +8,11 @@
|
|||
<documentation>component/fields/ФИАС.html</documentation>
|
||||
<internal>false</internal>
|
||||
<versions>
|
||||
<studioVersion>3.187.2</studioVersion>
|
||||
<studioVersion>3.187.3</studioVersion>
|
||||
<packageVersions>
|
||||
<entry>
|
||||
<key>ru.cg.webbpm.packages.base.resources</key>
|
||||
<value>3.187.2</value>
|
||||
<value>3.187.3</value>
|
||||
</entry>
|
||||
</packageVersions>
|
||||
</versions>
|
||||
|
|
|
|||
|
|
@ -8,11 +8,11 @@
|
|||
<documentation>component/fields/Поле_ввода_с_подбором_значения.html</documentation>
|
||||
<internal>false</internal>
|
||||
<versions>
|
||||
<studioVersion>3.187.2</studioVersion>
|
||||
<studioVersion>3.187.3</studioVersion>
|
||||
<packageVersions>
|
||||
<entry>
|
||||
<key>ru.cg.webbpm.packages.base.resources</key>
|
||||
<value>3.187.2</value>
|
||||
<value>3.187.3</value>
|
||||
</entry>
|
||||
</packageVersions>
|
||||
</versions>
|
||||
|
|
|
|||
|
|
@ -8,11 +8,11 @@
|
|||
<documentation>component/fields/Флаг.html</documentation>
|
||||
<internal>false</internal>
|
||||
<versions>
|
||||
<studioVersion>3.187.2</studioVersion>
|
||||
<studioVersion>3.187.3</studioVersion>
|
||||
<packageVersions>
|
||||
<entry>
|
||||
<key>ru.cg.webbpm.packages.base.resources</key>
|
||||
<value>3.187.2</value>
|
||||
<value>3.187.3</value>
|
||||
</entry>
|
||||
</packageVersions>
|
||||
</versions>
|
||||
|
|
|
|||
|
|
@ -8,11 +8,11 @@
|
|||
<documentation>component/fields/Выпадающий_список.html</documentation>
|
||||
<internal>false</internal>
|
||||
<versions>
|
||||
<studioVersion>3.187.2</studioVersion>
|
||||
<studioVersion>3.187.3</studioVersion>
|
||||
<packageVersions>
|
||||
<entry>
|
||||
<key>ru.cg.webbpm.packages.base.resources</key>
|
||||
<value>3.187.2</value>
|
||||
<value>3.187.3</value>
|
||||
</entry>
|
||||
</packageVersions>
|
||||
</versions>
|
||||
|
|
|
|||
|
|
@ -8,11 +8,11 @@
|
|||
<documentation>component/fields/Дата.html</documentation>
|
||||
<internal>false</internal>
|
||||
<versions>
|
||||
<studioVersion>3.187.2</studioVersion>
|
||||
<studioVersion>3.187.3</studioVersion>
|
||||
<packageVersions>
|
||||
<entry>
|
||||
<key>ru.cg.webbpm.packages.base.resources</key>
|
||||
<value>3.187.2</value>
|
||||
<value>3.187.3</value>
|
||||
</entry>
|
||||
</packageVersions>
|
||||
</versions>
|
||||
|
|
|
|||
|
|
@ -8,11 +8,11 @@
|
|||
<documentation>component/fields/EditableOneToMany.html</documentation>
|
||||
<internal>false</internal>
|
||||
<versions>
|
||||
<studioVersion>3.187.2</studioVersion>
|
||||
<studioVersion>3.187.3</studioVersion>
|
||||
<packageVersions>
|
||||
<entry>
|
||||
<key>ru.cg.webbpm.packages.base.resources</key>
|
||||
<value>3.187.2</value>
|
||||
<value>3.187.3</value>
|
||||
</entry>
|
||||
</packageVersions>
|
||||
</versions>
|
||||
|
|
|
|||
|
|
@ -8,11 +8,11 @@
|
|||
<documentation>component/fields/Файл.html</documentation>
|
||||
<internal>false</internal>
|
||||
<versions>
|
||||
<studioVersion>3.187.2</studioVersion>
|
||||
<studioVersion>3.187.3</studioVersion>
|
||||
<packageVersions>
|
||||
<entry>
|
||||
<key>ru.cg.webbpm.packages.base.resources</key>
|
||||
<value>3.187.2</value>
|
||||
<value>3.187.3</value>
|
||||
</entry>
|
||||
</packageVersions>
|
||||
</versions>
|
||||
|
|
|
|||
|
|
@ -8,11 +8,11 @@
|
|||
<documentation>component/fields/Файл.html</documentation>
|
||||
<internal>false</internal>
|
||||
<versions>
|
||||
<studioVersion>3.187.2</studioVersion>
|
||||
<studioVersion>3.187.3</studioVersion>
|
||||
<packageVersions>
|
||||
<entry>
|
||||
<key>ru.cg.webbpm.packages.base.resources</key>
|
||||
<value>3.187.2</value>
|
||||
<value>3.187.3</value>
|
||||
</entry>
|
||||
</packageVersions>
|
||||
</versions>
|
||||
|
|
|
|||
|
|
@ -8,11 +8,11 @@
|
|||
<documentation>component/fields/ManyToMany.html</documentation>
|
||||
<internal>false</internal>
|
||||
<versions>
|
||||
<studioVersion>3.187.2</studioVersion>
|
||||
<studioVersion>3.187.3</studioVersion>
|
||||
<packageVersions>
|
||||
<entry>
|
||||
<key>ru.cg.webbpm.packages.base.resources</key>
|
||||
<value>3.187.2</value>
|
||||
<value>3.187.3</value>
|
||||
</entry>
|
||||
</packageVersions>
|
||||
</versions>
|
||||
|
|
|
|||
|
|
@ -8,11 +8,11 @@
|
|||
<documentation>component/fields/ManyToManyField.html</documentation>
|
||||
<internal>false</internal>
|
||||
<versions>
|
||||
<studioVersion>3.187.2</studioVersion>
|
||||
<studioVersion>3.187.3</studioVersion>
|
||||
<packageVersions>
|
||||
<entry>
|
||||
<key>ru.cg.webbpm.packages.base.resources</key>
|
||||
<value>3.187.2</value>
|
||||
<value>3.187.3</value>
|
||||
</entry>
|
||||
</packageVersions>
|
||||
</versions>
|
||||
|
|
|
|||
|
|
@ -8,11 +8,11 @@
|
|||
<documentation>component/fields/Денежное_поле.html</documentation>
|
||||
<internal>true</internal>
|
||||
<versions>
|
||||
<studioVersion>3.187.2</studioVersion>
|
||||
<studioVersion>3.187.3</studioVersion>
|
||||
<packageVersions>
|
||||
<entry>
|
||||
<key>ru.cg.webbpm.packages.base.resources</key>
|
||||
<value>3.187.2</value>
|
||||
<value>3.187.3</value>
|
||||
</entry>
|
||||
</packageVersions>
|
||||
</versions>
|
||||
|
|
|
|||
|
|
@ -8,11 +8,11 @@
|
|||
<documentation>component/fields/Числовое_поле.html</documentation>
|
||||
<internal>false</internal>
|
||||
<versions>
|
||||
<studioVersion>3.187.2</studioVersion>
|
||||
<studioVersion>3.187.3</studioVersion>
|
||||
<packageVersions>
|
||||
<entry>
|
||||
<key>ru.cg.webbpm.packages.base.resources</key>
|
||||
<value>3.187.2</value>
|
||||
<value>3.187.3</value>
|
||||
</entry>
|
||||
</packageVersions>
|
||||
</versions>
|
||||
|
|
|
|||
|
|
@ -8,11 +8,11 @@
|
|||
<documentation>component/fields/OneToMany.html</documentation>
|
||||
<internal>true</internal>
|
||||
<versions>
|
||||
<studioVersion>3.187.2</studioVersion>
|
||||
<studioVersion>3.187.3</studioVersion>
|
||||
<packageVersions>
|
||||
<entry>
|
||||
<key>ru.cg.webbpm.packages.base.resources</key>
|
||||
<value>3.187.2</value>
|
||||
<value>3.187.3</value>
|
||||
</entry>
|
||||
</packageVersions>
|
||||
</versions>
|
||||
|
|
|
|||
|
|
@ -8,11 +8,11 @@
|
|||
<documentation>component/fields/OneToMany.html</documentation>
|
||||
<internal>false</internal>
|
||||
<versions>
|
||||
<studioVersion>3.187.2</studioVersion>
|
||||
<studioVersion>3.187.3</studioVersion>
|
||||
<packageVersions>
|
||||
<entry>
|
||||
<key>ru.cg.webbpm.packages.base.resources</key>
|
||||
<value>3.187.2</value>
|
||||
<value>3.187.3</value>
|
||||
</entry>
|
||||
</packageVersions>
|
||||
</versions>
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue