Commit a9a864e81f2ae89f60cac743ab5e4add9afc09af

Authored by Andrew Shvayka
Committed by GitHub
2 parents 399b1dfa df8da758

Merge pull request #5065 from volodymyr-babak/mail-setting-fix

[3.3.0] Fixed fetch of admin settings
@@ -15,6 +15,7 @@ @@ -15,6 +15,7 @@
15 */ 15 */
16 package org.thingsboard.server.service.edge; 16 package org.thingsboard.server.service.edge;
17 17
  18 +import freemarker.template.Configuration;
18 import lombok.Data; 19 import lombok.Data;
19 import org.springframework.beans.factory.annotation.Autowired; 20 import org.springframework.beans.factory.annotation.Autowired;
20 import org.springframework.context.annotation.Lazy; 21 import org.springframework.context.annotation.Lazy;
@@ -66,6 +67,9 @@ public class EdgeContextComponent { @@ -66,6 +67,9 @@ public class EdgeContextComponent {
66 private AdminSettingsService adminSettingsService; 67 private AdminSettingsService adminSettingsService;
67 68
68 @Autowired 69 @Autowired
  70 + private Configuration freemarkerConfig;
  71 +
  72 + @Autowired
69 private AssetService assetService; 73 private AssetService assetService;
70 74
71 @Autowired 75 @Autowired
@@ -50,7 +50,7 @@ public class EdgeSyncCursor { @@ -50,7 +50,7 @@ public class EdgeSyncCursor {
50 fetchers.add(new CustomerEdgeEventFetcher()); 50 fetchers.add(new CustomerEdgeEventFetcher());
51 fetchers.add(new CustomerUsersEdgeEventFetcher(ctx.getUserService(), edge.getCustomerId())); 51 fetchers.add(new CustomerUsersEdgeEventFetcher(ctx.getUserService(), edge.getCustomerId()));
52 } 52 }
53 - fetchers.add(new AdminSettingsEdgeEventFetcher(ctx.getAdminSettingsService())); 53 + fetchers.add(new AdminSettingsEdgeEventFetcher(ctx.getAdminSettingsService(), ctx.getFreemarkerConfig()));
54 fetchers.add(new AssetsEdgeEventFetcher(ctx.getAssetService())); 54 fetchers.add(new AssetsEdgeEventFetcher(ctx.getAssetService()));
55 fetchers.add(new DashboardsEdgeEventFetcher(ctx.getDashboardService())); 55 fetchers.add(new DashboardsEdgeEventFetcher(ctx.getDashboardService()));
56 } 56 }
@@ -19,12 +19,12 @@ import com.datastax.oss.driver.api.core.uuid.Uuids; @@ -19,12 +19,12 @@ import com.datastax.oss.driver.api.core.uuid.Uuids;
19 import com.fasterxml.jackson.databind.JsonNode; 19 import com.fasterxml.jackson.databind.JsonNode;
20 import com.fasterxml.jackson.databind.ObjectMapper; 20 import com.fasterxml.jackson.databind.ObjectMapper;
21 import com.fasterxml.jackson.databind.node.ObjectNode; 21 import com.fasterxml.jackson.databind.node.ObjectNode;
  22 +import freemarker.template.Configuration;
  23 +import freemarker.template.Template;
22 import lombok.AllArgsConstructor; 24 import lombok.AllArgsConstructor;
23 import lombok.extern.slf4j.Slf4j; 25 import lombok.extern.slf4j.Slf4j;
24 -import org.apache.commons.io.FileUtils;  
25 import org.apache.commons.lang3.StringUtils; 26 import org.apache.commons.lang3.StringUtils;
26 import org.apache.commons.lang3.text.WordUtils; 27 import org.apache.commons.lang3.text.WordUtils;
27 -import org.springframework.core.io.DefaultResourceLoader;  
28 import org.thingsboard.server.common.data.AdminSettings; 28 import org.thingsboard.server.common.data.AdminSettings;
29 import org.thingsboard.server.common.data.edge.Edge; 29 import org.thingsboard.server.common.data.edge.Edge;
30 import org.thingsboard.server.common.data.edge.EdgeEvent; 30 import org.thingsboard.server.common.data.edge.EdgeEvent;
@@ -37,9 +37,8 @@ import org.thingsboard.server.common.data.page.PageLink; @@ -37,9 +37,8 @@ import org.thingsboard.server.common.data.page.PageLink;
37 import org.thingsboard.server.dao.settings.AdminSettingsService; 37 import org.thingsboard.server.dao.settings.AdminSettingsService;
38 import org.thingsboard.server.service.edge.rpc.EdgeEventUtils; 38 import org.thingsboard.server.service.edge.rpc.EdgeEventUtils;
39 39
40 -import java.io.File;  
41 -import java.nio.charset.StandardCharsets;  
42 import java.util.ArrayList; 40 import java.util.ArrayList;
  41 +import java.util.Arrays;
43 import java.util.HashMap; 42 import java.util.HashMap;
44 import java.util.List; 43 import java.util.List;
45 import java.util.Map; 44 import java.util.Map;
@@ -53,6 +52,23 @@ public class AdminSettingsEdgeEventFetcher implements EdgeEventFetcher { @@ -53,6 +52,23 @@ public class AdminSettingsEdgeEventFetcher implements EdgeEventFetcher {
53 private static final ObjectMapper mapper = new ObjectMapper(); 52 private static final ObjectMapper mapper = new ObjectMapper();
54 53
55 private final AdminSettingsService adminSettingsService; 54 private final AdminSettingsService adminSettingsService;
  55 + private final Configuration freemarkerConfig;
  56 +
  57 + private static Pattern startPattern = Pattern.compile("<div class=\"content\".*?>");
  58 + private static Pattern endPattern = Pattern.compile("<div class=\"footer\".*?>");
  59 +
  60 + private static List<String> templatesNames = Arrays.asList(
  61 + "account.activated.ftl",
  62 + "account.lockout.ftl",
  63 + "activation.ftl",
  64 + "password.was.reset.ftl",
  65 + "reset.password.ftl",
  66 + "test.ftl");
  67 +
  68 + // TODO: fix format of next templates
  69 + // "state.disabled.ftl",
  70 + // "state.enabled.ftl",
  71 + // "state.warning.ftl",
56 72
57 @Override 73 @Override
58 public PageLink getPageLink(int pageSize) { 74 public PageLink getPageLink(int pageSize) {
@@ -85,23 +101,16 @@ public class AdminSettingsEdgeEventFetcher implements EdgeEventFetcher { @@ -85,23 +101,16 @@ public class AdminSettingsEdgeEventFetcher implements EdgeEventFetcher {
85 101
86 private AdminSettings loadMailTemplates() throws Exception { 102 private AdminSettings loadMailTemplates() throws Exception {
87 Map<String, Object> mailTemplates = new HashMap<>(); 103 Map<String, Object> mailTemplates = new HashMap<>();
88 - Pattern startPattern = Pattern.compile("<div class=\"content\".*?>");  
89 - Pattern endPattern = Pattern.compile("<div class=\"footer\".*?>");  
90 - File[] files = new DefaultResourceLoader().getResource("classpath:/templates/").getFile().listFiles();  
91 - for (File file : files) {  
92 - Map<String, String> mailTemplate = new HashMap<>();  
93 - String name = validateName(file.getName());  
94 - String stringTemplate = FileUtils.readFileToString(file, StandardCharsets.UTF_8);  
95 - Matcher start = startPattern.matcher(stringTemplate);  
96 - Matcher end = endPattern.matcher(stringTemplate);  
97 - if (start.find() && end.find()) {  
98 - String body = StringUtils.substringBetween(stringTemplate, start.group(), end.group()).replaceAll("\t", "");  
99 - String subject = StringUtils.substringBetween(body, "<h2>", "</h2>");  
100 - mailTemplate.put("subject", subject);  
101 - mailTemplate.put("body", body);  
102 - mailTemplates.put(name, mailTemplate);  
103 - } else {  
104 - log.error("Can't load mail template from file {}", file.getName()); 104 + for (String templatesName : templatesNames) {
  105 + Template template = freemarkerConfig.getTemplate(templatesName);
  106 + if (template != null) {
  107 + String name = validateName(template.getName());
  108 + Map<String, String> mailTemplate = getMailTemplateFromFile(template.getRootTreeNode().toString());
  109 + if (mailTemplate != null) {
  110 + mailTemplates.put(name, mailTemplate);
  111 + } else {
  112 + log.error("Can't load mail template from file {}", template.getName());
  113 + }
105 } 114 }
106 } 115 }
107 AdminSettings adminSettings = new AdminSettings(); 116 AdminSettings adminSettings = new AdminSettings();
@@ -111,9 +120,24 @@ public class AdminSettingsEdgeEventFetcher implements EdgeEventFetcher { @@ -111,9 +120,24 @@ public class AdminSettingsEdgeEventFetcher implements EdgeEventFetcher {
111 return adminSettings; 120 return adminSettings;
112 } 121 }
113 122
  123 + private Map<String, String> getMailTemplateFromFile(String stringTemplate) {
  124 + Map<String, String> mailTemplate = new HashMap<>();
  125 + Matcher start = startPattern.matcher(stringTemplate);
  126 + Matcher end = endPattern.matcher(stringTemplate);
  127 + if (start.find() && end.find()) {
  128 + String body = StringUtils.substringBetween(stringTemplate, start.group(), end.group()).replaceAll("\t", "");
  129 + String subject = StringUtils.substringBetween(body, "<h2>", "</h2>");
  130 + mailTemplate.put("subject", subject);
  131 + mailTemplate.put("body", body);
  132 + } else {
  133 + return null;
  134 + }
  135 + return mailTemplate;
  136 + }
  137 +
114 private String validateName(String name) throws Exception { 138 private String validateName(String name) throws Exception {
115 StringBuilder nameBuilder = new StringBuilder(); 139 StringBuilder nameBuilder = new StringBuilder();
116 - name = name.replace(".vm", ""); 140 + name = name.replace(".ftl", "");
117 String[] nameParts = name.split("\\."); 141 String[] nameParts = name.split("\\.");
118 if (nameParts.length >= 1) { 142 if (nameParts.length >= 1) {
119 nameBuilder.append(nameParts[0]); 143 nameBuilder.append(nameParts[0]);
@@ -37,6 +37,7 @@ import org.thingsboard.server.common.data.page.PageLink; @@ -37,6 +37,7 @@ import org.thingsboard.server.common.data.page.PageLink;
37 import org.thingsboard.server.common.data.security.Authority; 37 import org.thingsboard.server.common.data.security.Authority;
38 import org.thingsboard.server.dao.model.ModelConstants; 38 import org.thingsboard.server.dao.model.ModelConstants;
39 import org.thingsboard.server.edge.imitator.EdgeImitator; 39 import org.thingsboard.server.edge.imitator.EdgeImitator;
  40 +import org.thingsboard.server.gen.edge.v1.AdminSettingsUpdateMsg;
40 import org.thingsboard.server.gen.edge.v1.AssetUpdateMsg; 41 import org.thingsboard.server.gen.edge.v1.AssetUpdateMsg;
41 import org.thingsboard.server.gen.edge.v1.DeviceProfileUpdateMsg; 42 import org.thingsboard.server.gen.edge.v1.DeviceProfileUpdateMsg;
42 import org.thingsboard.server.gen.edge.v1.DeviceUpdateMsg; 43 import org.thingsboard.server.gen.edge.v1.DeviceUpdateMsg;
@@ -672,26 +673,26 @@ public abstract class BaseEdgeControllerTest extends AbstractControllerTest { @@ -672,26 +673,26 @@ public abstract class BaseEdgeControllerTest extends AbstractControllerTest {
672 EdgeImitator edgeImitator = new EdgeImitator("localhost", 7070, edge.getRoutingKey(), edge.getSecret()); 673 EdgeImitator edgeImitator = new EdgeImitator("localhost", 7070, edge.getRoutingKey(), edge.getSecret());
673 edgeImitator.ignoreType(UserCredentialsUpdateMsg.class); 674 edgeImitator.ignoreType(UserCredentialsUpdateMsg.class);
674 675
675 - edgeImitator.expectMessageAmount(7); 676 + edgeImitator.expectMessageAmount(11);
676 edgeImitator.connect(); 677 edgeImitator.connect();
677 Assert.assertTrue(edgeImitator.waitForMessages()); 678 Assert.assertTrue(edgeImitator.waitForMessages());
678 679
679 - Assert.assertEquals(7, edgeImitator.getDownlinkMsgs().size());  
680 Assert.assertEquals(2, edgeImitator.findAllMessagesByType(RuleChainUpdateMsg.class).size()); // one msg during sync process, another from edge creation 680 Assert.assertEquals(2, edgeImitator.findAllMessagesByType(RuleChainUpdateMsg.class).size()); // one msg during sync process, another from edge creation
681 Assert.assertEquals(1, edgeImitator.findAllMessagesByType(DeviceProfileUpdateMsg.class).size()); // one msg during sync process for 'default' device profile 681 Assert.assertEquals(1, edgeImitator.findAllMessagesByType(DeviceProfileUpdateMsg.class).size()); // one msg during sync process for 'default' device profile
682 Assert.assertEquals(1, edgeImitator.findAllMessagesByType(DeviceUpdateMsg.class).size()); // one msg once device assigned to edge 682 Assert.assertEquals(1, edgeImitator.findAllMessagesByType(DeviceUpdateMsg.class).size()); // one msg once device assigned to edge
683 Assert.assertEquals(2, edgeImitator.findAllMessagesByType(AssetUpdateMsg.class).size()); // two msgs - one during sync process, and one more once asset assigned to edge 683 Assert.assertEquals(2, edgeImitator.findAllMessagesByType(AssetUpdateMsg.class).size()); // two msgs - one during sync process, and one more once asset assigned to edge
684 Assert.assertEquals(1, edgeImitator.findAllMessagesByType(UserUpdateMsg.class).size()); // one msg during sync process for tenant admin user 684 Assert.assertEquals(1, edgeImitator.findAllMessagesByType(UserUpdateMsg.class).size()); // one msg during sync process for tenant admin user
  685 + Assert.assertEquals(4, edgeImitator.findAllMessagesByType(AdminSettingsUpdateMsg.class).size());
685 686
686 - edgeImitator.expectMessageAmount(4); 687 + edgeImitator.expectMessageAmount(8);
687 doPost("/api/edge/sync/" + edge.getId()); 688 doPost("/api/edge/sync/" + edge.getId());
688 Assert.assertTrue(edgeImitator.waitForMessages()); 689 Assert.assertTrue(edgeImitator.waitForMessages());
689 690
690 - Assert.assertEquals(4, edgeImitator.getDownlinkMsgs().size());  
691 Assert.assertEquals(1, edgeImitator.findAllMessagesByType(RuleChainUpdateMsg.class).size()); 691 Assert.assertEquals(1, edgeImitator.findAllMessagesByType(RuleChainUpdateMsg.class).size());
692 Assert.assertEquals(1, edgeImitator.findAllMessagesByType(DeviceProfileUpdateMsg.class).size()); 692 Assert.assertEquals(1, edgeImitator.findAllMessagesByType(DeviceProfileUpdateMsg.class).size());
693 Assert.assertEquals(1, edgeImitator.findAllMessagesByType(AssetUpdateMsg.class).size()); 693 Assert.assertEquals(1, edgeImitator.findAllMessagesByType(AssetUpdateMsg.class).size());
694 Assert.assertEquals(1, edgeImitator.findAllMessagesByType(UserUpdateMsg.class).size()); 694 Assert.assertEquals(1, edgeImitator.findAllMessagesByType(UserUpdateMsg.class).size());
  695 + Assert.assertEquals(4, edgeImitator.findAllMessagesByType(AdminSettingsUpdateMsg.class).size());
695 696
696 edgeImitator.allowIgnoredTypes(); 697 edgeImitator.allowIgnoredTypes();
697 try { 698 try {
@@ -86,6 +86,7 @@ import org.thingsboard.server.common.transport.adaptor.JsonConverter; @@ -86,6 +86,7 @@ import org.thingsboard.server.common.transport.adaptor.JsonConverter;
86 import org.thingsboard.server.controller.AbstractControllerTest; 86 import org.thingsboard.server.controller.AbstractControllerTest;
87 import org.thingsboard.server.dao.edge.EdgeEventService; 87 import org.thingsboard.server.dao.edge.EdgeEventService;
88 import org.thingsboard.server.edge.imitator.EdgeImitator; 88 import org.thingsboard.server.edge.imitator.EdgeImitator;
  89 +import org.thingsboard.server.gen.edge.v1.AdminSettingsUpdateMsg;
89 import org.thingsboard.server.gen.edge.v1.AlarmUpdateMsg; 90 import org.thingsboard.server.gen.edge.v1.AlarmUpdateMsg;
90 import org.thingsboard.server.gen.edge.v1.AssetUpdateMsg; 91 import org.thingsboard.server.gen.edge.v1.AssetUpdateMsg;
91 import org.thingsboard.server.gen.edge.v1.AttributeDeleteMsg; 92 import org.thingsboard.server.gen.edge.v1.AttributeDeleteMsg;
@@ -172,7 +173,7 @@ abstract public class BaseEdgeTest extends AbstractControllerTest { @@ -172,7 +173,7 @@ abstract public class BaseEdgeTest extends AbstractControllerTest {
172 installation(); 173 installation();
173 174
174 edgeImitator = new EdgeImitator("localhost", 7070, edge.getRoutingKey(), edge.getSecret()); 175 edgeImitator = new EdgeImitator("localhost", 7070, edge.getRoutingKey(), edge.getSecret());
175 - edgeImitator.expectMessageAmount(9); 176 + edgeImitator.expectMessageAmount(13);
176 edgeImitator.connect(); 177 edgeImitator.connect();
177 178
178 testReceivedInitialData(); 179 testReceivedInitialData();
@@ -328,9 +329,44 @@ abstract public class BaseEdgeTest extends AbstractControllerTest { @@ -328,9 +329,44 @@ abstract public class BaseEdgeTest extends AbstractControllerTest {
328 329
329 testAutoGeneratedCodeByProtobuf(ruleChainUpdateMsg); 330 testAutoGeneratedCodeByProtobuf(ruleChainUpdateMsg);
330 331
  332 + validateAdminSettings();
  333 +
331 log.info("Received data checked"); 334 log.info("Received data checked");
332 } 335 }
333 336
  337 + private void validateAdminSettings() throws JsonProcessingException {
  338 + List<AdminSettingsUpdateMsg> adminSettingsUpdateMsgs = edgeImitator.findAllMessagesByType(AdminSettingsUpdateMsg.class);
  339 + Assert.assertEquals(4, adminSettingsUpdateMsgs.size());
  340 +
  341 + for (AdminSettingsUpdateMsg adminSettingsUpdateMsg : adminSettingsUpdateMsgs) {
  342 + if (adminSettingsUpdateMsg.getKey().equals("mail")) {
  343 + validateMailAdminSettings(adminSettingsUpdateMsg);
  344 + }
  345 + if (adminSettingsUpdateMsg.getKey().equals("mailTemplates")) {
  346 + validateMailTemplatesAdminSettings(adminSettingsUpdateMsg);
  347 + }
  348 + }
  349 + }
  350 +
  351 + private void validateMailAdminSettings(AdminSettingsUpdateMsg adminSettingsUpdateMsg) throws JsonProcessingException {
  352 + JsonNode jsonNode = mapper.readTree(adminSettingsUpdateMsg.getJsonValue());
  353 + Assert.assertNotNull(jsonNode.get("mailFrom"));
  354 + Assert.assertNotNull(jsonNode.get("smtpProtocol"));
  355 + Assert.assertNotNull(jsonNode.get("smtpHost"));
  356 + Assert.assertNotNull(jsonNode.get("smtpPort"));
  357 + Assert.assertNotNull(jsonNode.get("timeout"));
  358 + }
  359 +
  360 + private void validateMailTemplatesAdminSettings(AdminSettingsUpdateMsg adminSettingsUpdateMsg) throws JsonProcessingException {
  361 + JsonNode jsonNode = mapper.readTree(adminSettingsUpdateMsg.getJsonValue());
  362 + Assert.assertNotNull(jsonNode.get("accountActivated"));
  363 + Assert.assertNotNull(jsonNode.get("accountLockout"));
  364 + Assert.assertNotNull(jsonNode.get("activation"));
  365 + Assert.assertNotNull(jsonNode.get("passwordWasReset"));
  366 + Assert.assertNotNull(jsonNode.get("resetPassword"));
  367 + Assert.assertNotNull(jsonNode.get("test"));
  368 + }
  369 +
334 private void testDevices() throws Exception { 370 private void testDevices() throws Exception {
335 log.info("Testing devices"); 371 log.info("Testing devices");
336 372
@@ -26,6 +26,7 @@ import lombok.extern.slf4j.Slf4j; @@ -26,6 +26,7 @@ import lombok.extern.slf4j.Slf4j;
26 import org.checkerframework.checker.nullness.qual.Nullable; 26 import org.checkerframework.checker.nullness.qual.Nullable;
27 import org.thingsboard.edge.rpc.EdgeGrpcClient; 27 import org.thingsboard.edge.rpc.EdgeGrpcClient;
28 import org.thingsboard.edge.rpc.EdgeRpcClient; 28 import org.thingsboard.edge.rpc.EdgeRpcClient;
  29 +import org.thingsboard.server.gen.edge.v1.AdminSettingsUpdateMsg;
29 import org.thingsboard.server.gen.edge.v1.AlarmUpdateMsg; 30 import org.thingsboard.server.gen.edge.v1.AlarmUpdateMsg;
30 import org.thingsboard.server.gen.edge.v1.AssetUpdateMsg; 31 import org.thingsboard.server.gen.edge.v1.AssetUpdateMsg;
31 import org.thingsboard.server.gen.edge.v1.CustomerUpdateMsg; 32 import org.thingsboard.server.gen.edge.v1.CustomerUpdateMsg;
@@ -167,6 +168,11 @@ public class EdgeImitator { @@ -167,6 +168,11 @@ public class EdgeImitator {
167 168
168 private ListenableFuture<List<Void>> processDownlinkMsg(DownlinkMsg downlinkMsg) { 169 private ListenableFuture<List<Void>> processDownlinkMsg(DownlinkMsg downlinkMsg) {
169 List<ListenableFuture<Void>> result = new ArrayList<>(); 170 List<ListenableFuture<Void>> result = new ArrayList<>();
  171 + if (downlinkMsg.getAdminSettingsUpdateMsgCount() > 0) {
  172 + for (AdminSettingsUpdateMsg adminSettingsUpdateMsg : downlinkMsg.getAdminSettingsUpdateMsgList()) {
  173 + result.add(saveDownlinkMsg(adminSettingsUpdateMsg));
  174 + }
  175 + }
170 if (downlinkMsg.getDeviceUpdateMsgCount() > 0) { 176 if (downlinkMsg.getDeviceUpdateMsgCount() > 0) {
171 for (DeviceUpdateMsg deviceUpdateMsg : downlinkMsg.getDeviceUpdateMsgList()) { 177 for (DeviceUpdateMsg deviceUpdateMsg : downlinkMsg.getDeviceUpdateMsgList()) {
172 result.add(saveDownlinkMsg(deviceUpdateMsg)); 178 result.add(saveDownlinkMsg(deviceUpdateMsg));