Commit e3d0da90be7735d8049bca1bf5c4800bb959bd23

Authored by AndrewVolosytnykhThingsboard
1 parent 4e229ea2

Implement fields validation

Showing 66 changed files with 477 additions and 148 deletions
@@ -26,12 +26,12 @@ import org.springframework.web.bind.annotation.ResponseBody; @@ -26,12 +26,12 @@ import org.springframework.web.bind.annotation.ResponseBody;
26 import org.springframework.web.bind.annotation.RestController; 26 import org.springframework.web.bind.annotation.RestController;
27 import org.thingsboard.rule.engine.api.MailService; 27 import org.thingsboard.rule.engine.api.MailService;
28 import org.thingsboard.rule.engine.api.SmsService; 28 import org.thingsboard.rule.engine.api.SmsService;
29 -import org.thingsboard.server.common.data.sms.config.TestSmsRequest;  
30 import org.thingsboard.server.common.data.AdminSettings; 29 import org.thingsboard.server.common.data.AdminSettings;
31 import org.thingsboard.server.common.data.UpdateMessage; 30 import org.thingsboard.server.common.data.UpdateMessage;
32 import org.thingsboard.server.common.data.exception.ThingsboardException; 31 import org.thingsboard.server.common.data.exception.ThingsboardException;
33 import org.thingsboard.server.common.data.id.TenantId; 32 import org.thingsboard.server.common.data.id.TenantId;
34 import org.thingsboard.server.common.data.security.model.SecuritySettings; 33 import org.thingsboard.server.common.data.security.model.SecuritySettings;
  34 +import org.thingsboard.server.common.data.sms.config.TestSmsRequest;
35 import org.thingsboard.server.dao.settings.AdminSettingsService; 35 import org.thingsboard.server.dao.settings.AdminSettingsService;
36 import org.thingsboard.server.queue.util.TbCoreComponent; 36 import org.thingsboard.server.queue.util.TbCoreComponent;
37 import org.thingsboard.server.service.security.permission.Operation; 37 import org.thingsboard.server.service.security.permission.Operation;
@@ -88,6 +88,7 @@ public class AdminController extends BaseController { @@ -88,6 +88,7 @@ public class AdminController extends BaseController {
88 } else if (adminSettings.getKey().equals("sms")) { 88 } else if (adminSettings.getKey().equals("sms")) {
89 smsService.updateSmsConfiguration(); 89 smsService.updateSmsConfiguration();
90 } 90 }
  91 +
91 return adminSettings; 92 return adminSettings;
92 } catch (Exception e) { 93 } catch (Exception e) {
93 throw handleException(e); 94 throw handleException(e);
@@ -34,6 +34,7 @@ import org.thingsboard.server.common.data.relation.EntityRelation; @@ -34,6 +34,7 @@ import org.thingsboard.server.common.data.relation.EntityRelation;
34 import org.thingsboard.server.common.data.relation.EntityRelationInfo; 34 import org.thingsboard.server.common.data.relation.EntityRelationInfo;
35 import org.thingsboard.server.common.data.relation.EntityRelationsQuery; 35 import org.thingsboard.server.common.data.relation.EntityRelationsQuery;
36 import org.thingsboard.server.common.data.relation.RelationTypeGroup; 36 import org.thingsboard.server.common.data.relation.RelationTypeGroup;
  37 +import org.thingsboard.server.dao.service.ConstraintValidator;
37 import org.thingsboard.server.queue.util.TbCoreComponent; 38 import org.thingsboard.server.queue.util.TbCoreComponent;
38 import org.thingsboard.server.service.security.permission.Operation; 39 import org.thingsboard.server.service.security.permission.Operation;
39 40
@@ -63,6 +64,7 @@ public class EntityRelationController extends BaseController { @@ -63,6 +64,7 @@ public class EntityRelationController extends BaseController {
63 if (relation.getTypeGroup() == null) { 64 if (relation.getTypeGroup() == null) {
64 relation.setTypeGroup(RelationTypeGroup.COMMON); 65 relation.setTypeGroup(RelationTypeGroup.COMMON);
65 } 66 }
  67 + ConstraintValidator.validateFields(relation);
66 relationService.saveRelation(getTenantId(), relation); 68 relationService.saveRelation(getTenantId(), relation);
67 69
68 logEntityAction(relation.getFrom(), null, getCurrentUser().getCustomerId(), 70 logEntityAction(relation.getFrom(), null, getCurrentUser().getCustomerId(),
@@ -48,7 +48,6 @@ import org.thingsboard.server.common.data.EntityType; @@ -48,7 +48,6 @@ import org.thingsboard.server.common.data.EntityType;
48 import org.thingsboard.server.common.data.TenantProfile; 48 import org.thingsboard.server.common.data.TenantProfile;
49 import org.thingsboard.server.common.data.audit.ActionType; 49 import org.thingsboard.server.common.data.audit.ActionType;
50 import org.thingsboard.server.common.data.exception.ThingsboardException; 50 import org.thingsboard.server.common.data.exception.ThingsboardException;
51 -import org.thingsboard.server.common.data.id.CustomerId;  
52 import org.thingsboard.server.common.data.id.DeviceId; 51 import org.thingsboard.server.common.data.id.DeviceId;
53 import org.thingsboard.server.common.data.id.EntityId; 52 import org.thingsboard.server.common.data.id.EntityId;
54 import org.thingsboard.server.common.data.id.EntityIdFactory; 53 import org.thingsboard.server.common.data.id.EntityIdFactory;
@@ -73,6 +72,7 @@ import org.thingsboard.server.common.data.kv.StringDataEntry; @@ -73,6 +72,7 @@ import org.thingsboard.server.common.data.kv.StringDataEntry;
73 import org.thingsboard.server.common.data.kv.TsKvEntry; 72 import org.thingsboard.server.common.data.kv.TsKvEntry;
74 import org.thingsboard.server.common.data.tenant.profile.DefaultTenantProfileConfiguration; 73 import org.thingsboard.server.common.data.tenant.profile.DefaultTenantProfileConfiguration;
75 import org.thingsboard.server.common.transport.adaptor.JsonConverter; 74 import org.thingsboard.server.common.transport.adaptor.JsonConverter;
  75 +import org.thingsboard.server.dao.service.ConstraintValidator;
76 import org.thingsboard.server.dao.timeseries.TimeseriesService; 76 import org.thingsboard.server.dao.timeseries.TimeseriesService;
77 import org.thingsboard.server.queue.util.TbCoreComponent; 77 import org.thingsboard.server.queue.util.TbCoreComponent;
78 import org.thingsboard.server.service.security.AccessValidator; 78 import org.thingsboard.server.service.security.AccessValidator;
@@ -138,7 +138,11 @@ public class TelemetryController extends BaseController { @@ -138,7 +138,11 @@ public class TelemetryController extends BaseController {
138 @ResponseBody 138 @ResponseBody
139 public DeferredResult<ResponseEntity> getAttributeKeys( 139 public DeferredResult<ResponseEntity> getAttributeKeys(
140 @PathVariable("entityType") String entityType, @PathVariable("entityId") String entityIdStr) throws ThingsboardException { 140 @PathVariable("entityType") String entityType, @PathVariable("entityId") String entityIdStr) throws ThingsboardException {
141 - return accessValidator.validateEntityAndCallback(getCurrentUser(), Operation.READ_ATTRIBUTES, entityType, entityIdStr, this::getAttributeKeysCallback); 141 + try {
  142 + return accessValidator.validateEntityAndCallback(getCurrentUser(), Operation.READ_ATTRIBUTES, entityType, entityIdStr, this::getAttributeKeysCallback);
  143 + } catch (Exception e) {
  144 + throw handleException(e);
  145 + }
142 } 146 }
143 147
144 @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") 148 @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')")
@@ -147,8 +151,12 @@ public class TelemetryController extends BaseController { @@ -147,8 +151,12 @@ public class TelemetryController extends BaseController {
147 public DeferredResult<ResponseEntity> getAttributeKeysByScope( 151 public DeferredResult<ResponseEntity> getAttributeKeysByScope(
148 @PathVariable("entityType") String entityType, @PathVariable("entityId") String entityIdStr 152 @PathVariable("entityType") String entityType, @PathVariable("entityId") String entityIdStr
149 , @PathVariable("scope") String scope) throws ThingsboardException { 153 , @PathVariable("scope") String scope) throws ThingsboardException {
150 - return accessValidator.validateEntityAndCallback(getCurrentUser(), Operation.READ_ATTRIBUTES, entityType, entityIdStr,  
151 - (result, tenantId, entityId) -> getAttributeKeysCallback(result, tenantId, entityId, scope)); 154 + try {
  155 + return accessValidator.validateEntityAndCallback(getCurrentUser(), Operation.READ_ATTRIBUTES, entityType, entityIdStr,
  156 + (result, tenantId, entityId) -> getAttributeKeysCallback(result, tenantId, entityId, scope));
  157 + } catch (Exception e) {
  158 + throw handleException(e);
  159 + }
152 } 160 }
153 161
154 @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") 162 @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')")
@@ -157,9 +165,13 @@ public class TelemetryController extends BaseController { @@ -157,9 +165,13 @@ public class TelemetryController extends BaseController {
157 public DeferredResult<ResponseEntity> getAttributes( 165 public DeferredResult<ResponseEntity> getAttributes(
158 @PathVariable("entityType") String entityType, @PathVariable("entityId") String entityIdStr, 166 @PathVariable("entityType") String entityType, @PathVariable("entityId") String entityIdStr,
159 @RequestParam(name = "keys", required = false) String keysStr) throws ThingsboardException { 167 @RequestParam(name = "keys", required = false) String keysStr) throws ThingsboardException {
160 - SecurityUser user = getCurrentUser();  
161 - return accessValidator.validateEntityAndCallback(getCurrentUser(), Operation.READ_ATTRIBUTES, entityType, entityIdStr,  
162 - (result, tenantId, entityId) -> getAttributeValuesCallback(result, user, entityId, null, keysStr)); 168 + try {
  169 + SecurityUser user = getCurrentUser();
  170 + return accessValidator.validateEntityAndCallback(getCurrentUser(), Operation.READ_ATTRIBUTES, entityType, entityIdStr,
  171 + (result, tenantId, entityId) -> getAttributeValuesCallback(result, user, entityId, null, keysStr));
  172 + } catch (Exception e) {
  173 + throw handleException(e);
  174 + }
163 } 175 }
164 176
165 @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") 177 @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')")
@@ -169,9 +181,13 @@ public class TelemetryController extends BaseController { @@ -169,9 +181,13 @@ public class TelemetryController extends BaseController {
169 @PathVariable("entityType") String entityType, @PathVariable("entityId") String entityIdStr, 181 @PathVariable("entityType") String entityType, @PathVariable("entityId") String entityIdStr,
170 @PathVariable("scope") String scope, 182 @PathVariable("scope") String scope,
171 @RequestParam(name = "keys", required = false) String keysStr) throws ThingsboardException { 183 @RequestParam(name = "keys", required = false) String keysStr) throws ThingsboardException {
172 - SecurityUser user = getCurrentUser();  
173 - return accessValidator.validateEntityAndCallback(getCurrentUser(), Operation.READ_ATTRIBUTES, entityType, entityIdStr,  
174 - (result, tenantId, entityId) -> getAttributeValuesCallback(result, user, entityId, scope, keysStr)); 184 + try {
  185 + SecurityUser user = getCurrentUser();
  186 + return accessValidator.validateEntityAndCallback(getCurrentUser(), Operation.READ_ATTRIBUTES, entityType, entityIdStr,
  187 + (result, tenantId, entityId) -> getAttributeValuesCallback(result, user, entityId, scope, keysStr));
  188 + } catch (Exception e) {
  189 + throw handleException(e);
  190 + }
175 } 191 }
176 192
177 @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") 193 @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')")
@@ -179,8 +195,12 @@ public class TelemetryController extends BaseController { @@ -179,8 +195,12 @@ public class TelemetryController extends BaseController {
179 @ResponseBody 195 @ResponseBody
180 public DeferredResult<ResponseEntity> getTimeseriesKeys( 196 public DeferredResult<ResponseEntity> getTimeseriesKeys(
181 @PathVariable("entityType") String entityType, @PathVariable("entityId") String entityIdStr) throws ThingsboardException { 197 @PathVariable("entityType") String entityType, @PathVariable("entityId") String entityIdStr) throws ThingsboardException {
182 - return accessValidator.validateEntityAndCallback(getCurrentUser(), Operation.READ_TELEMETRY, entityType, entityIdStr,  
183 - (result, tenantId, entityId) -> Futures.addCallback(tsService.findAllLatest(tenantId, entityId), getTsKeysToResponseCallback(result), MoreExecutors.directExecutor())); 198 + try {
  199 + return accessValidator.validateEntityAndCallback(getCurrentUser(), Operation.READ_TELEMETRY, entityType, entityIdStr,
  200 + (result, tenantId, entityId) -> Futures.addCallback(tsService.findAllLatest(tenantId, entityId), getTsKeysToResponseCallback(result), MoreExecutors.directExecutor()));
  201 + } catch (Exception e) {
  202 + throw handleException(e);
  203 + }
184 } 204 }
185 205
186 @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") 206 @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')")
@@ -190,10 +210,14 @@ public class TelemetryController extends BaseController { @@ -190,10 +210,14 @@ public class TelemetryController extends BaseController {
190 @PathVariable("entityType") String entityType, @PathVariable("entityId") String entityIdStr, 210 @PathVariable("entityType") String entityType, @PathVariable("entityId") String entityIdStr,
191 @RequestParam(name = "keys", required = false) String keysStr, 211 @RequestParam(name = "keys", required = false) String keysStr,
192 @RequestParam(name = "useStrictDataTypes", required = false, defaultValue = "false") Boolean useStrictDataTypes) throws ThingsboardException { 212 @RequestParam(name = "useStrictDataTypes", required = false, defaultValue = "false") Boolean useStrictDataTypes) throws ThingsboardException {
193 - SecurityUser user = getCurrentUser(); 213 + try {
  214 + SecurityUser user = getCurrentUser();
194 215
195 - return accessValidator.validateEntityAndCallback(getCurrentUser(), Operation.READ_TELEMETRY, entityType, entityIdStr,  
196 - (result, tenantId, entityId) -> getLatestTimeseriesValuesCallback(result, user, entityId, keysStr, useStrictDataTypes)); 216 + return accessValidator.validateEntityAndCallback(getCurrentUser(), Operation.READ_TELEMETRY, entityType, entityIdStr,
  217 + (result, tenantId, entityId) -> getLatestTimeseriesValuesCallback(result, user, entityId, keysStr, useStrictDataTypes));
  218 + } catch (Exception e) {
  219 + throw handleException(e);
  220 + }
197 } 221 }
198 222
199 223
@@ -211,15 +235,19 @@ public class TelemetryController extends BaseController { @@ -211,15 +235,19 @@ public class TelemetryController extends BaseController {
211 @RequestParam(name = "agg", defaultValue = "NONE") String aggStr, 235 @RequestParam(name = "agg", defaultValue = "NONE") String aggStr,
212 @RequestParam(name = "orderBy", defaultValue = "DESC") String orderBy, 236 @RequestParam(name = "orderBy", defaultValue = "DESC") String orderBy,
213 @RequestParam(name = "useStrictDataTypes", required = false, defaultValue = "false") Boolean useStrictDataTypes) throws ThingsboardException { 237 @RequestParam(name = "useStrictDataTypes", required = false, defaultValue = "false") Boolean useStrictDataTypes) throws ThingsboardException {
214 - return accessValidator.validateEntityAndCallback(getCurrentUser(), Operation.READ_TELEMETRY, entityType, entityIdStr,  
215 - (result, tenantId, entityId) -> {  
216 - // If interval is 0, convert this to a NONE aggregation, which is probably what the user really wanted  
217 - Aggregation agg = interval == 0L ? Aggregation.valueOf(Aggregation.NONE.name()) : Aggregation.valueOf(aggStr);  
218 - List<ReadTsKvQuery> queries = toKeysList(keys).stream().map(key -> new BaseReadTsKvQuery(key, startTs, endTs, interval, limit, agg, orderBy))  
219 - .collect(Collectors.toList());  
220 -  
221 - Futures.addCallback(tsService.findAll(tenantId, entityId, queries), getTsKvListCallback(result, useStrictDataTypes), MoreExecutors.directExecutor());  
222 - }); 238 + try {
  239 + return accessValidator.validateEntityAndCallback(getCurrentUser(), Operation.READ_TELEMETRY, entityType, entityIdStr,
  240 + (result, tenantId, entityId) -> {
  241 + // If interval is 0, convert this to a NONE aggregation, which is probably what the user really wanted
  242 + Aggregation agg = interval == 0L ? Aggregation.valueOf(Aggregation.NONE.name()) : Aggregation.valueOf(aggStr);
  243 + List<ReadTsKvQuery> queries = toKeysList(keys).stream().map(key -> new BaseReadTsKvQuery(key, startTs, endTs, interval, limit, agg, orderBy))
  244 + .collect(Collectors.toList());
  245 +
  246 + Futures.addCallback(tsService.findAll(tenantId, entityId, queries), getTsKvListCallback(result, useStrictDataTypes), MoreExecutors.directExecutor());
  247 + });
  248 + } catch (Exception e) {
  249 + throw handleException(e);
  250 + }
223 } 251 }
224 252
225 @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") 253 @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')")
@@ -227,8 +255,12 @@ public class TelemetryController extends BaseController { @@ -227,8 +255,12 @@ public class TelemetryController extends BaseController {
227 @ResponseBody 255 @ResponseBody
228 public DeferredResult<ResponseEntity> saveDeviceAttributes(@PathVariable("deviceId") String deviceIdStr, @PathVariable("scope") String scope, 256 public DeferredResult<ResponseEntity> saveDeviceAttributes(@PathVariable("deviceId") String deviceIdStr, @PathVariable("scope") String scope,
229 @RequestBody JsonNode request) throws ThingsboardException { 257 @RequestBody JsonNode request) throws ThingsboardException {
230 - EntityId entityId = EntityIdFactory.getByTypeAndUuid(EntityType.DEVICE, deviceIdStr);  
231 - return saveAttributes(getTenantId(), entityId, scope, request); 258 + try {
  259 + EntityId entityId = EntityIdFactory.getByTypeAndUuid(EntityType.DEVICE, deviceIdStr);
  260 + return saveAttributes(getTenantId(), entityId, scope, request);
  261 + } catch (Exception e) {
  262 + throw handleException(e);
  263 + }
232 } 264 }
233 265
234 @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") 266 @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')")
@@ -237,8 +269,12 @@ public class TelemetryController extends BaseController { @@ -237,8 +269,12 @@ public class TelemetryController extends BaseController {
237 public DeferredResult<ResponseEntity> saveEntityAttributesV1(@PathVariable("entityType") String entityType, @PathVariable("entityId") String entityIdStr, 269 public DeferredResult<ResponseEntity> saveEntityAttributesV1(@PathVariable("entityType") String entityType, @PathVariable("entityId") String entityIdStr,
238 @PathVariable("scope") String scope, 270 @PathVariable("scope") String scope,
239 @RequestBody JsonNode request) throws ThingsboardException { 271 @RequestBody JsonNode request) throws ThingsboardException {
240 - EntityId entityId = EntityIdFactory.getByTypeAndId(entityType, entityIdStr);  
241 - return saveAttributes(getTenantId(), entityId, scope, request); 272 + try {
  273 + EntityId entityId = EntityIdFactory.getByTypeAndId(entityType, entityIdStr);
  274 + return saveAttributes(getTenantId(), entityId, scope, request);
  275 + } catch (Exception e) {
  276 + throw handleException(e);
  277 + }
242 } 278 }
243 279
244 @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") 280 @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')")
@@ -247,8 +283,12 @@ public class TelemetryController extends BaseController { @@ -247,8 +283,12 @@ public class TelemetryController extends BaseController {
247 public DeferredResult<ResponseEntity> saveEntityAttributesV2(@PathVariable("entityType") String entityType, @PathVariable("entityId") String entityIdStr, 283 public DeferredResult<ResponseEntity> saveEntityAttributesV2(@PathVariable("entityType") String entityType, @PathVariable("entityId") String entityIdStr,
248 @PathVariable("scope") String scope, 284 @PathVariable("scope") String scope,
249 @RequestBody JsonNode request) throws ThingsboardException { 285 @RequestBody JsonNode request) throws ThingsboardException {
250 - EntityId entityId = EntityIdFactory.getByTypeAndId(entityType, entityIdStr);  
251 - return saveAttributes(getTenantId(), entityId, scope, request); 286 + try {
  287 + EntityId entityId = EntityIdFactory.getByTypeAndId(entityType, entityIdStr);
  288 + return saveAttributes(getTenantId(), entityId, scope, request);
  289 + } catch (Exception e) {
  290 + throw handleException(e);
  291 + }
252 } 292 }
253 293
254 @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") 294 @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')")
@@ -257,8 +297,12 @@ public class TelemetryController extends BaseController { @@ -257,8 +297,12 @@ public class TelemetryController extends BaseController {
257 public DeferredResult<ResponseEntity> saveEntityTelemetry(@PathVariable("entityType") String entityType, @PathVariable("entityId") String entityIdStr, 297 public DeferredResult<ResponseEntity> saveEntityTelemetry(@PathVariable("entityType") String entityType, @PathVariable("entityId") String entityIdStr,
258 @PathVariable("scope") String scope, 298 @PathVariable("scope") String scope,
259 @RequestBody String requestBody) throws ThingsboardException { 299 @RequestBody String requestBody) throws ThingsboardException {
260 - EntityId entityId = EntityIdFactory.getByTypeAndId(entityType, entityIdStr);  
261 - return saveTelemetry(getTenantId(), entityId, requestBody, 0L); 300 + try {
  301 + EntityId entityId = EntityIdFactory.getByTypeAndId(entityType, entityIdStr);
  302 + return saveTelemetry(getTenantId(), entityId, requestBody, 0L);
  303 + } catch (Exception e) {
  304 + throw handleException(e);
  305 + }
262 } 306 }
263 307
264 @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") 308 @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')")
@@ -267,8 +311,12 @@ public class TelemetryController extends BaseController { @@ -267,8 +311,12 @@ public class TelemetryController extends BaseController {
267 public DeferredResult<ResponseEntity> saveEntityTelemetryWithTTL(@PathVariable("entityType") String entityType, @PathVariable("entityId") String entityIdStr, 311 public DeferredResult<ResponseEntity> saveEntityTelemetryWithTTL(@PathVariable("entityType") String entityType, @PathVariable("entityId") String entityIdStr,
268 @PathVariable("scope") String scope, @PathVariable("ttl") Long ttl, 312 @PathVariable("scope") String scope, @PathVariable("ttl") Long ttl,
269 @RequestBody String requestBody) throws ThingsboardException { 313 @RequestBody String requestBody) throws ThingsboardException {
270 - EntityId entityId = EntityIdFactory.getByTypeAndId(entityType, entityIdStr);  
271 - return saveTelemetry(getTenantId(), entityId, requestBody, ttl); 314 + try {
  315 + EntityId entityId = EntityIdFactory.getByTypeAndId(entityType, entityIdStr);
  316 + return saveTelemetry(getTenantId(), entityId, requestBody, ttl);
  317 + } catch (Exception e) {
  318 + throw handleException(e);
  319 + }
272 } 320 }
273 321
274 @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") 322 @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')")
@@ -280,8 +328,12 @@ public class TelemetryController extends BaseController { @@ -280,8 +328,12 @@ public class TelemetryController extends BaseController {
280 @RequestParam(name = "startTs", required = false) Long startTs, 328 @RequestParam(name = "startTs", required = false) Long startTs,
281 @RequestParam(name = "endTs", required = false) Long endTs, 329 @RequestParam(name = "endTs", required = false) Long endTs,
282 @RequestParam(name = "rewriteLatestIfDeleted", defaultValue = "false") boolean rewriteLatestIfDeleted) throws ThingsboardException { 330 @RequestParam(name = "rewriteLatestIfDeleted", defaultValue = "false") boolean rewriteLatestIfDeleted) throws ThingsboardException {
283 - EntityId entityId = EntityIdFactory.getByTypeAndId(entityType, entityIdStr);  
284 - return deleteTimeseries(entityId, keysStr, deleteAllDataForKeys, startTs, endTs, rewriteLatestIfDeleted); 331 + try {
  332 + EntityId entityId = EntityIdFactory.getByTypeAndId(entityType, entityIdStr);
  333 + return deleteTimeseries(entityId, keysStr, deleteAllDataForKeys, startTs, endTs, rewriteLatestIfDeleted);
  334 + } catch (Exception e) {
  335 + throw handleException(e);
  336 + }
285 } 337 }
286 338
287 private DeferredResult<ResponseEntity> deleteTimeseries(EntityId entityIdStr, String keysStr, boolean deleteAllDataForKeys, 339 private DeferredResult<ResponseEntity> deleteTimeseries(EntityId entityIdStr, String keysStr, boolean deleteAllDataForKeys,
@@ -335,8 +387,12 @@ public class TelemetryController extends BaseController { @@ -335,8 +387,12 @@ public class TelemetryController extends BaseController {
335 public DeferredResult<ResponseEntity> deleteEntityAttributes(@PathVariable("deviceId") String deviceIdStr, 387 public DeferredResult<ResponseEntity> deleteEntityAttributes(@PathVariable("deviceId") String deviceIdStr,
336 @PathVariable("scope") String scope, 388 @PathVariable("scope") String scope,
337 @RequestParam(name = "keys") String keysStr) throws ThingsboardException { 389 @RequestParam(name = "keys") String keysStr) throws ThingsboardException {
338 - EntityId entityId = EntityIdFactory.getByTypeAndUuid(EntityType.DEVICE, deviceIdStr);  
339 - return deleteAttributes(entityId, scope, keysStr); 390 + try {
  391 + EntityId entityId = EntityIdFactory.getByTypeAndUuid(EntityType.DEVICE, deviceIdStr);
  392 + return deleteAttributes(entityId, scope, keysStr);
  393 + } catch (Exception e) {
  394 + throw handleException(e);
  395 + }
340 } 396 }
341 397
342 @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") 398 @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')")
@@ -345,8 +401,12 @@ public class TelemetryController extends BaseController { @@ -345,8 +401,12 @@ public class TelemetryController extends BaseController {
345 public DeferredResult<ResponseEntity> deleteEntityAttributes(@PathVariable("entityType") String entityType, @PathVariable("entityId") String entityIdStr, 401 public DeferredResult<ResponseEntity> deleteEntityAttributes(@PathVariable("entityType") String entityType, @PathVariable("entityId") String entityIdStr,
346 @PathVariable("scope") String scope, 402 @PathVariable("scope") String scope,
347 @RequestParam(name = "keys") String keysStr) throws ThingsboardException { 403 @RequestParam(name = "keys") String keysStr) throws ThingsboardException {
348 - EntityId entityId = EntityIdFactory.getByTypeAndId(entityType, entityIdStr);  
349 - return deleteAttributes(entityId, scope, keysStr); 404 + try {
  405 + EntityId entityId = EntityIdFactory.getByTypeAndId(entityType, entityIdStr);
  406 + return deleteAttributes(entityId, scope, keysStr);
  407 + } catch (Exception e) {
  408 + throw handleException(e);
  409 + }
350 } 410 }
351 411
352 private DeferredResult<ResponseEntity> deleteAttributes(EntityId entityIdSrc, String scope, String keysStr) throws ThingsboardException { 412 private DeferredResult<ResponseEntity> deleteAttributes(EntityId entityIdSrc, String scope, String keysStr) throws ThingsboardException {
@@ -392,6 +452,7 @@ public class TelemetryController extends BaseController { @@ -392,6 +452,7 @@ public class TelemetryController extends BaseController {
392 } 452 }
393 if (json.isObject()) { 453 if (json.isObject()) {
394 List<AttributeKvEntry> attributes = extractRequestAttributes(json); 454 List<AttributeKvEntry> attributes = extractRequestAttributes(json);
  455 + attributes.forEach(ConstraintValidator::validateFields);
395 if (attributes.isEmpty()) { 456 if (attributes.isEmpty()) {
396 return getImmediateDeferredResult("No attributes data found in request body!", HttpStatus.BAD_REQUEST); 457 return getImmediateDeferredResult("No attributes data found in request body!", HttpStatus.BAD_REQUEST);
397 } 458 }
@@ -17,30 +17,36 @@ package org.thingsboard.server.common.data; @@ -17,30 +17,36 @@ package org.thingsboard.server.common.data;
17 17
18 import lombok.EqualsAndHashCode; 18 import lombok.EqualsAndHashCode;
19 import org.thingsboard.server.common.data.id.UUIDBased; 19 import org.thingsboard.server.common.data.id.UUIDBased;
  20 +import org.thingsboard.server.common.data.validation.Length;
20 import org.thingsboard.server.common.data.validation.NoXss; 21 import org.thingsboard.server.common.data.validation.NoXss;
21 22
22 @EqualsAndHashCode(callSuper = true) 23 @EqualsAndHashCode(callSuper = true)
23 public abstract class ContactBased<I extends UUIDBased> extends SearchTextBasedWithAdditionalInfo<I> implements HasName { 24 public abstract class ContactBased<I extends UUIDBased> extends SearchTextBasedWithAdditionalInfo<I> implements HasName {
24 - 25 +
25 private static final long serialVersionUID = 5047448057830660988L; 26 private static final long serialVersionUID = 5047448057830660988L;
26 27
  28 + @Length(fieldName = "country")
27 @NoXss 29 @NoXss
28 protected String country; 30 protected String country;
  31 + @Length(fieldName = "state")
29 @NoXss 32 @NoXss
30 protected String state; 33 protected String state;
  34 + @Length(fieldName = "city")
31 @NoXss 35 @NoXss
32 protected String city; 36 protected String city;
33 @NoXss 37 @NoXss
34 protected String address; 38 protected String address;
35 @NoXss 39 @NoXss
36 protected String address2; 40 protected String address2;
  41 + @Length(fieldName = "zip or postal code")
37 @NoXss 42 @NoXss
38 protected String zip; 43 protected String zip;
  44 + @Length(fieldName = "phone")
39 @NoXss 45 @NoXss
40 protected String phone; 46 protected String phone;
41 @NoXss 47 @NoXss
42 protected String email; 48 protected String email;
43 - 49 +
44 public ContactBased() { 50 public ContactBased() {
45 super(); 51 super();
46 } 52 }
@@ -48,7 +54,7 @@ public abstract class ContactBased<I extends UUIDBased> extends SearchTextBasedW @@ -48,7 +54,7 @@ public abstract class ContactBased<I extends UUIDBased> extends SearchTextBasedW
48 public ContactBased(I id) { 54 public ContactBased(I id) {
49 super(id); 55 super(id);
50 } 56 }
51 - 57 +
52 public ContactBased(ContactBased<I> contact) { 58 public ContactBased(ContactBased<I> contact) {
53 super(contact); 59 super(contact);
54 this.country = contact.getCountry(); 60 this.country = contact.getCountry();
@@ -20,13 +20,15 @@ import com.fasterxml.jackson.annotation.JsonProperty; @@ -20,13 +20,15 @@ import com.fasterxml.jackson.annotation.JsonProperty;
20 import com.fasterxml.jackson.annotation.JsonProperty.Access; 20 import com.fasterxml.jackson.annotation.JsonProperty.Access;
21 import org.thingsboard.server.common.data.id.CustomerId; 21 import org.thingsboard.server.common.data.id.CustomerId;
22 import org.thingsboard.server.common.data.id.TenantId; 22 import org.thingsboard.server.common.data.id.TenantId;
  23 +import org.thingsboard.server.common.data.validation.Length;
23 import org.thingsboard.server.common.data.validation.NoXss; 24 import org.thingsboard.server.common.data.validation.NoXss;
24 25
25 public class Customer extends ContactBased<CustomerId> implements HasTenantId { 26 public class Customer extends ContactBased<CustomerId> implements HasTenantId {
26 - 27 +
27 private static final long serialVersionUID = -1599722990298929275L; 28 private static final long serialVersionUID = -1599722990298929275L;
28 29
29 @NoXss 30 @NoXss
  31 + @Length(fieldName = "title")
30 private String title; 32 private String title;
31 private TenantId tenantId; 33 private TenantId tenantId;
32 34
@@ -37,7 +39,7 @@ public class Customer extends ContactBased<CustomerId> implements HasTenantId { @@ -37,7 +39,7 @@ public class Customer extends ContactBased<CustomerId> implements HasTenantId {
37 public Customer(CustomerId id) { 39 public Customer(CustomerId id) {
38 super(id); 40 super(id);
39 } 41 }
40 - 42 +
41 public Customer(Customer customer) { 43 public Customer(Customer customer) {
42 super(customer); 44 super(customer);
43 this.tenantId = customer.getTenantId(); 45 this.tenantId = customer.getTenantId();
@@ -51,7 +53,7 @@ public class Customer extends ContactBased<CustomerId> implements HasTenantId { @@ -51,7 +53,7 @@ public class Customer extends ContactBased<CustomerId> implements HasTenantId {
51 public void setTenantId(TenantId tenantId) { 53 public void setTenantId(TenantId tenantId) {
52 this.tenantId = tenantId; 54 this.tenantId = tenantId;
53 } 55 }
54 - 56 +
55 public String getTitle() { 57 public String getTitle() {
56 return title; 58 return title;
57 } 59 }
@@ -19,6 +19,7 @@ import com.fasterxml.jackson.annotation.JsonProperty; @@ -19,6 +19,7 @@ import com.fasterxml.jackson.annotation.JsonProperty;
19 import org.thingsboard.server.common.data.id.CustomerId; 19 import org.thingsboard.server.common.data.id.CustomerId;
20 import org.thingsboard.server.common.data.id.DashboardId; 20 import org.thingsboard.server.common.data.id.DashboardId;
21 import org.thingsboard.server.common.data.id.TenantId; 21 import org.thingsboard.server.common.data.id.TenantId;
  22 +import org.thingsboard.server.common.data.validation.Length;
22 import org.thingsboard.server.common.data.validation.NoXss; 23 import org.thingsboard.server.common.data.validation.NoXss;
23 24
24 import javax.validation.Valid; 25 import javax.validation.Valid;
@@ -29,6 +30,7 @@ public class DashboardInfo extends SearchTextBased<DashboardId> implements HasNa @@ -29,6 +30,7 @@ public class DashboardInfo extends SearchTextBased<DashboardId> implements HasNa
29 30
30 private TenantId tenantId; 31 private TenantId tenantId;
31 @NoXss 32 @NoXss
  33 + @Length(fieldName = "title")
32 private String title; 34 private String title;
33 private String image; 35 private String image;
34 @Valid 36 @Valid
@@ -25,6 +25,7 @@ import org.thingsboard.server.common.data.id.DeviceId; @@ -25,6 +25,7 @@ import org.thingsboard.server.common.data.id.DeviceId;
25 import org.thingsboard.server.common.data.id.DeviceProfileId; 25 import org.thingsboard.server.common.data.id.DeviceProfileId;
26 import org.thingsboard.server.common.data.id.OtaPackageId; 26 import org.thingsboard.server.common.data.id.OtaPackageId;
27 import org.thingsboard.server.common.data.id.TenantId; 27 import org.thingsboard.server.common.data.id.TenantId;
  28 +import org.thingsboard.server.common.data.validation.Length;
28 import org.thingsboard.server.common.data.validation.NoXss; 29 import org.thingsboard.server.common.data.validation.NoXss;
29 30
30 import java.io.ByteArrayInputStream; 31 import java.io.ByteArrayInputStream;
@@ -39,10 +40,13 @@ public class Device extends SearchTextBasedWithAdditionalInfo<DeviceId> implemen @@ -39,10 +40,13 @@ public class Device extends SearchTextBasedWithAdditionalInfo<DeviceId> implemen
39 private TenantId tenantId; 40 private TenantId tenantId;
40 private CustomerId customerId; 41 private CustomerId customerId;
41 @NoXss 42 @NoXss
  43 + @Length(fieldName = "name")
42 private String name; 44 private String name;
43 @NoXss 45 @NoXss
  46 + @Length(fieldName = "type")
44 private String type; 47 private String type;
45 @NoXss 48 @NoXss
  49 + @Length(fieldName = "label")
46 private String label; 50 private String label;
47 private DeviceProfileId deviceProfileId; 51 private DeviceProfileId deviceProfileId;
48 private transient DeviceData deviceData; 52 private transient DeviceData deviceData;
@@ -26,6 +26,7 @@ import org.thingsboard.server.common.data.id.DeviceProfileId; @@ -26,6 +26,7 @@ import org.thingsboard.server.common.data.id.DeviceProfileId;
26 import org.thingsboard.server.common.data.id.OtaPackageId; 26 import org.thingsboard.server.common.data.id.OtaPackageId;
27 import org.thingsboard.server.common.data.id.RuleChainId; 27 import org.thingsboard.server.common.data.id.RuleChainId;
28 import org.thingsboard.server.common.data.id.TenantId; 28 import org.thingsboard.server.common.data.id.TenantId;
  29 +import org.thingsboard.server.common.data.validation.Length;
29 import org.thingsboard.server.common.data.validation.NoXss; 30 import org.thingsboard.server.common.data.validation.NoXss;
30 31
31 import javax.validation.Valid; 32 import javax.validation.Valid;
@@ -41,6 +42,7 @@ public class DeviceProfile extends SearchTextBased<DeviceProfileId> implements H @@ -41,6 +42,7 @@ public class DeviceProfile extends SearchTextBased<DeviceProfileId> implements H
41 42
42 private TenantId tenantId; 43 private TenantId tenantId;
43 @NoXss 44 @NoXss
  45 + @Length(fieldName = "name")
44 private String name; 46 private String name;
45 @NoXss 47 @NoXss
46 private String description; 48 private String description;
@@ -23,6 +23,7 @@ import org.thingsboard.server.common.data.id.EntityId; @@ -23,6 +23,7 @@ import org.thingsboard.server.common.data.id.EntityId;
23 import org.thingsboard.server.common.data.id.EntityViewId; 23 import org.thingsboard.server.common.data.id.EntityViewId;
24 import org.thingsboard.server.common.data.id.TenantId; 24 import org.thingsboard.server.common.data.id.TenantId;
25 import org.thingsboard.server.common.data.objects.TelemetryEntityView; 25 import org.thingsboard.server.common.data.objects.TelemetryEntityView;
  26 +import org.thingsboard.server.common.data.validation.Length;
26 import org.thingsboard.server.common.data.validation.NoXss; 27 import org.thingsboard.server.common.data.validation.NoXss;
27 28
28 /** 29 /**
@@ -41,8 +42,10 @@ public class EntityView extends SearchTextBasedWithAdditionalInfo<EntityViewId> @@ -41,8 +42,10 @@ public class EntityView extends SearchTextBasedWithAdditionalInfo<EntityViewId>
41 private TenantId tenantId; 42 private TenantId tenantId;
42 private CustomerId customerId; 43 private CustomerId customerId;
43 @NoXss 44 @NoXss
  45 + @Length(fieldName = "name")
44 private String name; 46 private String name;
45 @NoXss 47 @NoXss
  48 + @Length(fieldName = "type")
46 private String type; 49 private String type;
47 private TelemetryEntityView keys; 50 private TelemetryEntityView keys;
48 private long startTimeMs; 51 private long startTimeMs;
@@ -19,11 +19,12 @@ import com.fasterxml.jackson.annotation.JsonIgnore; @@ -19,11 +19,12 @@ import com.fasterxml.jackson.annotation.JsonIgnore;
19 import lombok.Data; 19 import lombok.Data;
20 import lombok.EqualsAndHashCode; 20 import lombok.EqualsAndHashCode;
21 import lombok.extern.slf4j.Slf4j; 21 import lombok.extern.slf4j.Slf4j;
22 -import org.thingsboard.server.common.data.ota.ChecksumAlgorithm;  
23 -import org.thingsboard.server.common.data.ota.OtaPackageType;  
24 import org.thingsboard.server.common.data.id.DeviceProfileId; 22 import org.thingsboard.server.common.data.id.DeviceProfileId;
25 import org.thingsboard.server.common.data.id.OtaPackageId; 23 import org.thingsboard.server.common.data.id.OtaPackageId;
26 import org.thingsboard.server.common.data.id.TenantId; 24 import org.thingsboard.server.common.data.id.TenantId;
  25 +import org.thingsboard.server.common.data.ota.ChecksumAlgorithm;
  26 +import org.thingsboard.server.common.data.ota.OtaPackageType;
  27 +import org.thingsboard.server.common.data.validation.Length;
27 28
28 @Slf4j 29 @Slf4j
29 @Data 30 @Data
@@ -35,10 +36,14 @@ public class OtaPackageInfo extends SearchTextBasedWithAdditionalInfo<OtaPackage @@ -35,10 +36,14 @@ public class OtaPackageInfo extends SearchTextBasedWithAdditionalInfo<OtaPackage
35 private TenantId tenantId; 36 private TenantId tenantId;
36 private DeviceProfileId deviceProfileId; 37 private DeviceProfileId deviceProfileId;
37 private OtaPackageType type; 38 private OtaPackageType type;
  39 + @Length(fieldName = "title")
38 private String title; 40 private String title;
  41 + @Length(fieldName = "version")
39 private String version; 42 private String version;
  43 + @Length(fieldName = "url")
40 private String url; 44 private String url;
41 private boolean hasData; 45 private boolean hasData;
  46 + @Length(fieldName = "file name")
42 private String fileName; 47 private String fileName;
43 private String contentType; 48 private String contentType;
44 private ChecksumAlgorithm checksumAlgorithm; 49 private ChecksumAlgorithm checksumAlgorithm;
@@ -19,6 +19,7 @@ import lombok.Data; @@ -19,6 +19,7 @@ import lombok.Data;
19 import lombok.EqualsAndHashCode; 19 import lombok.EqualsAndHashCode;
20 import lombok.extern.slf4j.Slf4j; 20 import lombok.extern.slf4j.Slf4j;
21 import org.thingsboard.server.common.data.id.TbResourceId; 21 import org.thingsboard.server.common.data.id.TbResourceId;
  22 +import org.thingsboard.server.common.data.validation.Length;
22 import org.thingsboard.server.common.data.validation.NoXss; 23 import org.thingsboard.server.common.data.validation.NoXss;
23 24
24 @Slf4j 25 @Slf4j
@@ -29,6 +30,7 @@ public class TbResource extends TbResourceInfo { @@ -29,6 +30,7 @@ public class TbResource extends TbResourceInfo {
29 private static final long serialVersionUID = 7379609705527272306L; 30 private static final long serialVersionUID = 7379609705527272306L;
30 31
31 @NoXss 32 @NoXss
  33 + @Length(fieldName = "file name")
32 private String fileName; 34 private String fileName;
33 35
34 private String data; 36 private String data;
@@ -21,6 +21,7 @@ import lombok.EqualsAndHashCode; @@ -21,6 +21,7 @@ import lombok.EqualsAndHashCode;
21 import lombok.extern.slf4j.Slf4j; 21 import lombok.extern.slf4j.Slf4j;
22 import org.thingsboard.server.common.data.id.TbResourceId; 22 import org.thingsboard.server.common.data.id.TbResourceId;
23 import org.thingsboard.server.common.data.id.TenantId; 23 import org.thingsboard.server.common.data.id.TenantId;
  24 +import org.thingsboard.server.common.data.validation.Length;
24 import org.thingsboard.server.common.data.validation.NoXss; 25 import org.thingsboard.server.common.data.validation.NoXss;
25 26
26 @Slf4j 27 @Slf4j
@@ -32,6 +33,7 @@ public class TbResourceInfo extends SearchTextBased<TbResourceId> implements Has @@ -32,6 +33,7 @@ public class TbResourceInfo extends SearchTextBased<TbResourceId> implements Has
32 33
33 private TenantId tenantId; 34 private TenantId tenantId;
34 @NoXss 35 @NoXss
  36 + @Length(fieldName = "title")
35 private String title; 37 private String title;
36 private ResourceType resourceType; 38 private ResourceType resourceType;
37 private String resourceKey; 39 private String resourceKey;
@@ -20,6 +20,7 @@ import com.fasterxml.jackson.annotation.JsonProperty; @@ -20,6 +20,7 @@ import com.fasterxml.jackson.annotation.JsonProperty;
20 import lombok.EqualsAndHashCode; 20 import lombok.EqualsAndHashCode;
21 import org.thingsboard.server.common.data.id.TenantId; 21 import org.thingsboard.server.common.data.id.TenantId;
22 import org.thingsboard.server.common.data.id.TenantProfileId; 22 import org.thingsboard.server.common.data.id.TenantProfileId;
  23 +import org.thingsboard.server.common.data.validation.Length;
23 import org.thingsboard.server.common.data.validation.NoXss; 24 import org.thingsboard.server.common.data.validation.NoXss;
24 25
25 @EqualsAndHashCode(callSuper = true) 26 @EqualsAndHashCode(callSuper = true)
@@ -27,8 +28,10 @@ public class Tenant extends ContactBased<TenantId> implements HasTenantId { @@ -27,8 +28,10 @@ public class Tenant extends ContactBased<TenantId> implements HasTenantId {
27 28
28 private static final long serialVersionUID = 8057243243859922101L; 29 private static final long serialVersionUID = 8057243243859922101L;
29 30
  31 + @Length(fieldName = "title")
30 @NoXss 32 @NoXss
31 private String title; 33 private String title;
  34 + @Length(fieldName = "region")
32 @NoXss 35 @NoXss
33 private String region; 36 private String region;
34 private TenantProfileId tenantProfileId; 37 private TenantProfileId tenantProfileId;
@@ -40,7 +43,7 @@ public class Tenant extends ContactBased<TenantId> implements HasTenantId { @@ -40,7 +43,7 @@ public class Tenant extends ContactBased<TenantId> implements HasTenantId {
40 public Tenant(TenantId id) { 43 public Tenant(TenantId id) {
41 super(id); 44 super(id);
42 } 45 }
43 - 46 +
44 public Tenant(Tenant tenant) { 47 public Tenant(Tenant tenant) {
45 super(tenant); 48 super(tenant);
46 this.title = tenant.getTitle(); 49 this.title = tenant.getTitle();
@@ -23,6 +23,7 @@ import lombok.extern.slf4j.Slf4j; @@ -23,6 +23,7 @@ import lombok.extern.slf4j.Slf4j;
23 import org.thingsboard.server.common.data.id.TenantProfileId; 23 import org.thingsboard.server.common.data.id.TenantProfileId;
24 import org.thingsboard.server.common.data.tenant.profile.DefaultTenantProfileConfiguration; 24 import org.thingsboard.server.common.data.tenant.profile.DefaultTenantProfileConfiguration;
25 import org.thingsboard.server.common.data.tenant.profile.TenantProfileData; 25 import org.thingsboard.server.common.data.tenant.profile.TenantProfileData;
  26 +import org.thingsboard.server.common.data.validation.Length;
26 import org.thingsboard.server.common.data.validation.NoXss; 27 import org.thingsboard.server.common.data.validation.NoXss;
27 28
28 import java.io.ByteArrayInputStream; 29 import java.io.ByteArrayInputStream;
@@ -37,6 +38,7 @@ import static org.thingsboard.server.common.data.SearchTextBasedWithAdditionalIn @@ -37,6 +38,7 @@ import static org.thingsboard.server.common.data.SearchTextBasedWithAdditionalIn
37 public class TenantProfile extends SearchTextBased<TenantProfileId> implements HasName { 38 public class TenantProfile extends SearchTextBased<TenantProfileId> implements HasName {
38 39
39 @NoXss 40 @NoXss
  41 + @Length(fieldName = "name")
40 private String name; 42 private String name;
41 @NoXss 43 @NoXss
42 private String description; 44 private String description;
@@ -23,7 +23,7 @@ import org.thingsboard.server.common.data.id.EntityId; @@ -23,7 +23,7 @@ import org.thingsboard.server.common.data.id.EntityId;
23 import org.thingsboard.server.common.data.id.TenantId; 23 import org.thingsboard.server.common.data.id.TenantId;
24 import org.thingsboard.server.common.data.id.UserId; 24 import org.thingsboard.server.common.data.id.UserId;
25 import org.thingsboard.server.common.data.security.Authority; 25 import org.thingsboard.server.common.data.security.Authority;
26 - 26 +import org.thingsboard.server.common.data.validation.Length;
27 import org.thingsboard.server.common.data.validation.NoXss; 27 import org.thingsboard.server.common.data.validation.NoXss;
28 28
29 @EqualsAndHashCode(callSuper = true) 29 @EqualsAndHashCode(callSuper = true)
@@ -36,8 +36,10 @@ public class User extends SearchTextBasedWithAdditionalInfo<UserId> implements H @@ -36,8 +36,10 @@ public class User extends SearchTextBasedWithAdditionalInfo<UserId> implements H
36 private String email; 36 private String email;
37 private Authority authority; 37 private Authority authority;
38 @NoXss 38 @NoXss
  39 + @Length(fieldName = "firs name")
39 private String firstName; 40 private String firstName;
40 @NoXss 41 @NoXss
  42 + @Length(fieldName = "last name")
41 private String lastName; 43 private String lastName;
42 44
43 public User() { 45 public User() {
@@ -28,6 +28,7 @@ import org.thingsboard.server.common.data.id.AlarmId; @@ -28,6 +28,7 @@ import org.thingsboard.server.common.data.id.AlarmId;
28 import org.thingsboard.server.common.data.id.CustomerId; 28 import org.thingsboard.server.common.data.id.CustomerId;
29 import org.thingsboard.server.common.data.id.EntityId; 29 import org.thingsboard.server.common.data.id.EntityId;
30 import org.thingsboard.server.common.data.id.TenantId; 30 import org.thingsboard.server.common.data.id.TenantId;
  31 +import org.thingsboard.server.common.data.validation.Length;
31 32
32 import java.util.List; 33 import java.util.List;
33 34
@@ -41,6 +42,7 @@ public class Alarm extends BaseData<AlarmId> implements HasName, HasTenantId, Ha @@ -41,6 +42,7 @@ public class Alarm extends BaseData<AlarmId> implements HasName, HasTenantId, Ha
41 42
42 private TenantId tenantId; 43 private TenantId tenantId;
43 private CustomerId customerId; 44 private CustomerId customerId;
  45 + @Length(fieldName = "type")
44 private String type; 46 private String type;
45 private EntityId originator; 47 private EntityId originator;
46 private AlarmSeverity severity; 48 private AlarmSeverity severity;
@@ -15,7 +15,6 @@ @@ -15,7 +15,6 @@
15 */ 15 */
16 package org.thingsboard.server.common.data.edge; 16 package org.thingsboard.server.common.data.edge;
17 17
18 -import com.fasterxml.jackson.databind.JsonNode;  
19 import lombok.EqualsAndHashCode; 18 import lombok.EqualsAndHashCode;
20 import lombok.Getter; 19 import lombok.Getter;
21 import lombok.Setter; 20 import lombok.Setter;
@@ -28,6 +27,7 @@ import org.thingsboard.server.common.data.id.CustomerId; @@ -28,6 +27,7 @@ import org.thingsboard.server.common.data.id.CustomerId;
28 import org.thingsboard.server.common.data.id.EdgeId; 27 import org.thingsboard.server.common.data.id.EdgeId;
29 import org.thingsboard.server.common.data.id.RuleChainId; 28 import org.thingsboard.server.common.data.id.RuleChainId;
30 import org.thingsboard.server.common.data.id.TenantId; 29 import org.thingsboard.server.common.data.id.TenantId;
  30 +import org.thingsboard.server.common.data.validation.Length;
31 31
32 @EqualsAndHashCode(callSuper = true) 32 @EqualsAndHashCode(callSuper = true)
33 @ToString 33 @ToString
@@ -40,8 +40,11 @@ public class Edge extends SearchTextBasedWithAdditionalInfo<EdgeId> implements H @@ -40,8 +40,11 @@ public class Edge extends SearchTextBasedWithAdditionalInfo<EdgeId> implements H
40 private TenantId tenantId; 40 private TenantId tenantId;
41 private CustomerId customerId; 41 private CustomerId customerId;
42 private RuleChainId rootRuleChainId; 42 private RuleChainId rootRuleChainId;
  43 + @Length(fieldName = "name")
43 private String name; 44 private String name;
  45 + @Length(fieldName = "type")
44 private String type; 46 private String type;
  47 + @Length(fieldName = "label")
45 private String label; 48 private String label;
46 private String routingKey; 49 private String routingKey;
47 private String secret; 50 private String secret;
@@ -15,8 +15,7 @@ @@ -15,8 +15,7 @@
15 */ 15 */
16 package org.thingsboard.server.common.data.kv; 16 package org.thingsboard.server.common.data.kv;
17 17
18 -import com.fasterxml.jackson.databind.JsonNode;  
19 - 18 +import javax.validation.Valid;
20 import java.util.Optional; 19 import java.util.Optional;
21 20
22 /** 21 /**
@@ -25,6 +24,7 @@ import java.util.Optional; @@ -25,6 +24,7 @@ import java.util.Optional;
25 public class BaseAttributeKvEntry implements AttributeKvEntry { 24 public class BaseAttributeKvEntry implements AttributeKvEntry {
26 25
27 private final long lastUpdateTs; 26 private final long lastUpdateTs;
  27 + @Valid
28 private final KvEntry kv; 28 private final KvEntry kv;
29 29
30 public BaseAttributeKvEntry(KvEntry kv, long lastUpdateTs) { 30 public BaseAttributeKvEntry(KvEntry kv, long lastUpdateTs) {
@@ -15,11 +15,14 @@ @@ -15,11 +15,14 @@
15 */ 15 */
16 package org.thingsboard.server.common.data.kv; 16 package org.thingsboard.server.common.data.kv;
17 17
  18 +import org.thingsboard.server.common.data.validation.Length;
  19 +
18 import java.util.Objects; 20 import java.util.Objects;
19 import java.util.Optional; 21 import java.util.Optional;
20 22
21 public abstract class BasicKvEntry implements KvEntry { 23 public abstract class BasicKvEntry implements KvEntry {
22 24
  25 + @Length(fieldName = "attribute key")
23 private final String key; 26 private final String key;
24 27
25 protected BasicKvEntry(String key) { 28 protected BasicKvEntry(String key) {
@@ -21,6 +21,7 @@ import java.util.Optional; @@ -21,6 +21,7 @@ import java.util.Optional;
21 public class StringDataEntry extends BasicKvEntry { 21 public class StringDataEntry extends BasicKvEntry {
22 22
23 private static final long serialVersionUID = 1L; 23 private static final long serialVersionUID = 1L;
  24 +
24 private final String value; 25 private final String value;
25 26
26 public StringDataEntry(String key, String value) { 27 public StringDataEntry(String key, String value) {
@@ -16,15 +16,12 @@ @@ -16,15 +16,12 @@
16 package org.thingsboard.server.common.data.relation; 16 package org.thingsboard.server.common.data.relation;
17 17
18 import com.fasterxml.jackson.annotation.JsonIgnore; 18 import com.fasterxml.jackson.annotation.JsonIgnore;
19 -import com.fasterxml.jackson.core.JsonProcessingException;  
20 import com.fasterxml.jackson.databind.JsonNode; 19 import com.fasterxml.jackson.databind.JsonNode;
21 -import com.fasterxml.jackson.databind.ObjectMapper;  
22 import lombok.extern.slf4j.Slf4j; 20 import lombok.extern.slf4j.Slf4j;
23 import org.thingsboard.server.common.data.SearchTextBasedWithAdditionalInfo; 21 import org.thingsboard.server.common.data.SearchTextBasedWithAdditionalInfo;
24 import org.thingsboard.server.common.data.id.EntityId; 22 import org.thingsboard.server.common.data.id.EntityId;
  23 +import org.thingsboard.server.common.data.validation.Length;
25 24
26 -import java.io.ByteArrayInputStream;  
27 -import java.io.IOException;  
28 import java.io.Serializable; 25 import java.io.Serializable;
29 26
30 @Slf4j 27 @Slf4j
@@ -38,6 +35,7 @@ public class EntityRelation implements Serializable { @@ -38,6 +35,7 @@ public class EntityRelation implements Serializable {
38 35
39 private EntityId from; 36 private EntityId from;
40 private EntityId to; 37 private EntityId to;
  38 + @Length(fieldName = "type")
41 private String type; 39 private String type;
42 private RelationTypeGroup typeGroup; 40 private RelationTypeGroup typeGroup;
43 private transient JsonNode additionalInfo; 41 private transient JsonNode additionalInfo;
@@ -26,6 +26,7 @@ import org.thingsboard.server.common.data.SearchTextBasedWithAdditionalInfo; @@ -26,6 +26,7 @@ import org.thingsboard.server.common.data.SearchTextBasedWithAdditionalInfo;
26 import org.thingsboard.server.common.data.id.RuleChainId; 26 import org.thingsboard.server.common.data.id.RuleChainId;
27 import org.thingsboard.server.common.data.id.RuleNodeId; 27 import org.thingsboard.server.common.data.id.RuleNodeId;
28 import org.thingsboard.server.common.data.id.TenantId; 28 import org.thingsboard.server.common.data.id.TenantId;
  29 +import org.thingsboard.server.common.data.validation.Length;
29 import org.thingsboard.server.common.data.validation.NoXss; 30 import org.thingsboard.server.common.data.validation.NoXss;
30 31
31 @Data 32 @Data
@@ -37,6 +38,7 @@ public class RuleChain extends SearchTextBasedWithAdditionalInfo<RuleChainId> im @@ -37,6 +38,7 @@ public class RuleChain extends SearchTextBasedWithAdditionalInfo<RuleChainId> im
37 38
38 private TenantId tenantId; 39 private TenantId tenantId;
39 @NoXss 40 @NoXss
  41 + @Length(fieldName = "name")
40 private String name; 42 private String name;
41 private RuleChainType type; 43 private RuleChainType type;
42 private RuleNodeId firstRuleNodeId; 44 private RuleNodeId firstRuleNodeId;
@@ -24,6 +24,7 @@ import org.thingsboard.server.common.data.HasName; @@ -24,6 +24,7 @@ import org.thingsboard.server.common.data.HasName;
24 import org.thingsboard.server.common.data.SearchTextBasedWithAdditionalInfo; 24 import org.thingsboard.server.common.data.SearchTextBasedWithAdditionalInfo;
25 import org.thingsboard.server.common.data.id.RuleChainId; 25 import org.thingsboard.server.common.data.id.RuleChainId;
26 import org.thingsboard.server.common.data.id.RuleNodeId; 26 import org.thingsboard.server.common.data.id.RuleNodeId;
  27 +import org.thingsboard.server.common.data.validation.Length;
27 28
28 @Data 29 @Data
29 @EqualsAndHashCode(callSuper = true) 30 @EqualsAndHashCode(callSuper = true)
@@ -33,7 +34,9 @@ public class RuleNode extends SearchTextBasedWithAdditionalInfo<RuleNodeId> impl @@ -33,7 +34,9 @@ public class RuleNode extends SearchTextBasedWithAdditionalInfo<RuleNodeId> impl
33 private static final long serialVersionUID = -5656679015121235465L; 34 private static final long serialVersionUID = -5656679015121235465L;
34 35
35 private RuleChainId ruleChainId; 36 private RuleChainId ruleChainId;
  37 + @Length(fieldName = "type")
36 private String type; 38 private String type;
  39 + @Length(fieldName = "name")
37 private String name; 40 private String name;
38 private boolean debugMode; 41 private boolean debugMode;
39 private transient JsonNode configuration; 42 private transient JsonNode configuration;
  1 +/**
  2 + * Copyright © 2016-2021 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.common.data.validation;
  17 +
  18 +import javax.validation.Constraint;
  19 +import javax.validation.Payload;
  20 +import java.lang.annotation.ElementType;
  21 +import java.lang.annotation.Retention;
  22 +import java.lang.annotation.RetentionPolicy;
  23 +import java.lang.annotation.Target;
  24 +
  25 +@Retention(RetentionPolicy.RUNTIME)
  26 +@Target(ElementType.FIELD)
  27 +@Constraint(validatedBy = {})
  28 +public @interface Length {
  29 + String message() default "length of {fieldName} should be equals or less than {max}";
  30 +
  31 + String fieldName();
  32 +
  33 + int max() default 255;
  34 +
  35 + Class<?>[] groups() default {};
  36 +
  37 + Class<? extends Payload>[] payload() default {};
  38 +}
@@ -19,10 +19,9 @@ import org.thingsboard.server.common.data.HasTenantId; @@ -19,10 +19,9 @@ import org.thingsboard.server.common.data.HasTenantId;
19 import org.thingsboard.server.common.data.SearchTextBased; 19 import org.thingsboard.server.common.data.SearchTextBased;
20 import org.thingsboard.server.common.data.id.TenantId; 20 import org.thingsboard.server.common.data.id.TenantId;
21 import org.thingsboard.server.common.data.id.WidgetsBundleId; 21 import org.thingsboard.server.common.data.id.WidgetsBundleId;
  22 +import org.thingsboard.server.common.data.validation.Length;
22 import org.thingsboard.server.common.data.validation.NoXss; 23 import org.thingsboard.server.common.data.validation.NoXss;
23 24
24 -import java.util.Arrays;  
25 -  
26 public class WidgetsBundle extends SearchTextBased<WidgetsBundleId> implements HasTenantId { 25 public class WidgetsBundle extends SearchTextBased<WidgetsBundleId> implements HasTenantId {
27 26
28 private static final long serialVersionUID = -7627368878362410489L; 27 private static final long serialVersionUID = -7627368878362410489L;
@@ -31,6 +30,7 @@ public class WidgetsBundle extends SearchTextBased<WidgetsBundleId> implements H @@ -31,6 +30,7 @@ public class WidgetsBundle extends SearchTextBased<WidgetsBundleId> implements H
31 @NoXss 30 @NoXss
32 private String alias; 31 private String alias;
33 @NoXss 32 @NoXss
  33 + @Length(fieldName = "title")
34 private String title; 34 private String title;
35 private String image; 35 private String image;
36 @NoXss 36 @NoXss
  1 +/**
  2 + * Copyright © 2016-2021 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.service;
  17 +
  18 +import lombok.extern.slf4j.Slf4j;
  19 +import org.hibernate.validator.HibernateValidator;
  20 +import org.hibernate.validator.HibernateValidatorConfiguration;
  21 +import org.hibernate.validator.cfg.ConstraintMapping;
  22 +import org.thingsboard.server.common.data.validation.Length;
  23 +import org.thingsboard.server.common.data.validation.NoXss;
  24 +
  25 +import javax.validation.ConstraintViolation;
  26 +import javax.validation.Validation;
  27 +import javax.validation.ValidationException;
  28 +import javax.validation.Validator;
  29 +import java.util.List;
  30 +import java.util.Set;
  31 +import java.util.stream.Collectors;
  32 +
  33 +@Slf4j
  34 +public class ConstraintValidator {
  35 +
  36 + private static Validator fieldsValidator;
  37 +
  38 + static {
  39 + initializeValidators();
  40 + }
  41 +
  42 + public static void validateFields(Object data) {
  43 + Set<ConstraintViolation<Object>> constraintsViolations = fieldsValidator.validate(data);
  44 + List<String> validationErrors = constraintsViolations.stream()
  45 + .map(ConstraintViolation::getMessage)
  46 + .distinct()
  47 + .collect(Collectors.toList());
  48 + if (!validationErrors.isEmpty()) {
  49 + throw new ValidationException("Validation error: " + String.join(", ", validationErrors));
  50 + }
  51 + }
  52 +
  53 + private static void initializeValidators() {
  54 + HibernateValidatorConfiguration validatorConfiguration = Validation.byProvider(HibernateValidator.class).configure();
  55 +
  56 + ConstraintMapping constraintMapping = validatorConfiguration.createConstraintMapping();
  57 + constraintMapping.constraintDefinition(NoXss.class).validatedBy(NoXssValidator.class);
  58 + constraintMapping.constraintDefinition(Length.class).validatedBy(StringLengthValidator.class);
  59 + validatorConfiguration.addMapping(constraintMapping);
  60 +
  61 + fieldsValidator = validatorConfiguration.buildValidatorFactory().getValidator();
  62 + }
  63 +}
@@ -17,51 +17,32 @@ package org.thingsboard.server.dao.service; @@ -17,51 +17,32 @@ package org.thingsboard.server.dao.service;
17 17
18 import com.fasterxml.jackson.databind.JsonNode; 18 import com.fasterxml.jackson.databind.JsonNode;
19 import lombok.extern.slf4j.Slf4j; 19 import lombok.extern.slf4j.Slf4j;
20 -import org.hibernate.validator.HibernateValidator;  
21 -import org.hibernate.validator.HibernateValidatorConfiguration;  
22 -import org.hibernate.validator.cfg.ConstraintMapping;  
23 import org.thingsboard.server.common.data.BaseData; 20 import org.thingsboard.server.common.data.BaseData;
24 import org.thingsboard.server.common.data.EntityType; 21 import org.thingsboard.server.common.data.EntityType;
25 import org.thingsboard.server.common.data.id.TenantId; 22 import org.thingsboard.server.common.data.id.TenantId;
26 -import org.thingsboard.server.common.data.tenant.profile.DefaultTenantProfileConfiguration;  
27 -import org.thingsboard.server.common.data.validation.NoXss;  
28 import org.thingsboard.server.dao.TenantEntityDao; 23 import org.thingsboard.server.dao.TenantEntityDao;
29 import org.thingsboard.server.dao.TenantEntityWithDataDao; 24 import org.thingsboard.server.dao.TenantEntityWithDataDao;
30 import org.thingsboard.server.dao.exception.DataValidationException; 25 import org.thingsboard.server.dao.exception.DataValidationException;
31 26
32 -import javax.validation.ConstraintViolation;  
33 -import javax.validation.Validation;  
34 -import javax.validation.Validator;  
35 import java.util.HashSet; 27 import java.util.HashSet;
36 import java.util.Iterator; 28 import java.util.Iterator;
37 -import java.util.List;  
38 import java.util.Set; 29 import java.util.Set;
39 import java.util.function.Function; 30 import java.util.function.Function;
40 import java.util.regex.Matcher; 31 import java.util.regex.Matcher;
41 import java.util.regex.Pattern; 32 import java.util.regex.Pattern;
42 -import java.util.stream.Collectors;  
43 33
44 @Slf4j 34 @Slf4j
45 public abstract class DataValidator<D extends BaseData<?>> { 35 public abstract class DataValidator<D extends BaseData<?>> {
46 private static final Pattern EMAIL_PATTERN = 36 private static final Pattern EMAIL_PATTERN =
47 Pattern.compile("^[A-Z0-9._%+-]+@[A-Z0-9.-]+\\.[A-Z]{2,}$", Pattern.CASE_INSENSITIVE); 37 Pattern.compile("^[A-Z0-9._%+-]+@[A-Z0-9.-]+\\.[A-Z]{2,}$", Pattern.CASE_INSENSITIVE);
48 38
49 - private static Validator fieldsValidator;  
50 -  
51 - static {  
52 - initializeFieldsValidator();  
53 - }  
54 -  
55 public void validate(D data, Function<D, TenantId> tenantIdFunction) { 39 public void validate(D data, Function<D, TenantId> tenantIdFunction) {
56 try { 40 try {
57 if (data == null) { 41 if (data == null) {
58 throw new DataValidationException("Data object can't be null!"); 42 throw new DataValidationException("Data object can't be null!");
59 } 43 }
60 44
61 - List<String> validationErrors = validateFields(data);  
62 - if (!validationErrors.isEmpty()) {  
63 - throw new IllegalArgumentException("Validation error: " + String.join(", ", validationErrors));  
64 - } 45 + ConstraintValidator.validateFields(data);
65 46
66 TenantId tenantId = tenantIdFunction.apply(data); 47 TenantId tenantId = tenantIdFunction.apply(data);
67 validateDataImpl(tenantId, data); 48 validateDataImpl(tenantId, data);
@@ -104,14 +85,6 @@ public abstract class DataValidator<D extends BaseData<?>> { @@ -104,14 +85,6 @@ public abstract class DataValidator<D extends BaseData<?>> {
104 return emailMatcher.matches(); 85 return emailMatcher.matches();
105 } 86 }
106 87
107 - private List<String> validateFields(D data) {  
108 - Set<ConstraintViolation<D>> constraintsViolations = fieldsValidator.validate(data);  
109 - return constraintsViolations.stream()  
110 - .map(ConstraintViolation::getMessage)  
111 - .distinct()  
112 - .collect(Collectors.toList());  
113 - }  
114 -  
115 protected void validateNumberOfEntitiesPerTenant(TenantId tenantId, 88 protected void validateNumberOfEntitiesPerTenant(TenantId tenantId,
116 TenantEntityDao tenantEntityDao, 89 TenantEntityDao tenantEntityDao,
117 long maxEntities, 90 long maxEntities,
@@ -126,10 +99,10 @@ public abstract class DataValidator<D extends BaseData<?>> { @@ -126,10 +99,10 @@ public abstract class DataValidator<D extends BaseData<?>> {
126 } 99 }
127 100
128 protected void validateMaxSumDataSizePerTenant(TenantId tenantId, 101 protected void validateMaxSumDataSizePerTenant(TenantId tenantId,
129 - TenantEntityWithDataDao dataDao,  
130 - long maxSumDataSize,  
131 - long currentDataSize,  
132 - EntityType entityType) { 102 + TenantEntityWithDataDao dataDao,
  103 + long maxSumDataSize,
  104 + long currentDataSize,
  105 + EntityType entityType) {
133 if (maxSumDataSize > 0) { 106 if (maxSumDataSize > 0) {
134 if (dataDao.sumDataSizeByTenantId(tenantId) + currentDataSize > maxSumDataSize) { 107 if (dataDao.sumDataSizeByTenantId(tenantId) + currentDataSize > maxSumDataSize) {
135 throw new DataValidationException(String.format("Failed to create the %s, files size limit is exhausted %d bytes!", 108 throw new DataValidationException(String.format("Failed to create the %s, files size limit is exhausted %d bytes!",
@@ -156,12 +129,4 @@ public abstract class DataValidator<D extends BaseData<?>> { @@ -156,12 +129,4 @@ public abstract class DataValidator<D extends BaseData<?>> {
156 } 129 }
157 } 130 }
158 131
159 - private static void initializeFieldsValidator() {  
160 - HibernateValidatorConfiguration validatorConfiguration = Validation.byProvider(HibernateValidator.class).configure();  
161 - ConstraintMapping constraintMapping = validatorConfiguration.createConstraintMapping();  
162 - constraintMapping.constraintDefinition(NoXss.class).validatedBy(NoXssValidator.class);  
163 - validatorConfiguration.addMapping(constraintMapping);  
164 -  
165 - fieldsValidator = validatorConfiguration.buildValidatorFactory().getValidator();  
166 - }  
167 } 132 }
  1 +/**
  2 + * Copyright © 2016-2021 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.service;
  17 +
  18 +import lombok.extern.slf4j.Slf4j;
  19 +import org.thingsboard.server.common.data.StringUtils;
  20 +import org.thingsboard.server.common.data.validation.Length;
  21 +
  22 +import javax.validation.ConstraintValidator;
  23 +import javax.validation.ConstraintValidatorContext;
  24 +
  25 +@Slf4j
  26 +public class StringLengthValidator implements ConstraintValidator<Length, String> {
  27 + private int max;
  28 +
  29 + @Override
  30 + public boolean isValid(String value, ConstraintValidatorContext context) {
  31 + if (StringUtils.isEmpty(value)) {
  32 + return true;
  33 + }
  34 + return value.trim().length() <= max;
  35 + }
  36 +
  37 + @Override
  38 + public void initialize(Length constraintAnnotation) {
  39 + this.max = constraintAnnotation.max();
  40 + }
  41 +}
@@ -36,6 +36,9 @@ @@ -36,6 +36,9 @@
36 <mat-error *ngIf="attributeFormGroup.get('key').hasError('required')"> 36 <mat-error *ngIf="attributeFormGroup.get('key').hasError('required')">
37 {{ 'attribute.key-required' | translate }} 37 {{ 'attribute.key-required' | translate }}
38 </mat-error> 38 </mat-error>
  39 + <mat-error *ngIf="attributeFormGroup.get('key').hasError('maxlength')">
  40 + {{ 'attribute.key-max-length' | translate }}
  41 + </mat-error>
39 </mat-form-field> 42 </mat-form-field>
40 <tb-value-input 43 <tb-value-input
41 formControlName="value" 44 formControlName="value"
@@ -56,7 +56,7 @@ export class AddAttributeDialogComponent extends DialogComponent<AddAttributeDia @@ -56,7 +56,7 @@ export class AddAttributeDialogComponent extends DialogComponent<AddAttributeDia
56 56
57 ngOnInit(): void { 57 ngOnInit(): void {
58 this.attributeFormGroup = this.fb.group({ 58 this.attributeFormGroup = this.fb.group({
59 - key: ['', [Validators.required]], 59 + key: ['', [Validators.required, Validators.maxLength(255)]],
60 value: [null, [Validators.required]] 60 value: [null, [Validators.required]]
61 }); 61 });
62 } 62 }
@@ -36,15 +36,15 @@ export abstract class ContactBasedComponent<T extends ContactBased<HasId>> exten @@ -36,15 +36,15 @@ export abstract class ContactBasedComponent<T extends ContactBased<HasId>> exten
36 36
37 buildForm(entity: T): FormGroup { 37 buildForm(entity: T): FormGroup {
38 const entityForm = this.buildEntityForm(entity); 38 const entityForm = this.buildEntityForm(entity);
39 - entityForm.addControl('country', this.fb.control(entity ? entity.country : '', []));  
40 - entityForm.addControl('city', this.fb.control(entity ? entity.city : '', []));  
41 - entityForm.addControl('state', this.fb.control(entity ? entity.state : '', [])); 39 + entityForm.addControl('country', this.fb.control(entity ? entity.country : '', [Validators.maxLength(255)]));
  40 + entityForm.addControl('city', this.fb.control(entity ? entity.city : '', [Validators.maxLength(255)]));
  41 + entityForm.addControl('state', this.fb.control(entity ? entity.state : '', [Validators.maxLength(255)]));
42 entityForm.addControl('zip', this.fb.control(entity ? entity.zip : '', 42 entityForm.addControl('zip', this.fb.control(entity ? entity.zip : '',
43 this.zipValidators(entity ? entity.country : '') 43 this.zipValidators(entity ? entity.country : '')
44 )); 44 ));
45 entityForm.addControl('address', this.fb.control(entity ? entity.address : '', [])); 45 entityForm.addControl('address', this.fb.control(entity ? entity.address : '', []));
46 entityForm.addControl('address2', this.fb.control(entity ? entity.address2 : '', [])); 46 entityForm.addControl('address2', this.fb.control(entity ? entity.address2 : '', []));
47 - entityForm.addControl('phone', this.fb.control(entity ? entity.phone : '', [])); 47 + entityForm.addControl('phone', this.fb.control(entity ? entity.phone : '', [Validators.maxLength(255)]));
48 entityForm.addControl('email', this.fb.control(entity ? entity.email : '', [Validators.email])); 48 entityForm.addControl('email', this.fb.control(entity ? entity.email : '', [Validators.email]));
49 return entityForm; 49 return entityForm;
50 } 50 }
@@ -41,6 +41,9 @@ @@ -41,6 +41,9 @@
41 <mat-error *ngIf="deviceProfileDetailsFormGroup.get('name').hasError('required')"> 41 <mat-error *ngIf="deviceProfileDetailsFormGroup.get('name').hasError('required')">
42 {{ 'device-profile.name-required' | translate }} 42 {{ 'device-profile.name-required' | translate }}
43 </mat-error> 43 </mat-error>
  44 + <mat-error *ngIf="deviceProfileDetailsFormGroup.get('name').hasError('maxlength')">
  45 + {{ 'device-profile.name-max-length' | translate }}
  46 + </mat-error>
44 </mat-form-field> 47 </mat-form-field>
45 <tb-rule-chain-autocomplete 48 <tb-rule-chain-autocomplete
46 labelText="device-profile.default-rule-chain" 49 labelText="device-profile.default-rule-chain"
@@ -105,7 +105,7 @@ export class AddDeviceProfileDialogComponent extends @@ -105,7 +105,7 @@ export class AddDeviceProfileDialogComponent extends
105 super(store, router, dialogRef); 105 super(store, router, dialogRef);
106 this.deviceProfileDetailsFormGroup = this.fb.group( 106 this.deviceProfileDetailsFormGroup = this.fb.group(
107 { 107 {
108 - name: [data.deviceProfileName, [Validators.required]], 108 + name: [data.deviceProfileName, [Validators.required, Validators.maxLength(255)]],
109 type: [DeviceProfileType.DEFAULT, [Validators.required]], 109 type: [DeviceProfileType.DEFAULT, [Validators.required]],
110 image: [null, []], 110 image: [null, []],
111 defaultRuleChainId: [null, []], 111 defaultRuleChainId: [null, []],
@@ -54,6 +54,9 @@ @@ -54,6 +54,9 @@
54 <mat-error *ngIf="entityForm.get('name').hasError('required')"> 54 <mat-error *ngIf="entityForm.get('name').hasError('required')">
55 {{ 'device-profile.name-required' | translate }} 55 {{ 'device-profile.name-required' | translate }}
56 </mat-error> 56 </mat-error>
  57 + <mat-error *ngIf="entityForm.get('name').hasError('maxlength')">
  58 + {{ 'device-profile.name-max-length' | translate }}
  59 + </mat-error>
57 </mat-form-field> 60 </mat-form-field>
58 <tb-rule-chain-autocomplete 61 <tb-rule-chain-autocomplete
59 labelText="device-profile.default-rule-chain" 62 labelText="device-profile.default-rule-chain"
@@ -102,7 +102,7 @@ export class DeviceProfileComponent extends EntityComponent<DeviceProfile> { @@ -102,7 +102,7 @@ export class DeviceProfileComponent extends EntityComponent<DeviceProfile> {
102 }; 102 };
103 const form = this.fb.group( 103 const form = this.fb.group(
104 { 104 {
105 - name: [entity ? entity.name : '', [Validators.required]], 105 + name: [entity ? entity.name : '', [Validators.required, Validators.maxLength(255)]],
106 type: [entity ? entity.type : null, [Validators.required]], 106 type: [entity ? entity.type : null, [Validators.required]],
107 image: [entity ? entity.image : null], 107 image: [entity ? entity.image : null],
108 transportType: [entity ? entity.transportType : null, [Validators.required]], 108 transportType: [entity ? entity.transportType : null, [Validators.required]],
@@ -48,6 +48,9 @@ @@ -48,6 +48,9 @@
48 <mat-error *ngIf="entityForm.get('name').hasError('required')"> 48 <mat-error *ngIf="entityForm.get('name').hasError('required')">
49 {{ 'tenant-profile.name-required' | translate }} 49 {{ 'tenant-profile.name-required' | translate }}
50 </mat-error> 50 </mat-error>
  51 + <mat-error *ngIf="entityForm.get('name').hasError('maxlength')">
  52 + {{ 'tenant-profile.name-max-length' | translate }}
  53 + </mat-error>
51 </mat-form-field> 54 </mat-form-field>
52 <div fxLayout="column"> 55 <div fxLayout="column">
53 <mat-checkbox class="hinted-checkbox" formControlName="isolatedTbCore"> 56 <mat-checkbox class="hinted-checkbox" formControlName="isolatedTbCore">
@@ -58,7 +58,7 @@ export class TenantProfileComponent extends EntityComponent<TenantProfile> { @@ -58,7 +58,7 @@ export class TenantProfileComponent extends EntityComponent<TenantProfile> {
58 buildForm(entity: TenantProfile): FormGroup { 58 buildForm(entity: TenantProfile): FormGroup {
59 return this.fb.group( 59 return this.fb.group(
60 { 60 {
61 - name: [entity ? entity.name : '', [Validators.required]], 61 + name: [entity ? entity.name : '', [Validators.required, Validators.maxLength(255)]],
62 isolatedTbCore: [entity ? entity.isolatedTbCore : false, []], 62 isolatedTbCore: [entity ? entity.isolatedTbCore : false, []],
63 isolatedTbRuleEngine: [entity ? entity.isolatedTbRuleEngine : false, []], 63 isolatedTbRuleEngine: [entity ? entity.isolatedTbRuleEngine : false, []],
64 profileData: [entity && !this.isAdd ? entity.profileData : { 64 profileData: [entity && !this.isAdd ? entity.profileData : {
@@ -44,10 +44,16 @@ @@ -44,10 +44,16 @@
44 <mat-error *ngIf="deviceWizardFormGroup.get('name').hasError('required')"> 44 <mat-error *ngIf="deviceWizardFormGroup.get('name').hasError('required')">
45 {{ 'device.name-required' | translate }} 45 {{ 'device.name-required' | translate }}
46 </mat-error> 46 </mat-error>
  47 + <mat-error *ngIf="deviceWizardFormGroup.get('name').hasError('maxlength')">
  48 + {{ 'device.name-max-length' | translate }}
  49 + </mat-error>
47 </mat-form-field> 50 </mat-form-field>
48 <mat-form-field class="mat-block"> 51 <mat-form-field class="mat-block">
49 <mat-label translate>device.label</mat-label> 52 <mat-label translate>device.label</mat-label>
50 <input matInput formControlName="label"> 53 <input matInput formControlName="label">
  54 + <mat-error *ngIf="deviceWizardFormGroup.get('label').hasError('maxlength')">
  55 + {{ 'device.label-max-length' | translate }}
  56 + </mat-error>
51 </mat-form-field> 57 </mat-form-field>
52 <div fxLayout="row" fxLayoutGap="16px"> 58 <div fxLayout="row" fxLayoutGap="16px">
53 <mat-radio-group fxLayout="column" formControlName="addProfileType" fxLayoutAlign="space-around"> 59 <mat-radio-group fxLayout="column" formControlName="addProfileType" fxLayoutAlign="space-around">
@@ -105,8 +105,8 @@ export class DeviceWizardDialogComponent extends @@ -105,8 +105,8 @@ export class DeviceWizardDialogComponent extends
105 private fb: FormBuilder) { 105 private fb: FormBuilder) {
106 super(store, router, dialogRef); 106 super(store, router, dialogRef);
107 this.deviceWizardFormGroup = this.fb.group({ 107 this.deviceWizardFormGroup = this.fb.group({
108 - name: ['', Validators.required],  
109 - label: [''], 108 + name: ['', [Validators.required, Validators.maxLength(255)]],
  109 + label: ['', Validators.maxLength(255)],
110 gateway: [false], 110 gateway: [false],
111 overwriteActivityTime: [false], 111 overwriteActivityTime: [false],
112 addProfileType: [0], 112 addProfileType: [0],
@@ -56,6 +56,9 @@ @@ -56,6 +56,9 @@
56 <mat-error *ngIf="entityForm.get('title').hasError('required')"> 56 <mat-error *ngIf="entityForm.get('title').hasError('required')">
57 {{ 'resource.title-required' | translate }} 57 {{ 'resource.title-required' | translate }}
58 </mat-error> 58 </mat-error>
  59 + <mat-error *ngIf="entityForm.get('title').hasError('maxlength')">
  60 + {{ 'resource.title-max-length' | translate }}
  61 + </mat-error>
59 </mat-form-field> 62 </mat-form-field>
60 <tb-file-input *ngIf="isAdd" 63 <tb-file-input *ngIf="isAdd"
61 formControlName="data" 64 formControlName="data"
@@ -29,7 +29,7 @@ import { @@ -29,7 +29,7 @@ import {
29 ResourceTypeMIMETypes, 29 ResourceTypeMIMETypes,
30 ResourceTypeTranslationMap 30 ResourceTypeTranslationMap
31 } from '@shared/models/resource.models'; 31 } from '@shared/models/resource.models';
32 -import { pairwise, startWith, takeUntil } from 'rxjs/operators'; 32 +import {filter, pairwise, startWith, takeUntil} from 'rxjs/operators';
33 import { ActionNotificationShow } from "@core/notification/notification.actions"; 33 import { ActionNotificationShow } from "@core/notification/notification.actions";
34 34
35 @Component({ 35 @Component({
@@ -56,16 +56,14 @@ export class ResourcesLibraryComponent extends EntityComponent<Resource> impleme @@ -56,16 +56,14 @@ export class ResourcesLibraryComponent extends EntityComponent<Resource> impleme
56 super.ngOnInit(); 56 super.ngOnInit();
57 this.entityForm.get('resourceType').valueChanges.pipe( 57 this.entityForm.get('resourceType').valueChanges.pipe(
58 startWith(ResourceType.LWM2M_MODEL), 58 startWith(ResourceType.LWM2M_MODEL),
59 - pairwise(), 59 + filter(() => this.isAdd),
60 takeUntil(this.destroy$) 60 takeUntil(this.destroy$)
61 - ).subscribe(([previousType, type]) => {  
62 - if (previousType === this.resourceType.LWM2M_MODEL) {  
63 - this.entityForm.get('title').setValidators(Validators.required);  
64 - this.entityForm.get('title').updateValueAndValidity({emitEvent: false});  
65 - } 61 + ).subscribe((type) => {
66 if (type === this.resourceType.LWM2M_MODEL) { 62 if (type === this.resourceType.LWM2M_MODEL) {
67 - this.entityForm.get('title').clearValidators();  
68 - this.entityForm.get('title').updateValueAndValidity({emitEvent: false}); 63 + this.entityForm.get('title').disable({emitEvent: false});
  64 + this.entityForm.patchValue({title: ''}, {emitEvent: false});
  65 + } else {
  66 + this.entityForm.get('title').enable({emitEvent: false})
69 } 67 }
70 this.entityForm.patchValue({ 68 this.entityForm.patchValue({
71 data: null, 69 data: null,
@@ -91,11 +89,8 @@ export class ResourcesLibraryComponent extends EntityComponent<Resource> impleme @@ -91,11 +89,8 @@ export class ResourcesLibraryComponent extends EntityComponent<Resource> impleme
91 buildForm(entity: Resource): FormGroup { 89 buildForm(entity: Resource): FormGroup {
92 const form = this.fb.group( 90 const form = this.fb.group(
93 { 91 {
94 - title: [entity ? entity.title : '', []],  
95 - resourceType: [{  
96 - value: entity?.resourceType ? entity.resourceType : ResourceType.LWM2M_MODEL,  
97 - disabled: !this.isAdd  
98 - }, [Validators.required]], 92 + title: [entity ? entity.title : "", [Validators.required, Validators.maxLength(255)]],
  93 + resourceType: [entity?.resourceType ? entity.resourceType : ResourceType.LWM2M_MODEL, [Validators.required]],
99 fileName: [entity ? entity.fileName : null, [Validators.required]], 94 fileName: [entity ? entity.fileName : null, [Validators.required]],
100 } 95 }
101 ); 96 );
@@ -76,6 +76,9 @@ @@ -76,6 +76,9 @@
76 <mat-error *ngIf="entityForm.get('name').hasError('required')"> 76 <mat-error *ngIf="entityForm.get('name').hasError('required')">
77 {{ 'asset.name-required' | translate }} 77 {{ 'asset.name-required' | translate }}
78 </mat-error> 78 </mat-error>
  79 + <mat-error *ngIf="entityForm.get('name').hasError('maxlength')">
  80 + {{ 'asset.name-max-length' | translate }}
  81 + </mat-error>
79 </mat-form-field> 82 </mat-form-field>
80 <tb-entity-subtype-autocomplete 83 <tb-entity-subtype-autocomplete
81 formControlName="type" 84 formControlName="type"
@@ -86,6 +89,9 @@ @@ -86,6 +89,9 @@
86 <mat-form-field class="mat-block"> 89 <mat-form-field class="mat-block">
87 <mat-label translate>asset.label</mat-label> 90 <mat-label translate>asset.label</mat-label>
88 <input matInput formControlName="label"> 91 <input matInput formControlName="label">
  92 + <mat-error *ngIf="entityForm.get('label').hasError('maxlength')">
  93 + {{ 'asset.label-max-length' | translate }}
  94 + </mat-error>
89 </mat-form-field> 95 </mat-form-field>
90 <div formGroupName="additionalInfo"> 96 <div formGroupName="additionalInfo">
91 <mat-form-field class="mat-block"> 97 <mat-form-field class="mat-block">
@@ -65,9 +65,9 @@ export class AssetComponent extends EntityComponent<AssetInfo> { @@ -65,9 +65,9 @@ export class AssetComponent extends EntityComponent<AssetInfo> {
65 buildForm(entity: AssetInfo): FormGroup { 65 buildForm(entity: AssetInfo): FormGroup {
66 return this.fb.group( 66 return this.fb.group(
67 { 67 {
68 - name: [entity ? entity.name : '', [Validators.required]],  
69 - type: [entity ? entity.type : null, [Validators.required]],  
70 - label: [entity ? entity.label : ''], 68 + name: [entity ? entity.name : '', [Validators.required, Validators.maxLength(255)]],
  69 + type: [entity ? entity.type : null, [Validators.required, Validators.maxLength(255)]],
  70 + label: [entity ? entity.label : '', Validators.maxLength(255)],
71 additionalInfo: this.fb.group( 71 additionalInfo: this.fb.group(
72 { 72 {
73 description: [entity && entity.additionalInfo ? entity.additionalInfo.description : ''], 73 description: [entity && entity.additionalInfo ? entity.additionalInfo.description : ''],
@@ -73,6 +73,9 @@ @@ -73,6 +73,9 @@
73 <mat-error *ngIf="entityForm.get('title').hasError('required')"> 73 <mat-error *ngIf="entityForm.get('title').hasError('required')">
74 {{ 'customer.title-required' | translate }} 74 {{ 'customer.title-required' | translate }}
75 </mat-error> 75 </mat-error>
  76 + <mat-error *ngIf="entityForm.get('title').hasError('maxlength')">
  77 + {{ 'customer.title-max-length' | translate }}
  78 + </mat-error>
76 </mat-form-field> 79 </mat-form-field>
77 <div formGroupName="additionalInfo" fxLayout="column"> 80 <div formGroupName="additionalInfo" fxLayout="column">
78 <mat-form-field class="mat-block"> 81 <mat-form-field class="mat-block">
@@ -57,7 +57,7 @@ export class CustomerComponent extends ContactBasedComponent<Customer> { @@ -57,7 +57,7 @@ export class CustomerComponent extends ContactBasedComponent<Customer> {
57 buildEntityForm(entity: Customer): FormGroup { 57 buildEntityForm(entity: Customer): FormGroup {
58 return this.fb.group( 58 return this.fb.group(
59 { 59 {
60 - title: [entity ? entity.title : '', [Validators.required]], 60 + title: [entity ? entity.title : '', [Validators.required, Validators.maxLength(255)]],
61 additionalInfo: this.fb.group( 61 additionalInfo: this.fb.group(
62 { 62 {
63 description: [entity && entity.additionalInfo ? entity.additionalInfo.description : ''], 63 description: [entity && entity.additionalInfo ? entity.additionalInfo.description : ''],
@@ -104,6 +104,9 @@ @@ -104,6 +104,9 @@
104 <mat-error *ngIf="entityForm.get('title').hasError('required')"> 104 <mat-error *ngIf="entityForm.get('title').hasError('required')">
105 {{ 'dashboard.title-required' | translate }} 105 {{ 'dashboard.title-required' | translate }}
106 </mat-error> 106 </mat-error>
  107 + <mat-error *ngIf="entityForm.get('title').hasError('maxlength')">
  108 + {{ 'dashboard.title-max-length' | translate }}
  109 + </mat-error>
107 </mat-form-field> 110 </mat-form-field>
108 <tb-image-input fxFlex 111 <tb-image-input fxFlex
109 label="{{'dashboard.image' | translate}}" 112 label="{{'dashboard.image' | translate}}"
@@ -79,7 +79,7 @@ export class DashboardFormComponent extends EntityComponent<Dashboard> { @@ -79,7 +79,7 @@ export class DashboardFormComponent extends EntityComponent<Dashboard> {
79 this.updateFields(entity); 79 this.updateFields(entity);
80 return this.fb.group( 80 return this.fb.group(
81 { 81 {
82 - title: [entity ? entity.title : '', [Validators.required]], 82 + title: [entity ? entity.title : '', [Validators.required, Validators.maxLength(255)]],
83 image: [entity ? entity.image : null], 83 image: [entity ? entity.image : null],
84 configuration: this.fb.group( 84 configuration: this.fb.group(
85 { 85 {
@@ -89,6 +89,9 @@ @@ -89,6 +89,9 @@
89 <mat-error *ngIf="entityForm.get('name').hasError('required')"> 89 <mat-error *ngIf="entityForm.get('name').hasError('required')">
90 {{ 'device.name-required' | translate }} 90 {{ 'device.name-required' | translate }}
91 </mat-error> 91 </mat-error>
  92 + <mat-error *ngIf="entityForm.get('name').hasError('maxlength')">
  93 + {{ 'device.name-max-length' | translate }}
  94 + </mat-error>
92 </mat-form-field> 95 </mat-form-field>
93 <tb-device-profile-autocomplete 96 <tb-device-profile-autocomplete
94 [selectDefaultProfile]="isAdd" 97 [selectDefaultProfile]="isAdd"
@@ -100,6 +103,9 @@ @@ -100,6 +103,9 @@
100 <mat-form-field class="mat-block"> 103 <mat-form-field class="mat-block">
101 <mat-label translate>device.label</mat-label> 104 <mat-label translate>device.label</mat-label>
102 <input matInput formControlName="label"> 105 <input matInput formControlName="label">
  106 + <mat-error *ngIf="entityForm.get('label').hasError('maxlength')">
  107 + {{ 'device.label-max-length' | translate }}
  108 + </mat-error>
103 </mat-form-field> 109 </mat-form-field>
104 <tb-ota-package-autocomplete 110 <tb-ota-package-autocomplete
105 [useFullEntityId]="true" 111 [useFullEntityId]="true"
@@ -81,11 +81,11 @@ export class DeviceComponent extends EntityComponent<DeviceInfo> { @@ -81,11 +81,11 @@ export class DeviceComponent extends EntityComponent<DeviceInfo> {
81 buildForm(entity: DeviceInfo): FormGroup { 81 buildForm(entity: DeviceInfo): FormGroup {
82 const form = this.fb.group( 82 const form = this.fb.group(
83 { 83 {
84 - name: [entity ? entity.name : '', [Validators.required]], 84 + name: [entity ? entity.name : '', [Validators.required, Validators.maxLength(255)]],
85 deviceProfileId: [entity ? entity.deviceProfileId : null, [Validators.required]], 85 deviceProfileId: [entity ? entity.deviceProfileId : null, [Validators.required]],
86 firmwareId: [entity ? entity.firmwareId : null], 86 firmwareId: [entity ? entity.firmwareId : null],
87 softwareId: [entity ? entity.softwareId : null], 87 softwareId: [entity ? entity.softwareId : null],
88 - label: [entity ? entity.label : ''], 88 + label: [entity ? entity.label : '', [Validators.maxLength(255)]],
89 deviceData: [entity ? entity.deviceData : null, [Validators.required]], 89 deviceData: [entity ? entity.deviceData : null, [Validators.required]],
90 additionalInfo: this.fb.group( 90 additionalInfo: this.fb.group(
91 { 91 {
@@ -126,6 +126,9 @@ @@ -126,6 +126,9 @@
126 <mat-error *ngIf="entityForm.get('name').hasError('required')"> 126 <mat-error *ngIf="entityForm.get('name').hasError('required')">
127 {{ 'edge.name-required' | translate }} 127 {{ 'edge.name-required' | translate }}
128 </mat-error> 128 </mat-error>
  129 + <mat-error *ngIf="entityForm.get('name').hasError('maxlength')">
  130 + {{ 'edge.name-max-length' | translate }}
  131 + </mat-error>
129 </mat-form-field> 132 </mat-form-field>
130 <tb-entity-subtype-autocomplete 133 <tb-entity-subtype-autocomplete
131 formControlName="type" 134 formControlName="type"
@@ -140,6 +143,9 @@ @@ -140,6 +143,9 @@
140 <mat-error *ngIf="entityForm.get('edgeLicenseKey').hasError('required')"> 143 <mat-error *ngIf="entityForm.get('edgeLicenseKey').hasError('required')">
141 {{ 'edge.edge-license-key-required' | translate }} 144 {{ 'edge.edge-license-key-required' | translate }}
142 </mat-error> 145 </mat-error>
  146 + <mat-error *ngIf="entityForm.get('type').hasError('maxlength')">
  147 + {{ 'edge.type-max-length' | translate }}
  148 + </mat-error>
143 </mat-form-field> 149 </mat-form-field>
144 </div> 150 </div>
145 <div [fxShow]="edgeScope !== 'customer_user'"> 151 <div [fxShow]="edgeScope !== 'customer_user'">
@@ -179,6 +185,9 @@ @@ -179,6 +185,9 @@
179 <mat-form-field class="mat-block"> 185 <mat-form-field class="mat-block">
180 <mat-label translate>edge.label</mat-label> 186 <mat-label translate>edge.label</mat-label>
181 <input matInput formControlName="label"> 187 <input matInput formControlName="label">
  188 + <mat-error *ngIf="entityForm.get('label').hasError('maxlength')">
  189 + {{ 'edge.label-max-length' | translate }}
  190 + </mat-error>
182 </mat-form-field> 191 </mat-form-field>
183 <div formGroupName="additionalInfo" fxLayout="column"> 192 <div formGroupName="additionalInfo" fxLayout="column">
184 <mat-form-field class="mat-block"> 193 <mat-form-field class="mat-block">
@@ -69,9 +69,9 @@ export class EdgeComponent extends EntityComponent<EdgeInfo> { @@ -69,9 +69,9 @@ export class EdgeComponent extends EntityComponent<EdgeInfo> {
69 buildForm(entity: EdgeInfo): FormGroup { 69 buildForm(entity: EdgeInfo): FormGroup {
70 const form = this.fb.group( 70 const form = this.fb.group(
71 { 71 {
72 - name: [entity ? entity.name : '', [Validators.required]],  
73 - type: [entity?.type ? entity.type : 'default', [Validators.required]],  
74 - label: [entity ? entity.label : ''], 72 + name: [entity ? entity.name : '', [Validators.required, Validators.maxLength(255)]],
  73 + type: [entity?.type ? entity.type : 'default', [Validators.required, Validators.maxLength(255)]],
  74 + label: [entity ? entity.label : '', Validators.maxLength(255)],
75 cloudEndpoint: [null, [Validators.required]], 75 cloudEndpoint: [null, [Validators.required]],
76 edgeLicenseKey: ['', [Validators.required]], 76 edgeLicenseKey: ['', [Validators.required]],
77 routingKey: this.fb.control({value: entity ? entity.routingKey : null, disabled: true}), 77 routingKey: this.fb.control({value: entity ? entity.routingKey : null, disabled: true}),
@@ -76,6 +76,9 @@ @@ -76,6 +76,9 @@
76 <mat-error *ngIf="entityForm.get('name').hasError('required')"> 76 <mat-error *ngIf="entityForm.get('name').hasError('required')">
77 {{ 'entity-view.name-required' | translate }} 77 {{ 'entity-view.name-required' | translate }}
78 </mat-error> 78 </mat-error>
  79 + <mat-error *ngIf="entityForm.get('name').hasError('maxlength')">
  80 + {{ 'entity-view.name-max-length' | translate }}
  81 + </mat-error>
79 </mat-form-field> 82 </mat-form-field>
80 <tb-entity-subtype-autocomplete 83 <tb-entity-subtype-autocomplete
81 formControlName="type" 84 formControlName="type"
@@ -80,8 +80,8 @@ export class EntityViewComponent extends EntityComponent<EntityViewInfo> { @@ -80,8 +80,8 @@ export class EntityViewComponent extends EntityComponent<EntityViewInfo> {
80 buildForm(entity: EntityViewInfo): FormGroup { 80 buildForm(entity: EntityViewInfo): FormGroup {
81 return this.fb.group( 81 return this.fb.group(
82 { 82 {
83 - name: [entity ? entity.name : '', [Validators.required]],  
84 - type: [entity ? entity.type : null, [Validators.required]], 83 + name: [entity ? entity.name : '', [Validators.required, Validators.maxLength(255)]],
  84 + type: [entity ? entity.type : null, Validators.required],
85 entityId: [entity ? entity.entityId : null, [Validators.required]], 85 entityId: [entity ? entity.entityId : null, [Validators.required]],
86 startTimeMs: [entity ? entity.startTimeMs : null], 86 startTimeMs: [entity ? entity.startTimeMs : null],
87 endTimeMs: [entity ? entity.endTimeMs : null], 87 endTimeMs: [entity ? entity.endTimeMs : null],
@@ -65,6 +65,9 @@ @@ -65,6 +65,9 @@
65 <mat-error *ngIf="entityForm.get('title').hasError('required')"> 65 <mat-error *ngIf="entityForm.get('title').hasError('required')">
66 {{ 'ota-update.title-required' | translate }} 66 {{ 'ota-update.title-required' | translate }}
67 </mat-error> 67 </mat-error>
  68 + <mat-error *ngIf="entityForm.get('title').hasError('maxlength')">
  69 + {{ 'ota-update.title-max-length' | translate }}
  70 + </mat-error>
68 </mat-form-field> 71 </mat-form-field>
69 <mat-form-field class="mat-block" fxFlex> 72 <mat-form-field class="mat-block" fxFlex>
70 <mat-label translate>ota-update.version</mat-label> 73 <mat-label translate>ota-update.version</mat-label>
@@ -72,6 +75,9 @@ @@ -72,6 +75,9 @@
72 <mat-error *ngIf="entityForm.get('version').hasError('required')"> 75 <mat-error *ngIf="entityForm.get('version').hasError('required')">
73 {{ 'ota-update.version-required' | translate }} 76 {{ 'ota-update.version-required' | translate }}
74 </mat-error> 77 </mat-error>
  78 + <mat-error *ngIf="entityForm.get('version').hasError('maxlength')">
  79 + {{ 'ota-update.version-max-length' | translate }}
  80 + </mat-error>
75 </mat-form-field> 81 </mat-form-field>
76 </div> 82 </div>
77 <tb-device-profile-autocomplete 83 <tb-device-profile-autocomplete
@@ -111,7 +117,8 @@ @@ -111,7 +117,8 @@
111 </mat-checkbox> 117 </mat-checkbox>
112 </section> 118 </section>
113 <div fxLayout="row" fxLayoutGap.gt-xs="8px" fxLayoutGap.sm="8px" 119 <div fxLayout="row" fxLayoutGap.gt-xs="8px" fxLayoutGap.sm="8px"
114 - fxLayout.xs="column" fxLayout.md="column" *ngIf="!(isAdd && this.entityForm.get('generateChecksum').value)"> 120 + fxLayout.xs="column" fxLayout.md="column"
  121 + *ngIf="!(isAdd && this.entityForm.get('generateChecksum').value)">
115 <mat-form-field class="mat-block" fxFlex="33"> 122 <mat-form-field class="mat-block" fxFlex="33">
116 <mat-label translate>ota-update.checksum-algorithm</mat-label> 123 <mat-label translate>ota-update.checksum-algorithm</mat-label>
117 <mat-select formControlName="checksumAlgorithm"> 124 <mat-select formControlName="checksumAlgorithm">
@@ -149,7 +156,8 @@ @@ -149,7 +156,8 @@
149 <input matInput formControlName="url" 156 <input matInput formControlName="url"
150 type="text" 157 type="text"
151 [required]="entityForm.get('isURL').value"> 158 [required]="entityForm.get('isURL').value">
152 - <mat-error *ngIf="entityForm.get('url').hasError('required') || entityForm.get('url').hasError('pattern')" translate> 159 + <mat-error *ngIf="entityForm.get('url').hasError('required') || entityForm.get('url').hasError('pattern')"
  160 + translate>
153 ota-update.direct-url-required 161 ota-update.direct-url-required
154 </mat-error> 162 </mat-error>
155 </mat-form-field> 163 </mat-form-field>
@@ -84,6 +84,9 @@ @@ -84,6 +84,9 @@
84 <mat-error *ngIf="entityForm.get('name').hasError('required')"> 84 <mat-error *ngIf="entityForm.get('name').hasError('required')">
85 {{ 'rulechain.name-required' | translate }} 85 {{ 'rulechain.name-required' | translate }}
86 </mat-error> 86 </mat-error>
  87 + <mat-error *ngIf="entityForm.get('name').hasError('maxlength')">
  88 + {{ 'rulechain.name-max-length' | translate }}
  89 + </mat-error>
87 </mat-form-field> 90 </mat-form-field>
88 <mat-checkbox fxFlex formControlName="debugMode" style="padding-bottom: 16px;"> 91 <mat-checkbox fxFlex formControlName="debugMode" style="padding-bottom: 16px;">
89 {{ 'rulechain.debug-mode' | translate }} 92 {{ 'rulechain.debug-mode' | translate }}
@@ -57,7 +57,7 @@ export class RuleChainComponent extends EntityComponent<RuleChain> { @@ -57,7 +57,7 @@ export class RuleChainComponent extends EntityComponent<RuleChain> {
57 buildForm(entity: RuleChain): FormGroup { 57 buildForm(entity: RuleChain): FormGroup {
58 return this.fb.group( 58 return this.fb.group(
59 { 59 {
60 - name: [entity ? entity.name : '', [Validators.required]], 60 + name: [entity ? entity.name : '', [Validators.required, Validators.maxLength(255)]],
61 debugMode: [entity ? entity.debugMode : false], 61 debugMode: [entity ? entity.debugMode : false],
62 additionalInfo: this.fb.group( 62 additionalInfo: this.fb.group(
63 { 63 {
@@ -48,6 +48,9 @@ @@ -48,6 +48,9 @@
48 <mat-error *ngIf="entityForm.get('title').hasError('required')"> 48 <mat-error *ngIf="entityForm.get('title').hasError('required')">
49 {{ 'tenant.title-required' | translate }} 49 {{ 'tenant.title-required' | translate }}
50 </mat-error> 50 </mat-error>
  51 + <mat-error *ngIf="entityForm.get('title').hasError('maxlength')">
  52 + {{ 'tenant.title-max-length' | translate }}
  53 + </mat-error>
51 </mat-form-field> 54 </mat-form-field>
52 <tb-tenant-profile-autocomplete 55 <tb-tenant-profile-autocomplete
53 [selectDefaultProfile]="isAdd" 56 [selectDefaultProfile]="isAdd"
@@ -51,7 +51,7 @@ export class TenantComponent extends ContactBasedComponent<TenantInfo> { @@ -51,7 +51,7 @@ export class TenantComponent extends ContactBasedComponent<TenantInfo> {
51 buildEntityForm(entity: TenantInfo): FormGroup { 51 buildEntityForm(entity: TenantInfo): FormGroup {
52 return this.fb.group( 52 return this.fb.group(
53 { 53 {
54 - title: [entity ? entity.title : '', [Validators.required]], 54 + title: [entity ? entity.title : '', [Validators.required, Validators.maxLength(255)]],
55 tenantProfileId: [entity ? entity.tenantProfileId : null, [Validators.required]], 55 tenantProfileId: [entity ? entity.tenantProfileId : null, [Validators.required]],
56 additionalInfo: this.fb.group( 56 additionalInfo: this.fb.group(
57 { 57 {
@@ -44,6 +44,9 @@ @@ -44,6 +44,9 @@
44 <mat-error *ngIf="entityForm.get('title').hasError('required')"> 44 <mat-error *ngIf="entityForm.get('title').hasError('required')">
45 {{ 'widgets-bundle.title-required' | translate }} 45 {{ 'widgets-bundle.title-required' | translate }}
46 </mat-error> 46 </mat-error>
  47 + <mat-error *ngIf="entityForm.get('title').hasError('maxlength')">
  48 + {{ 'widgets-bundle.title-max-length' | translate }}
  49 + </mat-error>
47 </mat-form-field> 50 </mat-form-field>
48 <tb-image-input fxFlex 51 <tb-image-input fxFlex
49 label="{{'widgets-bundle.image-preview' | translate}}" 52 label="{{'widgets-bundle.image-preview' | translate}}"
@@ -47,7 +47,7 @@ export class WidgetsBundleComponent extends EntityComponent<WidgetsBundle> { @@ -47,7 +47,7 @@ export class WidgetsBundleComponent extends EntityComponent<WidgetsBundle> {
47 buildForm(entity: WidgetsBundle): FormGroup { 47 buildForm(entity: WidgetsBundle): FormGroup {
48 return this.fb.group( 48 return this.fb.group(
49 { 49 {
50 - title: [entity ? entity.title : '', [Validators.required]], 50 + title: [entity ? entity.title : '', [Validators.required, Validators.maxLength(255)]],
51 image: [entity ? entity.image : ''], 51 image: [entity ? entity.image : ''],
52 description: [entity ? entity.description : '', Validators.maxLength(255)] 52 description: [entity ? entity.description : '', Validators.maxLength(255)]
53 } 53 }
@@ -28,10 +28,16 @@ @@ -28,10 +28,16 @@
28 <mat-form-field class="mat-block"> 28 <mat-form-field class="mat-block">
29 <mat-label translate>contact.city</mat-label> 29 <mat-label translate>contact.city</mat-label>
30 <input matInput formControlName="city"> 30 <input matInput formControlName="city">
  31 + <mat-error *ngIf="parentForm.get('city').hasError('maxlength')">
  32 + {{ 'contact.city-max-length' | translate }}
  33 + </mat-error>
31 </mat-form-field> 34 </mat-form-field>
32 <mat-form-field class="mat-block"> 35 <mat-form-field class="mat-block">
33 <mat-label translate>contact.state</mat-label> 36 <mat-label translate>contact.state</mat-label>
34 <input matInput formControlName="state"> 37 <input matInput formControlName="state">
  38 + <mat-error *ngIf="parentForm.get('state').hasError('maxlength')">
  39 + {{ 'contact.state-max-length' | translate }}
  40 + </mat-error>
35 </mat-form-field> 41 </mat-form-field>
36 <mat-form-field class="mat-block"> 42 <mat-form-field class="mat-block">
37 <mat-label translate>contact.postal-code</mat-label> 43 <mat-label translate>contact.postal-code</mat-label>
@@ -52,6 +58,9 @@ @@ -52,6 +58,9 @@
52 <mat-form-field class="mat-block"> 58 <mat-form-field class="mat-block">
53 <mat-label translate>contact.phone</mat-label> 59 <mat-label translate>contact.phone</mat-label>
54 <input matInput formControlName="phone"> 60 <input matInput formControlName="phone">
  61 + <mat-error *ngIf="parentForm.get('phone').hasError('maxlength')">
  62 + {{ 'contact.phone-max-length' | translate }}
  63 + </mat-error>
55 </mat-form-field> 64 </mat-form-field>
56 <mat-form-field class="mat-block"> 65 <mat-form-field class="mat-block">
57 <mat-label translate>contact.email</mat-label> 66 <mat-label translate>contact.email</mat-label>
@@ -40,4 +40,7 @@ @@ -40,4 +40,7 @@
40 <mat-error *ngIf="subTypeFormGroup.get('subType').hasError('required')"> 40 <mat-error *ngIf="subTypeFormGroup.get('subType').hasError('required')">
41 {{ entitySubtypeRequiredText | translate }} 41 {{ entitySubtypeRequiredText | translate }}
42 </mat-error> 42 </mat-error>
  43 + <mat-error *ngIf="subTypeFormGroup.get('subType').hasError('maxlength')">
  44 + {{ entitySubtypeMaxLength | translate }}
  45 + </mat-error>
43 </mat-form-field> 46 </mat-form-field>
@@ -15,7 +15,7 @@ @@ -15,7 +15,7 @@
15 /// 15 ///
16 16
17 import { AfterViewInit, Component, ElementRef, forwardRef, Input, OnDestroy, OnInit, ViewChild } from '@angular/core'; 17 import { AfterViewInit, Component, ElementRef, forwardRef, Input, OnDestroy, OnInit, ViewChild } from '@angular/core';
18 -import { ControlValueAccessor, FormBuilder, FormGroup, NG_VALUE_ACCESSOR } from '@angular/forms'; 18 +import { ControlValueAccessor, FormBuilder, FormGroup, NG_VALUE_ACCESSOR, Validators } from '@angular/forms';
19 import { Observable, of, Subscription, throwError } from 'rxjs'; 19 import { Observable, of, Subscription, throwError } from 'rxjs';
20 import { 20 import {
21 catchError, 21 catchError,
@@ -58,9 +58,11 @@ export class EntitySubTypeAutocompleteComponent implements ControlValueAccessor, @@ -58,9 +58,11 @@ export class EntitySubTypeAutocompleteComponent implements ControlValueAccessor,
58 entityType: EntityType; 58 entityType: EntityType;
59 59
60 private requiredValue: boolean; 60 private requiredValue: boolean;
  61 +
61 get required(): boolean { 62 get required(): boolean {
62 return this.requiredValue; 63 return this.requiredValue;
63 } 64 }
  65 +
64 @Input() 66 @Input()
65 set required(value: boolean) { 67 set required(value: boolean) {
66 this.requiredValue = coerceBooleanProperty(value); 68 this.requiredValue = coerceBooleanProperty(value);
@@ -74,6 +76,7 @@ export class EntitySubTypeAutocompleteComponent implements ControlValueAccessor, @@ -74,6 +76,7 @@ export class EntitySubTypeAutocompleteComponent implements ControlValueAccessor,
74 selectEntitySubtypeText: string; 76 selectEntitySubtypeText: string;
75 entitySubtypeText: string; 77 entitySubtypeText: string;
76 entitySubtypeRequiredText: string; 78 entitySubtypeRequiredText: string;
  79 + entitySubtypeMaxLength: string;
77 80
78 filteredSubTypes: Observable<Array<string>>; 81 filteredSubTypes: Observable<Array<string>>;
79 82
@@ -96,7 +99,7 @@ export class EntitySubTypeAutocompleteComponent implements ControlValueAccessor, @@ -96,7 +99,7 @@ export class EntitySubTypeAutocompleteComponent implements ControlValueAccessor,
96 private entityViewService: EntityViewService, 99 private entityViewService: EntityViewService,
97 private fb: FormBuilder) { 100 private fb: FormBuilder) {
98 this.subTypeFormGroup = this.fb.group({ 101 this.subTypeFormGroup = this.fb.group({
99 - subType: [null] 102 + subType: [null, Validators.maxLength(255)]
100 }); 103 });
101 } 104 }
102 105
@@ -114,6 +117,7 @@ export class EntitySubTypeAutocompleteComponent implements ControlValueAccessor, @@ -114,6 +117,7 @@ export class EntitySubTypeAutocompleteComponent implements ControlValueAccessor,
114 this.selectEntitySubtypeText = 'asset.select-asset-type'; 117 this.selectEntitySubtypeText = 'asset.select-asset-type';
115 this.entitySubtypeText = 'asset.asset-type'; 118 this.entitySubtypeText = 'asset.asset-type';
116 this.entitySubtypeRequiredText = 'asset.asset-type-required'; 119 this.entitySubtypeRequiredText = 'asset.asset-type-required';
  120 + this.entitySubtypeMaxLength = 'asset.asset-type-max-length';
117 this.broadcastSubscription = this.broadcast.on('assetSaved', () => { 121 this.broadcastSubscription = this.broadcast.on('assetSaved', () => {
118 this.subTypes = null; 122 this.subTypes = null;
119 }); 123 });
@@ -122,6 +126,7 @@ export class EntitySubTypeAutocompleteComponent implements ControlValueAccessor, @@ -122,6 +126,7 @@ export class EntitySubTypeAutocompleteComponent implements ControlValueAccessor,
122 this.selectEntitySubtypeText = 'device.select-device-type'; 126 this.selectEntitySubtypeText = 'device.select-device-type';
123 this.entitySubtypeText = 'device.device-type'; 127 this.entitySubtypeText = 'device.device-type';
124 this.entitySubtypeRequiredText = 'device.device-type-required'; 128 this.entitySubtypeRequiredText = 'device.device-type-required';
  129 + this.entitySubtypeMaxLength = 'device.device-type-max-length';
125 this.broadcastSubscription = this.broadcast.on('deviceSaved', () => { 130 this.broadcastSubscription = this.broadcast.on('deviceSaved', () => {
126 this.subTypes = null; 131 this.subTypes = null;
127 }); 132 });
@@ -130,6 +135,7 @@ export class EntitySubTypeAutocompleteComponent implements ControlValueAccessor, @@ -130,6 +135,7 @@ export class EntitySubTypeAutocompleteComponent implements ControlValueAccessor,
130 this.selectEntitySubtypeText = 'edge.select-edge-type'; 135 this.selectEntitySubtypeText = 'edge.select-edge-type';
131 this.entitySubtypeText = 'edge.edge-type'; 136 this.entitySubtypeText = 'edge.edge-type';
132 this.entitySubtypeRequiredText = 'edge.edge-type-required'; 137 this.entitySubtypeRequiredText = 'edge.edge-type-required';
  138 + this.entitySubtypeMaxLength = 'edge.type-max-length';
133 this.broadcastSubscription = this.broadcast.on('edgeSaved', () => { 139 this.broadcastSubscription = this.broadcast.on('edgeSaved', () => {
134 this.subTypes = null; 140 this.subTypes = null;
135 }); 141 });
@@ -138,6 +144,7 @@ export class EntitySubTypeAutocompleteComponent implements ControlValueAccessor, @@ -138,6 +144,7 @@ export class EntitySubTypeAutocompleteComponent implements ControlValueAccessor,
138 this.selectEntitySubtypeText = 'entity-view.select-entity-view-type'; 144 this.selectEntitySubtypeText = 'entity-view.select-entity-view-type';
139 this.entitySubtypeText = 'entity-view.entity-view-type'; 145 this.entitySubtypeText = 'entity-view.entity-view-type';
140 this.entitySubtypeRequiredText = 'entity-view.entity-view-type-required'; 146 this.entitySubtypeRequiredText = 'entity-view.entity-view-type-required';
  147 + this.entitySubtypeMaxLength = 'entity-view.type-max-length'
141 this.broadcastSubscription = this.broadcast.on('entityViewSaved', () => { 148 this.broadcastSubscription = this.broadcast.on('entityViewSaved', () => {
142 this.subTypes = null; 149 this.subTypes = null;
143 }); 150 });
@@ -149,7 +156,7 @@ export class EntitySubTypeAutocompleteComponent implements ControlValueAccessor, @@ -149,7 +156,7 @@ export class EntitySubTypeAutocompleteComponent implements ControlValueAccessor,
149 debounceTime(150), 156 debounceTime(150),
150 distinctUntilChanged(), 157 distinctUntilChanged(),
151 tap(value => { 158 tap(value => {
152 - this.updateView(value); 159 + this.updateView(value);
153 }), 160 }),
154 // startWith<string | EntitySubtype>(''), 161 // startWith<string | EntitySubtype>(''),
155 map(value => value ? value : ''), 162 map(value => value ? value : ''),
@@ -203,7 +210,7 @@ export class EntitySubTypeAutocompleteComponent implements ControlValueAccessor, @@ -203,7 +210,7 @@ export class EntitySubTypeAutocompleteComponent implements ControlValueAccessor,
203 fetchSubTypes(searchText?: string, strictMatch: boolean = false): Observable<Array<string>> { 210 fetchSubTypes(searchText?: string, strictMatch: boolean = false): Observable<Array<string>> {
204 this.searchText = searchText; 211 this.searchText = searchText;
205 return this.getSubTypes().pipe( 212 return this.getSubTypes().pipe(
206 - map(subTypes => subTypes.filter( subType => { 213 + map(subTypes => subTypes.filter(subType => {
207 if (strictMatch) { 214 if (strictMatch) {
208 return searchText ? subType === searchText : false; 215 return searchText ? subType === searchText : false;
209 } else { 216 } else {
@@ -39,4 +39,7 @@ @@ -39,4 +39,7 @@
39 <mat-error *ngIf="relationTypeFormGroup.get('relationType').hasError('required')"> 39 <mat-error *ngIf="relationTypeFormGroup.get('relationType').hasError('required')">
40 {{ 'relation.relation-type-required' | translate }} 40 {{ 'relation.relation-type-required' | translate }}
41 </mat-error> 41 </mat-error>
  42 + <mat-error *ngIf="relationTypeFormGroup.get('relationType').hasError('maxlength')">
  43 + {{ 'relation.relation-type-max-length' | translate }}
  44 + </mat-error>
42 </mat-form-field> 45 </mat-form-field>
@@ -68,7 +68,7 @@ export class RelationTypeAutocompleteComponent implements ControlValueAccessor, @@ -68,7 +68,7 @@ export class RelationTypeAutocompleteComponent implements ControlValueAccessor,
68 public translate: TranslateService, 68 public translate: TranslateService,
69 private fb: FormBuilder) { 69 private fb: FormBuilder) {
70 this.relationTypeFormGroup = this.fb.group({ 70 this.relationTypeFormGroup = this.fb.group({
71 - relationType: [null, this.required ? [Validators.required] : []] 71 + relationType: [null, this.required ? [Validators.required, Validators.maxLength(255)] : [Validators.maxLength(255)]]
72 }); 72 });
73 } 73 }
74 74
@@ -369,6 +369,7 @@ @@ -369,6 +369,7 @@
369 "management": "Asset management", 369 "management": "Asset management",
370 "view-assets": "View Assets", 370 "view-assets": "View Assets",
371 "add": "Add Asset", 371 "add": "Add Asset",
  372 + "asset-type-max-length": "Asset type should be less than 256",
372 "assign-to-customer": "Assign to customer", 373 "assign-to-customer": "Assign to customer",
373 "assign-asset-to-customer": "Assign Asset(s) To Customer", 374 "assign-asset-to-customer": "Assign Asset(s) To Customer",
374 "assign-asset-to-customer-text": "Please select the assets to assign to the customer", 375 "assign-asset-to-customer-text": "Please select the assets to assign to the customer",
@@ -391,6 +392,8 @@ @@ -391,6 +392,8 @@
391 "asset-types": "Asset types", 392 "asset-types": "Asset types",
392 "name": "Name", 393 "name": "Name",
393 "name-required": "Name is required.", 394 "name-required": "Name is required.",
  395 + "name-max-length": "Name should be less than 256",
  396 + "label-max-length": "Label should be less than 256",
394 "description": "Description", 397 "description": "Description",
395 "type": "Type", 398 "type": "Type",
396 "type-required": "Type is required.", 399 "type-required": "Type is required.",
@@ -449,6 +452,7 @@ @@ -449,6 +452,7 @@
449 "scope-shared": "Shared attributes", 452 "scope-shared": "Shared attributes",
450 "add": "Add attribute", 453 "add": "Add attribute",
451 "key": "Key", 454 "key": "Key",
  455 + "key-max-length": "Key should be less than 256",
452 "last-update-time": "Last update time", 456 "last-update-time": "Last update time",
453 "key-required": "Attribute key is required.", 457 "key-required": "Attribute key is required.",
454 "value": "Value", 458 "value": "Value",
@@ -590,7 +594,10 @@ @@ -590,7 +594,10 @@
590 "address2": "Address 2", 594 "address2": "Address 2",
591 "phone": "Phone", 595 "phone": "Phone",
592 "email": "Email", 596 "email": "Email",
593 - "no-address": "No address" 597 + "no-address": "No address",
  598 + "state-max-length": "State length should be less than 256",
  599 + "phone-max-length": "Phone number should be less than 256",
  600 + "city-max-length": "Specified city should be less than 256"
594 }, 601 },
595 "common": { 602 "common": {
596 "username": "Username", 603 "username": "Username",
@@ -646,6 +653,7 @@ @@ -646,6 +653,7 @@
646 "manage-dashboards": "Manage dashboards", 653 "manage-dashboards": "Manage dashboards",
647 "title": "Title", 654 "title": "Title",
648 "title-required": "Title is required.", 655 "title-required": "Title is required.",
  656 + "title-max-length": "Title should be less than 256",
649 "description": "Description", 657 "description": "Description",
650 "details": "Details", 658 "details": "Details",
651 "events": "Events", 659 "events": "Events",
@@ -700,6 +708,7 @@ @@ -700,6 +708,7 @@
700 "select-widget-subtitle": "List of available widget types", 708 "select-widget-subtitle": "List of available widget types",
701 "delete": "Delete dashboard", 709 "delete": "Delete dashboard",
702 "title-required": "Title is required.", 710 "title-required": "Title is required.",
  711 + "title-max-length": "Title should be less than 256",
703 "description": "Description", 712 "description": "Description",
704 "details": "Details", 713 "details": "Details",
705 "dashboard-details": "Dashboard details", 714 "dashboard-details": "Dashboard details",
@@ -886,6 +895,7 @@ @@ -886,6 +895,7 @@
886 "management": "Device management", 895 "management": "Device management",
887 "view-devices": "View Devices", 896 "view-devices": "View Devices",
888 "device-alias": "Device alias", 897 "device-alias": "Device alias",
  898 + "device-type-max-length": "Device type should be less than 256",
889 "aliases": "Device aliases", 899 "aliases": "Device aliases",
890 "no-alias-matching": "'{{alias}}' not found.", 900 "no-alias-matching": "'{{alias}}' not found.",
891 "no-aliases-found": "No aliases found.", 901 "no-aliases-found": "No aliases found.",
@@ -998,6 +1008,8 @@ @@ -998,6 +1008,8 @@
998 "device-types": "Device types", 1008 "device-types": "Device types",
999 "name": "Name", 1009 "name": "Name",
1000 "name-required": "Name is required.", 1010 "name-required": "Name is required.",
  1011 + "name-max-length": "Name should be less than 256",
  1012 + "label-max-length": "Label should be less than 256",
1001 "description": "Description", 1013 "description": "Description",
1002 "label": "Label", 1014 "label": "Label",
1003 "events": "Events", 1015 "events": "Events",
@@ -1050,6 +1062,7 @@ @@ -1050,6 +1062,7 @@
1050 "set-default": "Make device profile default", 1062 "set-default": "Make device profile default",
1051 "delete": "Delete device profile", 1063 "delete": "Delete device profile",
1052 "copyId": "Copy device profile Id", 1064 "copyId": "Copy device profile Id",
  1065 + "name-max-length": "Name should be less than 256",
1053 "new-device-profile-name": "Device profile name", 1066 "new-device-profile-name": "Device profile name",
1054 "new-device-profile-name-required": "Device profile name is required.", 1067 "new-device-profile-name-required": "Device profile name is required.",
1055 "name": "Name", 1068 "name": "Name",
@@ -1401,6 +1414,9 @@ @@ -1401,6 +1414,9 @@
1401 "edge": "Edge", 1414 "edge": "Edge",
1402 "edge-instances": "Edge instances", 1415 "edge-instances": "Edge instances",
1403 "edge-file": "Edge file", 1416 "edge-file": "Edge file",
  1417 + "name-max-length": "Name should be less than 256",
  1418 + "label-max-length": "Label should be less than 256",
  1419 + "type-max-length": "Type should be less than 256",
1404 "management": "Edge management", 1420 "management": "Edge management",
1405 "no-edges-matching": "No edges matching '{{entity}}' were found.", 1421 "no-edges-matching": "No edges matching '{{entity}}' were found.",
1406 "rulechain-templates": "Rule chain templates", 1422 "rulechain-templates": "Rule chain templates",
@@ -1741,6 +1757,8 @@ @@ -1741,6 +1757,8 @@
1741 "created-time": "Created time", 1757 "created-time": "Created time",
1742 "name": "Name", 1758 "name": "Name",
1743 "name-required": "Name is required.", 1759 "name-required": "Name is required.",
  1760 + "name-max-length": "Name should be less than 256",
  1761 + "type-max-length": "Entity view type should be less than 256",
1744 "description": "Description", 1762 "description": "Description",
1745 "events": "Events", 1763 "events": "Events",
1746 "details": "Details", 1764 "details": "Details",
@@ -2335,12 +2353,14 @@ @@ -2335,12 +2353,14 @@
2335 "selected-package": "{ count, plural, 1 {1 package} other {# packages} } selected", 2353 "selected-package": "{ count, plural, 1 {1 package} other {# packages} } selected",
2336 "title": "Title", 2354 "title": "Title",
2337 "title-required": "Title is required.", 2355 "title-required": "Title is required.",
  2356 + "title-max-length": "Title should be less than 256",
2338 "types": { 2357 "types": {
2339 "firmware": "Firmware", 2358 "firmware": "Firmware",
2340 "software": "Software" 2359 "software": "Software"
2341 }, 2360 },
2342 "version": "Version", 2361 "version": "Version",
2343 "version-required": "Version is required.", 2362 "version-required": "Version is required.",
  2363 + "version-max-length": "Version should be less than 256",
2344 "warning-after-save-no-edit": "Once the package is uploaded, you will not be able to modify title, version, device profile and package type." 2364 "warning-after-save-no-edit": "Once the package is uploaded, you will not be able to modify title, version, device profile and package type."
2345 }, 2365 },
2346 "position": { 2366 "position": {
@@ -2379,6 +2399,7 @@ @@ -2379,6 +2399,7 @@
2379 "delete": "Delete relation", 2399 "delete": "Delete relation",
2380 "relation-type": "Relation type", 2400 "relation-type": "Relation type",
2381 "relation-type-required": "Relation type is required.", 2401 "relation-type-required": "Relation type is required.",
  2402 + "relation-type-max-length": "Relation type should be less than 256",
2382 "any-relation-type": "Any type", 2403 "any-relation-type": "Any type",
2383 "add": "Add relation", 2404 "add": "Add relation",
2384 "edit": "Edit relation", 2405 "edit": "Edit relation",
@@ -2423,7 +2444,8 @@ @@ -2423,7 +2444,8 @@
2423 "selected-resources": "{ count, plural, 1 {1 resource} other {# resources} } selected", 2444 "selected-resources": "{ count, plural, 1 {1 resource} other {# resources} } selected",
2424 "system": "System", 2445 "system": "System",
2425 "title": "Title", 2446 "title": "Title",
2426 - "title-required": "Title is required." 2447 + "title-required": "Title is required.",
  2448 + "title-max-length": "Title should be less than 256"
2427 }, 2449 },
2428 "rulechain": { 2450 "rulechain": {
2429 "rulechain": "Rule chain", 2451 "rulechain": "Rule chain",
@@ -2432,6 +2454,7 @@ @@ -2432,6 +2454,7 @@
2432 "delete": "Delete rule chain", 2454 "delete": "Delete rule chain",
2433 "name": "Name", 2455 "name": "Name",
2434 "name-required": "Name is required.", 2456 "name-required": "Name is required.",
  2457 + "name-max-length": "Name should be less than 256",
2435 "description": "Description", 2458 "description": "Description",
2436 "add": "Add Rule Chain", 2459 "add": "Add Rule Chain",
2437 "set-root": "Make rule chain root", 2460 "set-root": "Make rule chain root",
@@ -2573,6 +2596,7 @@ @@ -2573,6 +2596,7 @@
2573 "add-tenant-text": "Add new tenant", 2596 "add-tenant-text": "Add new tenant",
2574 "no-tenants-text": "No tenants found", 2597 "no-tenants-text": "No tenants found",
2575 "tenant-details": "Tenant details", 2598 "tenant-details": "Tenant details",
  2599 + "title-max-length": "Title should be less than 256",
2576 "delete-tenant-title": "Are you sure you want to delete the tenant '{{tenantTitle}}'?", 2600 "delete-tenant-title": "Are you sure you want to delete the tenant '{{tenantTitle}}'?",
2577 "delete-tenant-text": "Be careful, after the confirmation the tenant and all related data will become unrecoverable.", 2601 "delete-tenant-text": "Be careful, after the confirmation the tenant and all related data will become unrecoverable.",
2578 "delete-tenants-title": "Are you sure you want to delete { count, plural, 1 {1 tenant} other {# tenants} }?", 2602 "delete-tenants-title": "Are you sure you want to delete { count, plural, 1 {1 tenant} other {# tenants} }?",
@@ -2602,6 +2626,7 @@ @@ -2602,6 +2626,7 @@
2602 "edit": "Edit tenant profile", 2626 "edit": "Edit tenant profile",
2603 "tenant-profile-details": "Tenant profile details", 2627 "tenant-profile-details": "Tenant profile details",
2604 "no-tenant-profiles-text": "No tenant profiles found", 2628 "no-tenant-profiles-text": "No tenant profiles found",
  2629 + "name-max-length": "Name should be less than 256",
2605 "search": "Search tenant profiles", 2630 "search": "Search tenant profiles",
2606 "selected-tenant-profiles": "{ count, plural, 1 {1 tenant profile} other {# tenant profiles} } selected", 2631 "selected-tenant-profiles": "{ count, plural, 1 {1 tenant profile} other {# tenant profiles} } selected",
2607 "no-tenant-profiles-matching": "No tenant profile matching '{{entity}}' were found.", 2632 "no-tenant-profiles-matching": "No tenant profile matching '{{entity}}' were found.",
@@ -2925,6 +2950,7 @@ @@ -2925,6 +2950,7 @@
2925 "delete": "Delete widgets bundle", 2950 "delete": "Delete widgets bundle",
2926 "title": "Title", 2951 "title": "Title",
2927 "title-required": "Title is required.", 2952 "title-required": "Title is required.",
  2953 + "title-max-length": "Title should be less than 256",
2928 "description": "Description", 2954 "description": "Description",
2929 "image-preview": "Image preview", 2955 "image-preview": "Image preview",
2930 "add-widgets-bundle-text": "Add new widgets bundle", 2956 "add-widgets-bundle-text": "Add new widgets bundle",