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 15 */
16 16 package org.thingsboard.server.service.edge;
17 17
  18 +import freemarker.template.Configuration;
18 19 import lombok.Data;
19 20 import org.springframework.beans.factory.annotation.Autowired;
20 21 import org.springframework.context.annotation.Lazy;
... ... @@ -66,6 +67,9 @@ public class EdgeContextComponent {
66 67 private AdminSettingsService adminSettingsService;
67 68
68 69 @Autowired
  70 + private Configuration freemarkerConfig;
  71 +
  72 + @Autowired
69 73 private AssetService assetService;
70 74
71 75 @Autowired
... ...
... ... @@ -50,7 +50,7 @@ public class EdgeSyncCursor {
50 50 fetchers.add(new CustomerEdgeEventFetcher());
51 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 54 fetchers.add(new AssetsEdgeEventFetcher(ctx.getAssetService()));
55 55 fetchers.add(new DashboardsEdgeEventFetcher(ctx.getDashboardService()));
56 56 }
... ...
... ... @@ -19,12 +19,12 @@ import com.datastax.oss.driver.api.core.uuid.Uuids;
19 19 import com.fasterxml.jackson.databind.JsonNode;
20 20 import com.fasterxml.jackson.databind.ObjectMapper;
21 21 import com.fasterxml.jackson.databind.node.ObjectNode;
  22 +import freemarker.template.Configuration;
  23 +import freemarker.template.Template;
22 24 import lombok.AllArgsConstructor;
23 25 import lombok.extern.slf4j.Slf4j;
24   -import org.apache.commons.io.FileUtils;
25 26 import org.apache.commons.lang3.StringUtils;
26 27 import org.apache.commons.lang3.text.WordUtils;
27   -import org.springframework.core.io.DefaultResourceLoader;
28 28 import org.thingsboard.server.common.data.AdminSettings;
29 29 import org.thingsboard.server.common.data.edge.Edge;
30 30 import org.thingsboard.server.common.data.edge.EdgeEvent;
... ... @@ -37,9 +37,8 @@ import org.thingsboard.server.common.data.page.PageLink;
37 37 import org.thingsboard.server.dao.settings.AdminSettingsService;
38 38 import org.thingsboard.server.service.edge.rpc.EdgeEventUtils;
39 39
40   -import java.io.File;
41   -import java.nio.charset.StandardCharsets;
42 40 import java.util.ArrayList;
  41 +import java.util.Arrays;
43 42 import java.util.HashMap;
44 43 import java.util.List;
45 44 import java.util.Map;
... ... @@ -53,6 +52,23 @@ public class AdminSettingsEdgeEventFetcher implements EdgeEventFetcher {
53 52 private static final ObjectMapper mapper = new ObjectMapper();
54 53
55 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 73 @Override
58 74 public PageLink getPageLink(int pageSize) {
... ... @@ -85,23 +101,16 @@ public class AdminSettingsEdgeEventFetcher implements EdgeEventFetcher {
85 101
86 102 private AdminSettings loadMailTemplates() throws Exception {
87 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 116 AdminSettings adminSettings = new AdminSettings();
... ... @@ -111,9 +120,24 @@ public class AdminSettingsEdgeEventFetcher implements EdgeEventFetcher {
111 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 138 private String validateName(String name) throws Exception {
115 139 StringBuilder nameBuilder = new StringBuilder();
116   - name = name.replace(".vm", "");
  140 + name = name.replace(".ftl", "");
117 141 String[] nameParts = name.split("\\.");
118 142 if (nameParts.length >= 1) {
119 143 nameBuilder.append(nameParts[0]);
... ...
... ... @@ -37,6 +37,7 @@ import org.thingsboard.server.common.data.page.PageLink;
37 37 import org.thingsboard.server.common.data.security.Authority;
38 38 import org.thingsboard.server.dao.model.ModelConstants;
39 39 import org.thingsboard.server.edge.imitator.EdgeImitator;
  40 +import org.thingsboard.server.gen.edge.v1.AdminSettingsUpdateMsg;
40 41 import org.thingsboard.server.gen.edge.v1.AssetUpdateMsg;
41 42 import org.thingsboard.server.gen.edge.v1.DeviceProfileUpdateMsg;
42 43 import org.thingsboard.server.gen.edge.v1.DeviceUpdateMsg;
... ... @@ -672,26 +673,26 @@ public abstract class BaseEdgeControllerTest extends AbstractControllerTest {
672 673 EdgeImitator edgeImitator = new EdgeImitator("localhost", 7070, edge.getRoutingKey(), edge.getSecret());
673 674 edgeImitator.ignoreType(UserCredentialsUpdateMsg.class);
674 675
675   - edgeImitator.expectMessageAmount(7);
  676 + edgeImitator.expectMessageAmount(11);
676 677 edgeImitator.connect();
677 678 Assert.assertTrue(edgeImitator.waitForMessages());
678 679
679   - Assert.assertEquals(7, edgeImitator.getDownlinkMsgs().size());
680 680 Assert.assertEquals(2, edgeImitator.findAllMessagesByType(RuleChainUpdateMsg.class).size()); // one msg during sync process, another from edge creation
681 681 Assert.assertEquals(1, edgeImitator.findAllMessagesByType(DeviceProfileUpdateMsg.class).size()); // one msg during sync process for 'default' device profile
682 682 Assert.assertEquals(1, edgeImitator.findAllMessagesByType(DeviceUpdateMsg.class).size()); // one msg once device assigned to edge
683 683 Assert.assertEquals(2, edgeImitator.findAllMessagesByType(AssetUpdateMsg.class).size()); // two msgs - one during sync process, and one more once asset assigned to edge
684 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 688 doPost("/api/edge/sync/" + edge.getId());
688 689 Assert.assertTrue(edgeImitator.waitForMessages());
689 690
690   - Assert.assertEquals(4, edgeImitator.getDownlinkMsgs().size());
691 691 Assert.assertEquals(1, edgeImitator.findAllMessagesByType(RuleChainUpdateMsg.class).size());
692 692 Assert.assertEquals(1, edgeImitator.findAllMessagesByType(DeviceProfileUpdateMsg.class).size());
693 693 Assert.assertEquals(1, edgeImitator.findAllMessagesByType(AssetUpdateMsg.class).size());
694 694 Assert.assertEquals(1, edgeImitator.findAllMessagesByType(UserUpdateMsg.class).size());
  695 + Assert.assertEquals(4, edgeImitator.findAllMessagesByType(AdminSettingsUpdateMsg.class).size());
695 696
696 697 edgeImitator.allowIgnoredTypes();
697 698 try {
... ...
... ... @@ -86,6 +86,7 @@ import org.thingsboard.server.common.transport.adaptor.JsonConverter;
86 86 import org.thingsboard.server.controller.AbstractControllerTest;
87 87 import org.thingsboard.server.dao.edge.EdgeEventService;
88 88 import org.thingsboard.server.edge.imitator.EdgeImitator;
  89 +import org.thingsboard.server.gen.edge.v1.AdminSettingsUpdateMsg;
89 90 import org.thingsboard.server.gen.edge.v1.AlarmUpdateMsg;
90 91 import org.thingsboard.server.gen.edge.v1.AssetUpdateMsg;
91 92 import org.thingsboard.server.gen.edge.v1.AttributeDeleteMsg;
... ... @@ -172,7 +173,7 @@ abstract public class BaseEdgeTest extends AbstractControllerTest {
172 173 installation();
173 174
174 175 edgeImitator = new EdgeImitator("localhost", 7070, edge.getRoutingKey(), edge.getSecret());
175   - edgeImitator.expectMessageAmount(9);
  176 + edgeImitator.expectMessageAmount(13);
176 177 edgeImitator.connect();
177 178
178 179 testReceivedInitialData();
... ... @@ -328,9 +329,44 @@ abstract public class BaseEdgeTest extends AbstractControllerTest {
328 329
329 330 testAutoGeneratedCodeByProtobuf(ruleChainUpdateMsg);
330 331
  332 + validateAdminSettings();
  333 +
331 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 370 private void testDevices() throws Exception {
335 371 log.info("Testing devices");
336 372
... ...
... ... @@ -26,6 +26,7 @@ import lombok.extern.slf4j.Slf4j;
26 26 import org.checkerframework.checker.nullness.qual.Nullable;
27 27 import org.thingsboard.edge.rpc.EdgeGrpcClient;
28 28 import org.thingsboard.edge.rpc.EdgeRpcClient;
  29 +import org.thingsboard.server.gen.edge.v1.AdminSettingsUpdateMsg;
29 30 import org.thingsboard.server.gen.edge.v1.AlarmUpdateMsg;
30 31 import org.thingsboard.server.gen.edge.v1.AssetUpdateMsg;
31 32 import org.thingsboard.server.gen.edge.v1.CustomerUpdateMsg;
... ... @@ -167,6 +168,11 @@ public class EdgeImitator {
167 168
168 169 private ListenableFuture<List<Void>> processDownlinkMsg(DownlinkMsg downlinkMsg) {
169 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 176 if (downlinkMsg.getDeviceUpdateMsgCount() > 0) {
171 177 for (DeviceUpdateMsg deviceUpdateMsg : downlinkMsg.getDeviceUpdateMsgList()) {
172 178 result.add(saveDownlinkMsg(deviceUpdateMsg));
... ...