Commit 8808d66c9d19a5d3f073019c1f7cc07780c1274b
Merge branch 'master' of https://github.com/ArtemHalushko/thingsboard into trip-select
Showing
60 changed files
with
987 additions
and
744 deletions
Too many changes to show.
To preserve performance only 60 of 724 files are displayed.
... | ... | @@ -153,12 +153,8 @@ |
153 | 153 | <artifactId>jjwt</artifactId> |
154 | 154 | </dependency> |
155 | 155 | <dependency> |
156 | - <groupId>org.apache.velocity</groupId> | |
157 | - <artifactId>velocity</artifactId> | |
158 | - </dependency> | |
159 | - <dependency> | |
160 | - <groupId>org.apache.velocity</groupId> | |
161 | - <artifactId>velocity-tools</artifactId> | |
156 | + <groupId>org.freemarker</groupId> | |
157 | + <artifactId>freemarker</artifactId> | |
162 | 158 | </dependency> |
163 | 159 | <dependency> |
164 | 160 | <groupId>commons-io</groupId> | ... | ... |
... | ... | @@ -130,7 +130,7 @@ |
130 | 130 | "controllerScript": " self.onInit = function() {\n var $scope = self.ctx.$scope;\n $scope.self = self;\n }\n \n \n self.actionSources = function () {\n return {\n 'tooltipAction': {\n name: 'widget-action.tooltip-tag-action',\n multiple: false\n }\n }\n };\n \n self.getSettingsSchema = function() {\n return TbTripAnimationWidget.getSettingsSchema();\n}\n", |
131 | 131 | "settingsSchema": "", |
132 | 132 | "dataKeySettingsSchema": "{}", |
133 | - "defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"entityAliasId\":null,\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"latitude\",\"color\":\"#2196f3\",\"settings\":{\"showLines\":true,\"fillLines\":true,\"showPoints\":false},\"_hash\":0.8587686344902596,\"funcBody\":\"var gpsData = [\\n37.771210000, -122.510960000,\\n 37.771990000, -122.497070000,\\n 37.772730000, -122.480740000,\\n 37.773360000, -122.466870000,\\n 37.774270000, -122.458520000,\\n 37.771980000, -122.454110000,\\n 37.768250000, -122.453380000,\\n 37.765920000, -122.456810000,\\n 37.765930000, -122.467680000,\\n 37.765500000, -122.477180000,\\n 37.765300000, -122.481660000,\\n 37.764780000, -122.493350000,\\n 37.764120000, -122.508360000,\\n 37.766410000, -122.510260000,\\n 37.770010000, -122.510830000,\\n 37.770980000, -122.510930000\\n];\\n let value = gpsData.indexOf(prevValue); \\nreturn gpsData[(value == -1 ? 0 : value + 2)];\",\"units\":null,\"decimals\":null,\"usePostProcessing\":null,\"postFuncBody\":null},{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"longitude\",\"color\":\"#ffc107\",\"settings\":{\"showLines\":true,\"fillLines\":false,\"showPoints\":false},\"_hash\":0.12775350966079668,\"funcBody\":\"var gpsData = [\\n37.771210000, -122.510960000,\\n 37.771990000, -122.497070000,\\n 37.772730000, -122.480740000,\\n 37.773360000, -122.466870000,\\n 37.774270000, -122.458520000,\\n 37.771980000, -122.454110000,\\n 37.768250000, -122.453380000,\\n 37.765920000, -122.456810000,\\n 37.765930000, -122.467680000,\\n 37.765500000, -122.477180000,\\n 37.765300000, -122.481660000,\\n 37.764780000, -122.493350000,\\n 37.764120000, -122.508360000,\\n 37.766410000, -122.510260000,\\n 37.770010000, -122.510830000,\\n 37.770980000, -122.510930000\\n];\\n let value = gpsData.indexOf(prevValue); \\nreturn gpsData[(value == -1 ? 1 : value + 2)];\",\"units\":null,\"decimals\":null,\"usePostProcessing\":null,\"postFuncBody\":null}]}],\"timewindow\":{\"history\":{\"interval\":1000,\"timewindowMs\":60000},\"aggregation\":{\"type\":\"NONE\",\"limit\":500}},\"showTitle\":true,\"backgroundColor\":\"#fff\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"8px\",\"settings\":{\"mapProvider\":\"OpenStreetMap.Mapnik\",\"latKeyName\":\"latitude\",\"lngKeyName\":\"longitude\",\"showLabel\":true,\"label\":\"${entityName}\",\"showTooltip\":true,\"tooltipColor\":\"#fff\",\"tooltipFontColor\":\"#000\",\"tooltipOpacity\":1,\"tooltipPattern\":\"<b>${entityName}</b><br/><br/><b>Latitude:</b> ${latitude:7}<br/><b>Longitude:</b> ${longitude:7}<br/><b>End Time:</b> ${maxTime}<br/><b>Start Time:</b> ${minTime}\",\"strokeWeight\":2,\"strokeOpacity\":1,\"pointSize\":10,\"markerImageSize\":34,\"rotationAngle\":180,\"provider\":\"openstreet-map\",\"normalizationStep\":1000,\"polKeyName\":\"coordinates\",\"decoratorSymbol\":\"arrowHead\",\"decoratorSymbolSize\":10,\"decoratorCustomColor\":\"#000\",\"decoratorOffset\":\"20px\",\"endDecoratorOffset\":\"20px\",\"decoratorRepeat\":\"20px\",\"polygonTooltipPattern\":\"<b>${entityName}</b><br/><br/><b>TimeStamp:</b> ${ts:7}\",\"polygonOpacity\":0.5,\"polygonStrokeOpacity\":1,\"polygonStrokeWeight\":1,\"pointTooltipOnRightPanel\":true,\"autocloseTooltip\":true},\"title\":\"Trip Animation\",\"dropShadow\":true,\"enableFullscreen\":true,\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"mobileHeight\":null,\"widgetStyle\":{},\"useDashboardTimewindow\":false,\"showLegend\":false,\"actions\":{},\"legendConfig\":{\"position\":\"bottom\",\"showMin\":false,\"showMax\":false,\"showAvg\":false,\"showTotal\":false},\"displayTimewindow\":true}" | |
133 | + "defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"entityAliasId\":null,\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"latitude\",\"color\":\"#2196f3\",\"settings\":{\"showLines\":true,\"fillLines\":true,\"showPoints\":false},\"_hash\":0.8587686344902596,\"funcBody\":\"var gpsData = [\\n37.771210000, -122.510960000,\\n 37.771990000, -122.497070000,\\n 37.772730000, -122.480740000,\\n 37.773360000, -122.466870000,\\n 37.774270000, -122.458520000,\\n 37.771980000, -122.454110000,\\n 37.768250000, -122.453380000,\\n 37.765920000, -122.456810000,\\n 37.765930000, -122.467680000,\\n 37.765500000, -122.477180000,\\n 37.765300000, -122.481660000,\\n 37.764780000, -122.493350000,\\n 37.764120000, -122.508360000,\\n 37.766410000, -122.510260000,\\n 37.770010000, -122.510830000,\\n 37.770980000, -122.510930000\\n];\\n let value = gpsData.indexOf(prevValue); \\nreturn gpsData[(value == -1 ? 0 : (value + 2) % gpsData.length)];\",\"units\":null,\"decimals\":null,\"usePostProcessing\":null,\"postFuncBody\":null},{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"longitude\",\"color\":\"#ffc107\",\"settings\":{\"showLines\":true,\"fillLines\":false,\"showPoints\":false},\"_hash\":0.12775350966079668,\"funcBody\":\"var gpsData = [\\n37.771210000, -122.510960000,\\n 37.771990000, -122.497070000,\\n 37.772730000, -122.480740000,\\n 37.773360000, -122.466870000,\\n 37.774270000, -122.458520000,\\n 37.771980000, -122.454110000,\\n 37.768250000, -122.453380000,\\n 37.765920000, -122.456810000,\\n 37.765930000, -122.467680000,\\n 37.765500000, -122.477180000,\\n 37.765300000, -122.481660000,\\n 37.764780000, -122.493350000,\\n 37.764120000, -122.508360000,\\n 37.766410000, -122.510260000,\\n 37.770010000, -122.510830000,\\n 37.770980000, -122.510930000\\n];\\n let value = gpsData.indexOf(prevValue); \\nreturn gpsData[(value == -1 ? 1 : (value + 2) % gpsData.length)];\",\"units\":null,\"decimals\":null,\"usePostProcessing\":null,\"postFuncBody\":null}]}],\"timewindow\":{\"history\":{\"interval\":1000,\"timewindowMs\":60000},\"aggregation\":{\"type\":\"NONE\",\"limit\":500}},\"showTitle\":true,\"backgroundColor\":\"#fff\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"8px\",\"settings\":{\"mapProvider\":\"OpenStreetMap.Mapnik\",\"latKeyName\":\"latitude\",\"lngKeyName\":\"longitude\",\"showLabel\":true,\"label\":\"${entityName}\",\"showTooltip\":true,\"tooltipColor\":\"#fff\",\"tooltipFontColor\":\"#000\",\"tooltipOpacity\":1,\"tooltipPattern\":\"<b>${entityName}</b><br/><br/><b>Latitude:</b> ${latitude:7}<br/><b>Longitude:</b> ${longitude:7}<br/><b>End Time:</b> ${maxTime}<br/><b>Start Time:</b> ${minTime}\",\"strokeWeight\":2,\"strokeOpacity\":1,\"pointSize\":10,\"markerImageSize\":34,\"rotationAngle\":180,\"provider\":\"openstreet-map\",\"normalizationStep\":1000,\"polKeyName\":\"coordinates\",\"decoratorSymbol\":\"arrowHead\",\"decoratorSymbolSize\":10,\"decoratorCustomColor\":\"#000\",\"decoratorOffset\":\"20px\",\"endDecoratorOffset\":\"20px\",\"decoratorRepeat\":\"20px\",\"polygonTooltipPattern\":\"<b>${entityName}</b><br/><br/><b>TimeStamp:</b> ${ts:7}\",\"polygonOpacity\":0.5,\"polygonStrokeOpacity\":1,\"polygonStrokeWeight\":1,\"pointTooltipOnRightPanel\":true,\"autocloseTooltip\":true},\"title\":\"Trip Animation\",\"dropShadow\":true,\"enableFullscreen\":true,\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"mobileHeight\":null,\"widgetStyle\":{},\"useDashboardTimewindow\":false,\"showLegend\":false,\"actions\":{},\"legendConfig\":{\"position\":\"bottom\",\"showMin\":false,\"showMax\":false,\"showAvg\":false,\"showTotal\":false},\"displayTimewindow\":true}" | |
134 | 134 | } |
135 | 135 | }, |
136 | 136 | { |
... | ... | @@ -150,4 +150,4 @@ |
150 | 150 | } |
151 | 151 | } |
152 | 152 | ] |
153 | -} | |
\ No newline at end of file | ||
153 | +} | ... | ... |
... | ... | @@ -56,6 +56,7 @@ import org.thingsboard.server.dao.audit.AuditLogService; |
56 | 56 | import org.thingsboard.server.dao.cassandra.CassandraCluster; |
57 | 57 | import org.thingsboard.server.dao.customer.CustomerService; |
58 | 58 | import org.thingsboard.server.dao.dashboard.DashboardService; |
59 | +import org.thingsboard.server.dao.device.ClaimDevicesService; | |
59 | 60 | import org.thingsboard.server.dao.device.DeviceService; |
60 | 61 | import org.thingsboard.server.dao.entityview.EntityViewService; |
61 | 62 | import org.thingsboard.server.dao.event.EventService; |
... | ... | @@ -218,6 +219,10 @@ public class ActorSystemContext { |
218 | 219 | @Getter |
219 | 220 | private MailService mailService; |
220 | 221 | |
222 | + @Autowired | |
223 | + @Getter | |
224 | + private ClaimDevicesService claimDevicesService; | |
225 | + | |
221 | 226 | //TODO: separate context for TbCore and TbRuleEngine |
222 | 227 | @Autowired(required = false) |
223 | 228 | @Getter | ... | ... |
... | ... | @@ -39,6 +39,7 @@ import org.thingsboard.server.common.msg.TbMsgMetaData; |
39 | 39 | import org.thingsboard.server.common.msg.queue.TbCallback; |
40 | 40 | import org.thingsboard.server.common.msg.rpc.ToDeviceRpcRequest; |
41 | 41 | import org.thingsboard.server.common.msg.timeout.DeviceActorServerSideRpcTimeoutMsg; |
42 | +import org.thingsboard.server.gen.transport.TransportProtos; | |
42 | 43 | import org.thingsboard.server.gen.transport.TransportProtos.AttributeUpdateNotificationMsg; |
43 | 44 | import org.thingsboard.server.gen.transport.TransportProtos.DeviceSessionsCacheEntry; |
44 | 45 | import org.thingsboard.server.gen.transport.TransportProtos.GetAttributeRequestMsg; |
... | ... | @@ -232,9 +233,17 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor { |
232 | 233 | if (msg.hasSubscriptionInfo()) { |
233 | 234 | handleSessionActivity(context, msg.getSessionInfo(), msg.getSubscriptionInfo()); |
234 | 235 | } |
236 | + if (msg.hasClaimDevice()) { | |
237 | + handleClaimDeviceMsg(context, msg.getSessionInfo(), msg.getClaimDevice()); | |
238 | + } | |
235 | 239 | callback.onSuccess(); |
236 | 240 | } |
237 | 241 | |
242 | + private void handleClaimDeviceMsg(ActorContext context, SessionInfoProto sessionInfo, TransportProtos.ClaimDeviceMsg msg) { | |
243 | + DeviceId deviceId = new DeviceId(new UUID(msg.getDeviceIdMSB(), msg.getDeviceIdLSB())); | |
244 | + systemContext.getClaimDevicesService().registerClaimingInfo(tenantId, deviceId, msg.getSecretKey(), msg.getDurationMs()); | |
245 | + } | |
246 | + | |
238 | 247 | private void reportSessionOpen() { |
239 | 248 | systemContext.getDeviceStateService().onDeviceConnect(deviceId); |
240 | 249 | } | ... | ... |
... | ... | @@ -15,28 +15,11 @@ |
15 | 15 | */ |
16 | 16 | package org.thingsboard.server.config; |
17 | 17 | |
18 | -import lombok.extern.slf4j.Slf4j; | |
19 | -import org.apache.commons.collections.ExtendedProperties; | |
20 | -import org.apache.commons.logging.Log; | |
21 | -import org.apache.commons.logging.LogFactory; | |
22 | -import org.apache.velocity.app.VelocityEngine; | |
23 | -import org.apache.velocity.exception.ResourceNotFoundException; | |
24 | -import org.apache.velocity.runtime.RuntimeConstants; | |
25 | -import org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader; | |
26 | 18 | import org.springframework.context.MessageSource; |
27 | 19 | import org.springframework.context.annotation.Bean; |
28 | 20 | import org.springframework.context.annotation.Configuration; |
29 | 21 | import org.springframework.context.annotation.Primary; |
30 | 22 | import org.springframework.context.support.ResourceBundleMessageSource; |
31 | -import org.springframework.core.io.DefaultResourceLoader; | |
32 | -import org.springframework.core.io.Resource; | |
33 | -import org.springframework.core.io.ResourceLoader; | |
34 | -import org.springframework.util.StringUtils; | |
35 | - | |
36 | -import java.io.File; | |
37 | -import java.io.IOException; | |
38 | -import java.io.InputStream; | |
39 | -import java.util.Arrays; | |
40 | 23 | |
41 | 24 | @Configuration |
42 | 25 | public class ThingsboardMessageConfiguration { |
... | ... | @@ -49,114 +32,4 @@ public class ThingsboardMessageConfiguration { |
49 | 32 | messageSource.setDefaultEncoding("UTF-8"); |
50 | 33 | return messageSource; |
51 | 34 | } |
52 | - | |
53 | - private static final String DEFAULT_RESOURCE_LOADER_PATH = "classpath:/templates/"; | |
54 | - | |
55 | - private ResourceLoader resourceLoader = new DefaultResourceLoader(); | |
56 | - | |
57 | - @Bean | |
58 | - public VelocityEngine velocityEngine() { | |
59 | - VelocityEngine velocityEngine = new VelocityEngine(); | |
60 | - try { | |
61 | - Resource resource = resourceLoader.getResource(DEFAULT_RESOURCE_LOADER_PATH); | |
62 | - File file = resource.getFile(); | |
63 | - velocityEngine.setProperty(RuntimeConstants.RESOURCE_LOADER, "file"); | |
64 | - velocityEngine.setProperty(RuntimeConstants.FILE_RESOURCE_LOADER_CACHE, "true"); | |
65 | - velocityEngine.setProperty(RuntimeConstants.FILE_RESOURCE_LOADER_PATH, file.getAbsolutePath()); | |
66 | - } catch (IOException e) { | |
67 | - initSpringResourceLoader(velocityEngine, DEFAULT_RESOURCE_LOADER_PATH); | |
68 | - } | |
69 | - velocityEngine.init(); | |
70 | - return velocityEngine; | |
71 | - } | |
72 | - | |
73 | - private void initSpringResourceLoader(VelocityEngine velocityEngine, String resourceLoaderPath) { | |
74 | - velocityEngine.setProperty( | |
75 | - RuntimeConstants.RESOURCE_LOADER, SpringResourceLoader.NAME); | |
76 | - velocityEngine.setProperty( | |
77 | - SpringResourceLoader.SPRING_RESOURCE_LOADER_CLASS, SpringResourceLoader.class.getName()); | |
78 | - velocityEngine.setProperty( | |
79 | - SpringResourceLoader.SPRING_RESOURCE_LOADER_CACHE, "true"); | |
80 | - velocityEngine.setApplicationAttribute( | |
81 | - SpringResourceLoader.SPRING_RESOURCE_LOADER, resourceLoader); | |
82 | - velocityEngine.setApplicationAttribute( | |
83 | - SpringResourceLoader.SPRING_RESOURCE_LOADER_PATH, resourceLoaderPath); | |
84 | - } | |
85 | - | |
86 | - @Slf4j | |
87 | - public static class SpringResourceLoader extends org.apache.velocity.runtime.resource.loader.ResourceLoader { | |
88 | - | |
89 | - public static final String NAME = "spring"; | |
90 | - | |
91 | - public static final String SPRING_RESOURCE_LOADER_CLASS = "spring.resource.loader.class"; | |
92 | - | |
93 | - public static final String SPRING_RESOURCE_LOADER_CACHE = "spring.resource.loader.cache"; | |
94 | - | |
95 | - public static final String SPRING_RESOURCE_LOADER = "spring.resource.loader"; | |
96 | - | |
97 | - public static final String SPRING_RESOURCE_LOADER_PATH = "spring.resource.loader.path"; | |
98 | - | |
99 | - private org.springframework.core.io.ResourceLoader resourceLoader; | |
100 | - | |
101 | - private String[] resourceLoaderPaths; | |
102 | - | |
103 | - | |
104 | - @Override | |
105 | - public void init(ExtendedProperties configuration) { | |
106 | - this.resourceLoader = (org.springframework.core.io.ResourceLoader) | |
107 | - this.rsvc.getApplicationAttribute(SPRING_RESOURCE_LOADER); | |
108 | - String resourceLoaderPath = (String) this.rsvc.getApplicationAttribute(SPRING_RESOURCE_LOADER_PATH); | |
109 | - if (this.resourceLoader == null) { | |
110 | - throw new IllegalArgumentException( | |
111 | - "'resourceLoader' application attribute must be present for SpringResourceLoader"); | |
112 | - } | |
113 | - if (resourceLoaderPath == null) { | |
114 | - throw new IllegalArgumentException( | |
115 | - "'resourceLoaderPath' application attribute must be present for SpringResourceLoader"); | |
116 | - } | |
117 | - this.resourceLoaderPaths = StringUtils.commaDelimitedListToStringArray(resourceLoaderPath); | |
118 | - for (int i = 0; i < this.resourceLoaderPaths.length; i++) { | |
119 | - String path = this.resourceLoaderPaths[i]; | |
120 | - if (!path.endsWith("/")) { | |
121 | - this.resourceLoaderPaths[i] = path + "/"; | |
122 | - } | |
123 | - } | |
124 | - if (log.isInfoEnabled()) { | |
125 | - log.info("SpringResourceLoader for Velocity: using resource loader [" + this.resourceLoader + | |
126 | - "] and resource loader paths " + Arrays.asList(this.resourceLoaderPaths)); | |
127 | - } | |
128 | - } | |
129 | - | |
130 | - @Override | |
131 | - public InputStream getResourceStream(String source) throws ResourceNotFoundException { | |
132 | - if (log.isDebugEnabled()) { | |
133 | - log.debug("Looking for Velocity resource with name [" + source + "]"); | |
134 | - } | |
135 | - for (String resourceLoaderPath : this.resourceLoaderPaths) { | |
136 | - org.springframework.core.io.Resource resource = | |
137 | - this.resourceLoader.getResource(resourceLoaderPath + source); | |
138 | - try { | |
139 | - return resource.getInputStream(); | |
140 | - } | |
141 | - catch (IOException ex) { | |
142 | - if (log.isDebugEnabled()) { | |
143 | - log.debug("Could not find Velocity resource: " + resource); | |
144 | - } | |
145 | - } | |
146 | - } | |
147 | - throw new ResourceNotFoundException( | |
148 | - "Could not find resource [" + source + "] in Spring resource loader path"); | |
149 | - } | |
150 | - | |
151 | - @Override | |
152 | - public boolean isSourceModified(org.apache.velocity.runtime.resource.Resource resource) { | |
153 | - return false; | |
154 | - } | |
155 | - | |
156 | - @Override | |
157 | - public long getLastModified(org.apache.velocity.runtime.resource.Resource resource) { | |
158 | - return 0; | |
159 | - } | |
160 | - | |
161 | - } | |
162 | 35 | } | ... | ... |
... | ... | @@ -135,7 +135,7 @@ public class UserController extends BaseController { |
135 | 135 | HttpServletRequest request) throws ThingsboardException { |
136 | 136 | try { |
137 | 137 | |
138 | - if (getCurrentUser().getAuthority() == Authority.TENANT_ADMIN) { | |
138 | + if (Authority.TENANT_ADMIN.equals(getCurrentUser().getAuthority())) { | |
139 | 139 | user.setTenantId(getCurrentUser().getTenantId()); |
140 | 140 | } |
141 | 141 | ... | ... |
... | ... | @@ -60,7 +60,7 @@ public class WidgetTypeController extends BaseController { |
60 | 60 | @ResponseBody |
61 | 61 | public WidgetType saveWidgetType(@RequestBody WidgetType widgetType) throws ThingsboardException { |
62 | 62 | try { |
63 | - if (getCurrentUser().getAuthority() == Authority.SYS_ADMIN) { | |
63 | + if (Authority.SYS_ADMIN.equals(getCurrentUser().getAuthority())) { | |
64 | 64 | widgetType.setTenantId(TenantId.SYS_TENANT_ID); |
65 | 65 | } else { |
66 | 66 | widgetType.setTenantId(getCurrentUser().getTenantId()); | ... | ... |
... | ... | @@ -61,7 +61,7 @@ public class WidgetsBundleController extends BaseController { |
61 | 61 | @ResponseBody |
62 | 62 | public WidgetsBundle saveWidgetsBundle(@RequestBody WidgetsBundle widgetsBundle) throws ThingsboardException { |
63 | 63 | try { |
64 | - if (getCurrentUser().getAuthority() == Authority.SYS_ADMIN) { | |
64 | + if (Authority.SYS_ADMIN.equals(getCurrentUser().getAuthority())) { | |
65 | 65 | widgetsBundle.setTenantId(TenantId.SYS_TENANT_ID); |
66 | 66 | } else { |
67 | 67 | widgetsBundle.setTenantId(getCurrentUser().getTenantId()); |
... | ... | @@ -103,7 +103,7 @@ public class WidgetsBundleController extends BaseController { |
103 | 103 | @RequestParam(required = false) String sortOrder) throws ThingsboardException { |
104 | 104 | try { |
105 | 105 | PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder); |
106 | - if (getCurrentUser().getAuthority() == Authority.SYS_ADMIN) { | |
106 | + if (Authority.SYS_ADMIN.equals(getCurrentUser().getAuthority())) { | |
107 | 107 | return checkNotNull(widgetsBundleService.findSystemWidgetsBundlesByPageLink(getTenantId(), pageLink)); |
108 | 108 | } else { |
109 | 109 | TenantId tenantId = getCurrentUser().getTenantId(); |
... | ... | @@ -119,7 +119,7 @@ public class WidgetsBundleController extends BaseController { |
119 | 119 | @ResponseBody |
120 | 120 | public List<WidgetsBundle> getWidgetsBundles() throws ThingsboardException { |
121 | 121 | try { |
122 | - if (getCurrentUser().getAuthority() == Authority.SYS_ADMIN) { | |
122 | + if (Authority.SYS_ADMIN.equals(getCurrentUser().getAuthority())) { | |
123 | 123 | return checkNotNull(widgetsBundleService.findSystemWidgetsBundles(getTenantId())); |
124 | 124 | } else { |
125 | 125 | TenantId tenantId = getCurrentUser().getTenantId(); | ... | ... |
application/src/main/java/org/thingsboard/server/service/install/DefaultSystemDataLoaderService.java
... | ... | @@ -131,6 +131,7 @@ public class DefaultSystemDataLoaderService implements SystemDataLoaderService { |
131 | 131 | node.put("username", ""); |
132 | 132 | node.put("password", ""); |
133 | 133 | node.put("tlsVersion", "TLSv1.2");//NOSONAR, key used to identify password field (not password value itself) |
134 | + node.put("enableProxy", false); | |
134 | 135 | mailSettings.setJsonValue(node); |
135 | 136 | adminSettingsService.saveAdminSettings(TenantId.SYS_TENANT_ID, mailSettings); |
136 | 137 | } | ... | ... |
... | ... | @@ -16,18 +16,17 @@ |
16 | 16 | package org.thingsboard.server.service.mail; |
17 | 17 | |
18 | 18 | import com.fasterxml.jackson.databind.JsonNode; |
19 | +import freemarker.template.Configuration; | |
20 | +import freemarker.template.Template; | |
19 | 21 | import lombok.extern.slf4j.Slf4j; |
20 | 22 | import org.apache.commons.lang3.StringUtils; |
21 | -import org.apache.velocity.VelocityContext; | |
22 | -import org.apache.velocity.app.VelocityEngine; | |
23 | -import org.apache.velocity.exception.VelocityException; | |
24 | 23 | import org.springframework.beans.factory.annotation.Autowired; |
25 | -import org.springframework.beans.factory.annotation.Qualifier; | |
26 | 24 | import org.springframework.context.MessageSource; |
27 | 25 | import org.springframework.core.NestedRuntimeException; |
28 | 26 | import org.springframework.mail.javamail.JavaMailSenderImpl; |
29 | 27 | import org.springframework.mail.javamail.MimeMessageHelper; |
30 | 28 | import org.springframework.stereotype.Service; |
29 | +import org.springframework.ui.freemarker.FreeMarkerTemplateUtils; | |
31 | 30 | import org.thingsboard.rule.engine.api.MailService; |
32 | 31 | import org.thingsboard.server.common.data.AdminSettings; |
33 | 32 | import org.thingsboard.server.common.data.exception.ThingsboardErrorCode; |
... | ... | @@ -40,8 +39,6 @@ import org.thingsboard.server.dao.settings.AdminSettingsService; |
40 | 39 | import javax.annotation.PostConstruct; |
41 | 40 | import javax.mail.MessagingException; |
42 | 41 | import javax.mail.internet.MimeMessage; |
43 | -import java.io.StringWriter; | |
44 | -import java.io.Writer; | |
45 | 42 | import java.util.HashMap; |
46 | 43 | import java.util.Locale; |
47 | 44 | import java.util.Map; |
... | ... | @@ -58,8 +55,7 @@ public class DefaultMailService implements MailService { |
58 | 55 | private MessageSource messages; |
59 | 56 | |
60 | 57 | @Autowired |
61 | - @Qualifier("velocityEngine") | |
62 | - private VelocityEngine engine; | |
58 | + private Configuration freemarkerConfig; | |
63 | 59 | |
64 | 60 | private JavaMailSenderImpl mailSender; |
65 | 61 | |
... | ... | @@ -118,6 +114,21 @@ public class DefaultMailService implements MailService { |
118 | 114 | javaMailProperties.put(MAIL_PROP + protocol + ".ssl.protocols", tlsVersion); |
119 | 115 | } |
120 | 116 | } |
117 | + | |
118 | + boolean enableProxy = jsonConfig.has("enableProxy") && jsonConfig.get("enableProxy").asBoolean(); | |
119 | + | |
120 | + if (enableProxy) { | |
121 | + javaMailProperties.put(MAIL_PROP + protocol + ".proxy.host", jsonConfig.get("proxyHost").asText()); | |
122 | + javaMailProperties.put(MAIL_PROP + protocol + ".proxy.port", jsonConfig.get("proxyPort").asText()); | |
123 | + String proxyUser = jsonConfig.get("proxyUser").asText(); | |
124 | + if (StringUtils.isNoneEmpty(proxyUser)) { | |
125 | + javaMailProperties.put(MAIL_PROP + protocol + ".proxy.user", proxyUser); | |
126 | + } | |
127 | + String proxyPassword = jsonConfig.get("proxyPassword").asText(); | |
128 | + if (StringUtils.isNoneEmpty(proxyPassword)) { | |
129 | + javaMailProperties.put(MAIL_PROP + protocol + ".proxy.password", proxyPassword); | |
130 | + } | |
131 | + } | |
121 | 132 | return javaMailProperties; |
122 | 133 | } |
123 | 134 | |
... | ... | @@ -140,11 +151,10 @@ public class DefaultMailService implements MailService { |
140 | 151 | String mailFrom = jsonConfig.get("mailFrom").asText(); |
141 | 152 | String subject = messages.getMessage("test.message.subject", null, Locale.US); |
142 | 153 | |
143 | - Map<String, Object> model = new HashMap<String, Object>(); | |
154 | + Map<String, Object> model = new HashMap<>(); | |
144 | 155 | model.put(TARGET_EMAIL, email); |
145 | 156 | |
146 | - String message = mergeTemplateIntoString(this.engine, | |
147 | - "test.vm", UTF_8, model); | |
157 | + String message = mergeTemplateIntoString("test.ftl", model); | |
148 | 158 | |
149 | 159 | sendMail(testMailSender, mailFrom, email, subject, message); |
150 | 160 | } |
... | ... | @@ -154,12 +164,11 @@ public class DefaultMailService implements MailService { |
154 | 164 | |
155 | 165 | String subject = messages.getMessage("activation.subject", null, Locale.US); |
156 | 166 | |
157 | - Map<String, Object> model = new HashMap<String, Object>(); | |
167 | + Map<String, Object> model = new HashMap<>(); | |
158 | 168 | model.put("activationLink", activationLink); |
159 | 169 | model.put(TARGET_EMAIL, email); |
160 | 170 | |
161 | - String message = mergeTemplateIntoString(this.engine, | |
162 | - "activation.vm", UTF_8, model); | |
171 | + String message = mergeTemplateIntoString("activation.ftl", model); | |
163 | 172 | |
164 | 173 | sendMail(mailSender, mailFrom, email, subject, message); |
165 | 174 | } |
... | ... | @@ -169,12 +178,11 @@ public class DefaultMailService implements MailService { |
169 | 178 | |
170 | 179 | String subject = messages.getMessage("account.activated.subject", null, Locale.US); |
171 | 180 | |
172 | - Map<String, Object> model = new HashMap<String, Object>(); | |
181 | + Map<String, Object> model = new HashMap<>(); | |
173 | 182 | model.put("loginLink", loginLink); |
174 | 183 | model.put(TARGET_EMAIL, email); |
175 | 184 | |
176 | - String message = mergeTemplateIntoString(this.engine, | |
177 | - "account.activated.vm", UTF_8, model); | |
185 | + String message = mergeTemplateIntoString("account.activated.ftl", model); | |
178 | 186 | |
179 | 187 | sendMail(mailSender, mailFrom, email, subject, message); |
180 | 188 | } |
... | ... | @@ -184,12 +192,11 @@ public class DefaultMailService implements MailService { |
184 | 192 | |
185 | 193 | String subject = messages.getMessage("reset.password.subject", null, Locale.US); |
186 | 194 | |
187 | - Map<String, Object> model = new HashMap<String, Object>(); | |
195 | + Map<String, Object> model = new HashMap<>(); | |
188 | 196 | model.put("passwordResetLink", passwordResetLink); |
189 | 197 | model.put(TARGET_EMAIL, email); |
190 | 198 | |
191 | - String message = mergeTemplateIntoString(this.engine, | |
192 | - "reset.password.vm", UTF_8, model); | |
199 | + String message = mergeTemplateIntoString("reset.password.ftl", model); | |
193 | 200 | |
194 | 201 | sendMail(mailSender, mailFrom, email, subject, message); |
195 | 202 | } |
... | ... | @@ -199,12 +206,11 @@ public class DefaultMailService implements MailService { |
199 | 206 | |
200 | 207 | String subject = messages.getMessage("password.was.reset.subject", null, Locale.US); |
201 | 208 | |
202 | - Map<String, Object> model = new HashMap<String, Object>(); | |
209 | + Map<String, Object> model = new HashMap<>(); | |
203 | 210 | model.put("loginLink", loginLink); |
204 | 211 | model.put(TARGET_EMAIL, email); |
205 | 212 | |
206 | - String message = mergeTemplateIntoString(this.engine, | |
207 | - "password.was.reset.vm", UTF_8, model); | |
213 | + String message = mergeTemplateIntoString("password.was.reset.ftl", model); | |
208 | 214 | |
209 | 215 | sendMail(mailSender, mailFrom, email, subject, message); |
210 | 216 | } |
... | ... | @@ -230,13 +236,12 @@ public class DefaultMailService implements MailService { |
230 | 236 | public void sendAccountLockoutEmail(String lockoutEmail, String email, Integer maxFailedLoginAttempts) throws ThingsboardException { |
231 | 237 | String subject = messages.getMessage("account.lockout.subject", null, Locale.US); |
232 | 238 | |
233 | - Map<String, Object> model = new HashMap<String, Object>(); | |
239 | + Map<String, Object> model = new HashMap<>(); | |
234 | 240 | model.put("lockoutAccount", lockoutEmail); |
235 | 241 | model.put("maxFailedLoginAttempts", maxFailedLoginAttempts); |
236 | 242 | model.put(TARGET_EMAIL, email); |
237 | 243 | |
238 | - String message = mergeTemplateIntoString(this.engine, | |
239 | - "account.lockout.vm", UTF_8, model); | |
244 | + String message = mergeTemplateIntoString("account.lockout.ftl", model); | |
240 | 245 | |
241 | 246 | sendMail(mailSender, mailFrom, email, subject, message); |
242 | 247 | } |
... | ... | @@ -257,20 +262,14 @@ public class DefaultMailService implements MailService { |
257 | 262 | } |
258 | 263 | } |
259 | 264 | |
260 | - private static String mergeTemplateIntoString(VelocityEngine velocityEngine, String templateLocation, | |
261 | - String encoding, Map<String, Object> model) throws VelocityException { | |
262 | - | |
263 | - StringWriter result = new StringWriter(); | |
264 | - mergeTemplate(velocityEngine, templateLocation, encoding, model, result); | |
265 | - return result.toString(); | |
266 | - } | |
267 | - | |
268 | - private static void mergeTemplate( | |
269 | - VelocityEngine velocityEngine, String templateLocation, String encoding, | |
270 | - Map<String, Object> model, Writer writer) throws VelocityException { | |
271 | - | |
272 | - VelocityContext velocityContext = new VelocityContext(model); | |
273 | - velocityEngine.mergeTemplate(templateLocation, encoding, velocityContext, writer); | |
265 | + private String mergeTemplateIntoString(String templateLocation, | |
266 | + Map<String, Object> model) throws ThingsboardException { | |
267 | + try { | |
268 | + Template template = freemarkerConfig.getTemplate(templateLocation); | |
269 | + return FreeMarkerTemplateUtils.processTemplateIntoString(template, model); | |
270 | + } catch (Exception e) { | |
271 | + throw handleException(e); | |
272 | + } | |
274 | 273 | } |
275 | 274 | |
276 | 275 | protected ThingsboardException handleException(Exception exception) { | ... | ... |
... | ... | @@ -46,6 +46,9 @@ import java.util.concurrent.atomic.AtomicInteger; |
46 | 46 | @Service |
47 | 47 | public class RemoteJsInvokeService extends AbstractJsInvokeService { |
48 | 48 | |
49 | + @Value("${queue.js.max_eval_requests_timeout}") | |
50 | + private long maxEvalRequestsTimeout; | |
51 | + | |
49 | 52 | @Value("${queue.js.max_requests_timeout}") |
50 | 53 | private long maxRequestsTimeout; |
51 | 54 | |
... | ... | @@ -59,22 +62,22 @@ public class RemoteJsInvokeService extends AbstractJsInvokeService { |
59 | 62 | @Value("${js.remote.stats.enabled:false}") |
60 | 63 | private boolean statsEnabled; |
61 | 64 | |
62 | - private final AtomicInteger kafkaPushedMsgs = new AtomicInteger(0); | |
63 | - private final AtomicInteger kafkaInvokeMsgs = new AtomicInteger(0); | |
64 | - private final AtomicInteger kafkaEvalMsgs = new AtomicInteger(0); | |
65 | - private final AtomicInteger kafkaFailedMsgs = new AtomicInteger(0); | |
66 | - private final AtomicInteger kafkaTimeoutMsgs = new AtomicInteger(0); | |
65 | + private final AtomicInteger queuePushedMsgs = new AtomicInteger(0); | |
66 | + private final AtomicInteger queueInvokeMsgs = new AtomicInteger(0); | |
67 | + private final AtomicInteger queueEvalMsgs = new AtomicInteger(0); | |
68 | + private final AtomicInteger queueFailedMsgs = new AtomicInteger(0); | |
69 | + private final AtomicInteger queueTimeoutMsgs = new AtomicInteger(0); | |
67 | 70 | |
68 | 71 | @Scheduled(fixedDelayString = "${js.remote.stats.print_interval_ms}") |
69 | 72 | public void printStats() { |
70 | 73 | if (statsEnabled) { |
71 | - int pushedMsgs = kafkaPushedMsgs.getAndSet(0); | |
72 | - int invokeMsgs = kafkaInvokeMsgs.getAndSet(0); | |
73 | - int evalMsgs = kafkaEvalMsgs.getAndSet(0); | |
74 | - int failed = kafkaFailedMsgs.getAndSet(0); | |
75 | - int timedOut = kafkaTimeoutMsgs.getAndSet(0); | |
74 | + int pushedMsgs = queuePushedMsgs.getAndSet(0); | |
75 | + int invokeMsgs = queueInvokeMsgs.getAndSet(0); | |
76 | + int evalMsgs = queueEvalMsgs.getAndSet(0); | |
77 | + int failed = queueFailedMsgs.getAndSet(0); | |
78 | + int timedOut = queueTimeoutMsgs.getAndSet(0); | |
76 | 79 | if (pushedMsgs > 0 || invokeMsgs > 0 || evalMsgs > 0 || failed > 0 || timedOut > 0) { |
77 | - log.info("Kafka JS Invoke Stats: pushed [{}] received [{}] invoke [{}] eval [{}] failed [{}] timedOut [{}]", | |
80 | + log.info("Queue JS Invoke Stats: pushed [{}] received [{}] invoke [{}] eval [{}] failed [{}] timedOut [{}]", | |
78 | 81 | pushedMsgs, invokeMsgs + evalMsgs, invokeMsgs, evalMsgs, failed, timedOut); |
79 | 82 | } |
80 | 83 | } |
... | ... | @@ -113,22 +116,22 @@ public class RemoteJsInvokeService extends AbstractJsInvokeService { |
113 | 116 | |
114 | 117 | log.trace("Post compile request for scriptId [{}]", scriptId); |
115 | 118 | ListenableFuture<TbProtoQueueMsg<JsInvokeProtos.RemoteJsResponse>> future = requestTemplate.send(new TbProtoJsQueueMsg<>(UUID.randomUUID(), jsRequestWrapper)); |
116 | - if (maxRequestsTimeout > 0) { | |
117 | - future = Futures.withTimeout(future, maxRequestsTimeout, TimeUnit.MILLISECONDS, timeoutExecutorService); | |
119 | + if (maxEvalRequestsTimeout > 0) { | |
120 | + future = Futures.withTimeout(future, maxEvalRequestsTimeout, TimeUnit.MILLISECONDS, timeoutExecutorService); | |
118 | 121 | } |
119 | - kafkaPushedMsgs.incrementAndGet(); | |
122 | + queuePushedMsgs.incrementAndGet(); | |
120 | 123 | Futures.addCallback(future, new FutureCallback<TbProtoQueueMsg<JsInvokeProtos.RemoteJsResponse>>() { |
121 | 124 | @Override |
122 | 125 | public void onSuccess(@Nullable TbProtoQueueMsg<JsInvokeProtos.RemoteJsResponse> result) { |
123 | - kafkaEvalMsgs.incrementAndGet(); | |
126 | + queueEvalMsgs.incrementAndGet(); | |
124 | 127 | } |
125 | 128 | |
126 | 129 | @Override |
127 | 130 | public void onFailure(Throwable t) { |
128 | 131 | if (t instanceof TimeoutException || (t.getCause() != null && t.getCause() instanceof TimeoutException)) { |
129 | - kafkaTimeoutMsgs.incrementAndGet(); | |
132 | + queueTimeoutMsgs.incrementAndGet(); | |
130 | 133 | } |
131 | - kafkaFailedMsgs.incrementAndGet(); | |
134 | + queueFailedMsgs.incrementAndGet(); | |
132 | 135 | } |
133 | 136 | }, MoreExecutors.directExecutor()); |
134 | 137 | return Futures.transform(future, response -> { |
... | ... | @@ -170,20 +173,20 @@ public class RemoteJsInvokeService extends AbstractJsInvokeService { |
170 | 173 | if (maxRequestsTimeout > 0) { |
171 | 174 | future = Futures.withTimeout(future, maxRequestsTimeout, TimeUnit.MILLISECONDS, timeoutExecutorService); |
172 | 175 | } |
173 | - kafkaPushedMsgs.incrementAndGet(); | |
176 | + queuePushedMsgs.incrementAndGet(); | |
174 | 177 | Futures.addCallback(future, new FutureCallback<TbProtoQueueMsg<JsInvokeProtos.RemoteJsResponse>>() { |
175 | 178 | @Override |
176 | 179 | public void onSuccess(@Nullable TbProtoQueueMsg<JsInvokeProtos.RemoteJsResponse> result) { |
177 | - kafkaInvokeMsgs.incrementAndGet(); | |
180 | + queueInvokeMsgs.incrementAndGet(); | |
178 | 181 | } |
179 | 182 | |
180 | 183 | @Override |
181 | 184 | public void onFailure(Throwable t) { |
182 | 185 | onScriptExecutionError(scriptId); |
183 | 186 | if (t instanceof TimeoutException || (t.getCause() != null && t.getCause() instanceof TimeoutException)) { |
184 | - kafkaTimeoutMsgs.incrementAndGet(); | |
187 | + queueTimeoutMsgs.incrementAndGet(); | |
185 | 188 | } |
186 | - kafkaFailedMsgs.incrementAndGet(); | |
189 | + queueFailedMsgs.incrementAndGet(); | |
187 | 190 | } |
188 | 191 | }, MoreExecutors.directExecutor()); |
189 | 192 | return Futures.transform(future, response -> { | ... | ... |
... | ... | @@ -105,7 +105,7 @@ public class CustomerUserPermissions extends AbstractPermissions { |
105 | 105 | |
106 | 106 | @Override |
107 | 107 | public boolean hasPermission(SecurityUser user, Operation operation, UserId userId, User userEntity) { |
108 | - if (userEntity.getAuthority() != Authority.CUSTOMER_USER) { | |
108 | + if (!Authority.CUSTOMER_USER.equals(userEntity.getAuthority())) { | |
109 | 109 | return false; |
110 | 110 | } |
111 | 111 | if (!user.getId().equals(userId)) { | ... | ... |
... | ... | @@ -57,7 +57,7 @@ public class SysAdminPermissions extends AbstractPermissions { |
57 | 57 | |
58 | 58 | @Override |
59 | 59 | public boolean hasPermission(SecurityUser user, Operation operation, UserId userId, User userEntity) { |
60 | - if (userEntity.getAuthority() == Authority.CUSTOMER_USER) { | |
60 | + if (Authority.CUSTOMER_USER.equals(userEntity.getAuthority())) { | |
61 | 61 | return false; |
62 | 62 | } |
63 | 63 | return true; | ... | ... |
... | ... | @@ -76,7 +76,7 @@ public class TenantAdminPermissions extends AbstractPermissions { |
76 | 76 | |
77 | 77 | @Override |
78 | 78 | public boolean hasPermission(SecurityUser user, Operation operation, UserId userId, User userEntity) { |
79 | - if (userEntity.getAuthority() == Authority.SYS_ADMIN) { | |
79 | + if (Authority.SYS_ADMIN.equals(userEntity.getAuthority())) { | |
80 | 80 | return false; |
81 | 81 | } |
82 | 82 | if (!user.getTenantId().equals(userEntity.getTenantId())) { | ... | ... |
... | ... | @@ -224,7 +224,7 @@ public class DefaultSubscriptionManagerService implements SubscriptionManagerSer |
224 | 224 | return null; |
225 | 225 | } |
226 | 226 | }, |
227 | - s -> (StringUtils.isEmpty(s.getScope()) || scope.equals(s.getScope().name())), | |
227 | + s -> (TbAttributeSubscriptionScope.ANY_SCOPE.equals(s.getScope()) || scope.equals(s.getScope().name())), | |
228 | 228 | s -> { |
229 | 229 | List<TsKvEntry> subscriptionUpdate = null; |
230 | 230 | for (AttributeKvEntry kv : attributes) { | ... | ... |
... | ... | @@ -345,7 +345,7 @@ public class DefaultTelemetryWebSocketService implements TelemetryWebSocketServi |
345 | 345 | keys.forEach(key -> subState.put(key, 0L)); |
346 | 346 | attributesData.forEach(v -> subState.put(v.getKey(), v.getTs())); |
347 | 347 | |
348 | - TbAttributeSubscriptionScope scope = StringUtils.isEmpty(cmd.getScope()) ? TbAttributeSubscriptionScope.SERVER_SCOPE : TbAttributeSubscriptionScope.valueOf(cmd.getScope()); | |
348 | + TbAttributeSubscriptionScope scope = StringUtils.isEmpty(cmd.getScope()) ? TbAttributeSubscriptionScope.ANY_SCOPE : TbAttributeSubscriptionScope.valueOf(cmd.getScope()); | |
349 | 349 | |
350 | 350 | TbAttributeSubscription sub = TbAttributeSubscription.builder() |
351 | 351 | .serviceId(serviceId) |
... | ... | @@ -442,7 +442,7 @@ public class DefaultTelemetryWebSocketService implements TelemetryWebSocketServi |
442 | 442 | Map<String, Long> subState = new HashMap<>(attributesData.size()); |
443 | 443 | attributesData.forEach(v -> subState.put(v.getKey(), v.getTs())); |
444 | 444 | |
445 | - TbAttributeSubscriptionScope scope = StringUtils.isEmpty(cmd.getScope()) ? TbAttributeSubscriptionScope.SERVER_SCOPE : TbAttributeSubscriptionScope.valueOf(cmd.getScope()); | |
445 | + TbAttributeSubscriptionScope scope = StringUtils.isEmpty(cmd.getScope()) ? TbAttributeSubscriptionScope.ANY_SCOPE : TbAttributeSubscriptionScope.valueOf(cmd.getScope()); | |
446 | 446 | |
447 | 447 | TbAttributeSubscription sub = TbAttributeSubscription.builder() |
448 | 448 | .serviceId(serviceId) | ... | ... |
application/src/main/resources/templates/account.activated.ftl
renamed from
application/src/main/resources/templates/account.activated.vm
1 | -#* | |
2 | - * Copyright © 2016-2020 The Thingsboard Authors | |
3 | - * | |
4 | - * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | - * you may not use this file except in compliance with the License. | |
6 | - * You may obtain a copy of the License at | |
7 | - * | |
8 | - * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | - * | |
10 | - * Unless required by applicable law or agreed to in writing, software | |
11 | - * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | - * See the License for the specific language governing permissions and | |
14 | - * limitations under the License. | |
15 | - *# | |
1 | +<#-- | |
2 | + | |
3 | + Copyright © 2016-2020 The Thingsboard Authors | |
4 | + | |
5 | + Licensed under the Apache License, Version 2.0 (the "License"); | |
6 | + you may not use this file except in compliance with the License. | |
7 | + You may obtain a copy of the License at | |
8 | + | |
9 | + http://www.apache.org/licenses/LICENSE-2.0 | |
10 | + | |
11 | + Unless required by applicable law or agreed to in writing, software | |
12 | + distributed under the License is distributed on an "AS IS" BASIS, | |
13 | + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
14 | + See the License for the specific language governing permissions and | |
15 | + limitations under the License. | |
16 | + | |
17 | +--> | |
16 | 18 | <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> |
17 | 19 | <html xmlns="http://www.w3.org/1999/xhtml" style="font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 14px; margin: 0;"> |
18 | 20 | <head> |
... | ... | @@ -96,7 +98,7 @@ background-color: #f6f6f6; |
96 | 98 | </tr> |
97 | 99 | <tr style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; margin: 0;"> |
98 | 100 | <td class="content-block" itemprop="handler" itemscope itemtype="http://schema.org/HttpActionHandler" style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; vertical-align: top; margin: 0; padding: 0 0 20px;" valign="top"> |
99 | - <a href="$loginLink" class="btn-primary" itemprop="url" style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; color: #FFF; text-decoration: none; line-height: 2em; font-weight: bold; text-align: center; cursor: pointer; display: inline-block; border-radius: 5px; text-transform: capitalize; background-color: #348eda; margin: 0; border-color: #348eda; border-style: solid; border-width: 10px 20px;">Login</a> | |
101 | + <a href="${loginLink}" class="btn-primary" itemprop="url" style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; color: #FFF; text-decoration: none; line-height: 2em; font-weight: bold; text-align: center; cursor: pointer; display: inline-block; border-radius: 5px; text-transform: capitalize; background-color: #348eda; margin: 0; border-color: #348eda; border-style: solid; border-width: 10px 20px;">Login</a> | |
100 | 102 | </td> |
101 | 103 | </tr> |
102 | 104 | <tr style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; margin: 0;"> |
... | ... | @@ -109,7 +111,7 @@ background-color: #f6f6f6; |
109 | 111 | <div class="footer" style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; width: 100%; clear: both; color: #999; margin: 0; padding: 20px;"> |
110 | 112 | <table width="100%" style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; margin: 0;"> |
111 | 113 | <tr style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; margin: 0;"> |
112 | - <td class="aligncenter content-block" style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 12px; vertical-align: top; color: #999; text-align: center; margin: 0; padding: 0 0 20px;" align="center" valign="top">This email was sent to <a href="mailto:$targetEmail" style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 12px; color: #999; text-decoration: underline; margin: 0;">$targetEmail</a> by Thingsboard.</td> | |
114 | + <td class="aligncenter content-block" style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 12px; vertical-align: top; color: #999; text-align: center; margin: 0; padding: 0 0 20px;" align="center" valign="top">This email was sent to <a href="mailto:${targetEmail}" style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 12px; color: #999; text-decoration: underline; margin: 0;">${targetEmail}</a> by Thingsboard.</td> | |
113 | 115 | </tr> |
114 | 116 | </table> |
115 | 117 | </div> | ... | ... |
application/src/main/resources/templates/account.lockout.ftl
renamed from
application/src/main/resources/templates/test.vm
1 | -#* | |
2 | - * Copyright © 2016-2020 The Thingsboard Authors | |
3 | - * | |
4 | - * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | - * you may not use this file except in compliance with the License. | |
6 | - * You may obtain a copy of the License at | |
7 | - * | |
8 | - * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | - * | |
10 | - * Unless required by applicable law or agreed to in writing, software | |
11 | - * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | - * See the License for the specific language governing permissions and | |
14 | - * limitations under the License. | |
15 | - *# | |
1 | +<#-- | |
2 | + | |
3 | + Copyright © 2016-2020 The Thingsboard Authors | |
4 | + | |
5 | + Licensed under the Apache License, Version 2.0 (the "License"); | |
6 | + you may not use this file except in compliance with the License. | |
7 | + You may obtain a copy of the License at | |
8 | + | |
9 | + http://www.apache.org/licenses/LICENSE-2.0 | |
10 | + | |
11 | + Unless required by applicable law or agreed to in writing, software | |
12 | + distributed under the License is distributed on an "AS IS" BASIS, | |
13 | + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
14 | + See the License for the specific language governing permissions and | |
15 | + limitations under the License. | |
16 | + | |
17 | +--> | |
16 | 18 | <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> |
17 | 19 | <html xmlns="http://www.w3.org/1999/xhtml" style="font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 14px; margin: 0;"> |
18 | 20 | <head> |
19 | 21 | <meta name="viewport" content="width=device-width" /> |
20 | 22 | <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> |
21 | -<title>Thingsboard - Test Message</title> | |
23 | +<title>Thingsboard - Account Lockout</title> | |
22 | 24 | |
23 | 25 | |
24 | 26 | <style type="text/css"> |
... | ... | @@ -81,12 +83,12 @@ background-color: #f6f6f6; |
81 | 83 | <meta itemprop="name" content="Confirm Email" style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; margin: 0;" /><table width="100%" cellpadding="0" cellspacing="0" style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; margin: 0;"> |
82 | 84 | <tr style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; margin: 0;"> |
83 | 85 | <td class="content-block" style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; color: #348eda; box-sizing: border-box; font-size: 14px; vertical-align: top; margin: 0; padding: 0 0 20px;" valign="top"> |
84 | - <h2>Test message from Thingsboard</h2> | |
86 | + <h2>Thingsboard user account has been locked out</h2> | |
85 | 87 | </td> |
86 | 88 | </tr> |
87 | 89 | <tr style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; margin: 0;"> |
88 | 90 | <td class="content-block" style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; vertical-align: top; margin: 0; padding: 0 0 20px;" valign="top"> |
89 | - This email is indicating that your outgoing mail settings were set up correctly. | |
91 | + Thingsboard user account ${lockoutAccount} has been lockout due to failed credentials were provided more than ${maxFailedLoginAttempts} times. | |
90 | 92 | </td> |
91 | 93 | </tr> |
92 | 94 | <tr style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; margin: 0;"> |
... | ... | @@ -99,7 +101,7 @@ background-color: #f6f6f6; |
99 | 101 | <div class="footer" style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; width: 100%; clear: both; color: #999; margin: 0; padding: 20px;"> |
100 | 102 | <table width="100%" style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; margin: 0;"> |
101 | 103 | <tr style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; margin: 0;"> |
102 | - <td class="aligncenter content-block" style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 12px; vertical-align: top; color: #999; text-align: center; margin: 0; padding: 0 0 20px;" align="center" valign="top">This email was sent to <a href="mailto:$targetEmail" style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 12px; color: #999; text-decoration: underline; margin: 0;">$targetEmail</a> by Thingsboard.</td> | |
104 | + <td class="aligncenter content-block" style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 12px; vertical-align: top; color: #999; text-align: center; margin: 0; padding: 0 0 20px;" align="center" valign="top">This email was sent to <a href="mailto:${targetEmail}" style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 12px; color: #999; text-decoration: underline; margin: 0;">${targetEmail}</a> by Thingsboard.</td> | |
103 | 105 | </tr> |
104 | 106 | </table> |
105 | 107 | </div> | ... | ... |
application/src/main/resources/templates/activation.ftl
renamed from
application/src/main/resources/templates/activation.vm
1 | -#* | |
2 | - * Copyright © 2016-2020 The Thingsboard Authors | |
3 | - * | |
4 | - * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | - * you may not use this file except in compliance with the License. | |
6 | - * You may obtain a copy of the License at | |
7 | - * | |
8 | - * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | - * | |
10 | - * Unless required by applicable law or agreed to in writing, software | |
11 | - * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | - * See the License for the specific language governing permissions and | |
14 | - * limitations under the License. | |
15 | - *# | |
1 | +<#-- | |
2 | + | |
3 | + Copyright © 2016-2020 The Thingsboard Authors | |
4 | + | |
5 | + Licensed under the Apache License, Version 2.0 (the "License"); | |
6 | + you may not use this file except in compliance with the License. | |
7 | + You may obtain a copy of the License at | |
8 | + | |
9 | + http://www.apache.org/licenses/LICENSE-2.0 | |
10 | + | |
11 | + Unless required by applicable law or agreed to in writing, software | |
12 | + distributed under the License is distributed on an "AS IS" BASIS, | |
13 | + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
14 | + See the License for the specific language governing permissions and | |
15 | + limitations under the License. | |
16 | + | |
17 | +--> | |
16 | 18 | <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> |
17 | 19 | <html xmlns="http://www.w3.org/1999/xhtml" style="font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 14px; margin: 0;"> |
18 | 20 | <head> |
... | ... | @@ -96,7 +98,7 @@ background-color: #f6f6f6; |
96 | 98 | </tr> |
97 | 99 | <tr style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; margin: 0;"> |
98 | 100 | <td class="content-block" itemprop="handler" itemscope itemtype="http://schema.org/HttpActionHandler" style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; vertical-align: top; margin: 0; padding: 0 0 20px;" valign="top"> |
99 | - <a href="$activationLink" class="btn-primary" itemprop="url" style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; color: #FFF; text-decoration: none; line-height: 2em; font-weight: bold; text-align: center; cursor: pointer; display: inline-block; border-radius: 5px; text-transform: capitalize; background-color: #348eda; margin: 0; border-color: #348eda; border-style: solid; border-width: 10px 20px;">Activate your account</a> | |
101 | + <a href="${activationLink}" class="btn-primary" itemprop="url" style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; color: #FFF; text-decoration: none; line-height: 2em; font-weight: bold; text-align: center; cursor: pointer; display: inline-block; border-radius: 5px; text-transform: capitalize; background-color: #348eda; margin: 0; border-color: #348eda; border-style: solid; border-width: 10px 20px;">Activate your account</a> | |
100 | 102 | </td> |
101 | 103 | </tr> |
102 | 104 | <tr style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; margin: 0;"> |
... | ... | @@ -109,7 +111,7 @@ background-color: #f6f6f6; |
109 | 111 | <div class="footer" style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; width: 100%; clear: both; color: #999; margin: 0; padding: 20px;"> |
110 | 112 | <table width="100%" style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; margin: 0;"> |
111 | 113 | <tr style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; margin: 0;"> |
112 | - <td class="aligncenter content-block" style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 12px; vertical-align: top; color: #999; text-align: center; margin: 0; padding: 0 0 20px;" align="center" valign="top">This email was sent to <a href="mailto:$targetEmail" style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 12px; color: #999; text-decoration: underline; margin: 0;">$targetEmail</a> by Thingsboard.</td> | |
114 | + <td class="aligncenter content-block" style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 12px; vertical-align: top; color: #999; text-align: center; margin: 0; padding: 0 0 20px;" align="center" valign="top">This email was sent to <a href="mailto:${targetEmail}" style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 12px; color: #999; text-decoration: underline; margin: 0;">${targetEmail}</a> by Thingsboard.</td> | |
113 | 115 | </tr> |
114 | 116 | </table> |
115 | 117 | </div> | ... | ... |
application/src/main/resources/templates/password.was.reset.ftl
renamed from
application/src/main/resources/templates/password.was.reset.vm
1 | -#* | |
2 | - * Copyright © 2016-2020 The Thingsboard Authors | |
3 | - * | |
4 | - * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | - * you may not use this file except in compliance with the License. | |
6 | - * You may obtain a copy of the License at | |
7 | - * | |
8 | - * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | - * | |
10 | - * Unless required by applicable law or agreed to in writing, software | |
11 | - * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | - * See the License for the specific language governing permissions and | |
14 | - * limitations under the License. | |
15 | - *# | |
1 | +<#-- | |
2 | + | |
3 | + Copyright © 2016-2020 The Thingsboard Authors | |
4 | + | |
5 | + Licensed under the Apache License, Version 2.0 (the "License"); | |
6 | + you may not use this file except in compliance with the License. | |
7 | + You may obtain a copy of the License at | |
8 | + | |
9 | + http://www.apache.org/licenses/LICENSE-2.0 | |
10 | + | |
11 | + Unless required by applicable law or agreed to in writing, software | |
12 | + distributed under the License is distributed on an "AS IS" BASIS, | |
13 | + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
14 | + See the License for the specific language governing permissions and | |
15 | + limitations under the License. | |
16 | + | |
17 | +--> | |
16 | 18 | <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> |
17 | 19 | <html xmlns="http://www.w3.org/1999/xhtml" style="font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 14px; margin: 0;"> |
18 | 20 | <head> |
... | ... | @@ -96,7 +98,7 @@ background-color: #f6f6f6; |
96 | 98 | </tr> |
97 | 99 | <tr style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; margin: 0;"> |
98 | 100 | <td class="content-block" itemprop="handler" itemscope itemtype="http://schema.org/HttpActionHandler" style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; vertical-align: top; margin: 0; padding: 0 0 20px;" valign="top"> |
99 | - <a href="$loginLink" class="btn-primary" itemprop="url" style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; color: #FFF; text-decoration: none; line-height: 2em; font-weight: bold; text-align: center; cursor: pointer; display: inline-block; border-radius: 5px; text-transform: capitalize; background-color: #348eda; margin: 0; border-color: #348eda; border-style: solid; border-width: 10px 20px;">Login</a> | |
101 | + <a href="${loginLink}" class="btn-primary" itemprop="url" style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; color: #FFF; text-decoration: none; line-height: 2em; font-weight: bold; text-align: center; cursor: pointer; display: inline-block; border-radius: 5px; text-transform: capitalize; background-color: #348eda; margin: 0; border-color: #348eda; border-style: solid; border-width: 10px 20px;">Login</a> | |
100 | 102 | </td> |
101 | 103 | </tr> |
102 | 104 | <tr style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; margin: 0;"> |
... | ... | @@ -109,7 +111,7 @@ background-color: #f6f6f6; |
109 | 111 | <div class="footer" style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; width: 100%; clear: both; color: #999; margin: 0; padding: 20px;"> |
110 | 112 | <table width="100%" style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; margin: 0;"> |
111 | 113 | <tr style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; margin: 0;"> |
112 | - <td class="aligncenter content-block" style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 12px; vertical-align: top; color: #999; text-align: center; margin: 0; padding: 0 0 20px;" align="center" valign="top">This email was sent to <a href="mailto:$targetEmail" style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 12px; color: #999; text-decoration: underline; margin: 0;">$targetEmail</a> by Thingsboard.</td> | |
114 | + <td class="aligncenter content-block" style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 12px; vertical-align: top; color: #999; text-align: center; margin: 0; padding: 0 0 20px;" align="center" valign="top">This email was sent to <a href="mailto:${targetEmail}" style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 12px; color: #999; text-decoration: underline; margin: 0;">${targetEmail}</a> by Thingsboard.</td> | |
113 | 115 | </tr> |
114 | 116 | </table> |
115 | 117 | </div> | ... | ... |
application/src/main/resources/templates/reset.password.ftl
renamed from
application/src/main/resources/templates/reset.password.vm
1 | -#* | |
2 | - * Copyright © 2016-2020 The Thingsboard Authors | |
3 | - * | |
4 | - * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | - * you may not use this file except in compliance with the License. | |
6 | - * You may obtain a copy of the License at | |
7 | - * | |
8 | - * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | - * | |
10 | - * Unless required by applicable law or agreed to in writing, software | |
11 | - * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | - * See the License for the specific language governing permissions and | |
14 | - * limitations under the License. | |
15 | - *# | |
1 | +<#-- | |
2 | + | |
3 | + Copyright © 2016-2020 The Thingsboard Authors | |
4 | + | |
5 | + Licensed under the Apache License, Version 2.0 (the "License"); | |
6 | + you may not use this file except in compliance with the License. | |
7 | + You may obtain a copy of the License at | |
8 | + | |
9 | + http://www.apache.org/licenses/LICENSE-2.0 | |
10 | + | |
11 | + Unless required by applicable law or agreed to in writing, software | |
12 | + distributed under the License is distributed on an "AS IS" BASIS, | |
13 | + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
14 | + See the License for the specific language governing permissions and | |
15 | + limitations under the License. | |
16 | + | |
17 | +--> | |
16 | 18 | <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> |
17 | 19 | <html xmlns="http://www.w3.org/1999/xhtml" style="font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 14px; margin: 0;"> |
18 | 20 | <head> |
... | ... | @@ -96,7 +98,7 @@ background-color: #f6f6f6; |
96 | 98 | </tr> |
97 | 99 | <tr style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; margin: 0;"> |
98 | 100 | <td class="content-block" itemprop="handler" itemscope itemtype="http://schema.org/HttpActionHandler" style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; vertical-align: top; margin: 0; padding: 0 0 20px;" valign="top"> |
99 | - <a href="$passwordResetLink" class="btn-primary" itemprop="url" style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; color: #FFF; text-decoration: none; line-height: 2em; font-weight: bold; text-align: center; cursor: pointer; display: inline-block; border-radius: 5px; text-transform: capitalize; background-color: #348eda; margin: 0; border-color: #348eda; border-style: solid; border-width: 10px 20px;">Reset password</a> | |
101 | + <a href="${passwordResetLink}" class="btn-primary" itemprop="url" style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; color: #FFF; text-decoration: none; line-height: 2em; font-weight: bold; text-align: center; cursor: pointer; display: inline-block; border-radius: 5px; text-transform: capitalize; background-color: #348eda; margin: 0; border-color: #348eda; border-style: solid; border-width: 10px 20px;">Reset password</a> | |
100 | 102 | </td> |
101 | 103 | </tr> |
102 | 104 | <tr style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; margin: 0;"> |
... | ... | @@ -109,7 +111,7 @@ background-color: #f6f6f6; |
109 | 111 | <div class="footer" style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; width: 100%; clear: both; color: #999; margin: 0; padding: 20px;"> |
110 | 112 | <table width="100%" style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; margin: 0;"> |
111 | 113 | <tr style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; margin: 0;"> |
112 | - <td class="aligncenter content-block" style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 12px; vertical-align: top; color: #999; text-align: center; margin: 0; padding: 0 0 20px;" align="center" valign="top">This email was sent to <a href="mailto:$targetEmail" style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 12px; color: #999; text-decoration: underline; margin: 0;">$targetEmail</a> by Thingsboard.</td> | |
114 | + <td class="aligncenter content-block" style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 12px; vertical-align: top; color: #999; text-align: center; margin: 0; padding: 0 0 20px;" align="center" valign="top">This email was sent to <a href="mailto:${targetEmail}" style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 12px; color: #999; text-decoration: underline; margin: 0;">${targetEmail}</a> by Thingsboard.</td> | |
113 | 115 | </tr> |
114 | 116 | </table> |
115 | 117 | </div> | ... | ... |
application/src/main/resources/templates/test.ftl
renamed from
application/src/main/resources/templates/account.lockout.vm
1 | -#* | |
2 | - * Copyright © 2016-2020 The Thingsboard Authors | |
3 | - * | |
4 | - * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | - * you may not use this file except in compliance with the License. | |
6 | - * You may obtain a copy of the License at | |
7 | - * | |
8 | - * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | - * | |
10 | - * Unless required by applicable law or agreed to in writing, software | |
11 | - * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | - * See the License for the specific language governing permissions and | |
14 | - * limitations under the License. | |
15 | - *# | |
1 | +<#-- | |
2 | + | |
3 | + Copyright © 2016-2020 The Thingsboard Authors | |
4 | + | |
5 | + Licensed under the Apache License, Version 2.0 (the "License"); | |
6 | + you may not use this file except in compliance with the License. | |
7 | + You may obtain a copy of the License at | |
8 | + | |
9 | + http://www.apache.org/licenses/LICENSE-2.0 | |
10 | + | |
11 | + Unless required by applicable law or agreed to in writing, software | |
12 | + distributed under the License is distributed on an "AS IS" BASIS, | |
13 | + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
14 | + See the License for the specific language governing permissions and | |
15 | + limitations under the License. | |
16 | + | |
17 | +--> | |
16 | 18 | <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> |
17 | 19 | <html xmlns="http://www.w3.org/1999/xhtml" style="font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 14px; margin: 0;"> |
18 | 20 | <head> |
19 | 21 | <meta name="viewport" content="width=device-width" /> |
20 | 22 | <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> |
21 | -<title>Thingsboard - Account Lockout</title> | |
23 | +<title>Thingsboard - Test Message</title> | |
22 | 24 | |
23 | 25 | |
24 | 26 | <style type="text/css"> |
... | ... | @@ -81,12 +83,12 @@ background-color: #f6f6f6; |
81 | 83 | <meta itemprop="name" content="Confirm Email" style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; margin: 0;" /><table width="100%" cellpadding="0" cellspacing="0" style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; margin: 0;"> |
82 | 84 | <tr style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; margin: 0;"> |
83 | 85 | <td class="content-block" style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; color: #348eda; box-sizing: border-box; font-size: 14px; vertical-align: top; margin: 0; padding: 0 0 20px;" valign="top"> |
84 | - <h2>Thingsboard user account has been locked out</h2> | |
86 | + <h2>Test message from Thingsboard</h2> | |
85 | 87 | </td> |
86 | 88 | </tr> |
87 | 89 | <tr style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; margin: 0;"> |
88 | 90 | <td class="content-block" style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; vertical-align: top; margin: 0; padding: 0 0 20px;" valign="top"> |
89 | - Thingsboard user account $lockoutAccount has been lockout due to failed credentials were provided more than $maxFailedLoginAttempts times. | |
91 | + This email is indicating that your outgoing mail settings were set up correctly. | |
90 | 92 | </td> |
91 | 93 | </tr> |
92 | 94 | <tr style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; margin: 0;"> |
... | ... | @@ -99,7 +101,7 @@ background-color: #f6f6f6; |
99 | 101 | <div class="footer" style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; width: 100%; clear: both; color: #999; margin: 0; padding: 20px;"> |
100 | 102 | <table width="100%" style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; margin: 0;"> |
101 | 103 | <tr style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; margin: 0;"> |
102 | - <td class="aligncenter content-block" style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 12px; vertical-align: top; color: #999; text-align: center; margin: 0; padding: 0 0 20px;" align="center" valign="top">This email was sent to <a href="mailto:$targetEmail" style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 12px; color: #999; text-decoration: underline; margin: 0;">$targetEmail</a> by Thingsboard.</td> | |
104 | + <td class="aligncenter content-block" style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 12px; vertical-align: top; color: #999; text-align: center; margin: 0; padding: 0 0 20px;" align="center" valign="top">This email was sent to <a href="mailto:${targetEmail}" style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 12px; color: #999; text-decoration: underline; margin: 0;">${targetEmail}</a> by Thingsboard.</td> | |
103 | 105 | </tr> |
104 | 106 | </table> |
105 | 107 | </div> | ... | ... |
... | ... | @@ -668,6 +668,8 @@ queue: |
668 | 668 | # JS Eval max pending requests |
669 | 669 | max_pending_requests: "${REMOTE_JS_MAX_PENDING_REQUESTS:10000}" |
670 | 670 | # JS Eval max request timeout |
671 | + max_eval_requests_timeout: "${REMOTE_JS_MAX_EVAL_REQUEST_TIMEOUT:60000}" | |
672 | + # JS max request timeout | |
671 | 673 | max_requests_timeout: "${REMOTE_JS_MAX_REQUEST_TIMEOUT:10000}" |
672 | 674 | # JS response poll interval |
673 | 675 | response_poll_interval: "${REMOTE_JS_RESPONSE_POLL_INTERVAL_MS:25}" | ... | ... |
common/dao-api/src/main/java/org/thingsboard/server/dao/cassandra/guava/GuavaMultiPageResultSet.java
0 → 100644
1 | +/** | |
2 | + * Copyright © 2016-2020 The Thingsboard Authors | |
3 | + * | |
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | + * you may not use this file except in compliance with the License. | |
6 | + * You may obtain a copy of the License at | |
7 | + * | |
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | + * | |
10 | + * Unless required by applicable law or agreed to in writing, software | |
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | + * See the License for the specific language governing permissions and | |
14 | + * limitations under the License. | |
15 | + */ | |
16 | +package org.thingsboard.server.dao.cassandra.guava; | |
17 | + | |
18 | +import com.datastax.oss.driver.api.core.cql.AsyncResultSet; | |
19 | +import com.datastax.oss.driver.api.core.cql.ColumnDefinitions; | |
20 | +import com.datastax.oss.driver.api.core.cql.ExecutionInfo; | |
21 | +import com.datastax.oss.driver.api.core.cql.ResultSet; | |
22 | +import com.datastax.oss.driver.api.core.cql.Row; | |
23 | +import com.datastax.oss.driver.api.core.cql.Statement; | |
24 | +import com.datastax.oss.driver.internal.core.util.CountingIterator; | |
25 | +import com.datastax.oss.driver.internal.core.util.concurrent.BlockingOperation; | |
26 | +import edu.umd.cs.findbugs.annotations.NonNull; | |
27 | + | |
28 | +import java.nio.ByteBuffer; | |
29 | +import java.util.ArrayList; | |
30 | +import java.util.Iterator; | |
31 | +import java.util.List; | |
32 | + | |
33 | +public class GuavaMultiPageResultSet implements ResultSet { | |
34 | + | |
35 | + private final RowIterator iterator; | |
36 | + private final List<ExecutionInfo> executionInfos = new ArrayList<>(); | |
37 | + private ColumnDefinitions columnDefinitions; | |
38 | + | |
39 | + public GuavaMultiPageResultSet(@NonNull GuavaSession session, @NonNull Statement statement, @NonNull AsyncResultSet firstPage) { | |
40 | + assert firstPage.hasMorePages(); | |
41 | + this.iterator = new RowIterator(session, statement, firstPage); | |
42 | + this.executionInfos.add(firstPage.getExecutionInfo()); | |
43 | + this.columnDefinitions = firstPage.getColumnDefinitions(); | |
44 | + } | |
45 | + | |
46 | + @NonNull | |
47 | + @Override | |
48 | + public ColumnDefinitions getColumnDefinitions() { | |
49 | + return columnDefinitions; | |
50 | + } | |
51 | + | |
52 | + @NonNull | |
53 | + @Override | |
54 | + public List<ExecutionInfo> getExecutionInfos() { | |
55 | + return executionInfos; | |
56 | + } | |
57 | + | |
58 | + @Override | |
59 | + public boolean isFullyFetched() { | |
60 | + return iterator.isFullyFetched(); | |
61 | + } | |
62 | + | |
63 | + @Override | |
64 | + public int getAvailableWithoutFetching() { | |
65 | + return iterator.remaining(); | |
66 | + } | |
67 | + | |
68 | + @NonNull | |
69 | + @Override | |
70 | + public Iterator<Row> iterator() { | |
71 | + return iterator; | |
72 | + } | |
73 | + | |
74 | + @Override | |
75 | + public boolean wasApplied() { | |
76 | + return iterator.wasApplied(); | |
77 | + } | |
78 | + | |
79 | + private class RowIterator extends CountingIterator<Row> { | |
80 | + private GuavaSession session; | |
81 | + private Statement statement; | |
82 | + private AsyncResultSet currentPage; | |
83 | + private Iterator<Row> currentRows; | |
84 | + | |
85 | + private RowIterator(GuavaSession session, Statement statement, AsyncResultSet firstPage) { | |
86 | + super(firstPage.remaining()); | |
87 | + this.session = session; | |
88 | + this.statement = statement; | |
89 | + this.currentPage = firstPage; | |
90 | + this.currentRows = firstPage.currentPage().iterator(); | |
91 | + } | |
92 | + | |
93 | + @Override | |
94 | + protected Row computeNext() { | |
95 | + maybeMoveToNextPage(); | |
96 | + return currentRows.hasNext() ? currentRows.next() : endOfData(); | |
97 | + } | |
98 | + | |
99 | + private void maybeMoveToNextPage() { | |
100 | + if (!currentRows.hasNext() && currentPage.hasMorePages()) { | |
101 | + BlockingOperation.checkNotDriverThread(); | |
102 | + ByteBuffer nextPagingState = currentPage.getExecutionInfo().getPagingState(); | |
103 | + this.statement = this.statement.setPagingState(nextPagingState); | |
104 | + AsyncResultSet nextPage = GuavaSession.getSafe(this.session.executeAsync(this.statement)); | |
105 | + currentPage = nextPage; | |
106 | + remaining += nextPage.remaining(); | |
107 | + currentRows = nextPage.currentPage().iterator(); | |
108 | + executionInfos.add(nextPage.getExecutionInfo()); | |
109 | + // The definitions can change from page to page if this result set was built from a bound | |
110 | + // 'SELECT *', and the schema was altered. | |
111 | + columnDefinitions = nextPage.getColumnDefinitions(); | |
112 | + } | |
113 | + } | |
114 | + | |
115 | + private boolean isFullyFetched() { | |
116 | + return !currentPage.hasMorePages(); | |
117 | + } | |
118 | + | |
119 | + private boolean wasApplied() { | |
120 | + return currentPage.wasApplied(); | |
121 | + } | |
122 | + } | |
123 | +} | ... | ... |
... | ... | @@ -17,13 +17,18 @@ package org.thingsboard.server.dao.cassandra.guava; |
17 | 17 | |
18 | 18 | import com.datastax.oss.driver.api.core.cql.AsyncResultSet; |
19 | 19 | import com.datastax.oss.driver.api.core.cql.PreparedStatement; |
20 | +import com.datastax.oss.driver.api.core.cql.ResultSet; | |
20 | 21 | import com.datastax.oss.driver.api.core.cql.SimpleStatement; |
21 | 22 | import com.datastax.oss.driver.api.core.cql.Statement; |
22 | 23 | import com.datastax.oss.driver.api.core.cql.SyncCqlSession; |
23 | 24 | import com.datastax.oss.driver.api.core.session.Session; |
24 | 25 | import com.datastax.oss.driver.api.core.type.reflect.GenericType; |
25 | 26 | import com.datastax.oss.driver.internal.core.cql.DefaultPrepareRequest; |
27 | +import com.datastax.oss.driver.internal.core.cql.SinglePageResultSet; | |
26 | 28 | import com.google.common.util.concurrent.ListenableFuture; |
29 | +import edu.umd.cs.findbugs.annotations.NonNull; | |
30 | + | |
31 | +import java.util.concurrent.ExecutionException; | |
27 | 32 | |
28 | 33 | public interface GuavaSession extends Session, SyncCqlSession { |
29 | 34 | |
... | ... | @@ -33,6 +38,16 @@ public interface GuavaSession extends Session, SyncCqlSession { |
33 | 38 | GenericType<ListenableFuture<PreparedStatement>> ASYNC_PREPARED = |
34 | 39 | new GenericType<ListenableFuture<PreparedStatement>>() {}; |
35 | 40 | |
41 | + @NonNull | |
42 | + default ResultSet execute(@NonNull Statement<?> statement) { | |
43 | + AsyncResultSet firstPage = getSafe(this.executeAsync(statement)); | |
44 | + if (firstPage.hasMorePages()) { | |
45 | + return new GuavaMultiPageResultSet(this, statement, firstPage); | |
46 | + } else { | |
47 | + return new SinglePageResultSet(firstPage); | |
48 | + } | |
49 | + } | |
50 | + | |
36 | 51 | default ListenableFuture<AsyncResultSet> executeAsync(Statement<?> statement) { |
37 | 52 | return this.execute(statement, ASYNC); |
38 | 53 | } |
... | ... | @@ -48,4 +63,12 @@ public interface GuavaSession extends Session, SyncCqlSession { |
48 | 63 | default ListenableFuture<PreparedStatement> prepareAsync(String statement) { |
49 | 64 | return this.prepareAsync(SimpleStatement.newInstance(statement)); |
50 | 65 | } |
66 | + | |
67 | + static AsyncResultSet getSafe(ListenableFuture<AsyncResultSet> future) { | |
68 | + try { | |
69 | + return future.get(); | |
70 | + } catch (InterruptedException | ExecutionException e) { | |
71 | + throw new IllegalStateException(e); | |
72 | + } | |
73 | + } | |
51 | 74 | } | ... | ... |
... | ... | @@ -13,9 +13,9 @@ |
13 | 13 | } |
14 | 14 | }, |
15 | 15 | "@azure/amqp-common": { |
16 | - "version": "1.0.0-preview.13", | |
17 | - "resolved": "https://registry.npmjs.org/@azure/amqp-common/-/amqp-common-1.0.0-preview.13.tgz", | |
18 | - "integrity": "sha512-v19NGXFm8Hzr2bj/DSWYc2anaDcoAeFQXJGuBT8QO7eS13vaELQNGaynOGipEcI313A1778R/FFCk4o+dylIiw==", | |
16 | + "version": "1.0.0-preview.15", | |
17 | + "resolved": "https://registry.npmjs.org/@azure/amqp-common/-/amqp-common-1.0.0-preview.15.tgz", | |
18 | + "integrity": "sha512-EoxNsVR7yLioNKRz5JBwQAE9pEdPVGCmmQbPKkZHP72vE5NhaLnOwHOCrk/311cuhJ8aQ60eiLUtF9J2XrEZyA==", | |
19 | 19 | "requires": { |
20 | 20 | "@types/async-lock": "^1.1.0", |
21 | 21 | "@types/is-buffer": "^2.0.0", |
... | ... | @@ -53,9 +53,9 @@ |
53 | 53 | } |
54 | 54 | }, |
55 | 55 | "@azure/core-http": { |
56 | - "version": "1.1.1", | |
57 | - "resolved": "https://registry.npmjs.org/@azure/core-http/-/core-http-1.1.1.tgz", | |
58 | - "integrity": "sha512-yBxH5CtYaCj0f1CKoi3OjQw5C5Go8TbgNA6Q2rX7XsDpN2eeKu0n3kRvzZnKW+brtO1u3YnBBuBLF2KcGoZv6g==", | |
56 | + "version": "1.1.2", | |
57 | + "resolved": "https://registry.npmjs.org/@azure/core-http/-/core-http-1.1.2.tgz", | |
58 | + "integrity": "sha512-xeZpTs6caBIrRipqZs70jgrA+mAFxII5XrBzbOCELPs18n4QWfchB20F94ITAk3GuFVDaSBsOhVL3GP1J+ncGg==", | |
59 | 59 | "requires": { |
60 | 60 | "@azure/abort-controller": "^1.0.0", |
61 | 61 | "@azure/core-auth": "^1.1.2", |
... | ... | @@ -116,11 +116,11 @@ |
116 | 116 | } |
117 | 117 | }, |
118 | 118 | "@azure/service-bus": { |
119 | - "version": "1.1.6", | |
120 | - "resolved": "https://registry.npmjs.org/@azure/service-bus/-/service-bus-1.1.6.tgz", | |
121 | - "integrity": "sha512-eCJXcJZGWdlVwLEqMcoIqtUrh/NtyFcDDfq/y8gdCOy3Dzuv8JkPTxjdjcxDthwG9mc5Qter3dGOTwh0U8gwiw==", | |
119 | + "version": "1.1.7", | |
120 | + "resolved": "https://registry.npmjs.org/@azure/service-bus/-/service-bus-1.1.7.tgz", | |
121 | + "integrity": "sha512-wns3egBrP6UyT9CIPkM66KsOVJwit7VJT0P/t8PPPfUaO6yx3bEeZyVDq6WMiibnbIkgHtW85xXml4WDb+nPMw==", | |
122 | 122 | "requires": { |
123 | - "@azure/amqp-common": "1.0.0-preview.13", | |
123 | + "@azure/amqp-common": "1.0.0-preview.15", | |
124 | 124 | "@azure/core-http": "^1.0.0", |
125 | 125 | "@opentelemetry/types": "^0.2.0", |
126 | 126 | "@types/is-buffer": "^2.0.0", |
... | ... | @@ -130,7 +130,7 @@ |
130 | 130 | "is-buffer": "^2.0.3", |
131 | 131 | "long": "^4.0.0", |
132 | 132 | "process": "^0.11.10", |
133 | - "rhea": "^1.0.18", | |
133 | + "rhea": "^1.0.21", | |
134 | 134 | "rhea-promise": "^0.1.15", |
135 | 135 | "tslib": "^1.10.0" |
136 | 136 | }, |
... | ... | @@ -151,18 +151,18 @@ |
151 | 151 | } |
152 | 152 | }, |
153 | 153 | "@babel/parser": { |
154 | - "version": "7.8.4", | |
155 | - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.8.4.tgz", | |
156 | - "integrity": "sha512-0fKu/QqildpXmPVaRBoXOlyBb3MC+J0A66x97qEfLOMkn3u6nfY5esWogQwi/K0BjASYy4DbnsEWnpNL6qT5Mw==", | |
154 | + "version": "7.9.6", | |
155 | + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.9.6.tgz", | |
156 | + "integrity": "sha512-AoeIEJn8vt+d/6+PXDRPaksYhnlbMIiejioBZvvMQsOjW/JYK6k/0dKnvvP3EhK5GfMBWDPtrxRtegWdAcdq9Q==", | |
157 | 157 | "dev": true |
158 | 158 | }, |
159 | 159 | "@babel/runtime": { |
160 | - "version": "7.8.4", | |
161 | - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.8.4.tgz", | |
162 | - "integrity": "sha512-neAp3zt80trRVBI1x0azq6c57aNBqYZH8KhMm3TaB7wEI5Q4A2SHfBHE8w9gOhI/lrqxtEbXZgQIrHP+wvSGwQ==", | |
160 | + "version": "7.9.6", | |
161 | + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.9.6.tgz", | |
162 | + "integrity": "sha512-64AF1xY3OAkFHqOb9s4jpgk1Mm5vDZ4L3acHvAml+53nO1XbXLuDodsVpO4OIUsmemlUHMxNdYMNJmsvOwLrvQ==", | |
163 | 163 | "dev": true, |
164 | 164 | "requires": { |
165 | - "regenerator-runtime": "^0.13.2" | |
165 | + "regenerator-runtime": "^0.13.4" | |
166 | 166 | } |
167 | 167 | }, |
168 | 168 | "@google-cloud/paginator": { |
... | ... | @@ -190,9 +190,9 @@ |
190 | 190 | "integrity": "sha512-VccZDcOql77obTnFh0TbNED/6ZbbmHDf8UMNnzO1d5g9V0Htfm4k5cllY8P1tJsRKC3zWYGRLaViiupcgVjBoQ==" |
191 | 191 | }, |
192 | 192 | "@google-cloud/pubsub": { |
193 | - "version": "1.7.2", | |
194 | - "resolved": "https://registry.npmjs.org/@google-cloud/pubsub/-/pubsub-1.7.2.tgz", | |
195 | - "integrity": "sha512-/TziioDSV4FS4wKF1sIaQ+1gvE+um83oHz1nRsZ3L87uWSoOciBjJAcocgPjqrpnW441+Nuw4w0QdSUV1Lka/g==", | |
193 | + "version": "1.7.3", | |
194 | + "resolved": "https://registry.npmjs.org/@google-cloud/pubsub/-/pubsub-1.7.3.tgz", | |
195 | + "integrity": "sha512-v+KdeaOS17WtHnsDf2bPGxKDT9HIRPYo3n+WsAEmvAzDHnh8q65mFcuYoQxuy2iRhmN/1ql2a0UU2tAAL7XZ8Q==", | |
196 | 196 | "requires": { |
197 | 197 | "@google-cloud/paginator": "^2.0.0", |
198 | 198 | "@google-cloud/precise-date": "^1.0.0", |
... | ... | @@ -372,9 +372,9 @@ |
372 | 372 | "integrity": "sha512-5tXH6Bx/kNGd3MgffdmP4dy2Z+G4eaXw0SE81Tq3BNadtnMR5/ySMzX4SLEzHJzSmPNn4HIdpQsBvXMUykr58w==" |
373 | 373 | }, |
374 | 374 | "@types/node": { |
375 | - "version": "13.13.4", | |
376 | - "resolved": "https://registry.npmjs.org/@types/node/-/node-13.13.4.tgz", | |
377 | - "integrity": "sha512-x26ur3dSXgv5AwKS0lNfbjpCakGIduWU1DU91Zz58ONRWrIKGunmZBNv4P7N+e27sJkiGDsw/3fT4AtsqQBrBA==" | |
375 | + "version": "14.0.1", | |
376 | + "resolved": "https://registry.npmjs.org/@types/node/-/node-14.0.1.tgz", | |
377 | + "integrity": "sha512-FAYBGwC+W6F9+huFIDtn43cpy7+SzG+atzRiTfdp3inUKL2hXnd4rG8hylJLIh4+hqrQy1P17kvJByE/z825hA==" | |
378 | 378 | }, |
379 | 379 | "@types/node-fetch": { |
380 | 380 | "version": "2.5.7", |
... | ... | @@ -449,9 +449,9 @@ |
449 | 449 | } |
450 | 450 | }, |
451 | 451 | "amqplib": { |
452 | - "version": "0.5.5", | |
453 | - "resolved": "https://registry.npmjs.org/amqplib/-/amqplib-0.5.5.tgz", | |
454 | - "integrity": "sha512-sWx1hbfHbyKMw6bXOK2k6+lHL8TESWxjAx5hG8fBtT7wcxoXNIsFxZMnFyBjxt3yL14vn7WqBDe5U6BGOadtLg==", | |
452 | + "version": "0.5.6", | |
453 | + "resolved": "https://registry.npmjs.org/amqplib/-/amqplib-0.5.6.tgz", | |
454 | + "integrity": "sha512-J4TR0WAMPBHN+tgTuhNsSObfM9eTVTZm/FNw0LyaGfbiLsBxqSameDNYpChUFXW4bnTKHDXy0ab+nuLhumnRrQ==", | |
455 | 455 | "requires": { |
456 | 456 | "bitsyntax": "~0.1.0", |
457 | 457 | "bluebird": "^3.5.2", |
... | ... | @@ -610,9 +610,9 @@ |
610 | 610 | "integrity": "sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ==" |
611 | 611 | }, |
612 | 612 | "async-lock": { |
613 | - "version": "1.2.2", | |
614 | - "resolved": "https://registry.npmjs.org/async-lock/-/async-lock-1.2.2.tgz", | |
615 | - "integrity": "sha512-uczz62z2fMWOFbyo6rG4NlV2SdxugJT6sZA2QcfB1XaSjEiOh8CuOb/TttyMnYQCda6nkWecJe465tGQDPJiKw==" | |
613 | + "version": "1.2.4", | |
614 | + "resolved": "https://registry.npmjs.org/async-lock/-/async-lock-1.2.4.tgz", | |
615 | + "integrity": "sha512-UBQJC2pbeyGutIfYmErGc9RaJYnpZ1FHaxuKwb0ahvGiiCkPUf3p67Io+YLPmmv3RHY+mF6JEtNW8FlHsraAaA==" | |
616 | 616 | }, |
617 | 617 | "asynckit": { |
618 | 618 | "version": "0.4.0", |
... | ... | @@ -626,9 +626,9 @@ |
626 | 626 | "dev": true |
627 | 627 | }, |
628 | 628 | "aws-sdk": { |
629 | - "version": "2.669.0", | |
630 | - "resolved": "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.669.0.tgz", | |
631 | - "integrity": "sha512-kuVcSRpDzvkgmeSmMX6Q32eTOb8UeihhUdavMrvUOP6fzSU19cNWS9HAIkYOi/jrEDK85cCZxXjxqE3JGZIGcw==", | |
629 | + "version": "2.677.0", | |
630 | + "resolved": "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.677.0.tgz", | |
631 | + "integrity": "sha512-vzQWRh1sgM0HRNmbLXgxnFPySLQrtSNgs9dNQsksGiYrJtf1wYjJSh4UHhekeyMuorQqef3m4AY0vFWsWyZSMg==", | |
632 | 632 | "requires": { |
633 | 633 | "buffer": "4.9.1", |
634 | 634 | "events": "1.1.1", |
... | ... | @@ -1136,11 +1136,11 @@ |
1136 | 1136 | "dev": true |
1137 | 1137 | }, |
1138 | 1138 | "config": { |
1139 | - "version": "3.2.5", | |
1140 | - "resolved": "https://registry.npmjs.org/config/-/config-3.2.5.tgz", | |
1141 | - "integrity": "sha512-8itpjyR01lAJanhAlPncBngYRZez/LoRLW8wnGi+6SEcsUyA1wvHvbpIrAJYDJT+W9BScnj4mYoUgbtp9I+0+Q==", | |
1139 | + "version": "3.3.1", | |
1140 | + "resolved": "https://registry.npmjs.org/config/-/config-3.3.1.tgz", | |
1141 | + "integrity": "sha512-+2/KaaaAzdwUBE3jgZON11L1ggLLhpf2FsGrfqYFHZW22ySGv/HqYIXrBwKKvn+XZh1UBUjHwAcrfsSkSygT+Q==", | |
1142 | 1142 | "requires": { |
1143 | - "json5": "^1.0.1" | |
1143 | + "json5": "^2.1.1" | |
1144 | 1144 | } |
1145 | 1145 | }, |
1146 | 1146 | "configstore": { |
... | ... | @@ -1680,16 +1680,17 @@ |
1680 | 1680 | "integrity": "sha512-8UEa58QDLauDNfpbrX55Q9jrGHThw2ZMdOky5Gl1CDtVeJDPVrG4Jxx1N8jw2gkWaff5UUuX1KJd+9zGe2B+ZA==" |
1681 | 1681 | }, |
1682 | 1682 | "fast-glob": { |
1683 | - "version": "3.1.1", | |
1684 | - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.1.1.tgz", | |
1685 | - "integrity": "sha512-nTCREpBY8w8r+boyFYAx21iL6faSsQynliPHM4Uf56SbkyohCNxpVPEH9xrF5TXKy+IsjkPUHDKiUkzBVRXn9g==", | |
1683 | + "version": "3.2.2", | |
1684 | + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.2.tgz", | |
1685 | + "integrity": "sha512-UDV82o4uQyljznxwMxyVRJgZZt3O5wENYojjzbaGEGZgeOxkLFf+V4cnUD+krzb2F72E18RhamkMZ7AdeggF7A==", | |
1686 | 1686 | "dev": true, |
1687 | 1687 | "requires": { |
1688 | 1688 | "@nodelib/fs.stat": "^2.0.2", |
1689 | 1689 | "@nodelib/fs.walk": "^1.2.3", |
1690 | 1690 | "glob-parent": "^5.1.0", |
1691 | 1691 | "merge2": "^1.3.0", |
1692 | - "micromatch": "^4.0.2" | |
1692 | + "micromatch": "^4.0.2", | |
1693 | + "picomatch": "^2.2.1" | |
1693 | 1694 | }, |
1694 | 1695 | "dependencies": { |
1695 | 1696 | "braces": { |
... | ... | @@ -1711,9 +1712,9 @@ |
1711 | 1712 | } |
1712 | 1713 | }, |
1713 | 1714 | "glob-parent": { |
1714 | - "version": "5.1.0", | |
1715 | - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.0.tgz", | |
1716 | - "integrity": "sha512-qjtRgnIVmOfnKUE3NJAQEdk+lKrxfw8t5ke7SXtfMTHcjsBfOfWXCQfdb30zfDoZQ2IRSIiidmjtbHZPZ++Ihw==", | |
1715 | + "version": "5.1.1", | |
1716 | + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.1.tgz", | |
1717 | + "integrity": "sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ==", | |
1717 | 1718 | "dev": true, |
1718 | 1719 | "requires": { |
1719 | 1720 | "is-glob": "^4.0.1" |
... | ... | @@ -1768,12 +1769,12 @@ |
1768 | 1769 | "integrity": "sha512-5rQdinSsycpzvAoHga2EDn+LRX1d5xLFsuNG0Kg61JrAT/tASXcLL0nf/33v+sAxlQcfYmWbTURa1mmAf55jGw==" |
1769 | 1770 | }, |
1770 | 1771 | "fastq": { |
1771 | - "version": "1.6.0", | |
1772 | - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.6.0.tgz", | |
1773 | - "integrity": "sha512-jmxqQ3Z/nXoeyDmWAzF9kH1aGZSis6e/SbfPmJpUnyZ0ogr6iscHQaml4wsEepEWSdtmpy+eVXmCRIMpxaXqOA==", | |
1772 | + "version": "1.8.0", | |
1773 | + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.8.0.tgz", | |
1774 | + "integrity": "sha512-SMIZoZdLh/fgofivvIkmknUXyPnvxRE3DhtZ5Me3Mrsk5gyPL42F0xr51TdRXskBxHfMp+07bcYzfsYEsSQA9Q==", | |
1774 | 1775 | "dev": true, |
1775 | 1776 | "requires": { |
1776 | - "reusify": "^1.0.0" | |
1777 | + "reusify": "^1.0.4" | |
1777 | 1778 | } |
1778 | 1779 | }, |
1779 | 1780 | "fecha": { |
... | ... | @@ -3038,11 +3039,18 @@ |
3038 | 3039 | "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=" |
3039 | 3040 | }, |
3040 | 3041 | "json5": { |
3041 | - "version": "1.0.1", | |
3042 | - "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", | |
3043 | - "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", | |
3042 | + "version": "2.1.3", | |
3043 | + "resolved": "https://registry.npmjs.org/json5/-/json5-2.1.3.tgz", | |
3044 | + "integrity": "sha512-KXPvOm8K9IJKFM0bmdn8QXh7udDh1g/giieX0NLCaMnb4hEiVFqnop2ImTXCc5e0/oHz3LTqmHGtExn5hfMkOA==", | |
3044 | 3045 | "requires": { |
3045 | - "minimist": "^1.2.0" | |
3046 | + "minimist": "^1.2.5" | |
3047 | + }, | |
3048 | + "dependencies": { | |
3049 | + "minimist": { | |
3050 | + "version": "1.2.5", | |
3051 | + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", | |
3052 | + "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==" | |
3053 | + } | |
3046 | 3054 | } |
3047 | 3055 | }, |
3048 | 3056 | "jsonfile": { |
... | ... | @@ -3269,7 +3277,8 @@ |
3269 | 3277 | "minimist": { |
3270 | 3278 | "version": "1.2.0", |
3271 | 3279 | "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", |
3272 | - "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=" | |
3280 | + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", | |
3281 | + "dev": true | |
3273 | 3282 | }, |
3274 | 3283 | "mixin-deep": { |
3275 | 3284 | "version": "1.3.2", |
... | ... | @@ -3293,18 +3302,18 @@ |
3293 | 3302 | } |
3294 | 3303 | }, |
3295 | 3304 | "mkdirp": { |
3296 | - "version": "0.5.1", | |
3297 | - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", | |
3298 | - "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", | |
3305 | + "version": "0.5.5", | |
3306 | + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", | |
3307 | + "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", | |
3299 | 3308 | "dev": true, |
3300 | 3309 | "requires": { |
3301 | - "minimist": "0.0.8" | |
3310 | + "minimist": "^1.2.5" | |
3302 | 3311 | }, |
3303 | 3312 | "dependencies": { |
3304 | 3313 | "minimist": { |
3305 | - "version": "0.0.8", | |
3306 | - "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", | |
3307 | - "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", | |
3314 | + "version": "1.2.5", | |
3315 | + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", | |
3316 | + "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", | |
3308 | 3317 | "dev": true |
3309 | 3318 | } |
3310 | 3319 | } |
... | ... | @@ -3629,9 +3638,9 @@ |
3629 | 3638 | "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=" |
3630 | 3639 | }, |
3631 | 3640 | "picomatch": { |
3632 | - "version": "2.2.1", | |
3633 | - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.1.tgz", | |
3634 | - "integrity": "sha512-ISBaA8xQNmwELC7eOjqFKMESB2VIqt4PPDD0nsS95b/9dZXvVKOlz9keMSnoGGKcOHXfTvDD6WMaRoSc9UuhRA==", | |
3641 | + "version": "2.2.2", | |
3642 | + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.2.tgz", | |
3643 | + "integrity": "sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==", | |
3635 | 3644 | "dev": true |
3636 | 3645 | }, |
3637 | 3646 | "pify": { |
... | ... | @@ -3641,23 +3650,23 @@ |
3641 | 3650 | "dev": true |
3642 | 3651 | }, |
3643 | 3652 | "pkg": { |
3644 | - "version": "4.4.3", | |
3645 | - "resolved": "https://registry.npmjs.org/pkg/-/pkg-4.4.3.tgz", | |
3646 | - "integrity": "sha512-1M0KNVLxNUzr0CGMhccPxx02G05GL3h9czbQGLswRB2gOvHeKAbld+1S5SGDNLOoFt+IYNNxqHtBhZA6Rer7QQ==", | |
3653 | + "version": "4.4.8", | |
3654 | + "resolved": "https://registry.npmjs.org/pkg/-/pkg-4.4.8.tgz", | |
3655 | + "integrity": "sha512-Fqqv0iaX48U3CFZxd6Dq6JKe7BrAWbgRAqMJkz/m8W3H5cqJ6suvsUWe5AJPRlN/AhbBYXBJ0XG9QlYPTXcVFA==", | |
3647 | 3656 | "dev": true, |
3648 | 3657 | "requires": { |
3649 | - "@babel/parser": "^7.7.5", | |
3650 | - "@babel/runtime": "^7.7.5", | |
3658 | + "@babel/parser": "^7.9.4", | |
3659 | + "@babel/runtime": "^7.9.2", | |
3651 | 3660 | "chalk": "^3.0.0", |
3652 | - "escodegen": "^1.13.0", | |
3661 | + "escodegen": "^1.14.1", | |
3653 | 3662 | "fs-extra": "^8.1.0", |
3654 | 3663 | "globby": "^11.0.0", |
3655 | 3664 | "into-stream": "^5.1.1", |
3656 | - "minimist": "^1.2.0", | |
3665 | + "minimist": "^1.2.5", | |
3657 | 3666 | "multistream": "^2.1.1", |
3658 | - "pkg-fetch": "^2.6.4", | |
3667 | + "pkg-fetch": "^2.6.7", | |
3659 | 3668 | "progress": "^2.0.3", |
3660 | - "resolve": "^1.15.0", | |
3669 | + "resolve": "^1.15.1", | |
3661 | 3670 | "stream-meter": "^1.0.4" |
3662 | 3671 | }, |
3663 | 3672 | "dependencies": { |
... | ... | @@ -3713,6 +3722,12 @@ |
3713 | 3722 | "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", |
3714 | 3723 | "dev": true |
3715 | 3724 | }, |
3725 | + "minimist": { | |
3726 | + "version": "1.2.5", | |
3727 | + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", | |
3728 | + "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", | |
3729 | + "dev": true | |
3730 | + }, | |
3716 | 3731 | "supports-color": { |
3717 | 3732 | "version": "7.1.0", |
3718 | 3733 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz", |
... | ... | @@ -3725,17 +3740,17 @@ |
3725 | 3740 | } |
3726 | 3741 | }, |
3727 | 3742 | "pkg-fetch": { |
3728 | - "version": "2.6.4", | |
3729 | - "resolved": "https://registry.npmjs.org/pkg-fetch/-/pkg-fetch-2.6.4.tgz", | |
3730 | - "integrity": "sha512-4j4jiuo6RRIuD9e9xUE6OQYnIkQCArZjkHXNYsSJjxhJeiHE16MA+rENMblvGLbeWsTY3BPfcYVCGFXzpfJetA==", | |
3743 | + "version": "2.6.8", | |
3744 | + "resolved": "https://registry.npmjs.org/pkg-fetch/-/pkg-fetch-2.6.8.tgz", | |
3745 | + "integrity": "sha512-CFG7jOeVD38lltLGA7xCJxYsD//GKLjl1P9tc/n9By2a4WEHQjfkBMrYdMS8WOHVP+r9L20fsZNbaKcubDAiQg==", | |
3731 | 3746 | "dev": true, |
3732 | 3747 | "requires": { |
3733 | - "@babel/runtime": "^7.7.5", | |
3748 | + "@babel/runtime": "^7.9.2", | |
3734 | 3749 | "byline": "^5.0.0", |
3735 | 3750 | "chalk": "^3.0.0", |
3736 | 3751 | "expand-template": "^2.0.3", |
3737 | 3752 | "fs-extra": "^8.1.0", |
3738 | - "minimist": "^1.2.0", | |
3753 | + "minimist": "^1.2.5", | |
3739 | 3754 | "progress": "^2.0.3", |
3740 | 3755 | "request": "^2.88.0", |
3741 | 3756 | "request-progress": "^3.0.0", |
... | ... | @@ -3795,6 +3810,12 @@ |
3795 | 3810 | "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", |
3796 | 3811 | "dev": true |
3797 | 3812 | }, |
3813 | + "minimist": { | |
3814 | + "version": "1.2.5", | |
3815 | + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", | |
3816 | + "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", | |
3817 | + "dev": true | |
3818 | + }, | |
3798 | 3819 | "supports-color": { |
3799 | 3820 | "version": "7.1.0", |
3800 | 3821 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz", |
... | ... | @@ -3858,6 +3879,13 @@ |
3858 | 3879 | "@types/long": "^4.0.1", |
3859 | 3880 | "@types/node": "^13.7.0", |
3860 | 3881 | "long": "^4.0.0" |
3882 | + }, | |
3883 | + "dependencies": { | |
3884 | + "@types/node": { | |
3885 | + "version": "13.13.6", | |
3886 | + "resolved": "https://registry.npmjs.org/@types/node/-/node-13.13.6.tgz", | |
3887 | + "integrity": "sha512-zqRj8ugfROCjXCNbmPBe2mmQ0fJWP9lQaN519hwunOgpHgVykme4G6FW95++dyNFDvJUk4rtExkVkL0eciu5NA==" | |
3888 | + } | |
3861 | 3889 | } |
3862 | 3890 | }, |
3863 | 3891 | "pseudomap": { |
... | ... | @@ -3963,9 +3991,9 @@ |
3963 | 3991 | } |
3964 | 3992 | }, |
3965 | 3993 | "regenerator-runtime": { |
3966 | - "version": "0.13.3", | |
3967 | - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.3.tgz", | |
3968 | - "integrity": "sha512-naKIZz2GQ8JWh///G7L3X6LaQUAMp2lvb1rvwwsURe/VXwD6VMfr+/1NuNw3ag8v2kY1aQ/go5SNn79O9JU7yw==", | |
3994 | + "version": "0.13.5", | |
3995 | + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.5.tgz", | |
3996 | + "integrity": "sha512-ZS5w8CpKFinUzOwW3c83oPeVXoNsrLsaCoLtJvAClH135j/R77RuymhiSErhm2lKcwSCIpmvIWSbDkIfAqKQlA==", | |
3969 | 3997 | "dev": true |
3970 | 3998 | }, |
3971 | 3999 | "regex-not": { |
... | ... | @@ -4057,9 +4085,9 @@ |
4057 | 4085 | "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=" |
4058 | 4086 | }, |
4059 | 4087 | "resolve": { |
4060 | - "version": "1.15.1", | |
4061 | - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.15.1.tgz", | |
4062 | - "integrity": "sha512-84oo6ZTtoTUpjgNEr5SJyzQhzL72gaRodsSfyxC/AXRvwu0Yse9H8eF9IpGo7b8YetZhlI6v7ZQ6bKBFV/6S7w==", | |
4088 | + "version": "1.17.0", | |
4089 | + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.17.0.tgz", | |
4090 | + "integrity": "sha512-ic+7JYiV8Vi2yzQGFWOkiZD5Z9z7O2Zhm9XMaTxdJExKasieFCr+yXZ/WmXsckHiKl12ar0y6XiXDx3m4RHn1w==", | |
4063 | 4091 | "dev": true, |
4064 | 4092 | "requires": { |
4065 | 4093 | "path-parse": "^1.0.6" |
... | ... | @@ -4103,9 +4131,9 @@ |
4103 | 4131 | "dev": true |
4104 | 4132 | }, |
4105 | 4133 | "rhea": { |
4106 | - "version": "1.0.20", | |
4107 | - "resolved": "https://registry.npmjs.org/rhea/-/rhea-1.0.20.tgz", | |
4108 | - "integrity": "sha512-qj4LSEykJ0SEYESQLg9Vee6VXH5xHN1pYj7ozPeUk+l+S1OaGKx1FugAu+g+3pPwK46WXV1PJD9XiRx8+tS4cw==", | |
4134 | + "version": "1.0.21", | |
4135 | + "resolved": "https://registry.npmjs.org/rhea/-/rhea-1.0.21.tgz", | |
4136 | + "integrity": "sha512-9ddxyJR0nlWmynukzZTWN+bSYWu7KLHVMkIH/7PpFG5RHfV5t7zXIfZ6rqJSJe9wBAgnNr2Xz41KM2nPujWiFQ==", | |
4109 | 4137 | "requires": { |
4110 | 4138 | "debug": "0.8.0 - 3.5.0" |
4111 | 4139 | } |
... | ... | @@ -4670,9 +4698,9 @@ |
4670 | 4698 | "integrity": "sha512-XrHUvV5HpdLmIj4uVMxHggLbFSZYIn7HEWsqePZcI50pco+MPqJ50wMGY794X7AOOhxOBAjbkqfAbEe/QMp2Lw==" |
4671 | 4699 | }, |
4672 | 4700 | "tslib": { |
4673 | - "version": "1.11.1", | |
4674 | - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.11.1.tgz", | |
4675 | - "integrity": "sha512-aZW88SY8kQbU7gpV19lN24LtXh/yD4ZZg6qieAJDDg+YBsJcSmLGK9QpnUjAKVG/xefmvJGd1WUmfpT/g6AJGA==" | |
4701 | + "version": "1.13.0", | |
4702 | + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.13.0.tgz", | |
4703 | + "integrity": "sha512-i/6DQjL8Xf3be4K/E6Wgpekn5Qasl1usyw++dAA35Ue5orEn65VIxOA+YvNNl9HV3qv70T7CNwjODHZrLwvd1Q==" | |
4676 | 4704 | }, |
4677 | 4705 | "tunnel": { |
4678 | 4706 | "version": "0.0.6", | ... | ... |
... | ... | @@ -12,14 +12,14 @@ |
12 | 12 | "start-prod": "NODE_ENV=production nodemon server.js" |
13 | 13 | }, |
14 | 14 | "dependencies": { |
15 | - "config": "^3.2.2", | |
15 | + "@azure/service-bus": "^1.1.7", | |
16 | + "@google-cloud/pubsub": "^1.7.3", | |
17 | + "amqplib": "^0.5.6", | |
18 | + "aws-sdk": "^2.677.0", | |
19 | + "azure-sb": "^0.11.1", | |
20 | + "config": "^3.3.1", | |
16 | 21 | "js-yaml": "^3.12.0", |
17 | 22 | "kafkajs": "^1.12.0", |
18 | - "@google-cloud/pubsub": "^1.7.1", | |
19 | - "aws-sdk": "^2.663.0", | |
20 | - "amqplib": "^0.5.5", | |
21 | - "@azure/service-bus": "^1.1.6", | |
22 | - "azure-sb": "^0.11.1", | |
23 | 23 | "long": "^4.0.0", |
24 | 24 | "uuid-parse": "^1.0.0", |
25 | 25 | "uuid-random": "^1.3.0", |
... | ... | @@ -40,7 +40,7 @@ |
40 | 40 | "devDependencies": { |
41 | 41 | "fs-extra": "^6.0.1", |
42 | 42 | "nodemon": "^1.17.5", |
43 | - "pkg": "^4.4.0" | |
43 | + "pkg": "^4.4.8" | |
44 | 44 | }, |
45 | 45 | "pkg": { |
46 | 46 | "assets": [ | ... | ... |
... | ... | @@ -100,7 +100,7 @@ function AwsSqsProducer() { |
100 | 100 | const params = { |
101 | 101 | MaxNumberOfMessages: 10, |
102 | 102 | QueueUrl: requestQueueURL, |
103 | - WaitTimeSeconds: poolInterval / 1000 | |
103 | + WaitTimeSeconds: pollInterval / 1000 | |
104 | 104 | }; |
105 | 105 | while (!stopped) { |
106 | 106 | let pollStartTs = new Date().getTime(); | ... | ... |
... | ... | @@ -68,9 +68,8 @@ function RabbitMqProducer() { |
68 | 68 | (async () => { |
69 | 69 | try { |
70 | 70 | logger.info('Starting ThingsBoard JavaScript Executor Microservice...'); |
71 | - const url = `amqp://${host}:${port}${vhost}`; | |
71 | + const url = `amqp://${username}:${password}@${host}:${port}${vhost}`; | |
72 | 72 | |
73 | - amqp.credentials.amqplain(username, password); | |
74 | 73 | connection = await new Promise((resolve, reject) => { |
75 | 74 | amqp.connect(url, function (err, connection) { |
76 | 75 | if (err) { | ... | ... |
... | ... | @@ -61,15 +61,14 @@ |
61 | 61 | <akka.version>2.6.3</akka.version> |
62 | 62 | <californium.version>1.0.2</californium.version> |
63 | 63 | <gson.version>2.6.2</gson.version> |
64 | - <velocity.version>1.7</velocity.version> | |
65 | - <velocity-tools.version>2.0</velocity-tools.version> | |
64 | + <freemarker.version>2.3.30</freemarker.version> | |
66 | 65 | <mail.version>1.6.2</mail.version> |
67 | 66 | <curator.version>4.2.0</curator.version> |
68 | 67 | <zookeeper.version>3.5.5</zookeeper.version> |
69 | 68 | <protobuf.version>3.11.4</protobuf.version> |
70 | 69 | <grpc.version>1.22.1</grpc.version> |
71 | 70 | <lombok.version>1.16.18</lombok.version> |
72 | - <paho.client.version>1.1.0</paho.client.version> | |
71 | + <paho.client.version>1.2.4</paho.client.version> | |
73 | 72 | <netty.version>4.1.49.Final</netty.version> |
74 | 73 | <os-maven-plugin.version>1.5.0</os-maven-plugin.version> |
75 | 74 | <rabbitmq.version>4.8.0</rabbitmq.version> |
... | ... | @@ -565,28 +564,9 @@ |
565 | 564 | <version>${jjwt.version}</version> |
566 | 565 | </dependency> |
567 | 566 | <dependency> |
568 | - <groupId>org.apache.velocity</groupId> | |
569 | - <artifactId>velocity</artifactId> | |
570 | - <version>${velocity.version}</version> | |
571 | - </dependency> | |
572 | - <dependency> | |
573 | - <groupId>org.apache.velocity</groupId> | |
574 | - <artifactId>velocity-tools</artifactId> | |
575 | - <version>${velocity-tools.version}</version> | |
576 | - <exclusions> | |
577 | - <exclusion> | |
578 | - <groupId>javax.servlet</groupId> | |
579 | - <artifactId>servlet-api</artifactId> | |
580 | - </exclusion> | |
581 | - <exclusion> | |
582 | - <groupId>dom4j</groupId> | |
583 | - <artifactId>dom4j</artifactId> | |
584 | - </exclusion> | |
585 | - <exclusion> | |
586 | - <groupId>antlr</groupId> | |
587 | - <artifactId>antlr</artifactId> | |
588 | - </exclusion> | |
589 | - </exclusions> | |
567 | + <groupId>org.freemarker</groupId> | |
568 | + <artifactId>freemarker</artifactId> | |
569 | + <version>${freemarker.version}</version> | |
590 | 570 | </dependency> |
591 | 571 | <dependency> |
592 | 572 | <groupId>org.yaml</groupId> |
... | ... | @@ -975,11 +955,6 @@ |
975 | 955 | <version>${commons-collections.version}</version> |
976 | 956 | </dependency> |
977 | 957 | <dependency> |
978 | - <groupId>org.yaml</groupId> | |
979 | - <artifactId>snakeyaml</artifactId> | |
980 | - <version>${snakeyaml.version}</version> | |
981 | - </dependency> | |
982 | - <dependency> | |
983 | 958 | <groupId>org.apache.struts</groupId> |
984 | 959 | <artifactId>struts-core</artifactId> |
985 | 960 | <version>${struts.version}</version> | ... | ... |
... | ... | @@ -147,6 +147,16 @@ public class TbSendEmailNode implements TbNode { |
147 | 147 | if (this.config.isEnableTls() && StringUtils.isNoneEmpty(this.config.getTlsVersion())) { |
148 | 148 | javaMailProperties.put(MAIL_PROP + protocol + ".ssl.protocols", this.config.getTlsVersion()); |
149 | 149 | } |
150 | + if (this.config.isEnableProxy()) { | |
151 | + javaMailProperties.put(MAIL_PROP + protocol + ".proxy.host", config.getProxyHost()); | |
152 | + javaMailProperties.put(MAIL_PROP + protocol + ".proxy.port", config.getProxyPort()); | |
153 | + if (StringUtils.isNoneEmpty(config.getProxyUser())) { | |
154 | + javaMailProperties.put(MAIL_PROP + protocol + ".proxy.user", config.getProxyUser()); | |
155 | + } | |
156 | + if (StringUtils.isNoneEmpty(config.getProxyPassword())) { | |
157 | + javaMailProperties.put(MAIL_PROP + protocol + ".proxy.password", config.getProxyPassword()); | |
158 | + } | |
159 | + } | |
150 | 160 | return javaMailProperties; |
151 | 161 | } |
152 | 162 | } | ... | ... |
... | ... | @@ -30,6 +30,11 @@ public class TbSendEmailNodeConfiguration implements NodeConfiguration { |
30 | 30 | private int timeout; |
31 | 31 | private boolean enableTls; |
32 | 32 | private String tlsVersion; |
33 | + private boolean enableProxy; | |
34 | + private String proxyHost; | |
35 | + private String proxyPort; | |
36 | + private String proxyUser; | |
37 | + private String proxyPassword; | |
33 | 38 | |
34 | 39 | @Override |
35 | 40 | public TbSendEmailNodeConfiguration defaultConfiguration() { |
... | ... | @@ -41,6 +46,7 @@ public class TbSendEmailNodeConfiguration implements NodeConfiguration { |
41 | 46 | configuration.setTimeout(10000); |
42 | 47 | configuration.setEnableTls(false); |
43 | 48 | configuration.setTlsVersion("TLSv1.2"); |
49 | + configuration.setEnableProxy(false); | |
44 | 50 | return configuration; |
45 | 51 | } |
46 | 52 | } | ... | ... |
... | ... | @@ -48,7 +48,7 @@ public class TbSynchronizationBeginNode implements TbNode { |
48 | 48 | |
49 | 49 | @Override |
50 | 50 | public void onMsg(TbContext ctx, TbMsg msg) { |
51 | - log.warn("Synchronization Start/End nodes are deprecated since TB 2.5. Use queue with submit strategy SEQUENTIAL_WITHIN_ORIGINATOR instead."); | |
51 | + log.warn("Synchronization Start/End nodes are deprecated since TB 2.5. Use queue with submit strategy SEQUENTIAL_BY_ORIGINATOR instead."); | |
52 | 52 | ctx.tellSuccess(msg); |
53 | 53 | } |
54 | 54 | ... | ... |
... | ... | @@ -49,7 +49,7 @@ public class TbSynchronizationEndNode implements TbNode { |
49 | 49 | |
50 | 50 | @Override |
51 | 51 | public void onMsg(TbContext ctx, TbMsg msg) { |
52 | - log.warn("Synchronization Start/End nodes are deprecated since TB 2.5. Use queue with submit strategy SEQUENTIAL_WITHIN_ORIGINATOR instead."); | |
52 | + log.warn("Synchronization Start/End nodes are deprecated since TB 2.5. Use queue with submit strategy SEQUENTIAL_BY_ORIGINATOR instead."); | |
53 | 53 | ctx.tellSuccess(msg); |
54 | 54 | } |
55 | 55 | ... | ... |
... | ... | @@ -155,19 +155,19 @@ queue: |
155 | 155 | pack-processing-timeout: "${TB_QUEUE_RULE_ENGINE_PACK_PROCESSING_TIMEOUT_MS:60000}" |
156 | 156 | stats: |
157 | 157 | enabled: "${TB_QUEUE_RULE_ENGINE_STATS_ENABLED:true}" |
158 | - print-interval-ms: "${TB_QUEUE_RULE_ENGINE_STATS_PRINT_INTERVAL_MS:10000}" | |
158 | + print-interval-ms: "${TB_QUEUE_RULE_ENGINE_STATS_PRINT_INTERVAL_MS:60000}" | |
159 | 159 | queues: |
160 | - - name: "Main" | |
160 | + - name: "${TB_QUEUE_RE_MAIN_QUEUE_NAME:Main}" | |
161 | 161 | topic: "${TB_QUEUE_RE_MAIN_TOPIC:tb_rule_engine.main}" |
162 | 162 | poll-interval: "${TB_QUEUE_RE_MAIN_POLL_INTERVAL_MS:25}" |
163 | 163 | partitions: "${TB_QUEUE_RE_MAIN_PARTITIONS:10}" |
164 | 164 | pack-processing-timeout: "${TB_QUEUE_RE_MAIN_PACK_PROCESSING_TIMEOUT_MS:60000}" |
165 | 165 | submit-strategy: |
166 | - type: "${TB_QUEUE_RE_MAIN_SUBMIT_STRATEGY_TYPE:BURST}" # BURST, BATCH, SEQUENTIAL_WITHIN_ORIGINATOR, SEQUENTIAL_WITHIN_TENANT, SEQUENTIAL | |
166 | + type: "${TB_QUEUE_RE_MAIN_SUBMIT_STRATEGY_TYPE:BURST}" # BURST, BATCH, SEQUENTIAL_BY_ORIGINATOR, SEQUENTIAL_BY_TENANT, SEQUENTIAL | |
167 | 167 | # For BATCH only |
168 | 168 | batch-size: "${TB_QUEUE_RE_MAIN_SUBMIT_STRATEGY_BATCH_SIZE:1000}" # Maximum number of messages in batch |
169 | 169 | processing-strategy: |
170 | - type: "${TB_QUEUE_RE_MAIN_PROCESSING_STRATEGY_TYPE:RETRY_FAILED_AND_TIMED_OUT}" # SKIP_ALL_FAILURES, RETRY_ALL, RETRY_FAILED, RETRY_TIMED_OUT, RETRY_FAILED_AND_TIMED_OUT | |
170 | + type: "${TB_QUEUE_RE_MAIN_PROCESSING_STRATEGY_TYPE:SKIP_ALL_FAILURES}" # SKIP_ALL_FAILURES, RETRY_ALL, RETRY_FAILED, RETRY_TIMED_OUT, RETRY_FAILED_AND_TIMED_OUT | |
171 | 171 | # For RETRY_ALL, RETRY_FAILED, RETRY_TIMED_OUT, RETRY_FAILED_AND_TIMED_OUT |
172 | 172 | retries: "${TB_QUEUE_RE_MAIN_PROCESSING_STRATEGY_RETRIES:3}" # Number of retries, 0 is unlimited |
173 | 173 | failure-percentage: "${TB_QUEUE_RE_MAIN_PROCESSING_STRATEGY_FAILURE_PERCENTAGE:0}" # Skip retry if failures or timeouts are less then X percentage of messages; |
... | ... | @@ -175,10 +175,10 @@ queue: |
175 | 175 | - name: "${TB_QUEUE_RE_HP_QUEUE_NAME:HighPriority}" |
176 | 176 | topic: "${TB_QUEUE_RE_HP_TOPIC:tb_rule_engine.hp}" |
177 | 177 | poll-interval: "${TB_QUEUE_RE_HP_POLL_INTERVAL_MS:25}" |
178 | - partitions: "${TB_QUEUE_RE_HP_PARTITIONS:3}" | |
178 | + partitions: "${TB_QUEUE_RE_HP_PARTITIONS:10}" | |
179 | 179 | pack-processing-timeout: "${TB_QUEUE_RE_HP_PACK_PROCESSING_TIMEOUT_MS:60000}" |
180 | 180 | submit-strategy: |
181 | - type: "${TB_QUEUE_RE_HP_SUBMIT_STRATEGY_TYPE:SEQUENTIAL_WITHIN_ORIGINATOR}" # BURST, BATCH, SEQUENTIAL_WITHIN_ORIGINATOR, SEQUENTIAL_WITHIN_TENANT, SEQUENTIAL | |
181 | + type: "${TB_QUEUE_RE_HP_SUBMIT_STRATEGY_TYPE:BURST}" # BURST, BATCH, SEQUENTIAL_BY_ORIGINATOR, SEQUENTIAL_BY_TENANT, SEQUENTIAL | |
182 | 182 | # For BATCH only |
183 | 183 | batch-size: "${TB_QUEUE_RE_HP_SUBMIT_STRATEGY_BATCH_SIZE:100}" # Maximum number of messages in batch |
184 | 184 | processing-strategy: |
... | ... | @@ -187,6 +187,21 @@ queue: |
187 | 187 | retries: "${TB_QUEUE_RE_HP_PROCESSING_STRATEGY_RETRIES:0}" # Number of retries, 0 is unlimited |
188 | 188 | failure-percentage: "${TB_QUEUE_RE_HP_PROCESSING_STRATEGY_FAILURE_PERCENTAGE:0}" # Skip retry if failures or timeouts are less then X percentage of messages; |
189 | 189 | pause-between-retries: "${TB_QUEUE_RE_HP_PROCESSING_STRATEGY_RETRY_PAUSE:5}"# Time in seconds to wait in consumer thread before retries; |
190 | + - name: "${TB_QUEUE_RE_SQ_QUEUE_NAME:SequentialByOriginator}" | |
191 | + topic: "${TB_QUEUE_RE_SQ_TOPIC:tb_rule_engine.sq}" | |
192 | + poll-interval: "${TB_QUEUE_RE_SQ_POLL_INTERVAL_MS:25}" | |
193 | + partitions: "${TB_QUEUE_RE_SQ_PARTITIONS:10}" | |
194 | + pack-processing-timeout: "${TB_QUEUE_RE_SQ_PACK_PROCESSING_TIMEOUT_MS:60000}" | |
195 | + submit-strategy: | |
196 | + type: "${TB_QUEUE_RE_SQ_SUBMIT_STRATEGY_TYPE:SEQUENTIAL_BY_ORIGINATOR}" # BURST, BATCH, SEQUENTIAL_BY_ORIGINATOR, SEQUENTIAL_BY_TENANT, SEQUENTIAL | |
197 | + # For BATCH only | |
198 | + batch-size: "${TB_QUEUE_RE_SQ_SUBMIT_STRATEGY_BATCH_SIZE:100}" # Maximum number of messages in batch | |
199 | + processing-strategy: | |
200 | + type: "${TB_QUEUE_RE_SQ_PROCESSING_STRATEGY_TYPE:RETRY_FAILED_AND_TIMED_OUT}" # SKIP_ALL_FAILURES, RETRY_ALL, RETRY_FAILED, RETRY_TIMED_OUT, RETRY_FAILED_AND_TIMED_OUT | |
201 | + # For RETRY_ALL, RETRY_FAILED, RETRY_TIMED_OUT, RETRY_FAILED_AND_TIMED_OUT | |
202 | + retries: "${TB_QUEUE_RE_SQ_PROCESSING_STRATEGY_RETRIES:3}" # Number of retries, 0 is unlimited | |
203 | + failure-percentage: "${TB_QUEUE_RE_SQ_PROCESSING_STRATEGY_FAILURE_PERCENTAGE:0}" # Skip retry if failures or timeouts are less then X percentage of messages; | |
204 | + pause-between-retries: "${TB_QUEUE_RE_SQ_PROCESSING_STRATEGY_RETRY_PAUSE:5}"# Time in seconds to wait in consumer thread before retries; | |
190 | 205 | transport: |
191 | 206 | # For high priority notifications that require minimum latency and processing time |
192 | 207 | notifications_topic: "${TB_QUEUE_TRANSPORT_NOTIFICATIONS_TOPIC:tb_transport.notifications}" | ... | ... |
... | ... | @@ -156,19 +156,19 @@ queue: |
156 | 156 | pack-processing-timeout: "${TB_QUEUE_RULE_ENGINE_PACK_PROCESSING_TIMEOUT_MS:60000}" |
157 | 157 | stats: |
158 | 158 | enabled: "${TB_QUEUE_RULE_ENGINE_STATS_ENABLED:true}" |
159 | - print-interval-ms: "${TB_QUEUE_RULE_ENGINE_STATS_PRINT_INTERVAL_MS:10000}" | |
159 | + print-interval-ms: "${TB_QUEUE_RULE_ENGINE_STATS_PRINT_INTERVAL_MS:60000}" | |
160 | 160 | queues: |
161 | - - name: "Main" | |
161 | + - name: "${TB_QUEUE_RE_MAIN_QUEUE_NAME:Main}" | |
162 | 162 | topic: "${TB_QUEUE_RE_MAIN_TOPIC:tb_rule_engine.main}" |
163 | 163 | poll-interval: "${TB_QUEUE_RE_MAIN_POLL_INTERVAL_MS:25}" |
164 | 164 | partitions: "${TB_QUEUE_RE_MAIN_PARTITIONS:10}" |
165 | 165 | pack-processing-timeout: "${TB_QUEUE_RE_MAIN_PACK_PROCESSING_TIMEOUT_MS:60000}" |
166 | 166 | submit-strategy: |
167 | - type: "${TB_QUEUE_RE_MAIN_SUBMIT_STRATEGY_TYPE:BURST}" # BURST, BATCH, SEQUENTIAL_WITHIN_ORIGINATOR, SEQUENTIAL_WITHIN_TENANT, SEQUENTIAL | |
167 | + type: "${TB_QUEUE_RE_MAIN_SUBMIT_STRATEGY_TYPE:BURST}" # BURST, BATCH, SEQUENTIAL_BY_ORIGINATOR, SEQUENTIAL_BY_TENANT, SEQUENTIAL | |
168 | 168 | # For BATCH only |
169 | 169 | batch-size: "${TB_QUEUE_RE_MAIN_SUBMIT_STRATEGY_BATCH_SIZE:1000}" # Maximum number of messages in batch |
170 | 170 | processing-strategy: |
171 | - type: "${TB_QUEUE_RE_MAIN_PROCESSING_STRATEGY_TYPE:RETRY_FAILED_AND_TIMED_OUT}" # SKIP_ALL_FAILURES, RETRY_ALL, RETRY_FAILED, RETRY_TIMED_OUT, RETRY_FAILED_AND_TIMED_OUT | |
171 | + type: "${TB_QUEUE_RE_MAIN_PROCESSING_STRATEGY_TYPE:SKIP_ALL_FAILURES}" # SKIP_ALL_FAILURES, RETRY_ALL, RETRY_FAILED, RETRY_TIMED_OUT, RETRY_FAILED_AND_TIMED_OUT | |
172 | 172 | # For RETRY_ALL, RETRY_FAILED, RETRY_TIMED_OUT, RETRY_FAILED_AND_TIMED_OUT |
173 | 173 | retries: "${TB_QUEUE_RE_MAIN_PROCESSING_STRATEGY_RETRIES:3}" # Number of retries, 0 is unlimited |
174 | 174 | failure-percentage: "${TB_QUEUE_RE_MAIN_PROCESSING_STRATEGY_FAILURE_PERCENTAGE:0}" # Skip retry if failures or timeouts are less then X percentage of messages; |
... | ... | @@ -176,10 +176,10 @@ queue: |
176 | 176 | - name: "${TB_QUEUE_RE_HP_QUEUE_NAME:HighPriority}" |
177 | 177 | topic: "${TB_QUEUE_RE_HP_TOPIC:tb_rule_engine.hp}" |
178 | 178 | poll-interval: "${TB_QUEUE_RE_HP_POLL_INTERVAL_MS:25}" |
179 | - partitions: "${TB_QUEUE_RE_HP_PARTITIONS:3}" | |
179 | + partitions: "${TB_QUEUE_RE_HP_PARTITIONS:10}" | |
180 | 180 | pack-processing-timeout: "${TB_QUEUE_RE_HP_PACK_PROCESSING_TIMEOUT_MS:60000}" |
181 | 181 | submit-strategy: |
182 | - type: "${TB_QUEUE_RE_HP_SUBMIT_STRATEGY_TYPE:SEQUENTIAL_WITHIN_ORIGINATOR}" # BURST, BATCH, SEQUENTIAL_WITHIN_ORIGINATOR, SEQUENTIAL_WITHIN_TENANT, SEQUENTIAL | |
182 | + type: "${TB_QUEUE_RE_HP_SUBMIT_STRATEGY_TYPE:BURST}" # BURST, BATCH, SEQUENTIAL_BY_ORIGINATOR, SEQUENTIAL_BY_TENANT, SEQUENTIAL | |
183 | 183 | # For BATCH only |
184 | 184 | batch-size: "${TB_QUEUE_RE_HP_SUBMIT_STRATEGY_BATCH_SIZE:100}" # Maximum number of messages in batch |
185 | 185 | processing-strategy: |
... | ... | @@ -188,6 +188,21 @@ queue: |
188 | 188 | retries: "${TB_QUEUE_RE_HP_PROCESSING_STRATEGY_RETRIES:0}" # Number of retries, 0 is unlimited |
189 | 189 | failure-percentage: "${TB_QUEUE_RE_HP_PROCESSING_STRATEGY_FAILURE_PERCENTAGE:0}" # Skip retry if failures or timeouts are less then X percentage of messages; |
190 | 190 | pause-between-retries: "${TB_QUEUE_RE_HP_PROCESSING_STRATEGY_RETRY_PAUSE:5}"# Time in seconds to wait in consumer thread before retries; |
191 | + - name: "${TB_QUEUE_RE_SQ_QUEUE_NAME:SequentialByOriginator}" | |
192 | + topic: "${TB_QUEUE_RE_SQ_TOPIC:tb_rule_engine.sq}" | |
193 | + poll-interval: "${TB_QUEUE_RE_SQ_POLL_INTERVAL_MS:25}" | |
194 | + partitions: "${TB_QUEUE_RE_SQ_PARTITIONS:10}" | |
195 | + pack-processing-timeout: "${TB_QUEUE_RE_SQ_PACK_PROCESSING_TIMEOUT_MS:60000}" | |
196 | + submit-strategy: | |
197 | + type: "${TB_QUEUE_RE_SQ_SUBMIT_STRATEGY_TYPE:SEQUENTIAL_BY_ORIGINATOR}" # BURST, BATCH, SEQUENTIAL_BY_ORIGINATOR, SEQUENTIAL_BY_TENANT, SEQUENTIAL | |
198 | + # For BATCH only | |
199 | + batch-size: "${TB_QUEUE_RE_SQ_SUBMIT_STRATEGY_BATCH_SIZE:100}" # Maximum number of messages in batch | |
200 | + processing-strategy: | |
201 | + type: "${TB_QUEUE_RE_SQ_PROCESSING_STRATEGY_TYPE:RETRY_FAILED_AND_TIMED_OUT}" # SKIP_ALL_FAILURES, RETRY_ALL, RETRY_FAILED, RETRY_TIMED_OUT, RETRY_FAILED_AND_TIMED_OUT | |
202 | + # For RETRY_ALL, RETRY_FAILED, RETRY_TIMED_OUT, RETRY_FAILED_AND_TIMED_OUT | |
203 | + retries: "${TB_QUEUE_RE_SQ_PROCESSING_STRATEGY_RETRIES:3}" # Number of retries, 0 is unlimited | |
204 | + failure-percentage: "${TB_QUEUE_RE_SQ_PROCESSING_STRATEGY_FAILURE_PERCENTAGE:0}" # Skip retry if failures or timeouts are less then X percentage of messages; | |
205 | + pause-between-retries: "${TB_QUEUE_RE_SQ_PROCESSING_STRATEGY_RETRY_PAUSE:5}"# Time in seconds to wait in consumer thread before retries; | |
191 | 206 | transport: |
192 | 207 | # For high priority notifications that require minimum latency and processing time |
193 | 208 | notifications_topic: "${TB_QUEUE_TRANSPORT_NOTIFICATIONS_TOPIC:tb_transport.notifications}" | ... | ... |
... | ... | @@ -176,19 +176,19 @@ queue: |
176 | 176 | pack-processing-timeout: "${TB_QUEUE_RULE_ENGINE_PACK_PROCESSING_TIMEOUT_MS:60000}" |
177 | 177 | stats: |
178 | 178 | enabled: "${TB_QUEUE_RULE_ENGINE_STATS_ENABLED:true}" |
179 | - print-interval-ms: "${TB_QUEUE_RULE_ENGINE_STATS_PRINT_INTERVAL_MS:10000}" | |
179 | + print-interval-ms: "${TB_QUEUE_RULE_ENGINE_STATS_PRINT_INTERVAL_MS:60000}" | |
180 | 180 | queues: |
181 | - - name: "Main" | |
181 | + - name: "${TB_QUEUE_RE_MAIN_QUEUE_NAME:Main}" | |
182 | 182 | topic: "${TB_QUEUE_RE_MAIN_TOPIC:tb_rule_engine.main}" |
183 | 183 | poll-interval: "${TB_QUEUE_RE_MAIN_POLL_INTERVAL_MS:25}" |
184 | 184 | partitions: "${TB_QUEUE_RE_MAIN_PARTITIONS:10}" |
185 | 185 | pack-processing-timeout: "${TB_QUEUE_RE_MAIN_PACK_PROCESSING_TIMEOUT_MS:60000}" |
186 | 186 | submit-strategy: |
187 | - type: "${TB_QUEUE_RE_MAIN_SUBMIT_STRATEGY_TYPE:BURST}" # BURST, BATCH, SEQUENTIAL_WITHIN_ORIGINATOR, SEQUENTIAL_WITHIN_TENANT, SEQUENTIAL | |
187 | + type: "${TB_QUEUE_RE_MAIN_SUBMIT_STRATEGY_TYPE:BURST}" # BURST, BATCH, SEQUENTIAL_BY_ORIGINATOR, SEQUENTIAL_BY_TENANT, SEQUENTIAL | |
188 | 188 | # For BATCH only |
189 | 189 | batch-size: "${TB_QUEUE_RE_MAIN_SUBMIT_STRATEGY_BATCH_SIZE:1000}" # Maximum number of messages in batch |
190 | 190 | processing-strategy: |
191 | - type: "${TB_QUEUE_RE_MAIN_PROCESSING_STRATEGY_TYPE:RETRY_FAILED_AND_TIMED_OUT}" # SKIP_ALL_FAILURES, RETRY_ALL, RETRY_FAILED, RETRY_TIMED_OUT, RETRY_FAILED_AND_TIMED_OUT | |
191 | + type: "${TB_QUEUE_RE_MAIN_PROCESSING_STRATEGY_TYPE:SKIP_ALL_FAILURES}" # SKIP_ALL_FAILURES, RETRY_ALL, RETRY_FAILED, RETRY_TIMED_OUT, RETRY_FAILED_AND_TIMED_OUT | |
192 | 192 | # For RETRY_ALL, RETRY_FAILED, RETRY_TIMED_OUT, RETRY_FAILED_AND_TIMED_OUT |
193 | 193 | retries: "${TB_QUEUE_RE_MAIN_PROCESSING_STRATEGY_RETRIES:3}" # Number of retries, 0 is unlimited |
194 | 194 | failure-percentage: "${TB_QUEUE_RE_MAIN_PROCESSING_STRATEGY_FAILURE_PERCENTAGE:0}" # Skip retry if failures or timeouts are less then X percentage of messages; |
... | ... | @@ -196,10 +196,10 @@ queue: |
196 | 196 | - name: "${TB_QUEUE_RE_HP_QUEUE_NAME:HighPriority}" |
197 | 197 | topic: "${TB_QUEUE_RE_HP_TOPIC:tb_rule_engine.hp}" |
198 | 198 | poll-interval: "${TB_QUEUE_RE_HP_POLL_INTERVAL_MS:25}" |
199 | - partitions: "${TB_QUEUE_RE_HP_PARTITIONS:3}" | |
199 | + partitions: "${TB_QUEUE_RE_HP_PARTITIONS:10}" | |
200 | 200 | pack-processing-timeout: "${TB_QUEUE_RE_HP_PACK_PROCESSING_TIMEOUT_MS:60000}" |
201 | 201 | submit-strategy: |
202 | - type: "${TB_QUEUE_RE_HP_SUBMIT_STRATEGY_TYPE:SEQUENTIAL_WITHIN_ORIGINATOR}" # BURST, BATCH, SEQUENTIAL_WITHIN_ORIGINATOR, SEQUENTIAL_WITHIN_TENANT, SEQUENTIAL | |
202 | + type: "${TB_QUEUE_RE_HP_SUBMIT_STRATEGY_TYPE:BURST}" # BURST, BATCH, SEQUENTIAL_BY_ORIGINATOR, SEQUENTIAL_BY_TENANT, SEQUENTIAL | |
203 | 203 | # For BATCH only |
204 | 204 | batch-size: "${TB_QUEUE_RE_HP_SUBMIT_STRATEGY_BATCH_SIZE:100}" # Maximum number of messages in batch |
205 | 205 | processing-strategy: |
... | ... | @@ -208,6 +208,21 @@ queue: |
208 | 208 | retries: "${TB_QUEUE_RE_HP_PROCESSING_STRATEGY_RETRIES:0}" # Number of retries, 0 is unlimited |
209 | 209 | failure-percentage: "${TB_QUEUE_RE_HP_PROCESSING_STRATEGY_FAILURE_PERCENTAGE:0}" # Skip retry if failures or timeouts are less then X percentage of messages; |
210 | 210 | pause-between-retries: "${TB_QUEUE_RE_HP_PROCESSING_STRATEGY_RETRY_PAUSE:5}"# Time in seconds to wait in consumer thread before retries; |
211 | + - name: "${TB_QUEUE_RE_SQ_QUEUE_NAME:SequentialByOriginator}" | |
212 | + topic: "${TB_QUEUE_RE_SQ_TOPIC:tb_rule_engine.sq}" | |
213 | + poll-interval: "${TB_QUEUE_RE_SQ_POLL_INTERVAL_MS:25}" | |
214 | + partitions: "${TB_QUEUE_RE_SQ_PARTITIONS:10}" | |
215 | + pack-processing-timeout: "${TB_QUEUE_RE_SQ_PACK_PROCESSING_TIMEOUT_MS:60000}" | |
216 | + submit-strategy: | |
217 | + type: "${TB_QUEUE_RE_SQ_SUBMIT_STRATEGY_TYPE:SEQUENTIAL_BY_ORIGINATOR}" # BURST, BATCH, SEQUENTIAL_BY_ORIGINATOR, SEQUENTIAL_BY_TENANT, SEQUENTIAL | |
218 | + # For BATCH only | |
219 | + batch-size: "${TB_QUEUE_RE_SQ_SUBMIT_STRATEGY_BATCH_SIZE:100}" # Maximum number of messages in batch | |
220 | + processing-strategy: | |
221 | + type: "${TB_QUEUE_RE_SQ_PROCESSING_STRATEGY_TYPE:RETRY_FAILED_AND_TIMED_OUT}" # SKIP_ALL_FAILURES, RETRY_ALL, RETRY_FAILED, RETRY_TIMED_OUT, RETRY_FAILED_AND_TIMED_OUT | |
222 | + # For RETRY_ALL, RETRY_FAILED, RETRY_TIMED_OUT, RETRY_FAILED_AND_TIMED_OUT | |
223 | + retries: "${TB_QUEUE_RE_SQ_PROCESSING_STRATEGY_RETRIES:3}" # Number of retries, 0 is unlimited | |
224 | + failure-percentage: "${TB_QUEUE_RE_SQ_PROCESSING_STRATEGY_FAILURE_PERCENTAGE:0}" # Skip retry if failures or timeouts are less then X percentage of messages; | |
225 | + pause-between-retries: "${TB_QUEUE_RE_SQ_PROCESSING_STRATEGY_RETRY_PAUSE:5}"# Time in seconds to wait in consumer thread before retries; | |
211 | 226 | transport: |
212 | 227 | # For high priority notifications that require minimum latency and processing time |
213 | 228 | notifications_topic: "${TB_QUEUE_TRANSPORT_NOTIFICATIONS_TOPIC:tb_transport.notifications}" | ... | ... |
... | ... | @@ -7969,14 +7969,6 @@ |
7969 | 7969 | "resolved": "https://registry.npmjs.org/leaflet/-/leaflet-1.6.0.tgz", |
7970 | 7970 | "integrity": "sha512-CPkhyqWUKZKFJ6K8umN5/D2wrJ2+/8UIpXppY7QDnUZW5bZL5+SEI2J7GBpwh4LIupOKqbNSQXgqmrEJopHVNQ==" |
7971 | 7971 | }, |
7972 | - "leaflet-geometryutil": { | |
7973 | - "version": "0.9.3", | |
7974 | - "resolved": "https://registry.npmjs.org/leaflet-geometryutil/-/leaflet-geometryutil-0.9.3.tgz", | |
7975 | - "integrity": "sha512-Wi6YvfNx/Xu9q35AEfXpsUXmIFLen/MO+C2qimxHRnjyeyOxBhdcZa6kSiReaOX0cGK7yQInqrzz0dkIqZ8Dpg==", | |
7976 | - "requires": { | |
7977 | - "leaflet": ">=0.7.0" | |
7978 | - } | |
7979 | - }, | |
7980 | 7972 | "leaflet-polylinedecorator": { |
7981 | 7973 | "version": "1.6.0", |
7982 | 7974 | "resolved": "https://registry.npmjs.org/leaflet-polylinedecorator/-/leaflet-polylinedecorator-1.6.0.tgz", | ... | ... |
... | ... | @@ -496,7 +496,7 @@ export function padValue(val: any, dec: number): string { |
496 | 496 | val = Math.abs(val); |
497 | 497 | |
498 | 498 | if (dec > 0) { |
499 | - strVal = val.toFixed(dec).toString() | |
499 | + strVal = val.toFixed(dec); | |
500 | 500 | } else { |
501 | 501 | strVal = Math.round(val).toString(); |
502 | 502 | } | ... | ... |
... | ... | @@ -18,7 +18,7 @@ import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; |
18 | 18 | import { |
19 | 19 | Component, |
20 | 20 | ComponentFactory, |
21 | - ComponentRef, | |
21 | + ComponentRef, HostBinding, | |
22 | 22 | Inject, |
23 | 23 | Injector, |
24 | 24 | OnDestroy, |
... | ... | @@ -46,6 +46,8 @@ export interface CustomDialogContainerData { |
46 | 46 | }) |
47 | 47 | export class CustomDialogContainerComponent extends DialogComponent<CustomDialogContainerComponent> implements OnDestroy { |
48 | 48 | |
49 | + @HostBinding('style.height') height = '0px'; | |
50 | + | |
49 | 51 | private readonly customComponentRef: ComponentRef<CustomDialogComponent>; |
50 | 52 | |
51 | 53 | constructor(protected store: Store<AppState>, | ... | ... |
... | ... | @@ -20,12 +20,12 @@ import 'leaflet-providers'; |
20 | 20 | import 'leaflet.markercluster/dist/leaflet.markercluster'; |
21 | 21 | |
22 | 22 | import { |
23 | - FormattedData, | |
24 | - MapSettings, | |
25 | - MarkerSettings, | |
26 | - PolygonSettings, | |
27 | - PolylineSettings, | |
28 | - UnitedMapSettings | |
23 | + FormattedData, | |
24 | + MapSettings, | |
25 | + MarkerSettings, | |
26 | + PolygonSettings, | |
27 | + PolylineSettings, | |
28 | + UnitedMapSettings | |
29 | 29 | } from './map-models'; |
30 | 30 | import { Marker } from './markers'; |
31 | 31 | import { BehaviorSubject, Observable } from 'rxjs'; |
... | ... | @@ -345,12 +345,12 @@ export default abstract class LeafletMap { |
345 | 345 | |
346 | 346 | // Polyline |
347 | 347 | |
348 | - updatePolylines(polyData: FormattedData[][]) { | |
349 | - polyData.forEach((data: FormattedData[]) => { | |
350 | - if (data.length) { | |
351 | - const dataSource = polyData.map(arr => arr[0]); | |
352 | - if (this.polylines.get(data[0].entityName)) { | |
353 | - this.updatePolyline(data[0].entityName, data, dataSource, this.options); | |
348 | + updatePolylines(polyData: FormattedData[][], data?: FormattedData) { | |
349 | + polyData.forEach((dataSource) => { | |
350 | + if (dataSource.length) { | |
351 | + data = data || dataSource[0]; | |
352 | + if (this.polylines.get(data.$datasource.entityName)) { | |
353 | + this.updatePolyline(data, dataSource, this.options); | |
354 | 354 | } |
355 | 355 | else { |
356 | 356 | this.createPolyline(data, dataSource, this.options); |
... | ... | @@ -359,28 +359,27 @@ export default abstract class LeafletMap { |
359 | 359 | }) |
360 | 360 | } |
361 | 361 | |
362 | - createPolyline(data: FormattedData[], dataSources: FormattedData[], settings: PolylineSettings) { | |
363 | - if (data.length) | |
364 | - this.ready$.subscribe(() => { | |
365 | - const poly = new Polyline(this.map, | |
366 | - data.map(el => this.convertPosition(el)).filter(el => !!el), data, dataSources, settings); | |
367 | - const bounds = poly.leafletPoly.getBounds(); | |
368 | - this.fitBounds(bounds); | |
369 | - this.polylines.set(data[0].entityName, poly); | |
370 | - }); | |
362 | + createPolyline(data: FormattedData, dataSources: FormattedData[], settings: PolylineSettings) { | |
363 | + this.ready$.subscribe(() => { | |
364 | + const poly = new Polyline(this.map, | |
365 | + dataSources.map(el => this.convertPosition(el)).filter(el => !!el), data, dataSources, settings); | |
366 | + const bounds = poly.leafletPoly.getBounds(); | |
367 | + this.fitBounds(bounds); | |
368 | + this.polylines.set(data.$datasource.entityName, poly); | |
369 | + }); | |
371 | 370 | } |
372 | 371 | |
373 | - updatePolyline(key: string, data: FormattedData[], dataSources: FormattedData[], settings: PolylineSettings) { | |
372 | + updatePolyline(data: FormattedData, dataSources: FormattedData[], settings: PolylineSettings) { | |
374 | 373 | this.ready$.subscribe(() => { |
375 | - const poly = this.polylines.get(key); | |
374 | + const poly = this.polylines.get(data.entityName); | |
376 | 375 | const oldBounds = poly.leafletPoly.getBounds(); |
377 | - poly.updatePolyline(settings, data.map(el => this.convertPosition(el)), dataSources); | |
376 | + poly.updatePolyline(settings, data.map(el => this.convertPosition(el)).filter(el => !!el), dataSources); | |
378 | 377 | const newBounds = poly.leafletPoly.getBounds(); |
379 | 378 | if (oldBounds.toBBoxString() !== newBounds.toBBoxString()) { |
380 | 379 | this.fitBounds(newBounds); |
381 | 380 | } |
382 | 381 | }); |
383 | - } | |
382 | + }Я | |
384 | 383 | |
385 | 384 | // Polygon |
386 | 385 | ... | ... |
... | ... | @@ -14,22 +14,28 @@ |
14 | 14 | /// limitations under the License. |
15 | 15 | /// |
16 | 16 | |
17 | -import { MapProviders, UnitedMapSettings, providerSets, hereProviders, defaultSettings } from './map-models'; | |
17 | +import { defaultSettings, hereProviders, MapProviders, providerSets, UnitedMapSettings } from './map-models'; | |
18 | 18 | import LeafletMap from './leaflet-map'; |
19 | 19 | import { |
20 | - commonMapSettingsSchema, | |
21 | - routeMapSettingsSchema, | |
22 | - markerClusteringSettingsSchema, | |
23 | - markerClusteringSettingsSchemaLeaflet, | |
24 | - mapProviderSchema, | |
25 | - mapPolygonSchema | |
20 | + commonMapSettingsSchema, | |
21 | + mapPolygonSchema, | |
22 | + mapProviderSchema, | |
23 | + markerClusteringSettingsSchema, | |
24 | + markerClusteringSettingsSchemaLeaflet, | |
25 | + routeMapSettingsSchema | |
26 | 26 | } from './schemes'; |
27 | -import { MapWidgetStaticInterface, MapWidgetInterface } from './map-widget.interface'; | |
28 | -import { initSchema, addToSchema, mergeSchemes, addCondition, addGroupInfo } from '@core/schema-utils'; | |
27 | +import { MapWidgetInterface, MapWidgetStaticInterface } from './map-widget.interface'; | |
28 | +import { addCondition, addGroupInfo, addToSchema, initSchema, mergeSchemes } from '@core/schema-utils'; | |
29 | 29 | import { of, Subject } from 'rxjs'; |
30 | 30 | import { WidgetContext } from '@app/modules/home/models/widget-component.models'; |
31 | 31 | import { getDefCenterPosition, parseArray, parseData, parseFunction, parseWithTranslation } from './maps-utils'; |
32 | -import { JsonSettingsSchema, WidgetActionDescriptor, DatasourceType, widgetType, Datasource } from '@shared/models/widget.models'; | |
32 | +import { | |
33 | + Datasource, | |
34 | + DatasourceType, | |
35 | + JsonSettingsSchema, | |
36 | + WidgetActionDescriptor, | |
37 | + widgetType | |
38 | +} from '@shared/models/widget.models'; | |
33 | 39 | import { EntityId } from '@shared/models/id/entity-id'; |
34 | 40 | import { AttributeScope, DataKeyType, LatestTelemetry } from '@shared/models/telemetry/telemetry.models'; |
35 | 41 | import { AttributeService } from '@core/http/attribute.service'; |
... | ... | @@ -39,7 +45,13 @@ import { UtilsService } from '@core/services/utils.service'; |
39 | 45 | // @dynamic |
40 | 46 | export class MapWidgetController implements MapWidgetInterface { |
41 | 47 | |
42 | - constructor(public mapProvider: MapProviders, private drawRoutes: boolean, public ctx: WidgetContext, $element: HTMLElement, isEdit?) { | |
48 | + constructor( | |
49 | + public mapProvider: MapProviders, | |
50 | + private drawRoutes: boolean, | |
51 | + public ctx: WidgetContext, | |
52 | + $element: HTMLElement, | |
53 | + isEdit?: boolean | |
54 | + ) { | |
43 | 55 | if (this.map) { |
44 | 56 | this.map.map.remove(); |
45 | 57 | delete this.map; | ... | ... |
... | ... | @@ -20,7 +20,7 @@ import { Datasource } from '@app/shared/models/widget.models'; |
20 | 20 | import _ from 'lodash'; |
21 | 21 | import { Observable, Observer, of } from 'rxjs'; |
22 | 22 | import { map } from 'rxjs/operators'; |
23 | -import { createLabelFromDatasource, hashCode, padValue } from '@core/utils'; | |
23 | +import { createLabelFromDatasource, hashCode, isNumber, isUndefined, padValue } from '@core/utils'; | |
24 | 24 | |
25 | 25 | export function createTooltip(target: L.Layer, |
26 | 26 | settings: MarkerSettings | PolylineSettings | PolygonSettings, |
... | ... | @@ -43,8 +43,9 @@ export function createTooltip(target: L.Layer, |
43 | 43 | const actions = document.getElementsByClassName('tb-custom-action'); |
44 | 44 | Array.from(actions).forEach( |
45 | 45 | (element: HTMLElement) => { |
46 | - if (element && settings.tooltipAction[element.id]) { | |
47 | - element.addEventListener('click', ($event) => settings.tooltipAction[element.id]($event, datasource)); | |
46 | + const actionName = element.getAttribute('data-action-name'); | |
47 | + if (element && settings.tooltipAction[actionName]) { | |
48 | + element.addEventListener('click', ($event) => settings.tooltipAction[actionName]($event, datasource)); | |
48 | 49 | } |
49 | 50 | }); |
50 | 51 | }); |
... | ... | @@ -55,10 +56,26 @@ export function getRatio(firsMoment: number, secondMoment: number, intermediateM |
55 | 56 | return (intermediateMoment - firsMoment) / (secondMoment - firsMoment); |
56 | 57 | } |
57 | 58 | |
58 | -export function findAngle(startPoint, endPoint) { | |
59 | - let angle = -Math.atan2(endPoint.latitude - startPoint.latitude, endPoint.longitude - startPoint.longitude); | |
60 | - angle = angle * 180 / Math.PI; | |
61 | - return parseInt(angle.toFixed(2), 10); | |
59 | +export function interpolateOnLineSegment( | |
60 | + pointA: FormattedData, | |
61 | + oointB: FormattedData, | |
62 | + latKeyName: string, | |
63 | + lngKeyName: string, | |
64 | + ratio: number | |
65 | +): { [key: string]: number } { | |
66 | + return { | |
67 | + [latKeyName]: (pointA[latKeyName] + (oointB[latKeyName] - pointA[latKeyName]) * ratio), | |
68 | + [lngKeyName]: (pointA[lngKeyName] + (oointB[lngKeyName] - pointA[lngKeyName]) * ratio) | |
69 | + }; | |
70 | +} | |
71 | + | |
72 | +export function findAngle(startPoint: FormattedData, endPoint: FormattedData, latKeyName: string, lngKeyName: string): number { | |
73 | + if(isUndefined(startPoint) || isUndefined(endPoint)){ | |
74 | + return 0; | |
75 | + } | |
76 | + let angle = -Math.atan2(endPoint[latKeyName] - startPoint[latKeyName], endPoint[lngKeyName] - startPoint[lngKeyName]); | |
77 | + angle = angle * 180 / Math.PI; | |
78 | + return parseInt(angle.toFixed(2), 10); | |
62 | 79 | } |
63 | 80 | |
64 | 81 | |
... | ... | @@ -111,38 +128,81 @@ export function aspectCache(imageUrl: string): Observable<number> { |
111 | 128 | |
112 | 129 | export type TranslateFunc = (key: string, defaultTranslation?: string) => string; |
113 | 130 | |
131 | +const varsRegex = /\${([^}]*)}/g; | |
132 | +const linkActionRegex = /<link-act name=['"]([^['"]*)['"]>([^<]*)<\/link-act>/g; | |
133 | +const buttonActionRegex = /<button-act name=['"]([^['"]*)['"]>([^<]*)<\/button-act>/g; | |
134 | + | |
135 | +function createLinkElement(actionName: string, actionText: string): string { | |
136 | + return `<a href="#" class="tb-custom-action" data-action-name=${actionName}>${actionText}</a>`; | |
137 | +} | |
138 | + | |
139 | +function createButtonElement(actionName: string, actionText: string) { | |
140 | + return `<button mat-button class="tb-custom-action" data-action-name=${actionName}>${actionText}</button>`; | |
141 | +} | |
142 | + | |
114 | 143 | function parseTemplate(template: string, data: { $datasource?: Datasource, [key: string]: any }, |
115 | - translateFn?: TranslateFunc) { | |
144 | + translateFn?: TranslateFunc) { | |
116 | 145 | let res = ''; |
117 | 146 | try { |
118 | - if (template.match(/<link-act/g)) { | |
119 | - template = template.replace(/<link-act/g, '<a href="#"').replace(/link-act>/g, 'a>') | |
120 | - .replace(/name=(['"])(.*?)(['"])/g, `class='tb-custom-action' id='$2'`); | |
121 | - } | |
122 | 147 | if (translateFn) { |
123 | 148 | template = translateFn(template); |
124 | 149 | } |
125 | 150 | template = createLabelFromDatasource(data.$datasource, template); |
126 | - const formatted = template.match(/\${([^}]*):\d*}/g); | |
127 | - if (formatted) | |
128 | - formatted.forEach(value => { | |
129 | - const [variable, digits] = value.replace('${', '').replace('}', '').split(':'); | |
130 | - data[variable] = padValue(data[variable], +digits); | |
131 | - if (data[variable] === 'NaN') data[variable] = ''; | |
132 | - template = template.replace(value, '${' + variable + '}'); | |
133 | - }); | |
134 | - const variables = template.match(/\${.*?}/g); | |
135 | - if (variables) { | |
136 | - variables.forEach(variable => { | |
137 | - variable = variable.replace('${', '').replace('}', ''); | |
138 | - if (!data[variable]) | |
139 | - data[variable] = ''; | |
140 | - }) | |
151 | + | |
152 | + let match = varsRegex.exec(template); | |
153 | + while (match !== null) { | |
154 | + const variable = match[0]; | |
155 | + let label = match[1]; | |
156 | + let valDec = 2; | |
157 | + const splitValues = label.split(':'); | |
158 | + if (splitValues.length > 1) { | |
159 | + label = splitValues[0]; | |
160 | + valDec = parseFloat(splitValues[1]); | |
161 | + } | |
162 | + | |
163 | + if (label.startsWith('#')) { | |
164 | + const keyIndexStr = label.substring(1); | |
165 | + const n = Math.floor(Number(keyIndexStr)); | |
166 | + if (String(n) === keyIndexStr && n >= 0) { | |
167 | + label = data.$datasource.dataKeys[n].label; | |
168 | + } | |
169 | + } | |
170 | + | |
171 | + const value = data[label] || ''; | |
172 | + let textValue: string; | |
173 | + if (isNumber(value)) { | |
174 | + textValue = padValue(value, valDec); | |
175 | + } else { | |
176 | + textValue = value; | |
177 | + } | |
178 | + template = template.split(variable).join(textValue); | |
179 | + match = varsRegex.exec(template); | |
141 | 180 | } |
181 | + | |
182 | + let actionTags: string; | |
183 | + let actionText: string; | |
184 | + let actionName: string; | |
185 | + let action: string; | |
186 | + | |
187 | + match = linkActionRegex.exec(template); | |
188 | + while (match !== null) { | |
189 | + [actionTags, actionName, actionText] = match; | |
190 | + action = createLinkElement(actionName, actionText); | |
191 | + template = template.split(actionTags).join(action); | |
192 | + match = linkActionRegex.exec(template); | |
193 | + } | |
194 | + | |
195 | + match = buttonActionRegex.exec(template); | |
196 | + while (match !== null) { | |
197 | + [actionTags, actionName, actionText] = match; | |
198 | + action = createButtonElement(actionName, actionText); | |
199 | + template = template.split(actionTags).join(action); | |
200 | + match = buttonActionRegex.exec(template); | |
201 | + } | |
202 | + | |
142 | 203 | const compiled = _.template(template); |
143 | 204 | res = compiled(data); |
144 | - } | |
145 | - catch (ex) { | |
205 | + } catch (ex) { | |
146 | 206 | console.log(ex, template) |
147 | 207 | } |
148 | 208 | return res; | ... | ... |
... | ... | @@ -14,18 +14,18 @@ |
14 | 14 | /// limitations under the License. |
15 | 15 | /// |
16 | 16 | |
17 | -import L, { LatLngExpression, LatLngTuple, LeafletMouseEvent } from 'leaflet'; | |
17 | +import L, { LatLngExpression, LeafletMouseEvent } from 'leaflet'; | |
18 | 18 | import { createTooltip, parseWithTranslation, safeExecute } from './maps-utils'; |
19 | 19 | import { FormattedData, PolygonSettings } from './map-models'; |
20 | 20 | |
21 | 21 | export class Polygon { |
22 | 22 | |
23 | 23 | leafletPoly: L.Polygon; |
24 | - tooltip; | |
25 | - data; | |
26 | - dataSources; | |
24 | + tooltip: L.Popup; | |
25 | + data: FormattedData; | |
26 | + dataSources: FormattedData[]; | |
27 | 27 | |
28 | - constructor(public map, polyData: FormattedData, dataSources, private settings: PolygonSettings) { | |
28 | + constructor(public map, polyData: FormattedData, dataSources: FormattedData[], private settings: PolygonSettings) { | |
29 | 29 | this.dataSources = dataSources; |
30 | 30 | this.data = polyData; |
31 | 31 | const polygonColor = this.getPolygonColor(settings); |
... | ... | @@ -61,7 +61,7 @@ export class Polygon { |
61 | 61 | this.tooltip.setContent(parseWithTranslation.parseTemplate(pattern, data, true)); |
62 | 62 | } |
63 | 63 | |
64 | - updatePolygon(data:{[coordinates:string]: LatLngTuple[]}, dataSources: FormattedData[], settings: PolygonSettings) { | |
64 | + updatePolygon(data: FormattedData, dataSources: FormattedData[], settings: PolygonSettings) { | |
65 | 65 | this.data = data; |
66 | 66 | this.dataSources = dataSources; |
67 | 67 | this.leafletPoly.setLatLngs(data[this.settings.polygonKeyName]); | ... | ... |
... | ... | @@ -17,82 +17,83 @@ |
17 | 17 | import L, { PolylineDecoratorOptions } from 'leaflet'; |
18 | 18 | import 'leaflet-polylinedecorator'; |
19 | 19 | |
20 | -import { PolylineSettings } from './map-models'; | |
20 | +import { FormattedData, PolylineSettings } from './map-models'; | |
21 | 21 | import { safeExecute } from '@home/components/widget/lib/maps/maps-utils'; |
22 | 22 | |
23 | 23 | export class Polyline { |
24 | 24 | |
25 | - leafletPoly: L.Polyline; | |
26 | - polylineDecorator: L.PolylineDecorator; | |
27 | - dataSources; | |
28 | - data; | |
25 | + leafletPoly: L.Polyline; | |
26 | + polylineDecorator: L.PolylineDecorator; | |
27 | + dataSources: FormattedData[]; | |
28 | + data: FormattedData; | |
29 | 29 | |
30 | - constructor(private map: L.Map, locations, data, dataSources, settings: PolylineSettings) { | |
31 | - this.dataSources = dataSources; | |
32 | - this.data = data; | |
30 | + constructor(private map: L.Map, locations: L.LatLng[], data: FormattedData, dataSources: FormattedData[], settings: PolylineSettings) { | |
31 | + this.dataSources = dataSources; | |
32 | + this.data = data; | |
33 | 33 | |
34 | - this.leafletPoly = L.polyline(locations, | |
35 | - this.getPolyStyle(settings) | |
36 | - ).addTo(this.map); | |
34 | + this.leafletPoly = L.polyline(locations, | |
35 | + this.getPolyStyle(settings) | |
36 | + ).addTo(this.map); | |
37 | 37 | |
38 | - if (settings.usePolylineDecorator) { | |
39 | - this.polylineDecorator = L.polylineDecorator(this.leafletPoly, this.getDecoratorSettings(settings)).addTo(this.map); | |
40 | - } | |
38 | + if (settings.usePolylineDecorator) { | |
39 | + this.polylineDecorator = L.polylineDecorator(this.leafletPoly, this.getDecoratorSettings(settings)).addTo(this.map); | |
41 | 40 | } |
41 | + } | |
42 | 42 | |
43 | - getDecoratorSettings(settings: PolylineSettings): PolylineDecoratorOptions { | |
44 | - return { | |
45 | - patterns: [ | |
46 | - { | |
47 | - offset: settings.decoratorOffset, | |
48 | - endOffset: settings.endDecoratorOffset, | |
49 | - repeat: settings.decoratorRepeat, | |
50 | - symbol: L.Symbol[settings.decoratorSymbol]({ | |
51 | - pixelSize: settings.decoratorSymbolSize, | |
52 | - polygon: false, | |
53 | - pathOptions: { | |
54 | - color: settings.useDecoratorCustomColor ? settings.decoratorCustomColor : this.getPolyStyle(settings).color, | |
55 | - stroke: true | |
56 | - } | |
57 | - }) | |
58 | - } | |
59 | - ], | |
60 | - interactive: false, | |
61 | - } as PolylineDecoratorOptions | |
43 | + getDecoratorSettings(settings: PolylineSettings): PolylineDecoratorOptions { | |
44 | + return { | |
45 | + patterns: [ | |
46 | + { | |
47 | + offset: settings.decoratorOffset, | |
48 | + endOffset: settings.endDecoratorOffset, | |
49 | + repeat: settings.decoratorRepeat, | |
50 | + symbol: L.Symbol[settings.decoratorSymbol]({ | |
51 | + pixelSize: settings.decoratorSymbolSize, | |
52 | + polygon: false, | |
53 | + pathOptions: { | |
54 | + color: settings.useDecoratorCustomColor ? settings.decoratorCustomColor : this.getPolyStyle(settings).color, | |
55 | + stroke: true | |
56 | + } | |
57 | + }) | |
58 | + } | |
59 | + ] | |
62 | 60 | } |
61 | + } | |
63 | 62 | |
64 | - updatePolyline(settings, data, dataSources) { | |
65 | - this.data = data; | |
66 | - this.dataSources = dataSources; | |
67 | - this.leafletPoly.setStyle(this.getPolyStyle(settings)); | |
68 | - // this.setPolylineLatLngs(data); | |
69 | - if (this.polylineDecorator) | |
70 | - this.polylineDecorator.setPaths(this.leafletPoly); | |
71 | - } | |
63 | + updatePolyline(locations: L.LatLng[], data: FormattedData, dataSources: FormattedData[], settings: PolylineSettings) { | |
64 | + this.data = data; | |
65 | + this.dataSources = dataSources; | |
66 | + this.leafletPoly.setLatLngs(locations); | |
67 | + this.leafletPoly.setStyle(this.getPolyStyle(settings)); | |
68 | + // this.setPolylineLatLngs(data); | |
69 | + if (this.polylineDecorator) | |
70 | + this.polylineDecorator.setPaths(this.leafletPoly); | |
71 | + } | |
72 | 72 | |
73 | - getPolyStyle(settings: PolylineSettings): L.PolylineOptions { | |
74 | - return { | |
75 | - color: settings.useColorFunction ? | |
76 | - safeExecute(settings.colorFunction, | |
77 | - [this.data, this.dataSources, this.dataSources[0]?.dsIndex]) : settings.color, | |
78 | - opacity: settings.useStrokeOpacityFunction ? | |
79 | - safeExecute(settings.strokeOpacityFunction, | |
80 | - [this.data, this.dataSources, this.dataSources[0]?.dsIndex]) : settings.strokeOpacity, | |
81 | - weight: settings.useStrokeWeightFunction ? | |
82 | - safeExecute(settings.strokeWeightFunction, | |
83 | - [this.data, this.dataSources, this.dataSources[0]?.dsIndex]) : settings.strokeWeight, | |
84 | - } | |
73 | + getPolyStyle(settings: PolylineSettings): L.PolylineOptions { | |
74 | + return { | |
75 | + interactive: false, | |
76 | + color: settings.useColorFunction ? | |
77 | + safeExecute(settings.colorFunction, | |
78 | + [this.data, this.dataSources, this.data.dsIndex]) : settings.color, | |
79 | + opacity: settings.useStrokeOpacityFunction ? | |
80 | + safeExecute(settings.strokeOpacityFunction, | |
81 | + [this.data, this.dataSources, this.data.dsIndex]) : settings.strokeOpacity, | |
82 | + weight: settings.useStrokeWeightFunction ? | |
83 | + safeExecute(settings.strokeWeightFunction, | |
84 | + [this.data, this.dataSources, this.data.dsIndex]) : settings.strokeWeight, | |
85 | 85 | } |
86 | + } | |
86 | 87 | |
87 | - removePolyline() { | |
88 | - this.map.removeLayer(this.leafletPoly); | |
89 | - } | |
88 | + removePolyline() { | |
89 | + this.map.removeLayer(this.leafletPoly); | |
90 | + } | |
90 | 91 | |
91 | - getPolylineLatLngs() { | |
92 | - return this.leafletPoly.getLatLngs(); | |
93 | - } | |
92 | + getPolylineLatLngs() { | |
93 | + return this.leafletPoly.getLatLngs(); | |
94 | + } | |
94 | 95 | |
95 | - setPolylineLatLngs(latLngs) { | |
96 | - this.leafletPoly.setLatLngs(latLngs); | |
97 | - } | |
96 | + setPolylineLatLngs(latLngs) { | |
97 | + this.leafletPoly.setLatLngs(latLngs); | |
98 | + } | |
98 | 99 | } | ... | ... |
... | ... | @@ -841,52 +841,57 @@ export const pathSchema = |
841 | 841 | }; |
842 | 842 | |
843 | 843 | export const pointSchema = |
844 | -{ | |
844 | + { | |
845 | 845 | schema: { |
846 | - title: 'Trip Animation Path Configuration', | |
847 | - type: 'object', | |
848 | - properties: { | |
849 | - showPoints: { | |
850 | - title: 'Show points', | |
851 | - type: 'boolean', | |
852 | - default: false | |
853 | - }, | |
854 | - pointColor: { | |
855 | - title: 'Point color', | |
856 | - type: 'string' | |
857 | - }, | |
858 | - pointSize: { | |
859 | - title: 'Point size (px)', | |
860 | - type: 'number', | |
861 | - default: 10 | |
862 | - }, | |
863 | - usePointAsAnchor: { | |
864 | - title: 'Use point as anchor', | |
865 | - type: 'boolean', | |
866 | - default: false | |
867 | - }, | |
868 | - pointAsAnchorFunction: { | |
869 | - title: 'Point as anchor function: f(data, dsData, dsIndex)', | |
870 | - type: 'string' | |
871 | - }, | |
872 | - pointTooltipOnRightPanel: { | |
873 | - title: 'Independant point tooltip', | |
874 | - type: 'boolean', | |
875 | - default: true | |
876 | - }, | |
846 | + title: 'Trip Animation Path Configuration', | |
847 | + type: 'object', | |
848 | + properties: { | |
849 | + showPoints: { | |
850 | + title: 'Show points', | |
851 | + type: 'boolean', | |
852 | + default: false | |
877 | 853 | }, |
878 | - required: [] | |
854 | + pointColor: { | |
855 | + title: 'Point color', | |
856 | + type: 'string' | |
857 | + }, | |
858 | + pointSize: { | |
859 | + title: 'Point size (px)', | |
860 | + type: 'number', | |
861 | + default: 10 | |
862 | + }, | |
863 | + usePointAsAnchor: { | |
864 | + title: 'Use point as anchor', | |
865 | + type: 'boolean', | |
866 | + default: false | |
867 | + }, | |
868 | + pointAsAnchorFunction: { | |
869 | + title: 'Point as anchor function: f(data, dsData, dsIndex)', | |
870 | + type: 'string' | |
871 | + }, | |
872 | + pointTooltipOnRightPanel: { | |
873 | + title: 'Independant point tooltip', | |
874 | + type: 'boolean', | |
875 | + default: true | |
876 | + }, | |
877 | + }, | |
878 | + required: [] | |
879 | 879 | }, |
880 | 880 | form: [ |
881 | - 'showPoints', { | |
882 | - key: 'pointColor', | |
883 | - type: 'color' | |
884 | - }, 'pointSize', 'usePointAsAnchor', { | |
885 | - key: 'pointAsAnchorFunction', | |
886 | - type: 'javascript' | |
887 | - }, 'pointTooltipOnRightPanel', | |
881 | + 'showPoints', | |
882 | + { | |
883 | + key: 'pointColor', | |
884 | + type: 'color' | |
885 | + }, | |
886 | + 'pointSize', | |
887 | + 'usePointAsAnchor', | |
888 | + { | |
889 | + key: 'pointAsAnchorFunction', | |
890 | + type: 'javascript' | |
891 | + }, | |
892 | + 'pointTooltipOnRightPanel', | |
888 | 893 | ] |
889 | -}; | |
894 | + }; | |
890 | 895 | |
891 | 896 | export const mapProviderSchema = |
892 | 897 | { | ... | ... |
... | ... | @@ -32,6 +32,12 @@ |
32 | 32 | [ngStyle]="{'background-color': settings.tooltipColor, 'opacity': settings.tooltipOpacity, 'color': settings.tooltipFontColor}"> |
33 | 33 | </div> |
34 | 34 | </div> |
35 | - <tb-history-selector *ngIf="historicalData" [settings]="settings" [intervals]="intervals" [anchors]="anchors" [useAnchors]="useAnchors" | |
36 | - (timeUpdated)="timeUpdated($event)"></tb-history-selector> | |
37 | -</div> | |
\ No newline at end of file | ||
35 | + <tb-history-selector *ngIf="historicalData" | |
36 | + [settings]="settings" | |
37 | + [minTime]="minTime" | |
38 | + [maxTime]="maxTime" | |
39 | + [step]="normalizationStep" | |
40 | + [anchors]="anchors" | |
41 | + [useAnchors]="useAnchors" | |
42 | + (timeUpdated)="timeUpdated($event)"></tb-history-selector> | |
43 | +</div> | ... | ... |
... | ... | @@ -14,21 +14,28 @@ |
14 | 14 | /// limitations under the License. |
15 | 15 | /// |
16 | 16 | |
17 | -import L from 'leaflet'; | |
18 | 17 | import _ from 'lodash'; |
19 | 18 | import tinycolor from 'tinycolor2'; |
20 | -import { interpolateOnPointSegment } from 'leaflet-geometryutil'; | |
21 | 19 | |
22 | 20 | import { AfterViewInit, ChangeDetectorRef, Component, Input, OnInit, SecurityContext, ViewChild } from '@angular/core'; |
23 | 21 | import { MapWidgetController, TbMapWidgetV2 } from '../lib/maps/map-widget2'; |
24 | -import { MapProviders, FormattedData } from '../lib/maps/map-models'; | |
25 | -import { initSchema, addToSchema, addGroupInfo, addCondition } from '@app/core/schema-utils'; | |
26 | -import { tripAnimationSchema, mapPolygonSchema, pathSchema, pointSchema } from '../lib/maps/schemes'; | |
22 | +import { FormattedData, MapProviders } from '../lib/maps/map-models'; | |
23 | +import { addCondition, addGroupInfo, addToSchema, initSchema } from '@app/core/schema-utils'; | |
24 | +import { mapPolygonSchema, pathSchema, pointSchema, tripAnimationSchema } from '../lib/maps/schemes'; | |
27 | 25 | import { DomSanitizer } from '@angular/platform-browser'; |
28 | 26 | import { WidgetContext } from '@app/modules/home/models/widget-component.models'; |
29 | -import { findAngle, getRatio, parseArray, parseWithTranslation, safeExecute } from '../lib/maps/maps-utils'; | |
27 | +import { | |
28 | + findAngle, | |
29 | + getRatio, | |
30 | + interpolateOnLineSegment, | |
31 | + parseArray, | |
32 | + parseFunction, | |
33 | + parseWithTranslation, | |
34 | + safeExecute | |
35 | +} from '../lib/maps/maps-utils'; | |
30 | 36 | import { JsonSettingsSchema, WidgetConfig } from '@shared/models/widget.models'; |
31 | 37 | import moment from 'moment'; |
38 | +import { isUndefined } from '@core/utils'; | |
32 | 39 | |
33 | 40 | |
34 | 41 | @Component({ |
... | ... | @@ -46,20 +53,22 @@ export class TripAnimationComponent implements OnInit, AfterViewInit { |
46 | 53 | @ViewChild('map') mapContainer; |
47 | 54 | |
48 | 55 | mapWidget: MapWidgetController; |
49 | - historicalData; | |
56 | + historicalData: FormattedData[][]; | |
57 | + normalizationStep: number; | |
58 | + interpolatedTimeData = []; | |
50 | 59 | intervals = []; |
51 | - normalizationStep = 1000; | |
52 | - interpolatedData = []; | |
53 | 60 | widgetConfig: WidgetConfig; |
54 | 61 | settings; |
55 | 62 | mainTooltip = ''; |
56 | 63 | visibleTooltip = false; |
57 | - activeTrip; | |
64 | + activeTrip: FormattedData; | |
58 | 65 | label; |
59 | - minTime; | |
60 | - maxTime; | |
61 | - anchors = []; | |
62 | - useAnchors = false; | |
66 | + minTime: number; | |
67 | + minTimeFormat: string; | |
68 | + maxTime: number; | |
69 | + maxTimeFormat: string; | |
70 | + anchors: number[] = []; | |
71 | + useAnchors: boolean; | |
63 | 72 | |
64 | 73 | static getSettingsSchema(): JsonSettingsSchema { |
65 | 74 | const schema = initSchema(); |
... | ... | @@ -86,7 +95,8 @@ export class TripAnimationComponent implements OnInit, AfterViewInit { |
86 | 95 | rotationAngle: 0 |
87 | 96 | } |
88 | 97 | this.settings = { ...settings, ...this.ctx.settings }; |
89 | - this.useAnchors = this.settings.usePointAsAnchor && this.settings.showPoints; | |
98 | + this.useAnchors = this.settings.showPoints && this.settings.usePointAsAnchor; | |
99 | + this.settings.pointAsAnchorFunction = parseFunction(this.settings.pointAsAnchorFunction, ['data', 'dsData', 'dsIndex']); | |
90 | 100 | this.settings.fitMapBounds = true; |
91 | 101 | this.normalizationStep = this.settings.normalizationStep; |
92 | 102 | const subscription = this.ctx.subscriptions[Object.keys(this.ctx.subscriptions)[0]]; |
... | ... | @@ -95,7 +105,7 @@ export class TripAnimationComponent implements OnInit, AfterViewInit { |
95 | 105 | if (this.historicalData.length) { |
96 | 106 | this.activeTrip = this.historicalData[0][0]; |
97 | 107 | this.calculateIntervals(); |
98 | - this.timeUpdated(this.intervals[0]); | |
108 | + this.timeUpdated(this.minTime); | |
99 | 109 | } |
100 | 110 | this.mapWidget.map.map?.invalidateSize(); |
101 | 111 | this.cd.detectChanges(); |
... | ... | @@ -108,30 +118,40 @@ export class TripAnimationComponent implements OnInit, AfterViewInit { |
108 | 118 | } |
109 | 119 | |
110 | 120 | timeUpdated(time: number) { |
111 | - this.minTime = moment(this.intervals[this.intervals.length - 1]).format('YYYY-MM-DD HH:mm:ss'); | |
112 | - this.maxTime = moment(this.intervals[0]).format('YYYY-MM-DD HH:mm:ss'); | |
113 | - const currentPosition = this.interpolatedData | |
121 | + const currentPosition = this.interpolatedTimeData | |
114 | 122 | .map(dataSource => dataSource[time]) |
115 | 123 | .filter(ds => ds) |
116 | 124 | .map(ds => { |
117 | - ds.minTime = this.minTime; | |
118 | - ds.maxTime = this.maxTime; | |
125 | + ds.minTime = this.minTimeFormat; | |
126 | + ds.maxTime = this.maxTimeFormat; | |
119 | 127 | return ds; |
120 | 128 | }); |
129 | + if (isUndefined(currentPosition[0])) { | |
130 | + const timePoints = Object.keys(this.interpolatedTimeData[0]).map(item => parseInt(item, 10)); | |
131 | + for (let i = 1; i < timePoints.length; i++) { | |
132 | + if (timePoints[i - 1] < time && timePoints[i] > time) { | |
133 | + const beforePosition = this.interpolatedTimeData[0][timePoints[i - 1]]; | |
134 | + const afterPosition = this.interpolatedTimeData[0][timePoints[i]]; | |
135 | + const ratio = getRatio(timePoints[i - 1], timePoints[i], time); | |
136 | + currentPosition[0] = { | |
137 | + ...beforePosition, | |
138 | + time, | |
139 | + ...interpolateOnLineSegment(beforePosition, afterPosition, this.settings.latKeyName, this.settings.lngKeyName, ratio) | |
140 | + } | |
141 | + break; | |
142 | + } | |
143 | + } | |
144 | + } | |
121 | 145 | this.activeTrip = currentPosition[0]; |
122 | 146 | this.calcLabel(); |
123 | 147 | this.calcTooltip(); |
124 | 148 | if (this.mapWidget) { |
125 | - this.mapWidget.map.updatePolylines(this.interpolatedData.map(ds => _.values(ds))); | |
149 | + this.mapWidget.map.updatePolylines(this.interpolatedTimeData.map(ds => _.values(ds)), this.activeTrip); | |
126 | 150 | if (this.settings.showPolygon) { |
127 | - this.mapWidget.map.updatePolygons(this.interpolatedData); | |
151 | + this.mapWidget.map.updatePolygons(this.interpolatedTimeData); | |
128 | 152 | } |
129 | 153 | if (this.settings.showPoints) { |
130 | - this.mapWidget.map.updatePoints(this.historicalData[0], this.calcTooltip); | |
131 | - this.anchors = this.historicalData[0] | |
132 | - .filter(data => | |
133 | - this.settings.usePointAsAnchor || | |
134 | - safeExecute(this.settings.pointAsAnchorFunction, [this.historicalData, data, data.dsIndex])).map(data => data.time); | |
154 | + this.mapWidget.map.updatePoints(_.values(_.union(this.interpolatedTimeData)[0]), this.calcTooltip); | |
135 | 155 | } |
136 | 156 | this.mapWidget.map.updateMarkers(currentPosition, this.calcTooltip); |
137 | 157 | } |
... | ... | @@ -142,22 +162,31 @@ export class TripAnimationComponent implements OnInit, AfterViewInit { |
142 | 162 | |
143 | 163 | calculateIntervals() { |
144 | 164 | this.historicalData.forEach((dataSource, index) => { |
145 | - this.intervals = []; | |
146 | - for (let time = dataSource[0]?.time; time < dataSource[dataSource.length - 1]?.time; time += this.normalizationStep) { | |
147 | - this.intervals.push(time); | |
148 | - } | |
149 | - this.intervals.push(dataSource[dataSource.length - 1]?.time); | |
150 | - this.interpolatedData[index] = this.interpolateArray(dataSource, this.intervals); | |
165 | + this.minTime = dataSource[0]?.time || Infinity; | |
166 | + this.minTimeFormat = this.minTime !== Infinity ? moment(this.minTime).format('YYYY-MM-DD HH:mm:ss') : ''; | |
167 | + this.maxTime = dataSource[dataSource.length - 1]?.time || -Infinity; | |
168 | + this.maxTimeFormat = this.maxTime !== -Infinity ? moment(this.maxTime).format('YYYY-MM-DD HH:mm:ss') : ''; | |
169 | + this.interpolatedTimeData[index] = this.interpolateArray(dataSource); | |
151 | 170 | }); |
171 | + if (this.useAnchors) { | |
172 | + const anchorDate = Object.entries(_.union(this.interpolatedTimeData)[0]); | |
173 | + this.anchors = anchorDate | |
174 | + .filter((data: [string, FormattedData]) => safeExecute(this.settings.pointAsAnchorFunction, [data[1], anchorDate, data[1].dsIndex])) | |
175 | + .map(data => parseInt(data[0], 10)); | |
176 | + } | |
152 | 177 | } |
153 | 178 | |
154 | 179 | calcTooltip = (point?: FormattedData, setTooltip = true) => { |
155 | 180 | if (!point) { |
156 | 181 | point = this.activeTrip; |
157 | 182 | } |
158 | - const data = { ...point, maxTime: this.maxTime, minTime: this.minTime } | |
183 | + const data = { | |
184 | + ...this.activeTrip, | |
185 | + maxTime: this.maxTimeFormat, | |
186 | + minTime: this.minTimeFormat | |
187 | + } | |
159 | 188 | const tooltipPattern: string = this.settings.useTooltipFunction ? |
160 | - safeExecute(this.settings.tooolTipFunction, [data, this.historicalData, 0]) : this.settings.tooltipPattern; | |
189 | + safeExecute(this.settings.tooolTipFunction, [data, this.historicalData, point.dsIndex]) : this.settings.tooltipPattern; | |
161 | 190 | const tooltipText = parseWithTranslation.parseTemplate(tooltipPattern, data, true); |
162 | 191 | if (setTooltip) { |
163 | 192 | this.mainTooltip = this.sanitizer.sanitize( |
... | ... | @@ -168,34 +197,34 @@ export class TripAnimationComponent implements OnInit, AfterViewInit { |
168 | 197 | } |
169 | 198 | |
170 | 199 | calcLabel() { |
171 | - const data = { ...this.activeTrip, maxTime: this.maxTime, minTime: this.minTime } | |
200 | + const data = { | |
201 | + ...this.activeTrip, | |
202 | + maxTime: this.maxTimeFormat, | |
203 | + minTime: this.minTimeFormat | |
204 | + } | |
172 | 205 | const labelText: string = this.settings.useLabelFunction ? |
173 | - safeExecute(this.settings.labelFunction, [data, this.historicalData, 0]) : this.settings.label; | |
206 | + safeExecute(this.settings.labelFunction, [data, this.historicalData, data.dsIndex]) : this.settings.label; | |
174 | 207 | this.label = (parseWithTranslation.parseTemplate(labelText, data, true)); |
175 | 208 | } |
176 | 209 | |
177 | - interpolateArray(originData, interpolatedIntervals) { | |
210 | + interpolateArray(originData: FormattedData[]) { | |
178 | 211 | const result = {}; |
179 | - for (let i = 1, j = 0; i < originData.length && j < interpolatedIntervals.length;) { | |
180 | - const currentTime = interpolatedIntervals[j]; | |
181 | - while (originData[i].time < currentTime) i++; | |
182 | - const before = originData[i - 1]; | |
183 | - const after = originData[i]; | |
184 | - const interpolation = interpolateOnPointSegment( | |
185 | - new L.Point(before.latitude, before.longitude), | |
186 | - new L.Point(after.latitude, after.longitude), | |
187 | - getRatio(before.time, after.time, currentTime)); | |
188 | - result[currentTime] = ({ | |
189 | - ...originData[i], | |
190 | - rotationAngle: findAngle(before, after) + this.settings.rotationAngle, | |
191 | - latitude: interpolation.x, | |
192 | - longitude: interpolation.y | |
193 | - }); | |
194 | - j++; | |
212 | + const latKeyName = this.settings.latKeyName; | |
213 | + const lngKeyName = this.settings.lngKeyName; | |
214 | + for (const data of originData) { | |
215 | + const currentTime = data.time; | |
216 | + const normalizeTime = this.minTime + Math.ceil((currentTime - this.minTime) / this.normalizationStep) * this.normalizationStep; | |
217 | + result[normalizeTime] = { | |
218 | + ...data, | |
219 | + rotationAngle: this.settings.rotationAngle | |
220 | + }; | |
221 | + } | |
222 | + const timeStamp = Object.keys(result); | |
223 | + for (let i = 0; i < timeStamp.length - 1; i++) { | |
224 | + result[timeStamp[i]].rotationAngle += findAngle(result[timeStamp[i]], result[timeStamp[i + 1]], latKeyName, lngKeyName) | |
195 | 225 | } |
196 | 226 | return result; |
197 | 227 | } |
198 | 228 | } |
199 | 229 | |
200 | 230 | export let TbTripAnimationWidget = TripAnimationComponent; |
201 | - | ... | ... |
... | ... | @@ -19,7 +19,7 @@ |
19 | 19 | tb-fullscreen |
20 | 20 | [fullscreen]="fullscreen" (fullscreenChanged)="onFullscreen()" fxLayout="column"> |
21 | 21 | <div fxLayout="row" fxLayoutAlign="start center" style="height: 40px;" class="tb-json-content-toolbar"> |
22 | - <label class="tb-title no-padding">{{ label }}</label> | |
22 | + <label class="tb-title no-padding" [ngClass]="{'tb-error': !contentValid}">{{ label }}</label> | |
23 | 23 | <span fxFlex></span> |
24 | 24 | <button type="button" |
25 | 25 | mat-button *ngIf="!readonly && !disabled" class="tidy" (click)="beautifyJSON()"> | ... | ... |
... | ... | @@ -92,6 +92,15 @@ export class JsonContentComponent implements OnInit, ControlValueAccessor, Valid |
92 | 92 | this.validateContentValue = coerceBooleanProperty(value); |
93 | 93 | } |
94 | 94 | |
95 | + private validateOnChangeValue: boolean; | |
96 | + get validateOnChange(): boolean { | |
97 | + return this.validateOnChangeValue; | |
98 | + } | |
99 | + @Input() | |
100 | + set validateOnChange(value: boolean) { | |
101 | + this.validateOnChangeValue = coerceBooleanProperty(value); | |
102 | + } | |
103 | + | |
95 | 104 | fullscreen = false; |
96 | 105 | |
97 | 106 | contentBody: string; |
... | ... | @@ -256,7 +265,7 @@ export class JsonContentComponent implements OnInit, ControlValueAccessor, Valid |
256 | 265 | const editorValue = this.jsonEditor.getValue(); |
257 | 266 | if (this.contentBody !== editorValue) { |
258 | 267 | this.contentBody = editorValue; |
259 | - this.contentValid = true; | |
268 | + this.contentValid = !this.validateOnChange || this.doValidate(); | |
260 | 269 | this.propagateChange(this.contentBody); |
261 | 270 | } |
262 | 271 | } | ... | ... |
... | ... | @@ -117,6 +117,11 @@ export class KeyValMapComponent extends PageComponent implements ControlValueAcc |
117 | 117 | this.valueChangeSubscription = this.kvListFormGroup.valueChanges.subscribe(() => { |
118 | 118 | this.updateModel(); |
119 | 119 | }); |
120 | + if (this.disabled) { | |
121 | + this.kvListFormGroup.disable({emitEvent: false}); | |
122 | + } else { | |
123 | + this.kvListFormGroup.enable({emitEvent: false}); | |
124 | + } | |
120 | 125 | } |
121 | 126 | |
122 | 127 | public removeKeyVal(index: number) { | ... | ... |
... | ... | @@ -27,8 +27,8 @@ |
27 | 27 | <mat-slider [(ngModel)]="index" [min]="minTimeIndex" [max]="maxTimeIndex" (change)="changeIndex()"> |
28 | 28 | </mat-slider> |
29 | 29 | <div class="panel-timer"> |
30 | - <span *ngIf="this.intervals[this.index]">{{ this.intervals[this.index] | date:'medium'}}</span> | |
31 | - <span *ngIf="!this.intervals[this.index]">{{ "widget.no-data-found" | translate}}</span> | |
30 | + <span *ngIf="this.currentTime">{{ this.currentTime | date:'medium'}}</span> | |
31 | + <span *ngIf="!this.currentTime">{{ "widget.no-data-found" | translate}}</span> | |
32 | 32 | </div> |
33 | 33 | </div> |
34 | 34 | <button mat-icon-button class="mat-icon-button" aria-label="Next" (click)="moveNext()"> |
... | ... | @@ -47,8 +47,9 @@ |
47 | 47 | pause_circle_outline |
48 | 48 | </mat-icon> |
49 | 49 | </button> |
50 | - <mat-select matInput [(ngModel)]="speed" (selectionChange)="reeneble()" class="speed-select" | |
50 | + <mat-select [(ngModel)]="speed" (selectionChange)="reeneble()" class="speed-select" | |
51 | 51 | aria-label="Speed selector"> |
52 | 52 | <mat-option [value]="speedValue" *ngFor="let speedValue of speeds">{{speedValue}} </mat-option> |
53 | 53 | </mat-select> |
54 | - </div> | |
\ No newline at end of file | ||
54 | + </div> | |
55 | +</div> | ... | ... |
... | ... | @@ -14,7 +14,7 @@ |
14 | 14 | /// limitations under the License. |
15 | 15 | /// |
16 | 16 | |
17 | -import { Component, OnInit, OnChanges, Input, Output, EventEmitter, ChangeDetectorRef } from '@angular/core'; | |
17 | +import { ChangeDetectorRef, Component, EventEmitter, Input, OnChanges, OnInit, Output } from '@angular/core'; | |
18 | 18 | import { interval } from 'rxjs'; |
19 | 19 | import { filter } from 'rxjs/operators'; |
20 | 20 | import { HistorySelectSettings } from '@app/modules/home/components/widget/lib/maps/map-models'; |
... | ... | @@ -27,13 +27,14 @@ import { HistorySelectSettings } from '@app/modules/home/components/widget/lib/m |
27 | 27 | export class HistorySelectorComponent implements OnInit, OnChanges { |
28 | 28 | |
29 | 29 | @Input() settings: HistorySelectSettings |
30 | - @Input() intervals = []; | |
30 | + @Input() minTime: number; | |
31 | + @Input() maxTime: number; | |
32 | + @Input() step = 1000; | |
31 | 33 | @Input() anchors = []; |
32 | 34 | @Input() useAnchors = false; |
33 | 35 | |
34 | 36 | @Output() timeUpdated: EventEmitter<number> = new EventEmitter(); |
35 | 37 | |
36 | - animationTime; | |
37 | 38 | minTimeIndex = 0; |
38 | 39 | maxTimeIndex = 0; |
39 | 40 | speed = 1; |
... | ... | @@ -41,6 +42,7 @@ export class HistorySelectorComponent implements OnInit, OnChanges { |
41 | 42 | playing = false; |
42 | 43 | interval; |
43 | 44 | speeds = [1, 5, 10, 25]; |
45 | + currentTime = null; | |
44 | 46 | |
45 | 47 | |
46 | 48 | constructor(private cd: ChangeDetectorRef) { } |
... | ... | @@ -49,7 +51,8 @@ export class HistorySelectorComponent implements OnInit, OnChanges { |
49 | 51 | } |
50 | 52 | |
51 | 53 | ngOnChanges() { |
52 | - this.maxTimeIndex = this.intervals?.length - 1; | |
54 | + this.maxTimeIndex = Math.ceil((this.maxTime - this.minTime) / this.step); | |
55 | + this.currentTime = this.minTime === Infinity ? null : this.minTime; | |
53 | 56 | } |
54 | 57 | |
55 | 58 | play() { |
... | ... | @@ -59,17 +62,18 @@ export class HistorySelectorComponent implements OnInit, OnChanges { |
59 | 62 | .pipe( |
60 | 63 | filter(() => this.playing)).subscribe(() => { |
61 | 64 | this.index++; |
62 | - if (this.index < this.maxTimeIndex) { | |
65 | + this.currentTime = this.minTime + this.index * this.step; | |
66 | + if (this.index <= this.maxTimeIndex) { | |
63 | 67 | this.cd.detectChanges(); |
64 | - this.timeUpdated.emit(this.intervals[this.index]); | |
68 | + this.timeUpdated.emit(this.currentTime); | |
65 | 69 | } |
66 | 70 | else { |
67 | 71 | this.interval.complete(); |
68 | 72 | } |
69 | 73 | }, err => { |
70 | - console.log(err); | |
74 | + console.error(err); | |
71 | 75 | }, () => { |
72 | - this.index = this.minTimeIndex; | |
76 | + this.currentTime = this.index = this.minTimeIndex; | |
73 | 77 | this.playing = false; |
74 | 78 | this.interval = null; |
75 | 79 | this.cd.detectChanges(); |
... | ... | @@ -87,18 +91,19 @@ export class HistorySelectorComponent implements OnInit, OnChanges { |
87 | 91 | |
88 | 92 | pause() { |
89 | 93 | this.playing = false; |
94 | + this.currentTime = this.minTime + this.index * this.step; | |
90 | 95 | this.cd.detectChanges(); |
91 | - this.timeUpdated.emit(this.intervals[this.index]); | |
96 | + this.timeUpdated.emit(this.currentTime); | |
92 | 97 | } |
93 | 98 | |
94 | 99 | moveNext() { |
95 | 100 | if (this.index < this.maxTimeIndex) { |
96 | 101 | if (this.useAnchors) { |
97 | - const anchorIndex = this.findIndex(this.intervals[this.index], this.anchors)+1; | |
98 | - this.index = this.findIndex(this.anchors[anchorIndex], this.intervals); | |
99 | - } | |
100 | - else | |
102 | + const anchorIndex = this.findIndex(this.currentTime, this.anchors) + 1; | |
103 | + this.index = Math.floor((this.anchors[anchorIndex] - this.minTime) / this.step); | |
104 | + } else { | |
101 | 105 | this.index++; |
106 | + } | |
102 | 107 | } |
103 | 108 | this.pause(); |
104 | 109 | } |
... | ... | @@ -106,15 +111,23 @@ export class HistorySelectorComponent implements OnInit, OnChanges { |
106 | 111 | movePrev() { |
107 | 112 | if (this.index > this.minTimeIndex) { |
108 | 113 | if (this.useAnchors) { |
109 | - const anchorIndex = this.findIndex(this.intervals[this.index], this.anchors) - 1; | |
110 | - this.index = this.findIndex(this.anchors[anchorIndex], this.intervals); | |
111 | - } | |
112 | - else | |
114 | + const anchorIndex = this.findIndex(this.currentTime, this.anchors) - 1; | |
115 | + this.index = Math.floor((this.anchors[anchorIndex] - this.minTime) / this.step); | |
116 | + } else { | |
113 | 117 | this.index--; |
118 | + } | |
114 | 119 | } |
115 | 120 | this.pause(); |
116 | 121 | } |
117 | 122 | |
123 | + findIndex(value: number, array: number[]): number { | |
124 | + let i = 0; | |
125 | + while (array[i] < value) { | |
126 | + i++; | |
127 | + } | |
128 | + return i; | |
129 | + } | |
130 | + | |
118 | 131 | moveStart() { |
119 | 132 | this.index = this.minTimeIndex; |
120 | 133 | this.pause(); |
... | ... | @@ -125,15 +138,8 @@ export class HistorySelectorComponent implements OnInit, OnChanges { |
125 | 138 | this.pause(); |
126 | 139 | } |
127 | 140 | |
128 | - findIndex(value, array: any[]) { | |
129 | - let i = 0; | |
130 | - while (array[i] < value) { | |
131 | - i++; | |
132 | - }; | |
133 | - return i; | |
134 | - } | |
135 | - | |
136 | 141 | changeIndex() { |
137 | - this.timeUpdated.emit(this.intervals[this.index]); | |
142 | + this.currentTime = this.minTime + this.index * this.step; | |
143 | + this.timeUpdated.emit(this.currentTime); | |
138 | 144 | } |
139 | 145 | } | ... | ... |
... | ... | @@ -90,6 +90,14 @@ |
90 | 90 | "timeout-invalid": "That doesn't look like a valid timeout.", |
91 | 91 | "enable-tls": "Enable TLS", |
92 | 92 | "tls-version": "TLS version", |
93 | + "enable-proxy": "Enable proxy", | |
94 | + "proxy-host": "Proxy host", | |
95 | + "proxy-host-required": "Proxy host is required.", | |
96 | + "proxy-port": "Proxy port", | |
97 | + "proxy-port-required": "You must supply a proxy port.", | |
98 | + "proxy-port-invalid": "That doesn't look like a valid proxy port.", | |
99 | + "proxy-user": "Proxy user", | |
100 | + "proxy-password": "Proxy password", | |
93 | 101 | "send-test-mail": "Send test mail", |
94 | 102 | "security-settings": "Security settings", |
95 | 103 | "password-policy": "Password policy", | ... | ... |