From 50dc46e5fff2832145fa0233055e1321542568ee Mon Sep 17 00:00:00 2001 From: YevhenBondarenko Date: Thu, 19 Oct 2023 17:51:07 +0200 Subject: [PATCH 1/8] moved device connectivity from yml to AdminSettings --- .../install/ThingsboardInstallService.java | 1 + .../DefaultSystemDataLoaderService.java | 48 ++++++++++++ .../update/DefaultDataUpdateService.java | 22 ++++++ .../DeviceConnectivityControllerTest.java | 21 ++++-- ...ectivityControllerWithDefaultPortTest.java | 22 +++--- .../DeviceConnectivityConfiguration.java | 1 + .../dao/device/DeviceConnectivityInfo.java | 1 - .../device/DeviceConnectivityServiceImpl.java | 73 ++++++++++++------- dao/src/test/resources/sql/system-data.sql | 10 +++ 9 files changed, 155 insertions(+), 44 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/install/ThingsboardInstallService.java b/application/src/main/java/org/thingsboard/server/install/ThingsboardInstallService.java index 3829b3cf45..9f51fcf288 100644 --- a/application/src/main/java/org/thingsboard/server/install/ThingsboardInstallService.java +++ b/application/src/main/java/org/thingsboard/server/install/ThingsboardInstallService.java @@ -265,6 +265,7 @@ public class ThingsboardInstallService { case "3.6.0": log.info("Upgrading ThingsBoard from version 3.6.0 to 3.6.1 ..."); databaseEntitiesUpgradeService.upgradeDatabase("3.6.0"); + dataUpdateService.updateData("3.6.0"); //TODO DON'T FORGET to update switch statement in the CacheCleanupService if you need to clear the cache break; default: diff --git a/application/src/main/java/org/thingsboard/server/service/install/DefaultSystemDataLoaderService.java b/application/src/main/java/org/thingsboard/server/service/install/DefaultSystemDataLoaderService.java index 19d7780a79..61bcf1a5a3 100644 --- a/application/src/main/java/org/thingsboard/server/service/install/DefaultSystemDataLoaderService.java +++ b/application/src/main/java/org/thingsboard/server/service/install/DefaultSystemDataLoaderService.java @@ -264,6 +264,7 @@ public class DefaultSystemDataLoaderService implements SystemDataLoaderService { ObjectNode node = JacksonUtil.newObjectNode(); node.put("baseUrl", "http://localhost:8080"); node.put("prohibitDifferentUrl", false); + node.set("connectivity", createDeviceConnectivityConfiguration()); generalSettings.setJsonValue(node); adminSettingsService.saveAdminSettings(TenantId.SYS_TENANT_ID, generalSettings); @@ -284,6 +285,53 @@ public class DefaultSystemDataLoaderService implements SystemDataLoaderService { node.put("showChangePassword", false); mailSettings.setJsonValue(node); adminSettingsService.saveAdminSettings(TenantId.SYS_TENANT_ID, mailSettings); + + AdminSettings connectivitySettings = new AdminSettings(); + connectivitySettings.setTenantId(TenantId.SYS_TENANT_ID); + connectivitySettings.setKey("connectivity"); + connectivitySettings.setJsonValue(createDeviceConnectivityConfiguration()); + adminSettingsService.saveAdminSettings(TenantId.SYS_TENANT_ID, connectivitySettings); + } + + private ObjectNode createDeviceConnectivityConfiguration() { + ObjectNode config = JacksonUtil.newObjectNode(); + + ObjectNode http = JacksonUtil.newObjectNode(); + http.put("enabled", true); + http.put("host", ""); + http.put("port", 8080); + config.set("http", http); + + ObjectNode https = JacksonUtil.newObjectNode(); + https.put("enabled", false); + https.put("host", ""); + https.put("port", 443); + config.set("https", https); + + ObjectNode mqtt = JacksonUtil.newObjectNode(); + mqtt.put("enabled", true); + mqtt.put("host", ""); + mqtt.put("port", 1883); + config.set("mqtt", mqtt); + + ObjectNode mqtts = JacksonUtil.newObjectNode(); + mqtts.put("enabled", false); + mqtts.put("host", ""); + mqtts.put("port", 8883); + config.set("mqtts", mqtts); + + ObjectNode coap = JacksonUtil.newObjectNode(); + coap.put("enabled", true); + coap.put("host", ""); + coap.put("port", 5683); + config.set("coap", coap); + + ObjectNode coaps = JacksonUtil.newObjectNode(); + coaps.put("enabled", false); + coaps.put("host", ""); + coaps.put("port", 5684); + config.set("coaps", coaps); + return config; } @Override diff --git a/application/src/main/java/org/thingsboard/server/service/install/update/DefaultDataUpdateService.java b/application/src/main/java/org/thingsboard/server/service/install/update/DefaultDataUpdateService.java index d16b8c362b..b55a77ce51 100644 --- a/application/src/main/java/org/thingsboard/server/service/install/update/DefaultDataUpdateService.java +++ b/application/src/main/java/org/thingsboard/server/service/install/update/DefaultDataUpdateService.java @@ -32,6 +32,7 @@ import org.thingsboard.rule.engine.flow.TbRuleChainInputNode; import org.thingsboard.rule.engine.flow.TbRuleChainInputNodeConfiguration; import org.thingsboard.rule.engine.profile.TbDeviceProfileNode; import org.thingsboard.rule.engine.profile.TbDeviceProfileNodeConfiguration; +import org.thingsboard.server.common.data.AdminSettings; import org.thingsboard.server.common.data.DataConstants; import org.thingsboard.server.common.data.EntityView; import org.thingsboard.server.common.data.Tenant; @@ -70,6 +71,7 @@ import org.thingsboard.server.common.data.util.TbPair; import org.thingsboard.server.dao.DaoUtil; import org.thingsboard.server.dao.alarm.AlarmDao; import org.thingsboard.server.dao.audit.AuditLogDao; +import org.thingsboard.server.dao.device.DeviceConnectivityConfiguration; import org.thingsboard.server.dao.edge.EdgeEventDao; import org.thingsboard.server.dao.entity.EntityService; import org.thingsboard.server.dao.entityview.EntityViewService; @@ -78,6 +80,7 @@ import org.thingsboard.server.dao.model.sql.DeviceProfileEntity; import org.thingsboard.server.dao.queue.QueueService; import org.thingsboard.server.dao.relation.RelationService; import org.thingsboard.server.dao.rule.RuleChainService; +import org.thingsboard.server.dao.settings.AdminSettingsService; import org.thingsboard.server.dao.sql.JpaExecutorService; import org.thingsboard.server.dao.sql.device.DeviceProfileRepository; import org.thingsboard.server.dao.tenant.TenantProfileService; @@ -161,6 +164,12 @@ public class DefaultDataUpdateService implements DataUpdateService { @Autowired JpaExecutorService jpaExecutorService; + @Autowired + AdminSettingsService adminSettingsService; + + @Autowired + DeviceConnectivityConfiguration connectivityConfiguration; + @Override public void updateData(String fromVersion) throws Exception { switch (fromVersion) { @@ -214,6 +223,11 @@ public class DefaultDataUpdateService implements DataUpdateService { case "3.5.1": log.info("Updating data from version 3.5.1 to 3.6.0 ..."); migrateEdgeEvents("Starting edge events migration - adding seq_id column. "); + migrateDeviceConnectivity(); + break; + case "3.6.0": + log.info("Updating data from version 3.6.0 to 3.6.1 ..."); + migrateDeviceConnectivity(); break; default: throw new RuntimeException("Unable to update data, unsupported fromVersion: " + fromVersion); @@ -230,6 +244,14 @@ public class DefaultDataUpdateService implements DataUpdateService { } } + private void migrateDeviceConnectivity() { + AdminSettings connectivitySettings = new AdminSettings(); + connectivitySettings.setTenantId(TenantId.SYS_TENANT_ID); + connectivitySettings.setKey("connectivity"); + connectivitySettings.setJsonValue(JacksonUtil.valueToTree(connectivityConfiguration.getConnectivity())); + adminSettingsService.saveAdminSettings(TenantId.SYS_TENANT_ID, connectivitySettings); + } + @Override public void upgradeRuleNodes() { try { diff --git a/application/src/test/java/org/thingsboard/server/controller/DeviceConnectivityControllerTest.java b/application/src/test/java/org/thingsboard/server/controller/DeviceConnectivityControllerTest.java index 1eaf719921..9f8e8d625a 100644 --- a/application/src/test/java/org/thingsboard/server/controller/DeviceConnectivityControllerTest.java +++ b/application/src/test/java/org/thingsboard/server/controller/DeviceConnectivityControllerTest.java @@ -17,12 +17,14 @@ package org.thingsboard.server.controller; import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.node.ObjectNode; import com.google.common.util.concurrent.ListeningExecutorService; import com.google.common.util.concurrent.MoreExecutors; import org.junit.After; import org.junit.Assert; import org.junit.Before; import org.junit.Test; +import org.junit.jupiter.api.BeforeAll; import org.mockito.AdditionalAnswers; import org.mockito.Mockito; import org.springframework.context.annotation.Bean; @@ -32,6 +34,7 @@ import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.TestPropertySource; import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.common.util.ThingsBoardExecutors; +import org.thingsboard.server.common.data.AdminSettings; import org.thingsboard.server.common.data.Device; import org.thingsboard.server.common.data.DeviceProfile; import org.thingsboard.server.common.data.DeviceProfileType; @@ -44,6 +47,7 @@ import org.thingsboard.server.common.data.device.profile.DefaultDeviceProfileCon import org.thingsboard.server.common.data.device.profile.DeviceProfileData; import org.thingsboard.server.common.data.device.profile.MqttDeviceProfileTransportConfiguration; import org.thingsboard.server.common.data.id.DeviceProfileId; +import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.security.Authority; import org.thingsboard.server.common.data.security.DeviceCredentials; import org.thingsboard.server.common.data.security.DeviceCredentialsType; @@ -65,12 +69,7 @@ import static org.thingsboard.server.dao.util.DeviceConnectivityUtil.MQTTS; import static org.thingsboard.server.dao.util.DeviceConnectivityUtil.CA_ROOT_CERT_PEM; @TestPropertySource(properties = { - "device.connectivity.https.enabled=true", - "device.connectivity.http.port=8080", - "device.connectivity.https.port=444", - "device.connectivity.mqtts.enabled=true", - "device.connectivity.mqtts.pem_cert_file=/tmp/" + CA_ROOT_CERT_PEM, - "device.connectivity.coaps.enabled=true", + "device.connectivity.mqtts.pem_cert_file=/tmp/" + CA_ROOT_CERT_PEM }) @ContextConfiguration(classes = {DeviceConnectivityControllerTest.Config.class}) @DaoSqlTest @@ -122,6 +121,16 @@ public class DeviceConnectivityControllerTest extends AbstractControllerTest { loginSysAdmin(); + AdminSettings adminSettings = doGet("/api/admin/settings/connectivity", AdminSettings.class); + JsonNode connectivity = adminSettings.getJsonValue(); + + ((ObjectNode)connectivity.get("http")).put("port", 8080); + ((ObjectNode)connectivity.get("https")).put("enabled", true); + ((ObjectNode)connectivity.get("https")).put("port", 444); + ((ObjectNode)connectivity.get("mqtts")).put("enabled", true); + ((ObjectNode)connectivity.get("coaps")).put("enabled", true); + doPost("/api/admin/settings", adminSettings); + Tenant tenant = new Tenant(); tenant.setTitle("My tenant"); savedTenant = doPost("/api/tenant", tenant, Tenant.class); diff --git a/application/src/test/java/org/thingsboard/server/controller/DeviceConnectivityControllerWithDefaultPortTest.java b/application/src/test/java/org/thingsboard/server/controller/DeviceConnectivityControllerWithDefaultPortTest.java index bba834912f..0889f458ba 100644 --- a/application/src/test/java/org/thingsboard/server/controller/DeviceConnectivityControllerWithDefaultPortTest.java +++ b/application/src/test/java/org/thingsboard/server/controller/DeviceConnectivityControllerWithDefaultPortTest.java @@ -17,6 +17,7 @@ package org.thingsboard.server.controller; import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.node.ObjectNode; import com.google.common.util.concurrent.ListeningExecutorService; import com.google.common.util.concurrent.MoreExecutors; import org.junit.After; @@ -28,8 +29,8 @@ import org.mockito.Mockito; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Primary; import org.springframework.test.context.ContextConfiguration; -import org.springframework.test.context.TestPropertySource; import org.thingsboard.common.util.ThingsBoardExecutors; +import org.thingsboard.server.common.data.AdminSettings; import org.thingsboard.server.common.data.Device; import org.thingsboard.server.common.data.Tenant; import org.thingsboard.server.common.data.User; @@ -43,14 +44,6 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers. import static org.thingsboard.server.dao.util.DeviceConnectivityUtil.HTTP; import static org.thingsboard.server.dao.util.DeviceConnectivityUtil.HTTPS; -@TestPropertySource(properties = { - "device.connectivity.https.enabled=true", - "device.connectivity.http.port=80", - "device.connectivity.mqtt.enabled=false", - "device.connectivity.mqtts.enabled=false", - "device.connectivity.coap.enabled=false", - "device.connectivity.coaps.enabled=false", -}) @ContextConfiguration(classes = {DeviceConnectivityControllerWithDefaultPortTest.Config.class}) @DaoSqlTest public class DeviceConnectivityControllerWithDefaultPortTest extends AbstractControllerTest { @@ -73,6 +66,17 @@ public class DeviceConnectivityControllerWithDefaultPortTest extends AbstractCon loginSysAdmin(); + AdminSettings adminSettings = doGet("/api/admin/settings/connectivity", AdminSettings.class); + JsonNode connectivity = adminSettings.getJsonValue(); + + ((ObjectNode) connectivity.get("http")).put("port", 80); + ((ObjectNode) connectivity.get("https")).put("enabled", true); + ((ObjectNode) connectivity.get("mqtt")).put("enabled", false); + ((ObjectNode) connectivity.get("mqtts")).put("enabled", false); + ((ObjectNode) connectivity.get("coaps")).put("enabled", false); + ((ObjectNode) connectivity.get("coap")).put("enabled", false); + doPost("/api/admin/settings", adminSettings); + Tenant tenant = new Tenant(); tenant.setTitle("My tenant"); savedTenant = doPost("/api/tenant", tenant, Tenant.class); diff --git a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceConnectivityConfiguration.java b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceConnectivityConfiguration.java index 227b531be0..df55eee2e4 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceConnectivityConfiguration.java +++ b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceConnectivityConfiguration.java @@ -25,6 +25,7 @@ import java.util.Map; @Configuration @ConfigurationProperties(prefix = "device") @Data +@Deprecated(since = "3.6.1") public class DeviceConnectivityConfiguration { private Map connectivity = new HashMap<>(); diff --git a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceConnectivityInfo.java b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceConnectivityInfo.java index b243be9995..0f8723fcfb 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceConnectivityInfo.java +++ b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceConnectivityInfo.java @@ -22,5 +22,4 @@ public class DeviceConnectivityInfo { private boolean enabled; private String host; private String port; - private String pemCertFile; } diff --git a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceConnectivityServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceConnectivityServiceImpl.java index 28d8f20b81..74a248c1a3 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceConnectivityServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceConnectivityServiceImpl.java @@ -18,14 +18,16 @@ package org.thingsboard.server.dao.device; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.node.ArrayNode; import com.fasterxml.jackson.databind.node.ObjectNode; +import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.bouncycastle.cert.X509CertificateHolder; import org.bouncycastle.openssl.PEMParser; -import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; import org.springframework.core.io.ByteArrayResource; import org.springframework.core.io.Resource; import org.springframework.stereotype.Service; import org.thingsboard.common.util.JacksonUtil; +import org.thingsboard.server.common.data.AdminSettings; import org.thingsboard.server.common.data.Device; import org.thingsboard.server.common.data.DeviceProfile; import org.thingsboard.server.common.data.DeviceTransportType; @@ -33,8 +35,10 @@ import org.thingsboard.server.common.data.ResourceUtils; import org.thingsboard.server.common.data.StringUtils; import org.thingsboard.server.common.data.device.profile.MqttDeviceProfileTransportConfiguration; import org.thingsboard.server.common.data.id.DeviceId; +import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.security.DeviceCredentials; import org.thingsboard.server.common.data.security.DeviceCredentialsType; +import org.thingsboard.server.dao.settings.AdminSettingsService; import org.thingsboard.server.dao.util.DeviceConnectivityUtil; import javax.annotation.PostConstruct; @@ -64,6 +68,7 @@ import static org.thingsboard.server.dao.util.DeviceConnectivityUtil.WINDOWS; @Service("DeviceConnectivityDaoService") @Slf4j +@RequiredArgsConstructor public class DeviceConnectivityServiceImpl implements DeviceConnectivityService { public static final String INCORRECT_TENANT_ID = "Incorrect tenantId "; @@ -74,20 +79,18 @@ public class DeviceConnectivityServiceImpl implements DeviceConnectivityService private final Map certs = new ConcurrentHashMap<>(); - @Autowired - private DeviceCredentialsService deviceCredentialsService; + private final DeviceCredentialsService deviceCredentialsService; + private final DeviceProfileService deviceProfileService; + private final AdminSettingsService adminSettingsService; - @Autowired - private DeviceProfileService deviceProfileService; - - @Autowired - private DeviceConnectivityConfiguration deviceConnectivityConfiguration; + @Value("${device.connectivity.mqtts.pem_cert_file}") + private String mqttsPemCertFile; @PostConstruct private void init() { - DeviceConnectivityInfo mqtts = deviceConnectivityConfiguration.getConnectivity(MQTTS); + DeviceConnectivityInfo mqtts = getConnectivity(MQTTS); if (mqtts != null && mqtts.isEnabled()) { - String certFilePath = mqtts.getPemCertFile(); + String certFilePath = mqttsPemCertFile; if (StringUtils.isBlank(certFilePath) || !ResourceUtils.resourceExists(this, certFilePath)) { String error = StringUtils.isBlank(certFilePath) ? "path is empty" : "file is not exists"; log.error("MQTTS is enabled but cert {}!", error); @@ -149,11 +152,11 @@ public class DeviceConnectivityServiceImpl implements DeviceConnectivityService DeviceCredentials creds = deviceCredentialsService.findDeviceCredentialsByDeviceId(device.getTenantId(), deviceId); ObjectNode commands = JacksonUtil.newObjectNode(); - if (deviceConnectivityConfiguration.isEnabled(MQTT)) { + if (isEnabled(MQTT)) { Optional.ofNullable(getGatewayDockerCommands(baseUrl, creds, MQTT)) .ifPresent(v -> commands.set(MQTT, v)); } - if (deviceConnectivityConfiguration.isEnabled(MQTTS)) { + if (isEnabled(MQTTS)) { Optional.ofNullable(getGatewayDockerCommands(baseUrl, creds, MQTTS)) .ifPresent(v -> commands.set(MQTTS, v)); } @@ -163,15 +166,15 @@ public class DeviceConnectivityServiceImpl implements DeviceConnectivityService @Override public Resource getPemCertFile(String protocol) { return certs.computeIfAbsent(protocol, key -> { - DeviceConnectivityInfo connectivity = deviceConnectivityConfiguration.getConnectivity(protocol); - if (connectivity == null) { + DeviceConnectivityInfo connectivity = getConnectivity(protocol); + if (!MQTTS.equals(protocol) || connectivity == null) { log.warn("Unknown connectivity protocol: {}", protocol); return null; } - String certFilePath = connectivity.getPemCertFile(); - if (StringUtils.isNotBlank(certFilePath) && ResourceUtils.resourceExists(this, certFilePath)) { + + if (StringUtils.isNotBlank(mqttsPemCertFile) && ResourceUtils.resourceExists(this, mqttsPemCertFile)) { try { - return getCert(certFilePath); + return getCert(mqttsPemCertFile); } catch (Exception e) { String msg = String.format("Failed to read %s server certificate!", protocol); log.warn(msg); @@ -183,6 +186,20 @@ public class DeviceConnectivityServiceImpl implements DeviceConnectivityService }); } + private DeviceConnectivityInfo getConnectivity(String protocol) { + AdminSettings connectivitySettings = adminSettingsService.findAdminSettingsByKey(TenantId.SYS_TENANT_ID, "connectivity"); + JsonNode connectivity; + if (connectivitySettings != null && (connectivity = connectivitySettings.getJsonValue()) != null) { + return JacksonUtil.convertValue(connectivity.get(protocol), DeviceConnectivityInfo.class); + } + return null; + } + + public boolean isEnabled(String protocol) { + var info = getConnectivity(protocol); + return info != null && info.isEnabled(); + } + private Resource getCert(String path) throws Exception { StringBuilder pemContentBuilder = new StringBuilder(); @@ -221,7 +238,7 @@ public class DeviceConnectivityServiceImpl implements DeviceConnectivityService } private String getHttpPublishCommand(String protocol, String baseUrl, DeviceCredentials deviceCredentials) throws URISyntaxException { - DeviceConnectivityInfo properties = deviceConnectivityConfiguration.getConnectivity(protocol); + DeviceConnectivityInfo properties = getConnectivity(protocol); if (properties == null || !properties.isEnabled() || deviceCredentials.getCredentialsType() != DeviceCredentialsType.ACCESS_TOKEN) { return null; @@ -247,7 +264,7 @@ public class DeviceConnectivityServiceImpl implements DeviceConnectivityService ObjectNode dockerMqttCommands = JacksonUtil.newObjectNode(); - if (deviceConnectivityConfiguration.isEnabled(MQTT)) { + if (isEnabled(MQTT)) { Optional.ofNullable(getMqttPublishCommand(baseUrl, topic, deviceCredentials)). ifPresent(v -> mqttCommands.put(MQTT, v)); @@ -255,7 +272,7 @@ public class DeviceConnectivityServiceImpl implements DeviceConnectivityService .ifPresent(v -> dockerMqttCommands.put(MQTT, v)); } - if (deviceConnectivityConfiguration.isEnabled(MQTTS)) { + if (isEnabled(MQTTS)) { List mqttsPublishCommand = getMqttsPublishCommand(baseUrl, topic, deviceCredentials); if (mqttsPublishCommand != null) { ArrayNode arrayNode = mqttCommands.putArray(MQTTS); @@ -273,14 +290,14 @@ public class DeviceConnectivityServiceImpl implements DeviceConnectivityService } private String getMqttPublishCommand(String baseUrl, String deviceTelemetryTopic, DeviceCredentials deviceCredentials) throws URISyntaxException { - DeviceConnectivityInfo properties = deviceConnectivityConfiguration.getConnectivity(MQTT); + DeviceConnectivityInfo properties = getConnectivity(MQTT); String mqttHost = getHost(baseUrl, properties); String mqttPort = properties.getPort().isEmpty() ? null : properties.getPort(); return DeviceConnectivityUtil.getMqttPublishCommand(MQTT, mqttHost, mqttPort, deviceTelemetryTopic, deviceCredentials); } private List getMqttsPublishCommand(String baseUrl, String deviceTelemetryTopic, DeviceCredentials deviceCredentials) throws URISyntaxException { - DeviceConnectivityInfo properties = deviceConnectivityConfiguration.getConnectivity(MQTTS); + DeviceConnectivityInfo properties = getConnectivity(MQTTS); String mqttHost = getHost(baseUrl, properties); String mqttPort = properties.getPort().isEmpty() ? null : properties.getPort(); String pubCommand = DeviceConnectivityUtil.getMqttPublishCommand(MQTTS, mqttHost, mqttPort, deviceTelemetryTopic, deviceCredentials); @@ -296,7 +313,7 @@ public class DeviceConnectivityServiceImpl implements DeviceConnectivityService private JsonNode getGatewayDockerCommands(String baseUrl, DeviceCredentials deviceCredentials, String mqttType) throws URISyntaxException { ObjectNode dockerLaunchCommands = JacksonUtil.newObjectNode(); - DeviceConnectivityInfo properties = deviceConnectivityConfiguration.getConnectivity().get(mqttType); + DeviceConnectivityInfo properties = getConnectivity(mqttType); String mqttHost = getHost(baseUrl, properties); String mqttPort = properties.getPort().isEmpty() ? null : properties.getPort(); Optional.ofNullable(DeviceConnectivityUtil.getGatewayLaunchCommand(LINUX, mqttHost, mqttPort, deviceCredentials)) @@ -307,7 +324,7 @@ public class DeviceConnectivityServiceImpl implements DeviceConnectivityService } private String getDockerMqttPublishCommand(String protocol, String baseUrl, String deviceTelemetryTopic, DeviceCredentials deviceCredentials) throws URISyntaxException { - DeviceConnectivityInfo properties = deviceConnectivityConfiguration.getConnectivity(protocol); + DeviceConnectivityInfo properties = getConnectivity(protocol); String mqttHost = getHost(baseUrl, properties); String mqttPort = properties.getPort().isEmpty() ? null : properties.getPort(); return DeviceConnectivityUtil.getDockerMqttPublishCommand(protocol, baseUrl, mqttHost, mqttPort, deviceTelemetryTopic, deviceCredentials); @@ -323,7 +340,7 @@ public class DeviceConnectivityServiceImpl implements DeviceConnectivityService ObjectNode dockerCoapCommands = JacksonUtil.newObjectNode(); - if (deviceConnectivityConfiguration.isEnabled(COAP)) { + if (isEnabled(COAP)) { Optional.ofNullable(getCoapPublishCommand(COAP, baseUrl, deviceCredentials)) .ifPresent(v -> coapCommands.put(COAP, v)); @@ -331,7 +348,7 @@ public class DeviceConnectivityServiceImpl implements DeviceConnectivityService .ifPresent(v -> dockerCoapCommands.put(COAP, v)); } - if (deviceConnectivityConfiguration.isEnabled(COAPS)) { + if (isEnabled(COAPS)) { Optional.ofNullable(getCoapPublishCommand(COAPS, baseUrl, deviceCredentials)) .ifPresent(v -> coapCommands.put(COAPS, v)); @@ -347,14 +364,14 @@ public class DeviceConnectivityServiceImpl implements DeviceConnectivityService } private String getCoapPublishCommand(String protocol, String baseUrl, DeviceCredentials deviceCredentials) throws URISyntaxException { - DeviceConnectivityInfo properties = deviceConnectivityConfiguration.getConnectivity(protocol); + DeviceConnectivityInfo properties = getConnectivity(protocol); String hostName = getHost(baseUrl, properties); String port = properties.getPort().isEmpty() ? "" : ":" + properties.getPort(); return DeviceConnectivityUtil.getCoapPublishCommand(protocol, hostName, port, deviceCredentials); } private String getDockerCoapPublishCommand(String protocol, String baseUrl, DeviceCredentials deviceCredentials) throws URISyntaxException { - DeviceConnectivityInfo properties = deviceConnectivityConfiguration.getConnectivity(protocol); + DeviceConnectivityInfo properties = getConnectivity(protocol); String host = getHost(baseUrl, properties); String port = properties.getPort().isEmpty() ? "" : ":" + properties.getPort(); return DeviceConnectivityUtil.getDockerCoapPublishCommand(protocol, host, port, deviceCredentials); diff --git a/dao/src/test/resources/sql/system-data.sql b/dao/src/test/resources/sql/system-data.sql index debf698623..7a79f1114d 100644 --- a/dao/src/test/resources/sql/system-data.sql +++ b/dao/src/test/resources/sql/system-data.sql @@ -43,6 +43,16 @@ VALUES ( '6eaaefa6-4612-11e7-a919-92ebcb67fe33', 1592576748000, '13814000-1dd2-1 "password": "" }' ); +INSERT INTO admin_settings ( id, created_time, tenant_id, key, json_value ) +VALUES ( '23199d80-6e7e-11ee-8829-ef9fd52a6141', 1697719852888, '13814000-1dd2-11b2-8080-808080808080', 'connectivity', '{ + "http":{"enabled":true,"host":"","port":"8080"}, + "https":{"enabled":false,"host":"","port":"443"}, + "mqtt":{"enabled":true,"host":"","port":"1883"}, + "mqtts":{"enabled":false,"host":"","port":"8883"}, + "coap":{"enabled":true,"host":"","port":"5683"}, + "coaps":{"enabled":false,"host":"","port":"5684"} +}' ); + INSERT INTO queue ( id, created_time, tenant_id, name, topic, poll_interval, partitions, consumer_per_partition, pack_processing_timeout, submit_strategy, processing_strategy ) VALUES ( '6eaaefa6-4612-11e7-a919-92ebcb67fe33', 1592576748000 ,'13814000-1dd2-11b2-8080-808080808080', 'Main' ,'tb_rule_engine.main', 25, 10, true, 2000, '{"type": "BURST", "batchSize": 1000}', From 32ffaa2ac134878420aabaa2f50f7e3aab394947 Mon Sep 17 00:00:00 2001 From: YevhenBondarenko Date: Thu, 19 Oct 2023 18:01:38 +0200 Subject: [PATCH 2/8] minor improvements --- .../server/dao/device/DeviceConnectivityServiceImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceConnectivityServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceConnectivityServiceImpl.java index 74a248c1a3..ff07a5df5c 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceConnectivityServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceConnectivityServiceImpl.java @@ -83,7 +83,7 @@ public class DeviceConnectivityServiceImpl implements DeviceConnectivityService private final DeviceProfileService deviceProfileService; private final AdminSettingsService adminSettingsService; - @Value("${device.connectivity.mqtts.pem_cert_file}") + @Value("${device.connectivity.mqtts.pem_cert_file:}") private String mqttsPemCertFile; @PostConstruct From 27964a0836085d08963b3bcc238e374dcce4e433 Mon Sep 17 00:00:00 2001 From: YevhenBondarenko Date: Thu, 19 Oct 2023 22:00:02 +0200 Subject: [PATCH 3/8] fixed tests --- .../server/controller/DeviceConnectivityControllerTest.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/application/src/test/java/org/thingsboard/server/controller/DeviceConnectivityControllerTest.java b/application/src/test/java/org/thingsboard/server/controller/DeviceConnectivityControllerTest.java index 9f8e8d625a..adec1951dd 100644 --- a/application/src/test/java/org/thingsboard/server/controller/DeviceConnectivityControllerTest.java +++ b/application/src/test/java/org/thingsboard/server/controller/DeviceConnectivityControllerTest.java @@ -125,9 +125,12 @@ public class DeviceConnectivityControllerTest extends AbstractControllerTest { JsonNode connectivity = adminSettings.getJsonValue(); ((ObjectNode)connectivity.get("http")).put("port", 8080); + ((ObjectNode)connectivity.get("http")).put("enabled", true); ((ObjectNode)connectivity.get("https")).put("enabled", true); ((ObjectNode)connectivity.get("https")).put("port", 444); + ((ObjectNode)connectivity.get("mqtt")).put("enabled", true); ((ObjectNode)connectivity.get("mqtts")).put("enabled", true); + ((ObjectNode)connectivity.get("coap")).put("enabled", true); ((ObjectNode)connectivity.get("coaps")).put("enabled", true); doPost("/api/admin/settings", adminSettings); From 7fc04e4b24cf4826004ca803a5c2331e3e65a631 Mon Sep 17 00:00:00 2001 From: YevhenBondarenko Date: Fri, 20 Oct 2023 16:17:01 +0200 Subject: [PATCH 4/8] fixed install --- .../dao/device/DeviceConnectivityServiceImpl.java | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) diff --git a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceConnectivityServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceConnectivityServiceImpl.java index ff07a5df5c..9f67093529 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceConnectivityServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceConnectivityServiceImpl.java @@ -41,7 +41,6 @@ import org.thingsboard.server.common.data.security.DeviceCredentialsType; import org.thingsboard.server.dao.settings.AdminSettingsService; import org.thingsboard.server.dao.util.DeviceConnectivityUtil; -import javax.annotation.PostConstruct; import java.io.InputStream; import java.io.InputStreamReader; import java.net.URI; @@ -86,18 +85,6 @@ public class DeviceConnectivityServiceImpl implements DeviceConnectivityService @Value("${device.connectivity.mqtts.pem_cert_file:}") private String mqttsPemCertFile; - @PostConstruct - private void init() { - DeviceConnectivityInfo mqtts = getConnectivity(MQTTS); - if (mqtts != null && mqtts.isEnabled()) { - String certFilePath = mqttsPemCertFile; - if (StringUtils.isBlank(certFilePath) || !ResourceUtils.resourceExists(this, certFilePath)) { - String error = StringUtils.isBlank(certFilePath) ? "path is empty" : "file is not exists"; - log.error("MQTTS is enabled but cert {}!", error); - } - } - } - @Override public JsonNode findDevicePublishTelemetryCommands(String baseUrl, Device device) throws URISyntaxException { DeviceId deviceId = device.getId(); @@ -189,7 +176,7 @@ public class DeviceConnectivityServiceImpl implements DeviceConnectivityService private DeviceConnectivityInfo getConnectivity(String protocol) { AdminSettings connectivitySettings = adminSettingsService.findAdminSettingsByKey(TenantId.SYS_TENANT_ID, "connectivity"); JsonNode connectivity; - if (connectivitySettings != null && (connectivity = connectivitySettings.getJsonValue()) != null) { + if (connectivitySettings != null && (connectivity = connectivitySettings.getJsonValue()) != null) { return JacksonUtil.convertValue(connectivity.get(protocol), DeviceConnectivityInfo.class); } return null; From 4cdd5ce6d489d6a38508157fd6586de0e3088732 Mon Sep 17 00:00:00 2001 From: rusikv Date: Tue, 24 Oct 2023 16:00:56 +0300 Subject: [PATCH 5/8] UI: Device connectivity ui implementation --- .../admin/general-settings.component.html | 237 +++++++++++++++--- .../admin/general-settings.component.scss | 20 ++ .../pages/admin/general-settings.component.ts | 96 +++++-- .../src/app/shared/models/settings.models.ts | 33 +++ .../assets/locale/locale.constant-en_US.json | 17 ++ 5 files changed, 348 insertions(+), 55 deletions(-) diff --git a/ui-ngx/src/app/modules/home/pages/admin/general-settings.component.html b/ui-ngx/src/app/modules/home/pages/admin/general-settings.component.html index da0e9fede3..9703f99581 100644 --- a/ui-ngx/src/app/modules/home/pages/admin/general-settings.component.html +++ b/ui-ngx/src/app/modules/home/pages/admin/general-settings.component.html @@ -15,39 +15,206 @@ limitations under the License. --> -
- - - -
- admin.general-settings -
-
-
- - -
- -
-
- - admin.base-url - - - {{ 'admin.base-url-required' | translate }} - - - + + + +
+ admin.general-settings +
+
+
+ + +
+ + +
+ + admin.base-url + + + {{ 'admin.base-url-required' | translate }} + + +
+ {{ 'admin.prohibit-different-url' | translate }} - -
admin.prohibit-different-url-hint
-
- -
-
- -
-
-
+ + + +
+ + +
+ + + + + + + admin.device-connectivity.device-connectivity + + + + +
+ + + {{ "admin.device-connectivity.http-https" | translate }} + {{ 'admin.device-connectivity.mqtt-mqtts' | translate }} + {{ 'admin.device-connectivity.coap-coaps' | translate }} + + {{ 'admin.device-connectivity.hint' | translate }} +
+
+ + {{ 'admin.device-connectivity.http' | translate }} + +
+ + admin.device-connectivity.host + + + + admin.device-connectivity.port + + + {{ 'admin.device-connectivity.port-pattern' | translate }} + + + {{ 'admin.device-connectivity.port-range' | translate }} + + +
+
+
+ + {{ 'admin.device-connectivity.https' | translate }} + +
+ + admin.device-connectivity.host + + + + admin.device-connectivity.port + + + {{ 'admin.device-connectivity.port-pattern' | translate }} + + + {{ 'admin.device-connectivity.port-range' | translate }} + + +
+
+
+ + {{ 'admin.device-connectivity.mqtt' | translate }} + +
+ + admin.device-connectivity.host + + + + admin.device-connectivity.port + + + {{ 'admin.device-connectivity.port-pattern' | translate }} + + + {{ 'admin.device-connectivity.port-range' | translate }} + + +
+
+
+ + {{ 'admin.device-connectivity.mqtts' | translate }} + +
+ + admin.device-connectivity.host + + + + admin.device-connectivity.port + + + {{ 'admin.device-connectivity.port-pattern' | translate }} + + + {{ 'admin.device-connectivity.port-range' | translate }} + + +
+
+
+ + {{ 'admin.device-connectivity.coap' | translate }} + +
+ + admin.device-connectivity.host + + + + admin.device-connectivity.port + + + {{ 'admin.device-connectivity.port-pattern' | translate }} + + + {{ 'admin.device-connectivity.port-range' | translate }} + + +
+
+
+ + {{ 'admin.device-connectivity.coaps' | translate }} + +
+ + admin.device-connectivity.host + + + + admin.device-connectivity.port + + + {{ 'admin.device-connectivity.port-pattern' | translate }} + + + {{ 'admin.device-connectivity.port-range' | translate }} + + +
+
+
+ + +
+
+
+
diff --git a/ui-ngx/src/app/modules/home/pages/admin/general-settings.component.scss b/ui-ngx/src/app/modules/home/pages/admin/general-settings.component.scss index 4b2d51d1e9..6740b496b2 100644 --- a/ui-ngx/src/app/modules/home/pages/admin/general-settings.component.scss +++ b/ui-ngx/src/app/modules/home/pages/admin/general-settings.component.scss @@ -14,6 +14,26 @@ * limitations under the License. */ :host { + .settings-card { + .toggle-group { + display: block; + margin-bottom: 12px; + } + .hint { + display: block; + } + .fields-group { + .slide { + padding: 16px 0; + } + .fields-row { + display: flex; + flex-direction: row; + justify-content: space-between; + gap: 12px; + } + } + } } :host ::ng-deep { diff --git a/ui-ngx/src/app/modules/home/pages/admin/general-settings.component.ts b/ui-ngx/src/app/modules/home/pages/admin/general-settings.component.ts index 9aee40d431..0ccc3eb75d 100644 --- a/ui-ngx/src/app/modules/home/pages/admin/general-settings.component.ts +++ b/ui-ngx/src/app/modules/home/pages/admin/general-settings.component.ts @@ -14,13 +14,13 @@ /// limitations under the License. /// -import { Component, OnInit } from '@angular/core'; +import { Component } from '@angular/core'; import { Store } from '@ngrx/store'; import { AppState } from '@core/core.state'; import { PageComponent } from '@shared/components/page.component'; import { Router } from '@angular/router'; import { UntypedFormBuilder, UntypedFormGroup, Validators } from '@angular/forms'; -import { AdminSettings, GeneralSettings } from '@shared/models/settings.models'; +import { AdminSettings, DeviceConnectivitySettings, GeneralSettings } from '@shared/models/settings.models'; import { AdminService } from '@core/http/admin.service'; import { HasConfirmForm } from '@core/guards/confirm-on-exit.guard'; @@ -29,26 +29,27 @@ import { HasConfirmForm } from '@core/guards/confirm-on-exit.guard'; templateUrl: './general-settings.component.html', styleUrls: ['./general-settings.component.scss', './settings-card.scss'] }) -export class GeneralSettingsComponent extends PageComponent implements OnInit, HasConfirmForm { +export class GeneralSettingsComponent extends PageComponent implements HasConfirmForm { generalSettings: UntypedFormGroup; - adminSettings: AdminSettings; + private adminSettings: AdminSettings; + + deviceConnectivitySettingsForm: UntypedFormGroup; + private deviceConnectivitySettings: AdminSettings; + + protocol = 'http'; constructor(protected store: Store, private router: Router, private adminService: AdminService, public fb: UntypedFormBuilder) { super(store); - } - - ngOnInit() { this.buildGeneralServerSettingsForm(); - this.adminService.getAdminSettings('general').subscribe( - (adminSettings) => { - this.adminSettings = adminSettings; - this.generalSettings.reset(this.adminSettings.jsonValue); - } - ); + this.adminService.getAdminSettings('general') + .subscribe(adminSettings => this.processGeneralSettings(adminSettings)); + this.buildDeviceConnectivitySettingsForm(); + this.adminService.getAdminSettings('connectivity') + .subscribe(deviceConnectivitySettings => this.processDeviceConnectivitySettings(deviceConnectivitySettings)); } buildGeneralServerSettingsForm() { @@ -58,18 +59,73 @@ export class GeneralSettingsComponent extends PageComponent implements OnInit, H }); } + buildDeviceConnectivitySettingsForm() { + this.deviceConnectivitySettingsForm = this.fb.group({ + http: this.fb.group({ + enabled: [false, []], + host: ['', []], + port: [null, [Validators.min(1), Validators.max(65535), Validators.pattern('[0-9]*')]] + }), + https: this.fb.group({ + enabled: [false, []], + host: ['', []], + port: [null, [Validators.min(1), Validators.max(65535), Validators.pattern('[0-9]*')]] + }), + mqtt: this.fb.group({ + enabled: [false, []], + host: ['', []], + port: [null, [Validators.min(1), Validators.max(65535), Validators.pattern('[0-9]*')]] + }), + mqtts: this.fb.group({ + enabled: [false, []], + host: ['', []], + port: [null, [Validators.min(1), Validators.max(65535), Validators.pattern('[0-9]*')]] + }), + coap: this.fb.group({ + enabled: [false, []], + host: ['', []], + port: [null, [Validators.min(1), Validators.max(65535), Validators.pattern('[0-9]*')]] + }), + coaps: this.fb.group({ + enabled: [false, []], + host: ['', []], + port: [null, [Validators.min(1), Validators.max(65535), Validators.pattern('[0-9]*')]] + }), + }); + } + save(): void { this.adminSettings.jsonValue = {...this.adminSettings.jsonValue, ...this.generalSettings.value}; - this.adminService.saveAdminSettings(this.adminSettings).subscribe( - (adminSettings) => { - this.adminSettings = adminSettings; - this.generalSettings.reset(this.adminSettings.jsonValue); - } - ); + this.adminService.saveAdminSettings(this.adminSettings) + .subscribe(adminSettings => this.processGeneralSettings(adminSettings)); + } + + saveDeviceConnectivitySettings(): void { + this.deviceConnectivitySettings.jsonValue = {...this.deviceConnectivitySettings.jsonValue, ...this.deviceConnectivitySettingsForm.value}; + this.adminService.saveAdminSettings(this.deviceConnectivitySettings) + .subscribe(deviceConnectivitySettings => this.processDeviceConnectivitySettings(deviceConnectivitySettings)); + } + + discardGeneralSettings(): void { + this.generalSettings.reset(this.adminSettings.jsonValue); + } + + discardDeviceConnectivitySettings(): void { + this.deviceConnectivitySettingsForm.reset(this.deviceConnectivitySettings.jsonValue); + } + + private processGeneralSettings(generalSettings: AdminSettings): void { + this.adminSettings = generalSettings; + this.generalSettings.reset(this.adminSettings.jsonValue); + } + + private processDeviceConnectivitySettings(deviceConnectivitySettings: AdminSettings): void { + this.deviceConnectivitySettings = deviceConnectivitySettings; + this.deviceConnectivitySettingsForm.reset(this.deviceConnectivitySettings.jsonValue); } confirmForm(): UntypedFormGroup { - return this.generalSettings; + return this.generalSettings.dirty ? this.generalSettings : this.deviceConnectivitySettingsForm; } } diff --git a/ui-ngx/src/app/shared/models/settings.models.ts b/ui-ngx/src/app/shared/models/settings.models.ts index 14f601dbe4..3ac54cd28e 100644 --- a/ui-ngx/src/app/shared/models/settings.models.ts +++ b/ui-ngx/src/app/shared/models/settings.models.ts @@ -87,6 +87,39 @@ export interface GeneralSettings { baseUrl: string; } +export interface DeviceConnectivitySettings { + http: { + enabled: boolean; + host: string; + port: number; + }, + https: { + enabled: boolean; + host: string; + port: number; + }, + mqtt: { + enabled: boolean; + host: string; + port: number; + }, + mqtts: { + enabled: boolean; + host: string; + port: number; + }, + coap: { + enabled: boolean; + host: string; + port: number; + }, + coaps: { + enabled: boolean; + host: string; + port: number; + } +} + export interface UserPasswordPolicy { minimumLength: number; minimumUppercaseLetters: number; diff --git a/ui-ngx/src/assets/locale/locale.constant-en_US.json b/ui-ngx/src/assets/locale/locale.constant-en_US.json index b4c0f07c85..eb797fbf58 100644 --- a/ui-ngx/src/assets/locale/locale.constant-en_US.json +++ b/ui-ngx/src/assets/locale/locale.constant-en_US.json @@ -105,6 +105,23 @@ "base-url-required": "Base URL is required.", "prohibit-different-url": "Prohibit to use hostname from the client request headers", "prohibit-different-url-hint": "This setting should be enabled for production environments. May cause security issues when disabled", + "device-connectivity": { + "device-connectivity": "Device connectivity", + "http-https": "HTTP/HTTPS", + "mqtt-mqtts": "MQTT/MQTTS", + "coap-coaps": "COAP/COAPS", + "http": "HTPP", + "https": "HTTPS", + "mqtt": "MQTT", + "mqtts": "MQTTS", + "coap": "COAP", + "coaps": "COAPS", + "hint": "If host or port fields are empty will be used default protocol value.", + "host": "Host", + "port": "Port", + "port-pattern": "Port must be a positive integer.", + "port-range": "Port should be in a range from 1 to 65535." + }, "mail-from": "Mail From", "mail-from-required": "Mail From is required.", "smtp-protocol": "SMTP protocol", From 673d28fe921d5fb1c111be8d90a05ea836ba9289 Mon Sep 17 00:00:00 2001 From: rusikv Date: Wed, 25 Oct 2023 16:28:25 +0300 Subject: [PATCH 6/8] UI: device connectivity settings template refactor --- .../admin/general-settings.component.html | 172 ++++-------------- .../admin/general-settings.component.scss | 22 +-- 2 files changed, 40 insertions(+), 154 deletions(-) diff --git a/ui-ngx/src/app/modules/home/pages/admin/general-settings.component.html b/ui-ngx/src/app/modules/home/pages/admin/general-settings.component.html index 9703f99581..e1bb63bcce 100644 --- a/ui-ngx/src/app/modules/home/pages/admin/general-settings.component.html +++ b/ui-ngx/src/app/modules/home/pages/admin/general-settings.component.html @@ -28,7 +28,7 @@
-
+
admin.base-url @@ -65,145 +65,49 @@
- + {{ "admin.device-connectivity.http-https" | translate }} {{ 'admin.device-connectivity.mqtt-mqtts' | translate }} {{ 'admin.device-connectivity.coap-coaps' | translate }} - {{ 'admin.device-connectivity.hint' | translate }} +
{{ 'admin.device-connectivity.hint' | translate }}
-
- - {{ 'admin.device-connectivity.http' | translate }} - -
- - admin.device-connectivity.host - - - - admin.device-connectivity.port - - - {{ 'admin.device-connectivity.port-pattern' | translate }} - - - {{ 'admin.device-connectivity.port-range' | translate }} - - -
-
-
- - {{ 'admin.device-connectivity.https' | translate }} - -
- - admin.device-connectivity.host - - - - admin.device-connectivity.port - - - {{ 'admin.device-connectivity.port-pattern' | translate }} - - - {{ 'admin.device-connectivity.port-range' | translate }} - - -
-
-
- - {{ 'admin.device-connectivity.mqtt' | translate }} - -
- - admin.device-connectivity.host - - - - admin.device-connectivity.port - - - {{ 'admin.device-connectivity.port-pattern' | translate }} - - - {{ 'admin.device-connectivity.port-range' | translate }} - - -
-
-
- - {{ 'admin.device-connectivity.mqtts' | translate }} - -
- - admin.device-connectivity.host - - - - admin.device-connectivity.port - - - {{ 'admin.device-connectivity.port-pattern' | translate }} - - - {{ 'admin.device-connectivity.port-range' | translate }} - - -
-
-
- - {{ 'admin.device-connectivity.coap' | translate }} - -
- - admin.device-connectivity.host - - - - admin.device-connectivity.port - - - {{ 'admin.device-connectivity.port-pattern' | translate }} - - - {{ 'admin.device-connectivity.port-range' | translate }} - - -
-
-
- - {{ 'admin.device-connectivity.coaps' | translate }} - -
- - admin.device-connectivity.host - - - - admin.device-connectivity.port - - - {{ 'admin.device-connectivity.port-pattern' | translate }} - - - {{ 'admin.device-connectivity.port-range' | translate }} - - + + + + + + + + + + + + + +
+ + {{ 'admin.device-connectivity.' + protocol | translate }} + +
+ + admin.device-connectivity.host + + + + admin.device-connectivity.port + + + {{ 'admin.device-connectivity.port-pattern' | translate }} + + + {{ 'admin.device-connectivity.port-range' | translate }} + + +
-
+
+
- -
- - -
- + +
diff --git a/ui-ngx/src/app/modules/home/pages/admin/general-settings.component.scss b/ui-ngx/src/app/modules/home/pages/admin/general-settings.component.scss index f557735eb6..80dcf76da8 100644 --- a/ui-ngx/src/app/modules/home/pages/admin/general-settings.component.scss +++ b/ui-ngx/src/app/modules/home/pages/admin/general-settings.component.scss @@ -13,13 +13,24 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +@import "../../../../../scss/constants"; + :host { .settings-card { .toggle-group { - display: block; + max-width: 670px; + width: 100%; + margin: 0 auto; + + .tb-form-hint { + text-align: center; + } } - .margin-bottom { - margin-bottom: 12px; + + @media #{$mat-xs} { + .tb-form-row { + gap: 0; + } } } } diff --git a/ui-ngx/src/app/modules/home/pages/admin/general-settings.component.ts b/ui-ngx/src/app/modules/home/pages/admin/general-settings.component.ts index d0ec896374..f96e34f449 100644 --- a/ui-ngx/src/app/modules/home/pages/admin/general-settings.component.ts +++ b/ui-ngx/src/app/modules/home/pages/admin/general-settings.component.ts @@ -14,12 +14,11 @@ /// limitations under the License. /// -import { Component } from '@angular/core'; +import { Component, OnDestroy } from '@angular/core'; import { Store } from '@ngrx/store'; import { AppState } from '@core/core.state'; import { PageComponent } from '@shared/components/page.component'; -import { Router } from '@angular/router'; -import { UntypedFormBuilder, UntypedFormGroup, Validators } from '@angular/forms'; +import { FormBuilder, FormGroup, Validators } from '@angular/forms'; import { AdminSettings, DeviceConnectivityProtocol, @@ -28,26 +27,29 @@ import { } from '@shared/models/settings.models'; import { AdminService } from '@core/http/admin.service'; import { HasConfirmForm } from '@core/guards/confirm-on-exit.guard'; +import { Subject } from 'rxjs'; +import { takeUntil } from 'rxjs/operators'; @Component({ selector: 'tb-general-settings', templateUrl: './general-settings.component.html', styleUrls: ['./general-settings.component.scss', './settings-card.scss'] }) -export class GeneralSettingsComponent extends PageComponent implements HasConfirmForm { +export class GeneralSettingsComponent extends PageComponent implements HasConfirmForm, OnDestroy { - generalSettings: UntypedFormGroup; - private adminSettings: AdminSettings; + generalSettings: FormGroup; + deviceConnectivitySettingsForm: FormGroup; + + protocol: DeviceConnectivityProtocol = 'http'; - deviceConnectivitySettingsForm: UntypedFormGroup; + private adminSettings: AdminSettings; private deviceConnectivitySettings: AdminSettings; - protocol: DeviceConnectivityProtocol = 'http'; + private readonly destroy$ = new Subject(); constructor(protected store: Store, - private router: Router, private adminService: AdminService, - public fb: UntypedFormBuilder) { + public fb: FormBuilder) { super(store); this.buildGeneralServerSettingsForm(); this.adminService.getAdminSettings('general') @@ -57,46 +59,48 @@ export class GeneralSettingsComponent extends PageComponent implements HasConfir .subscribe(deviceConnectivitySettings => this.processDeviceConnectivitySettings(deviceConnectivitySettings)); } - buildGeneralServerSettingsForm() { + ngOnDestroy() { + super.ngOnDestroy(); + this.destroy$.next(); + this.destroy$.complete(); + } + + private buildGeneralServerSettingsForm() { this.generalSettings = this.fb.group({ baseUrl: ['', [Validators.required]], prohibitDifferentUrl: ['',[]] }); } - buildDeviceConnectivitySettingsForm() { + private buildDeviceConnectivitySettingsForm() { this.deviceConnectivitySettingsForm = this.fb.group({ - http: this.fb.group({ - enabled: [false, []], - host: ['', []], - port: [null, [Validators.min(1), Validators.max(65535), Validators.pattern('[0-9]*')]] - }), - https: this.fb.group({ - enabled: [false, []], - host: ['', []], - port: [null, [Validators.min(1), Validators.max(65535), Validators.pattern('[0-9]*')]] - }), - mqtt: this.fb.group({ - enabled: [false, []], - host: ['', []], - port: [null, [Validators.min(1), Validators.max(65535), Validators.pattern('[0-9]*')]] - }), - mqtts: this.fb.group({ - enabled: [false, []], - host: ['', []], - port: [null, [Validators.min(1), Validators.max(65535), Validators.pattern('[0-9]*')]] - }), - coap: this.fb.group({ - enabled: [false, []], - host: ['', []], - port: [null, [Validators.min(1), Validators.max(65535), Validators.pattern('[0-9]*')]] - }), - coaps: this.fb.group({ - enabled: [false, []], - host: ['', []], - port: [null, [Validators.min(1), Validators.max(65535), Validators.pattern('[0-9]*')]] - }), + http: this.buildDeviceConnectivityInfoForm(), + https: this.buildDeviceConnectivityInfoForm(), + mqtt: this.buildDeviceConnectivityInfoForm(), + mqtts: this.buildDeviceConnectivityInfoForm(), + coap: this.buildDeviceConnectivityInfoForm(), + coaps: this.buildDeviceConnectivityInfoForm() + }); + } + + private buildDeviceConnectivityInfoForm(): FormGroup { + const formGroup = this.fb.group({ + enabled: [false, []], + host: [{value: '', disabled: true}], + port: [{value: null, disabled: true}, [Validators.min(1), Validators.max(65535), Validators.pattern('[0-9]*')]] + }); + formGroup.get('enabled').valueChanges.pipe( + takeUntil(this.destroy$) + ).subscribe(value => { + if (value) { + formGroup.get('host').enable({emitEvent: false}); + formGroup.get('port').enable({emitEvent: false}); + } else { + formGroup.get('host').disable({emitEvent: false}); + formGroup.get('port').disable({emitEvent: false}); + } }); + return formGroup; } save(): void { @@ -106,7 +110,10 @@ export class GeneralSettingsComponent extends PageComponent implements HasConfir } saveDeviceConnectivitySettings(): void { - this.deviceConnectivitySettings.jsonValue = {...this.deviceConnectivitySettings.jsonValue, ...this.deviceConnectivitySettingsForm.value}; + this.deviceConnectivitySettings.jsonValue = { + ...this.deviceConnectivitySettings.jsonValue, + ...this.deviceConnectivitySettingsForm.value + }; this.adminService.saveAdminSettings(this.deviceConnectivitySettings) .subscribe(deviceConnectivitySettings => this.processDeviceConnectivitySettings(deviceConnectivitySettings)); } @@ -129,7 +136,7 @@ export class GeneralSettingsComponent extends PageComponent implements HasConfir this.deviceConnectivitySettingsForm.reset(this.deviceConnectivitySettings.jsonValue); } - confirmForm(): UntypedFormGroup { + confirmForm(): FormGroup { return this.generalSettings.dirty ? this.generalSettings : this.deviceConnectivitySettingsForm; } diff --git a/ui-ngx/src/assets/locale/locale.constant-en_US.json b/ui-ngx/src/assets/locale/locale.constant-en_US.json index eb797fbf58..1e80914f5f 100644 --- a/ui-ngx/src/assets/locale/locale.constant-en_US.json +++ b/ui-ngx/src/assets/locale/locale.constant-en_US.json @@ -107,16 +107,16 @@ "prohibit-different-url-hint": "This setting should be enabled for production environments. May cause security issues when disabled", "device-connectivity": { "device-connectivity": "Device connectivity", - "http-https": "HTTP/HTTPS", - "mqtt-mqtts": "MQTT/MQTTS", - "coap-coaps": "COAP/COAPS", - "http": "HTPP", - "https": "HTTPS", + "http-s": "HTTP(s)", + "mqtt-s": "MQTT(s)", + "coap-s": "COAP(s)", + "http": "HTTP", + "https": "HTTPs", "mqtt": "MQTT", - "mqtts": "MQTTS", + "mqtts": "MQTTs", "coap": "COAP", - "coaps": "COAPS", - "hint": "If host or port fields are empty will be used default protocol value.", + "coaps": "COAPs", + "hint": "If host or port fields are empty, default protocol value will be used.", "host": "Host", "port": "Port", "port-pattern": "Port must be a positive integer.",