Commit 71bed873b01bffc8107c6d6bdd68f9a7fbd64176
Committed by
GitHub
Merge pull request #5166 from ViacheslavKlimov/fields-validation
[3.3.2] Fields length validation
Showing
81 changed files
with
662 additions
and
141 deletions
@@ -76,6 +76,7 @@ import org.thingsboard.server.common.data.kv.StringDataEntry; | @@ -76,6 +76,7 @@ import org.thingsboard.server.common.data.kv.StringDataEntry; | ||
76 | import org.thingsboard.server.common.data.kv.TsKvEntry; | 76 | import org.thingsboard.server.common.data.kv.TsKvEntry; |
77 | import org.thingsboard.server.common.data.tenant.profile.DefaultTenantProfileConfiguration; | 77 | import org.thingsboard.server.common.data.tenant.profile.DefaultTenantProfileConfiguration; |
78 | import org.thingsboard.server.common.transport.adaptor.JsonConverter; | 78 | import org.thingsboard.server.common.transport.adaptor.JsonConverter; |
79 | +import org.thingsboard.server.dao.service.ConstraintValidator; | ||
79 | import org.thingsboard.server.dao.timeseries.TimeseriesService; | 80 | import org.thingsboard.server.dao.timeseries.TimeseriesService; |
80 | import org.thingsboard.server.queue.util.TbCoreComponent; | 81 | import org.thingsboard.server.queue.util.TbCoreComponent; |
81 | import org.thingsboard.server.service.security.AccessValidator; | 82 | import org.thingsboard.server.service.security.AccessValidator; |
@@ -184,7 +185,11 @@ public class TelemetryController extends BaseController { | @@ -184,7 +185,11 @@ public class TelemetryController extends BaseController { | ||
184 | public DeferredResult<ResponseEntity> getAttributeKeys( | 185 | public DeferredResult<ResponseEntity> getAttributeKeys( |
185 | @ApiParam(value = ENTITY_TYPE_PARAM_DESCRIPTION, required = true, defaultValue = "DEVICE") @PathVariable("entityType") String entityType, | 186 | @ApiParam(value = ENTITY_TYPE_PARAM_DESCRIPTION, required = true, defaultValue = "DEVICE") @PathVariable("entityType") String entityType, |
186 | @ApiParam(value = ENTITY_ID_PARAM_DESCRIPTION, required = true) @PathVariable("entityId") String entityIdStr) throws ThingsboardException { | 187 | @ApiParam(value = ENTITY_ID_PARAM_DESCRIPTION, required = true) @PathVariable("entityId") String entityIdStr) throws ThingsboardException { |
187 | - return accessValidator.validateEntityAndCallback(getCurrentUser(), Operation.READ_ATTRIBUTES, entityType, entityIdStr, this::getAttributeKeysCallback); | 188 | + try { |
189 | + return accessValidator.validateEntityAndCallback(getCurrentUser(), Operation.READ_ATTRIBUTES, entityType, entityIdStr, this::getAttributeKeysCallback); | ||
190 | + } catch (Exception e) { | ||
191 | + throw handleException(e); | ||
192 | + } | ||
188 | } | 193 | } |
189 | 194 | ||
190 | @ApiOperation(value = "Get all attribute keys by scope (getAttributeKeysByScope)", | 195 | @ApiOperation(value = "Get all attribute keys by scope (getAttributeKeysByScope)", |
@@ -201,8 +206,12 @@ public class TelemetryController extends BaseController { | @@ -201,8 +206,12 @@ public class TelemetryController extends BaseController { | ||
201 | @ApiParam(value = ENTITY_TYPE_PARAM_DESCRIPTION, required = true, defaultValue = "DEVICE") @PathVariable("entityType") String entityType, | 206 | @ApiParam(value = ENTITY_TYPE_PARAM_DESCRIPTION, required = true, defaultValue = "DEVICE") @PathVariable("entityType") String entityType, |
202 | @ApiParam(value = ENTITY_ID_PARAM_DESCRIPTION, required = true) @PathVariable("entityId") String entityIdStr, | 207 | @ApiParam(value = ENTITY_ID_PARAM_DESCRIPTION, required = true) @PathVariable("entityId") String entityIdStr, |
203 | @ApiParam(value = ATTRIBUTES_SCOPE_DESCRIPTION, required = true, allowableValues = ATTRIBUTES_SCOPE_ALLOWED_VALUES) @PathVariable("scope") String scope) throws ThingsboardException { | 208 | @ApiParam(value = ATTRIBUTES_SCOPE_DESCRIPTION, required = true, allowableValues = ATTRIBUTES_SCOPE_ALLOWED_VALUES) @PathVariable("scope") String scope) throws ThingsboardException { |
204 | - return accessValidator.validateEntityAndCallback(getCurrentUser(), Operation.READ_ATTRIBUTES, entityType, entityIdStr, | ||
205 | - (result, tenantId, entityId) -> getAttributeKeysCallback(result, tenantId, entityId, scope)); | 209 | + try { |
210 | + return accessValidator.validateEntityAndCallback(getCurrentUser(), Operation.READ_ATTRIBUTES, entityType, entityIdStr, | ||
211 | + (result, tenantId, entityId) -> getAttributeKeysCallback(result, tenantId, entityId, scope)); | ||
212 | + } catch (Exception e) { | ||
213 | + throw handleException(e); | ||
214 | + } | ||
206 | } | 215 | } |
207 | 216 | ||
208 | @ApiOperation(value = "Get attributes (getAttributes)", | 217 | @ApiOperation(value = "Get attributes (getAttributes)", |
@@ -220,9 +229,13 @@ public class TelemetryController extends BaseController { | @@ -220,9 +229,13 @@ public class TelemetryController extends BaseController { | ||
220 | @ApiParam(value = ENTITY_TYPE_PARAM_DESCRIPTION, required = true, defaultValue = "DEVICE") @PathVariable("entityType") String entityType, | 229 | @ApiParam(value = ENTITY_TYPE_PARAM_DESCRIPTION, required = true, defaultValue = "DEVICE") @PathVariable("entityType") String entityType, |
221 | @ApiParam(value = ENTITY_ID_PARAM_DESCRIPTION, required = true) @PathVariable("entityId") String entityIdStr, | 230 | @ApiParam(value = ENTITY_ID_PARAM_DESCRIPTION, required = true) @PathVariable("entityId") String entityIdStr, |
222 | @ApiParam(value = ATTRIBUTES_KEYS_DESCRIPTION) @RequestParam(name = "keys", required = false) String keysStr) throws ThingsboardException { | 231 | @ApiParam(value = ATTRIBUTES_KEYS_DESCRIPTION) @RequestParam(name = "keys", required = false) String keysStr) throws ThingsboardException { |
223 | - SecurityUser user = getCurrentUser(); | ||
224 | - return accessValidator.validateEntityAndCallback(getCurrentUser(), Operation.READ_ATTRIBUTES, entityType, entityIdStr, | ||
225 | - (result, tenantId, entityId) -> getAttributeValuesCallback(result, user, entityId, null, keysStr)); | 232 | + try { |
233 | + SecurityUser user = getCurrentUser(); | ||
234 | + return accessValidator.validateEntityAndCallback(getCurrentUser(), Operation.READ_ATTRIBUTES, entityType, entityIdStr, | ||
235 | + (result, tenantId, entityId) -> getAttributeValuesCallback(result, user, entityId, null, keysStr)); | ||
236 | + } catch (Exception e) { | ||
237 | + throw handleException(e); | ||
238 | + } | ||
226 | } | 239 | } |
227 | 240 | ||
228 | 241 | ||
@@ -244,9 +257,13 @@ public class TelemetryController extends BaseController { | @@ -244,9 +257,13 @@ public class TelemetryController extends BaseController { | ||
244 | @ApiParam(value = ENTITY_ID_PARAM_DESCRIPTION, required = true) @PathVariable("entityId") String entityIdStr, | 257 | @ApiParam(value = ENTITY_ID_PARAM_DESCRIPTION, required = true) @PathVariable("entityId") String entityIdStr, |
245 | @ApiParam(value = ATTRIBUTES_SCOPE_DESCRIPTION, allowableValues = ATTRIBUTES_SCOPE_ALLOWED_VALUES, required = true) @PathVariable("scope") String scope, | 258 | @ApiParam(value = ATTRIBUTES_SCOPE_DESCRIPTION, allowableValues = ATTRIBUTES_SCOPE_ALLOWED_VALUES, required = true) @PathVariable("scope") String scope, |
246 | @ApiParam(value = ATTRIBUTES_KEYS_DESCRIPTION) @RequestParam(name = "keys", required = false) String keysStr) throws ThingsboardException { | 259 | @ApiParam(value = ATTRIBUTES_KEYS_DESCRIPTION) @RequestParam(name = "keys", required = false) String keysStr) throws ThingsboardException { |
247 | - SecurityUser user = getCurrentUser(); | ||
248 | - return accessValidator.validateEntityAndCallback(getCurrentUser(), Operation.READ_ATTRIBUTES, entityType, entityIdStr, | ||
249 | - (result, tenantId, entityId) -> getAttributeValuesCallback(result, user, entityId, scope, keysStr)); | 260 | + try { |
261 | + SecurityUser user = getCurrentUser(); | ||
262 | + return accessValidator.validateEntityAndCallback(getCurrentUser(), Operation.READ_ATTRIBUTES, entityType, entityIdStr, | ||
263 | + (result, tenantId, entityId) -> getAttributeValuesCallback(result, user, entityId, scope, keysStr)); | ||
264 | + } catch (Exception e) { | ||
265 | + throw handleException(e); | ||
266 | + } | ||
250 | } | 267 | } |
251 | 268 | ||
252 | @ApiOperation(value = "Get time-series keys (getTimeseriesKeys)", | 269 | @ApiOperation(value = "Get time-series keys (getTimeseriesKeys)", |
@@ -259,8 +276,12 @@ public class TelemetryController extends BaseController { | @@ -259,8 +276,12 @@ public class TelemetryController extends BaseController { | ||
259 | public DeferredResult<ResponseEntity> getTimeseriesKeys( | 276 | public DeferredResult<ResponseEntity> getTimeseriesKeys( |
260 | @ApiParam(value = ENTITY_TYPE_PARAM_DESCRIPTION, required = true, defaultValue = "DEVICE") @PathVariable("entityType") String entityType, | 277 | @ApiParam(value = ENTITY_TYPE_PARAM_DESCRIPTION, required = true, defaultValue = "DEVICE") @PathVariable("entityType") String entityType, |
261 | @ApiParam(value = ENTITY_ID_PARAM_DESCRIPTION, required = true) @PathVariable("entityId") String entityIdStr) throws ThingsboardException { | 278 | @ApiParam(value = ENTITY_ID_PARAM_DESCRIPTION, required = true) @PathVariable("entityId") String entityIdStr) throws ThingsboardException { |
262 | - return accessValidator.validateEntityAndCallback(getCurrentUser(), Operation.READ_TELEMETRY, entityType, entityIdStr, | ||
263 | - (result, tenantId, entityId) -> Futures.addCallback(tsService.findAllLatest(tenantId, entityId), getTsKeysToResponseCallback(result), MoreExecutors.directExecutor())); | 279 | + try { |
280 | + return accessValidator.validateEntityAndCallback(getCurrentUser(), Operation.READ_TELEMETRY, entityType, entityIdStr, | ||
281 | + (result, tenantId, entityId) -> Futures.addCallback(tsService.findAllLatest(tenantId, entityId), getTsKeysToResponseCallback(result), MoreExecutors.directExecutor())); | ||
282 | + } catch (Exception e) { | ||
283 | + throw handleException(e); | ||
284 | + } | ||
264 | } | 285 | } |
265 | 286 | ||
266 | @ApiOperation(value = "Get latest time-series value (getLatestTimeseries)", | 287 | @ApiOperation(value = "Get latest time-series value (getLatestTimeseries)", |
@@ -285,9 +306,13 @@ public class TelemetryController extends BaseController { | @@ -285,9 +306,13 @@ public class TelemetryController extends BaseController { | ||
285 | @ApiParam(value = TELEMETRY_KEYS_DESCRIPTION) @RequestParam(name = "keys", required = false) String keysStr, | 306 | @ApiParam(value = TELEMETRY_KEYS_DESCRIPTION) @RequestParam(name = "keys", required = false) String keysStr, |
286 | @ApiParam(value = STRICT_DATA_TYPES_DESCRIPTION) | 307 | @ApiParam(value = STRICT_DATA_TYPES_DESCRIPTION) |
287 | @RequestParam(name = "useStrictDataTypes", required = false, defaultValue = "false") Boolean useStrictDataTypes) throws ThingsboardException { | 308 | @RequestParam(name = "useStrictDataTypes", required = false, defaultValue = "false") Boolean useStrictDataTypes) throws ThingsboardException { |
288 | - SecurityUser user = getCurrentUser(); | ||
289 | - return accessValidator.validateEntityAndCallback(getCurrentUser(), Operation.READ_TELEMETRY, entityType, entityIdStr, | ||
290 | - (result, tenantId, entityId) -> getLatestTimeseriesValuesCallback(result, user, entityId, keysStr, useStrictDataTypes)); | 309 | + try { |
310 | + SecurityUser user = getCurrentUser(); | ||
311 | + return accessValidator.validateEntityAndCallback(getCurrentUser(), Operation.READ_TELEMETRY, entityType, entityIdStr, | ||
312 | + (result, tenantId, entityId) -> getLatestTimeseriesValuesCallback(result, user, entityId, keysStr, useStrictDataTypes)); | ||
313 | + } catch (Exception e) { | ||
314 | + throw handleException(e); | ||
315 | + } | ||
291 | } | 316 | } |
292 | 317 | ||
293 | @ApiOperation(value = "Get time-series data (getTimeseries)", | 318 | @ApiOperation(value = "Get time-series data (getTimeseries)", |
@@ -324,15 +349,19 @@ public class TelemetryController extends BaseController { | @@ -324,15 +349,19 @@ public class TelemetryController extends BaseController { | ||
324 | @RequestParam(name = "orderBy", defaultValue = "DESC") String orderBy, | 349 | @RequestParam(name = "orderBy", defaultValue = "DESC") String orderBy, |
325 | @ApiParam(value = STRICT_DATA_TYPES_DESCRIPTION) | 350 | @ApiParam(value = STRICT_DATA_TYPES_DESCRIPTION) |
326 | @RequestParam(name = "useStrictDataTypes", required = false, defaultValue = "false") Boolean useStrictDataTypes) throws ThingsboardException { | 351 | @RequestParam(name = "useStrictDataTypes", required = false, defaultValue = "false") Boolean useStrictDataTypes) throws ThingsboardException { |
327 | - return accessValidator.validateEntityAndCallback(getCurrentUser(), Operation.READ_TELEMETRY, entityType, entityIdStr, | ||
328 | - (result, tenantId, entityId) -> { | ||
329 | - // If interval is 0, convert this to a NONE aggregation, which is probably what the user really wanted | ||
330 | - Aggregation agg = interval == 0L ? Aggregation.valueOf(Aggregation.NONE.name()) : Aggregation.valueOf(aggStr); | ||
331 | - List<ReadTsKvQuery> queries = toKeysList(keys).stream().map(key -> new BaseReadTsKvQuery(key, startTs, endTs, interval, limit, agg, orderBy)) | ||
332 | - .collect(Collectors.toList()); | ||
333 | - | ||
334 | - Futures.addCallback(tsService.findAll(tenantId, entityId, queries), getTsKvListCallback(result, useStrictDataTypes), MoreExecutors.directExecutor()); | ||
335 | - }); | 352 | + try { |
353 | + return accessValidator.validateEntityAndCallback(getCurrentUser(), Operation.READ_TELEMETRY, entityType, entityIdStr, | ||
354 | + (result, tenantId, entityId) -> { | ||
355 | + // If interval is 0, convert this to a NONE aggregation, which is probably what the user really wanted | ||
356 | + Aggregation agg = interval == 0L ? Aggregation.valueOf(Aggregation.NONE.name()) : Aggregation.valueOf(aggStr); | ||
357 | + List<ReadTsKvQuery> queries = toKeysList(keys).stream().map(key -> new BaseReadTsKvQuery(key, startTs, endTs, interval, limit, agg, orderBy)) | ||
358 | + .collect(Collectors.toList()); | ||
359 | + | ||
360 | + Futures.addCallback(tsService.findAll(tenantId, entityId, queries), getTsKvListCallback(result, useStrictDataTypes), MoreExecutors.directExecutor()); | ||
361 | + }); | ||
362 | + } catch (Exception e) { | ||
363 | + throw handleException(e); | ||
364 | + } | ||
336 | } | 365 | } |
337 | 366 | ||
338 | @ApiOperation(value = "Save device attributes (saveDeviceAttributes)", | 367 | @ApiOperation(value = "Save device attributes (saveDeviceAttributes)", |
@@ -356,8 +385,12 @@ public class TelemetryController extends BaseController { | @@ -356,8 +385,12 @@ public class TelemetryController extends BaseController { | ||
356 | @ApiParam(value = DEVICE_ID_PARAM_DESCRIPTION, required = true) @PathVariable("deviceId") String deviceIdStr, | 385 | @ApiParam(value = DEVICE_ID_PARAM_DESCRIPTION, required = true) @PathVariable("deviceId") String deviceIdStr, |
357 | @ApiParam(value = ATTRIBUTES_SCOPE_DESCRIPTION, allowableValues = ATTRIBUTES_SCOPE_ALLOWED_VALUES, required = true) @PathVariable("scope") String scope, | 386 | @ApiParam(value = ATTRIBUTES_SCOPE_DESCRIPTION, allowableValues = ATTRIBUTES_SCOPE_ALLOWED_VALUES, required = true) @PathVariable("scope") String scope, |
358 | @ApiParam(value = ATTRIBUTES_JSON_REQUEST_DESCRIPTION, required = true) @RequestBody JsonNode request) throws ThingsboardException { | 387 | @ApiParam(value = ATTRIBUTES_JSON_REQUEST_DESCRIPTION, required = true) @RequestBody JsonNode request) throws ThingsboardException { |
359 | - EntityId entityId = EntityIdFactory.getByTypeAndUuid(EntityType.DEVICE, deviceIdStr); | ||
360 | - return saveAttributes(getTenantId(), entityId, scope, request); | 388 | + try { |
389 | + EntityId entityId = EntityIdFactory.getByTypeAndUuid(EntityType.DEVICE, deviceIdStr); | ||
390 | + return saveAttributes(getTenantId(), entityId, scope, request); | ||
391 | + } catch (Exception e) { | ||
392 | + throw handleException(e); | ||
393 | + } | ||
361 | } | 394 | } |
362 | 395 | ||
363 | @ApiOperation(value = "Save entity attributes (saveEntityAttributesV1)", | 396 | @ApiOperation(value = "Save entity attributes (saveEntityAttributesV1)", |
@@ -380,8 +413,12 @@ public class TelemetryController extends BaseController { | @@ -380,8 +413,12 @@ public class TelemetryController extends BaseController { | ||
380 | @ApiParam(value = ENTITY_ID_PARAM_DESCRIPTION, required = true) @PathVariable("entityId") String entityIdStr, | 413 | @ApiParam(value = ENTITY_ID_PARAM_DESCRIPTION, required = true) @PathVariable("entityId") String entityIdStr, |
381 | @ApiParam(value = ATTRIBUTES_SCOPE_DESCRIPTION, allowableValues = ATTRIBUTES_SCOPE_ALLOWED_VALUES) @PathVariable("scope") String scope, | 414 | @ApiParam(value = ATTRIBUTES_SCOPE_DESCRIPTION, allowableValues = ATTRIBUTES_SCOPE_ALLOWED_VALUES) @PathVariable("scope") String scope, |
382 | @ApiParam(value = ATTRIBUTES_JSON_REQUEST_DESCRIPTION, required = true) @RequestBody JsonNode request) throws ThingsboardException { | 415 | @ApiParam(value = ATTRIBUTES_JSON_REQUEST_DESCRIPTION, required = true) @RequestBody JsonNode request) throws ThingsboardException { |
383 | - EntityId entityId = EntityIdFactory.getByTypeAndId(entityType, entityIdStr); | ||
384 | - return saveAttributes(getTenantId(), entityId, scope, request); | 416 | + try { |
417 | + EntityId entityId = EntityIdFactory.getByTypeAndId(entityType, entityIdStr); | ||
418 | + return saveAttributes(getTenantId(), entityId, scope, request); | ||
419 | + } catch (Exception e) { | ||
420 | + throw handleException(e); | ||
421 | + } | ||
385 | } | 422 | } |
386 | 423 | ||
387 | @ApiOperation(value = "Save entity attributes (saveEntityAttributesV2)", | 424 | @ApiOperation(value = "Save entity attributes (saveEntityAttributesV2)", |
@@ -404,8 +441,12 @@ public class TelemetryController extends BaseController { | @@ -404,8 +441,12 @@ public class TelemetryController extends BaseController { | ||
404 | @ApiParam(value = ENTITY_ID_PARAM_DESCRIPTION, required = true) @PathVariable("entityId") String entityIdStr, | 441 | @ApiParam(value = ENTITY_ID_PARAM_DESCRIPTION, required = true) @PathVariable("entityId") String entityIdStr, |
405 | @ApiParam(value = ATTRIBUTES_SCOPE_DESCRIPTION, allowableValues = ATTRIBUTES_SCOPE_ALLOWED_VALUES, required = true) @PathVariable("scope") String scope, | 442 | @ApiParam(value = ATTRIBUTES_SCOPE_DESCRIPTION, allowableValues = ATTRIBUTES_SCOPE_ALLOWED_VALUES, required = true) @PathVariable("scope") String scope, |
406 | @ApiParam(value = ATTRIBUTES_JSON_REQUEST_DESCRIPTION, required = true) @RequestBody JsonNode request) throws ThingsboardException { | 443 | @ApiParam(value = ATTRIBUTES_JSON_REQUEST_DESCRIPTION, required = true) @RequestBody JsonNode request) throws ThingsboardException { |
407 | - EntityId entityId = EntityIdFactory.getByTypeAndId(entityType, entityIdStr); | ||
408 | - return saveAttributes(getTenantId(), entityId, scope, request); | 444 | + try { |
445 | + EntityId entityId = EntityIdFactory.getByTypeAndId(entityType, entityIdStr); | ||
446 | + return saveAttributes(getTenantId(), entityId, scope, request); | ||
447 | + } catch (Exception e) { | ||
448 | + throw handleException(e); | ||
449 | + } | ||
409 | } | 450 | } |
410 | 451 | ||
411 | 452 | ||
@@ -429,8 +470,12 @@ public class TelemetryController extends BaseController { | @@ -429,8 +470,12 @@ public class TelemetryController extends BaseController { | ||
429 | @ApiParam(value = ENTITY_ID_PARAM_DESCRIPTION, required = true) @PathVariable("entityId") String entityIdStr, | 470 | @ApiParam(value = ENTITY_ID_PARAM_DESCRIPTION, required = true) @PathVariable("entityId") String entityIdStr, |
430 | @ApiParam(value = TELEMETRY_SCOPE_DESCRIPTION, required = true, allowableValues = "ANY") @PathVariable("scope") String scope, | 471 | @ApiParam(value = TELEMETRY_SCOPE_DESCRIPTION, required = true, allowableValues = "ANY") @PathVariable("scope") String scope, |
431 | @ApiParam(value = TELEMETRY_JSON_REQUEST_DESCRIPTION, required = true) @RequestBody String requestBody) throws ThingsboardException { | 472 | @ApiParam(value = TELEMETRY_JSON_REQUEST_DESCRIPTION, required = true) @RequestBody String requestBody) throws ThingsboardException { |
432 | - EntityId entityId = EntityIdFactory.getByTypeAndId(entityType, entityIdStr); | ||
433 | - return saveTelemetry(getTenantId(), entityId, requestBody, 0L); | 473 | + try { |
474 | + EntityId entityId = EntityIdFactory.getByTypeAndId(entityType, entityIdStr); | ||
475 | + return saveTelemetry(getTenantId(), entityId, requestBody, 0L); | ||
476 | + } catch (Exception e) { | ||
477 | + throw handleException(e); | ||
478 | + } | ||
434 | } | 479 | } |
435 | 480 | ||
436 | @ApiOperation(value = "Save or update time-series data with TTL (saveEntityTelemetryWithTTL)", | 481 | @ApiOperation(value = "Save or update time-series data with TTL (saveEntityTelemetryWithTTL)", |
@@ -455,8 +500,12 @@ public class TelemetryController extends BaseController { | @@ -455,8 +500,12 @@ public class TelemetryController extends BaseController { | ||
455 | @ApiParam(value = TELEMETRY_SCOPE_DESCRIPTION, required = true, allowableValues = "ANY") @PathVariable("scope") String scope, | 500 | @ApiParam(value = TELEMETRY_SCOPE_DESCRIPTION, required = true, allowableValues = "ANY") @PathVariable("scope") String scope, |
456 | @ApiParam(value = "A long value representing TTL (Time to Live) parameter.", required = true) @PathVariable("ttl") Long ttl, | 501 | @ApiParam(value = "A long value representing TTL (Time to Live) parameter.", required = true) @PathVariable("ttl") Long ttl, |
457 | @ApiParam(value = TELEMETRY_JSON_REQUEST_DESCRIPTION, required = true) @RequestBody String requestBody) throws ThingsboardException { | 502 | @ApiParam(value = TELEMETRY_JSON_REQUEST_DESCRIPTION, required = true) @RequestBody String requestBody) throws ThingsboardException { |
458 | - EntityId entityId = EntityIdFactory.getByTypeAndId(entityType, entityIdStr); | ||
459 | - return saveTelemetry(getTenantId(), entityId, requestBody, ttl); | 503 | + try { |
504 | + EntityId entityId = EntityIdFactory.getByTypeAndId(entityType, entityIdStr); | ||
505 | + return saveTelemetry(getTenantId(), entityId, requestBody, ttl); | ||
506 | + } catch (Exception e) { | ||
507 | + throw handleException(e); | ||
508 | + } | ||
460 | } | 509 | } |
461 | 510 | ||
462 | @ApiOperation(value = "Delete entity time-series data (deleteEntityTimeseries)", | 511 | @ApiOperation(value = "Delete entity time-series data (deleteEntityTimeseries)", |
@@ -489,8 +538,12 @@ public class TelemetryController extends BaseController { | @@ -489,8 +538,12 @@ public class TelemetryController extends BaseController { | ||
489 | @RequestParam(name = "endTs", required = false) Long endTs, | 538 | @RequestParam(name = "endTs", required = false) Long endTs, |
490 | @ApiParam(value = "If the parameter is set to true, the latest telemetry will be rewritten in case that current latest value was removed, otherwise, in case that parameter is set to false the new latest value will not set.") | 539 | @ApiParam(value = "If the parameter is set to true, the latest telemetry will be rewritten in case that current latest value was removed, otherwise, in case that parameter is set to false the new latest value will not set.") |
491 | @RequestParam(name = "rewriteLatestIfDeleted", defaultValue = "false") boolean rewriteLatestIfDeleted) throws ThingsboardException { | 540 | @RequestParam(name = "rewriteLatestIfDeleted", defaultValue = "false") boolean rewriteLatestIfDeleted) throws ThingsboardException { |
492 | - EntityId entityId = EntityIdFactory.getByTypeAndId(entityType, entityIdStr); | ||
493 | - return deleteTimeseries(entityId, keysStr, deleteAllDataForKeys, startTs, endTs, rewriteLatestIfDeleted); | 541 | + try { |
542 | + EntityId entityId = EntityIdFactory.getByTypeAndId(entityType, entityIdStr); | ||
543 | + return deleteTimeseries(entityId, keysStr, deleteAllDataForKeys, startTs, endTs, rewriteLatestIfDeleted); | ||
544 | + } catch (Exception e) { | ||
545 | + throw handleException(e); | ||
546 | + } | ||
494 | } | 547 | } |
495 | 548 | ||
496 | private DeferredResult<ResponseEntity> deleteTimeseries(EntityId entityIdStr, String keysStr, boolean deleteAllDataForKeys, | 549 | private DeferredResult<ResponseEntity> deleteTimeseries(EntityId entityIdStr, String keysStr, boolean deleteAllDataForKeys, |
@@ -556,8 +609,12 @@ public class TelemetryController extends BaseController { | @@ -556,8 +609,12 @@ public class TelemetryController extends BaseController { | ||
556 | @ApiParam(value = DEVICE_ID_PARAM_DESCRIPTION, required = true) @PathVariable(DEVICE_ID) String deviceIdStr, | 609 | @ApiParam(value = DEVICE_ID_PARAM_DESCRIPTION, required = true) @PathVariable(DEVICE_ID) String deviceIdStr, |
557 | @ApiParam(value = ATTRIBUTES_SCOPE_DESCRIPTION, allowableValues = ATTRIBUTES_SCOPE_ALLOWED_VALUES, required = true) @PathVariable("scope") String scope, | 610 | @ApiParam(value = ATTRIBUTES_SCOPE_DESCRIPTION, allowableValues = ATTRIBUTES_SCOPE_ALLOWED_VALUES, required = true) @PathVariable("scope") String scope, |
558 | @ApiParam(value = ATTRIBUTES_KEYS_DESCRIPTION, required = true) @RequestParam(name = "keys") String keysStr) throws ThingsboardException { | 611 | @ApiParam(value = ATTRIBUTES_KEYS_DESCRIPTION, required = true) @RequestParam(name = "keys") String keysStr) throws ThingsboardException { |
559 | - EntityId entityId = EntityIdFactory.getByTypeAndUuid(EntityType.DEVICE, deviceIdStr); | ||
560 | - return deleteAttributes(entityId, scope, keysStr); | 612 | + try { |
613 | + EntityId entityId = EntityIdFactory.getByTypeAndUuid(EntityType.DEVICE, deviceIdStr); | ||
614 | + return deleteAttributes(entityId, scope, keysStr); | ||
615 | + } catch (Exception e) { | ||
616 | + throw handleException(e); | ||
617 | + } | ||
561 | } | 618 | } |
562 | 619 | ||
563 | @ApiOperation(value = "Delete entity attributes (deleteEntityAttributes)", | 620 | @ApiOperation(value = "Delete entity attributes (deleteEntityAttributes)", |
@@ -580,8 +637,12 @@ public class TelemetryController extends BaseController { | @@ -580,8 +637,12 @@ public class TelemetryController extends BaseController { | ||
580 | @ApiParam(value = ENTITY_ID_PARAM_DESCRIPTION, required = true) @PathVariable("entityId") String entityIdStr, | 637 | @ApiParam(value = ENTITY_ID_PARAM_DESCRIPTION, required = true) @PathVariable("entityId") String entityIdStr, |
581 | @ApiParam(value = ATTRIBUTES_SCOPE_DESCRIPTION, required = true, allowableValues = ATTRIBUTES_SCOPE_ALLOWED_VALUES) @PathVariable("scope") String scope, | 638 | @ApiParam(value = ATTRIBUTES_SCOPE_DESCRIPTION, required = true, allowableValues = ATTRIBUTES_SCOPE_ALLOWED_VALUES) @PathVariable("scope") String scope, |
582 | @ApiParam(value = ATTRIBUTES_KEYS_DESCRIPTION, required = true) @RequestParam(name = "keys") String keysStr) throws ThingsboardException { | 639 | @ApiParam(value = ATTRIBUTES_KEYS_DESCRIPTION, required = true) @RequestParam(name = "keys") String keysStr) throws ThingsboardException { |
583 | - EntityId entityId = EntityIdFactory.getByTypeAndId(entityType, entityIdStr); | ||
584 | - return deleteAttributes(entityId, scope, keysStr); | 640 | + try { |
641 | + EntityId entityId = EntityIdFactory.getByTypeAndId(entityType, entityIdStr); | ||
642 | + return deleteAttributes(entityId, scope, keysStr); | ||
643 | + } catch (Exception e) { | ||
644 | + throw handleException(e); | ||
645 | + } | ||
585 | } | 646 | } |
586 | 647 | ||
587 | private DeferredResult<ResponseEntity> deleteAttributes(EntityId entityIdSrc, String scope, String keysStr) throws ThingsboardException { | 648 | private DeferredResult<ResponseEntity> deleteAttributes(EntityId entityIdSrc, String scope, String keysStr) throws ThingsboardException { |
@@ -627,6 +688,7 @@ public class TelemetryController extends BaseController { | @@ -627,6 +688,7 @@ public class TelemetryController extends BaseController { | ||
627 | } | 688 | } |
628 | if (json.isObject()) { | 689 | if (json.isObject()) { |
629 | List<AttributeKvEntry> attributes = extractRequestAttributes(json); | 690 | List<AttributeKvEntry> attributes = extractRequestAttributes(json); |
691 | + attributes.forEach(ConstraintValidator::validateFields); | ||
630 | if (attributes.isEmpty()) { | 692 | if (attributes.isEmpty()) { |
631 | return getImmediateDeferredResult("No attributes data found in request body!", HttpStatus.BAD_REQUEST); | 693 | return getImmediateDeferredResult("No attributes data found in request body!", HttpStatus.BAD_REQUEST); |
632 | } | 694 | } |
@@ -100,6 +100,20 @@ public abstract class BaseAssetControllerTest extends AbstractControllerTest { | @@ -100,6 +100,20 @@ public abstract class BaseAssetControllerTest extends AbstractControllerTest { | ||
100 | } | 100 | } |
101 | 101 | ||
102 | @Test | 102 | @Test |
103 | + public void testSaveAssetWithViolationOfLengthValidation() throws Exception { | ||
104 | + Asset asset = new Asset(); | ||
105 | + asset.setName(RandomStringUtils.randomAlphabetic(300)); | ||
106 | + asset.setType("default"); | ||
107 | + doPost("/api/asset", asset).andExpect(statusReason(containsString("length of name must be equal or less than 255"))); | ||
108 | + asset.setName("Normal name"); | ||
109 | + asset.setType(RandomStringUtils.randomAlphabetic(300)); | ||
110 | + doPost("/api/asset", asset).andExpect(statusReason(containsString("length of type must be equal or less than 255"))); | ||
111 | + asset.setType("default"); | ||
112 | + asset.setLabel(RandomStringUtils.randomAlphabetic(300)); | ||
113 | + doPost("/api/asset", asset).andExpect(statusReason(containsString("length of label must be equal or less than 255"))); | ||
114 | + } | ||
115 | + | ||
116 | + @Test | ||
103 | public void testUpdateAssetFromDifferentTenant() throws Exception { | 117 | public void testUpdateAssetFromDifferentTenant() throws Exception { |
104 | Asset asset = new Asset(); | 118 | Asset asset = new Asset(); |
105 | asset.setName("My asset"); | 119 | asset.setName("My asset"); |
@@ -91,6 +91,28 @@ public abstract class BaseCustomerControllerTest extends AbstractControllerTest | @@ -91,6 +91,28 @@ public abstract class BaseCustomerControllerTest extends AbstractControllerTest | ||
91 | } | 91 | } |
92 | 92 | ||
93 | @Test | 93 | @Test |
94 | + public void testSaveCustomerWithViolationOfValidation() throws Exception { | ||
95 | + Customer customer = new Customer(); | ||
96 | + customer.setTitle(RandomStringUtils.randomAlphabetic(300)); | ||
97 | + doPost("/api/customer", customer).andExpect(statusReason(containsString("length of title must be equal or less than 255"))); | ||
98 | + customer.setTitle("Normal title"); | ||
99 | + customer.setCity(RandomStringUtils.randomAlphabetic(300)); | ||
100 | + doPost("/api/customer", customer).andExpect(statusReason(containsString("length of city must be equal or less than 255"))); | ||
101 | + customer.setCity("Normal city"); | ||
102 | + customer.setCountry(RandomStringUtils.randomAlphabetic(300)); | ||
103 | + doPost("/api/customer", customer).andExpect(statusReason(containsString("length of country must be equal or less than 255"))); | ||
104 | + customer.setCountry("Ukraine"); | ||
105 | + customer.setPhone(RandomStringUtils.randomAlphabetic(300)); | ||
106 | + doPost("/api/customer", customer).andExpect(statusReason(containsString("length of phone must be equal or less than 255"))); | ||
107 | + customer.setPhone("+3892555554512"); | ||
108 | + customer.setState(RandomStringUtils.randomAlphabetic(300)); | ||
109 | + doPost("/api/customer", customer).andExpect(statusReason(containsString("length of state must be equal or less than 255"))); | ||
110 | + customer.setState("Normal state"); | ||
111 | + customer.setZip(RandomStringUtils.randomAlphabetic(300)); | ||
112 | + doPost("/api/customer", customer).andExpect(statusReason(containsString("length of zip or postal code must be equal or less than 255"))); | ||
113 | + } | ||
114 | + | ||
115 | + @Test | ||
94 | public void testUpdateCustomerFromDifferentTenant() throws Exception { | 116 | public void testUpdateCustomerFromDifferentTenant() throws Exception { |
95 | Customer customer = new Customer(); | 117 | Customer customer = new Customer(); |
96 | customer.setTitle("My customer"); | 118 | customer.setTitle("My customer"); |
@@ -94,6 +94,13 @@ public abstract class BaseDashboardControllerTest extends AbstractControllerTest | @@ -94,6 +94,13 @@ public abstract class BaseDashboardControllerTest extends AbstractControllerTest | ||
94 | } | 94 | } |
95 | 95 | ||
96 | @Test | 96 | @Test |
97 | + public void testSaveDashboardInfoWithViolationOfValidation() throws Exception { | ||
98 | + Dashboard dashboard = new Dashboard(); | ||
99 | + dashboard.setTitle(RandomStringUtils.randomAlphabetic(300)); | ||
100 | + doPost("/api/dashboard", dashboard).andExpect(statusReason(containsString("length of title must be equal or less than 255"))); | ||
101 | + } | ||
102 | + | ||
103 | + @Test | ||
97 | public void testUpdateDashboardFromDifferentTenant() throws Exception { | 104 | public void testUpdateDashboardFromDifferentTenant() throws Exception { |
98 | Dashboard dashboard = new Dashboard(); | 105 | Dashboard dashboard = new Dashboard(); |
99 | dashboard.setTitle("My dashboard"); | 106 | dashboard.setTitle("My dashboard"); |
@@ -115,6 +115,20 @@ public abstract class BaseDeviceControllerTest extends AbstractControllerTest { | @@ -115,6 +115,20 @@ public abstract class BaseDeviceControllerTest extends AbstractControllerTest { | ||
115 | } | 115 | } |
116 | 116 | ||
117 | @Test | 117 | @Test |
118 | + public void saveDeviceWithViolationOfValidation() throws Exception { | ||
119 | + Device device = new Device(); | ||
120 | + device.setName(RandomStringUtils.randomAlphabetic(300)); | ||
121 | + device.setType("default"); | ||
122 | + doPost("/api/device", device).andExpect(statusReason(containsString("length of name must be equal or less than 255"))); | ||
123 | + device.setName("Normal Name"); | ||
124 | + device.setType(RandomStringUtils.randomAlphabetic(300)); | ||
125 | + doPost("/api/device", device).andExpect(statusReason(containsString("length of type must be equal or less than 255"))); | ||
126 | + device.setType("Normal type"); | ||
127 | + device.setLabel(RandomStringUtils.randomAlphabetic(300)); | ||
128 | + doPost("/api/device", device).andExpect(statusReason(containsString("length of label must be equal or less than 255"))); | ||
129 | + } | ||
130 | + | ||
131 | + @Test | ||
118 | public void testUpdateDeviceFromDifferentTenant() throws Exception { | 132 | public void testUpdateDeviceFromDifferentTenant() throws Exception { |
119 | Device device = new Device(); | 133 | Device device = new Device(); |
120 | device.setName("My device"); | 134 | device.setName("My device"); |
@@ -22,6 +22,7 @@ import com.google.protobuf.DynamicMessage; | @@ -22,6 +22,7 @@ import com.google.protobuf.DynamicMessage; | ||
22 | import com.google.protobuf.InvalidProtocolBufferException; | 22 | import com.google.protobuf.InvalidProtocolBufferException; |
23 | import com.google.protobuf.util.JsonFormat; | 23 | import com.google.protobuf.util.JsonFormat; |
24 | import com.squareup.wire.schema.internal.parser.ProtoFileElement; | 24 | import com.squareup.wire.schema.internal.parser.ProtoFileElement; |
25 | +import org.apache.commons.lang3.RandomStringUtils; | ||
25 | import org.junit.After; | 26 | import org.junit.After; |
26 | import org.junit.Assert; | 27 | import org.junit.Assert; |
27 | import org.junit.Before; | 28 | import org.junit.Before; |
@@ -110,6 +111,12 @@ public abstract class BaseDeviceProfileControllerTest extends AbstractController | @@ -110,6 +111,12 @@ public abstract class BaseDeviceProfileControllerTest extends AbstractController | ||
110 | } | 111 | } |
111 | 112 | ||
112 | @Test | 113 | @Test |
114 | + public void saveDeviceProfileWithViolationOfValidation() throws Exception { | ||
115 | + doPost("/api/deviceProfile", this.createDeviceProfile(RandomStringUtils.randomAlphabetic(300), null)) | ||
116 | + .andExpect(statusReason(containsString("length of name must be equal or less than 255"))); | ||
117 | + } | ||
118 | + | ||
119 | + @Test | ||
113 | public void testFindDeviceProfileById() throws Exception { | 120 | public void testFindDeviceProfileById() throws Exception { |
114 | DeviceProfile deviceProfile = this.createDeviceProfile("Device Profile", null); | 121 | DeviceProfile deviceProfile = this.createDeviceProfile("Device Profile", null); |
115 | DeviceProfile savedDeviceProfile = doPost("/api/deviceProfile", deviceProfile, DeviceProfile.class); | 122 | DeviceProfile savedDeviceProfile = doPost("/api/deviceProfile", deviceProfile, DeviceProfile.class); |
@@ -48,6 +48,7 @@ import org.thingsboard.server.gen.edge.v1.UserUpdateMsg; | @@ -48,6 +48,7 @@ import org.thingsboard.server.gen.edge.v1.UserUpdateMsg; | ||
48 | import java.util.ArrayList; | 48 | import java.util.ArrayList; |
49 | import java.util.Collections; | 49 | import java.util.Collections; |
50 | import java.util.List; | 50 | import java.util.List; |
51 | +import java.util.Random; | ||
51 | 52 | ||
52 | import static org.hamcrest.Matchers.containsString; | 53 | import static org.hamcrest.Matchers.containsString; |
53 | import static org.hamcrest.Matchers.nullValue; | 54 | import static org.hamcrest.Matchers.nullValue; |
@@ -113,6 +114,18 @@ public abstract class BaseEdgeControllerTest extends AbstractControllerTest { | @@ -113,6 +114,18 @@ public abstract class BaseEdgeControllerTest extends AbstractControllerTest { | ||
113 | } | 114 | } |
114 | 115 | ||
115 | @Test | 116 | @Test |
117 | + public void testSaveEdgeWithViolationOfLengthValidation() throws Exception { | ||
118 | + Edge edge = constructEdge(RandomStringUtils.randomAlphabetic(300), "default"); | ||
119 | + doPost("/api/edge", edge).andExpect(statusReason(containsString("length of name must be equal or less than 255"))); | ||
120 | + edge.setName("normal name"); | ||
121 | + edge.setType(RandomStringUtils.randomAlphabetic(300)); | ||
122 | + doPost("/api/edge", edge).andExpect(statusReason(containsString("length of type must be equal or less than 255"))); | ||
123 | + edge.setType("normal type"); | ||
124 | + edge.setLabel(RandomStringUtils.randomAlphabetic(300)); | ||
125 | + doPost("/api/edge", edge).andExpect(statusReason(containsString("length of label must be equal or less than 255"))); | ||
126 | + } | ||
127 | + | ||
128 | + @Test | ||
116 | public void testFindEdgeById() throws Exception { | 129 | public void testFindEdgeById() throws Exception { |
117 | Edge edge = constructEdge("My edge", "default"); | 130 | Edge edge = constructEdge("My edge", "default"); |
118 | Edge savedEdge = doPost("/api/edge", edge, Edge.class); | 131 | Edge savedEdge = doPost("/api/edge", edge, Edge.class); |
@@ -133,6 +133,14 @@ public abstract class BaseEntityViewControllerTest extends AbstractControllerTes | @@ -133,6 +133,14 @@ public abstract class BaseEntityViewControllerTest extends AbstractControllerTes | ||
133 | assertEquals(foundEntityView.getKeys(), telemetry); | 133 | assertEquals(foundEntityView.getKeys(), telemetry); |
134 | } | 134 | } |
135 | 135 | ||
136 | + @Test | ||
137 | + public void testSaveEntityViewWithViolationOfValidation() throws Exception { | ||
138 | + EntityView entityView = createEntityView(RandomStringUtils.randomAlphabetic(300), 0, 0); | ||
139 | + doPost("/api/entityView", entityView).andExpect(statusReason(containsString("length of name must be equal or less than 255"))); | ||
140 | + entityView.setName("Normal name"); | ||
141 | + entityView.setType(RandomStringUtils.randomAlphabetic(300)); | ||
142 | + doPost("/api/entityView", entityView).andExpect(statusReason(containsString("length of type must be equal or less than 255"))); | ||
143 | + } | ||
136 | 144 | ||
137 | @Test | 145 | @Test |
138 | public void testUpdateEntityViewFromDifferentTenant() throws Exception { | 146 | public void testUpdateEntityViewFromDifferentTenant() throws Exception { |
@@ -16,6 +16,7 @@ | @@ -16,6 +16,7 @@ | ||
16 | package org.thingsboard.server.controller; | 16 | package org.thingsboard.server.controller; |
17 | 17 | ||
18 | import com.fasterxml.jackson.core.type.TypeReference; | 18 | import com.fasterxml.jackson.core.type.TypeReference; |
19 | +import org.apache.commons.lang3.RandomStringUtils; | ||
19 | import org.junit.After; | 20 | import org.junit.After; |
20 | import org.junit.Assert; | 21 | import org.junit.Assert; |
21 | import org.junit.Before; | 22 | import org.junit.Before; |
@@ -40,6 +41,7 @@ import java.util.ArrayList; | @@ -40,6 +41,7 @@ import java.util.ArrayList; | ||
40 | import java.util.Collections; | 41 | import java.util.Collections; |
41 | import java.util.List; | 42 | import java.util.List; |
42 | 43 | ||
44 | +import static org.hamcrest.Matchers.containsString; | ||
43 | import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; | 45 | import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; |
44 | import static org.thingsboard.server.common.data.ota.OtaPackageType.FIRMWARE; | 46 | import static org.thingsboard.server.common.data.ota.OtaPackageType.FIRMWARE; |
45 | 47 | ||
@@ -118,6 +120,24 @@ public abstract class BaseOtaPackageControllerTest extends AbstractControllerTes | @@ -118,6 +120,24 @@ public abstract class BaseOtaPackageControllerTest extends AbstractControllerTes | ||
118 | } | 120 | } |
119 | 121 | ||
120 | @Test | 122 | @Test |
123 | + public void saveOtaPackageInfoWithViolationOfLengthValidation() throws Exception { | ||
124 | + SaveOtaPackageInfoRequest firmwareInfo = new SaveOtaPackageInfoRequest(); | ||
125 | + firmwareInfo.setDeviceProfileId(deviceProfileId); | ||
126 | + firmwareInfo.setType(FIRMWARE); | ||
127 | + firmwareInfo.setTitle(RandomStringUtils.randomAlphabetic(300)); | ||
128 | + firmwareInfo.setVersion(VERSION); | ||
129 | + firmwareInfo.setUsesUrl(false); | ||
130 | + doPost("/api/otaPackage", firmwareInfo).andExpect(statusReason(containsString("length of title must be equal or less than 255"))); | ||
131 | + firmwareInfo.setTitle(TITLE); | ||
132 | + firmwareInfo.setVersion(RandomStringUtils.randomAlphabetic(300)); | ||
133 | + doPost("/api/otaPackage", firmwareInfo).andExpect(statusReason(containsString("length of version must be equal or less than 255"))); | ||
134 | + firmwareInfo.setVersion(VERSION); | ||
135 | + firmwareInfo.setUsesUrl(true); | ||
136 | + firmwareInfo.setUrl(RandomStringUtils.randomAlphabetic(300)); | ||
137 | + doPost("/api/otaPackage", firmwareInfo).andExpect(statusReason(containsString("length of url must be equal or less than 255"))); | ||
138 | + } | ||
139 | + | ||
140 | + @Test | ||
121 | public void testSaveFirmwareData() throws Exception { | 141 | public void testSaveFirmwareData() throws Exception { |
122 | SaveOtaPackageInfoRequest firmwareInfo = new SaveOtaPackageInfoRequest(); | 142 | SaveOtaPackageInfoRequest firmwareInfo = new SaveOtaPackageInfoRequest(); |
123 | firmwareInfo.setDeviceProfileId(deviceProfileId); | 143 | firmwareInfo.setDeviceProfileId(deviceProfileId); |
@@ -16,6 +16,7 @@ | @@ -16,6 +16,7 @@ | ||
16 | package org.thingsboard.server.controller; | 16 | package org.thingsboard.server.controller; |
17 | 17 | ||
18 | import com.fasterxml.jackson.core.type.TypeReference; | 18 | import com.fasterxml.jackson.core.type.TypeReference; |
19 | +import org.apache.commons.lang3.RandomStringUtils; | ||
19 | import org.junit.After; | 20 | import org.junit.After; |
20 | import org.junit.Assert; | 21 | import org.junit.Assert; |
21 | import org.junit.Before; | 22 | import org.junit.Before; |
@@ -33,6 +34,7 @@ import java.util.ArrayList; | @@ -33,6 +34,7 @@ import java.util.ArrayList; | ||
33 | import java.util.Collections; | 34 | import java.util.Collections; |
34 | import java.util.List; | 35 | import java.util.List; |
35 | 36 | ||
37 | +import static org.hamcrest.Matchers.containsString; | ||
36 | import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; | 38 | import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; |
37 | 39 | ||
38 | public abstract class BaseRuleChainControllerTest extends AbstractControllerTest { | 40 | public abstract class BaseRuleChainControllerTest extends AbstractControllerTest { |
@@ -85,6 +87,13 @@ public abstract class BaseRuleChainControllerTest extends AbstractControllerTest | @@ -85,6 +87,13 @@ public abstract class BaseRuleChainControllerTest extends AbstractControllerTest | ||
85 | } | 87 | } |
86 | 88 | ||
87 | @Test | 89 | @Test |
90 | + public void testSaveRuleChainWithViolationOfLengthValidation() throws Exception { | ||
91 | + RuleChain ruleChain = new RuleChain(); | ||
92 | + ruleChain.setName(RandomStringUtils.randomAlphabetic(300)); | ||
93 | + doPost("/api/ruleChain", ruleChain).andExpect(statusReason(containsString("length of name must be equal or less than 255"))); | ||
94 | + } | ||
95 | + | ||
96 | + @Test | ||
88 | public void testFindRuleChainById() throws Exception { | 97 | public void testFindRuleChainById() throws Exception { |
89 | RuleChain ruleChain = new RuleChain(); | 98 | RuleChain ruleChain = new RuleChain(); |
90 | ruleChain.setName("RuleChain"); | 99 | ruleChain.setName("RuleChain"); |
@@ -16,6 +16,7 @@ | @@ -16,6 +16,7 @@ | ||
16 | package org.thingsboard.server.controller; | 16 | package org.thingsboard.server.controller; |
17 | 17 | ||
18 | import com.fasterxml.jackson.core.type.TypeReference; | 18 | import com.fasterxml.jackson.core.type.TypeReference; |
19 | +import org.apache.commons.lang3.RandomStringUtils; | ||
19 | import org.junit.After; | 20 | import org.junit.After; |
20 | import org.junit.Assert; | 21 | import org.junit.Assert; |
21 | import org.junit.Before; | 22 | import org.junit.Before; |
@@ -33,6 +34,7 @@ import java.util.ArrayList; | @@ -33,6 +34,7 @@ import java.util.ArrayList; | ||
33 | import java.util.Collections; | 34 | import java.util.Collections; |
34 | import java.util.List; | 35 | import java.util.List; |
35 | 36 | ||
37 | +import static org.hamcrest.Matchers.containsString; | ||
36 | import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; | 38 | import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; |
37 | 39 | ||
38 | public abstract class BaseTbResourceControllerTest extends AbstractControllerTest { | 40 | public abstract class BaseTbResourceControllerTest extends AbstractControllerTest { |
@@ -99,6 +101,16 @@ public abstract class BaseTbResourceControllerTest extends AbstractControllerTes | @@ -99,6 +101,16 @@ public abstract class BaseTbResourceControllerTest extends AbstractControllerTes | ||
99 | } | 101 | } |
100 | 102 | ||
101 | @Test | 103 | @Test |
104 | + public void saveResourceInfoWithViolationOfLengthValidation() throws Exception { | ||
105 | + TbResource resource = new TbResource(); | ||
106 | + resource.setResourceType(ResourceType.JKS); | ||
107 | + resource.setTitle(RandomStringUtils.randomAlphabetic(300)); | ||
108 | + resource.setFileName(DEFAULT_FILE_NAME); | ||
109 | + resource.setData("Test Data"); | ||
110 | + doPost("/api/resource", resource).andExpect(statusReason(containsString("length of title must be equal or less than 255"))); | ||
111 | + } | ||
112 | + | ||
113 | + @Test | ||
102 | public void testUpdateTbResourceFromDifferentTenant() throws Exception { | 114 | public void testUpdateTbResourceFromDifferentTenant() throws Exception { |
103 | TbResource resource = new TbResource(); | 115 | TbResource resource = new TbResource(); |
104 | resource.setResourceType(ResourceType.JKS); | 116 | resource.setResourceType(ResourceType.JKS); |
@@ -52,6 +52,14 @@ public abstract class BaseTenantControllerTest extends AbstractControllerTest { | @@ -52,6 +52,14 @@ public abstract class BaseTenantControllerTest extends AbstractControllerTest { | ||
52 | doDelete("/api/tenant/"+savedTenant.getId().getId().toString()) | 52 | doDelete("/api/tenant/"+savedTenant.getId().getId().toString()) |
53 | .andExpect(status().isOk()); | 53 | .andExpect(status().isOk()); |
54 | } | 54 | } |
55 | + | ||
56 | + @Test | ||
57 | + public void testSaveTenantWithViolationOfValidation() throws Exception { | ||
58 | + loginSysAdmin(); | ||
59 | + Tenant tenant = new Tenant(); | ||
60 | + tenant.setTitle(RandomStringUtils.randomAlphanumeric(300)); | ||
61 | + doPost("/api/tenant", tenant).andExpect(statusReason(containsString("length of title must be equal or less than 255"))); | ||
62 | + } | ||
55 | 63 | ||
56 | @Test | 64 | @Test |
57 | public void testFindTenantById() throws Exception { | 65 | public void testFindTenantById() throws Exception { |
@@ -16,6 +16,7 @@ | @@ -16,6 +16,7 @@ | ||
16 | package org.thingsboard.server.controller; | 16 | package org.thingsboard.server.controller; |
17 | 17 | ||
18 | import com.fasterxml.jackson.core.type.TypeReference; | 18 | import com.fasterxml.jackson.core.type.TypeReference; |
19 | +import org.apache.commons.lang3.RandomStringUtils; | ||
19 | import org.junit.After; | 20 | import org.junit.After; |
20 | import org.junit.Assert; | 21 | import org.junit.Assert; |
21 | import org.junit.Test; | 22 | import org.junit.Test; |
@@ -75,6 +76,13 @@ public abstract class BaseTenantProfileControllerTest extends AbstractController | @@ -75,6 +76,13 @@ public abstract class BaseTenantProfileControllerTest extends AbstractController | ||
75 | } | 76 | } |
76 | 77 | ||
77 | @Test | 78 | @Test |
79 | + public void testSaveTenantProfileWithViolationOfLengthValidation() throws Exception { | ||
80 | + loginSysAdmin(); | ||
81 | + TenantProfile tenantProfile = this.createTenantProfile(RandomStringUtils.randomAlphabetic(300)); | ||
82 | + doPost("/api/tenantProfile", tenantProfile).andExpect(statusReason(containsString("length of name must be equal or less than 255"))); | ||
83 | + } | ||
84 | + | ||
85 | + @Test | ||
78 | public void testFindTenantProfileById() throws Exception { | 86 | public void testFindTenantProfileById() throws Exception { |
79 | loginSysAdmin(); | 87 | loginSysAdmin(); |
80 | TenantProfile tenantProfile = this.createTenantProfile("Tenant Profile"); | 88 | TenantProfile tenantProfile = this.createTenantProfile("Tenant Profile"); |
@@ -106,6 +106,28 @@ public abstract class BaseUserControllerTest extends AbstractControllerTest { | @@ -106,6 +106,28 @@ public abstract class BaseUserControllerTest extends AbstractControllerTest { | ||
106 | } | 106 | } |
107 | 107 | ||
108 | @Test | 108 | @Test |
109 | + public void testSaveUserWithViolationOfFiledValidation() throws Exception { | ||
110 | + loginSysAdmin(); | ||
111 | + | ||
112 | + Tenant tenant = new Tenant(); | ||
113 | + tenant.setTitle("My tenant"); | ||
114 | + Tenant savedTenant = doPost("/api/tenant", tenant, Tenant.class); | ||
115 | + Assert.assertNotNull(savedTenant); | ||
116 | + | ||
117 | + String email = "tenant2@thingsboard.org"; | ||
118 | + User user = new User(); | ||
119 | + user.setAuthority(Authority.TENANT_ADMIN); | ||
120 | + user.setTenantId(savedTenant.getId()); | ||
121 | + user.setEmail(email); | ||
122 | + user.setFirstName(RandomStringUtils.randomAlphabetic(300)); | ||
123 | + user.setLastName("Downs"); | ||
124 | + doPost("/api/user", user).andExpect(statusReason(containsString("Validation error: length of first name must be equal or less than 255"))); | ||
125 | + user.setFirstName("Normal name"); | ||
126 | + user.setLastName(RandomStringUtils.randomAlphabetic(300)); | ||
127 | + doPost("/api/user", user).andExpect(statusReason(containsString("length of last name must be equal or less than 255"))); | ||
128 | + } | ||
129 | + | ||
130 | + @Test | ||
109 | public void testUpdateUserFromDifferentTenant() throws Exception { | 131 | public void testUpdateUserFromDifferentTenant() throws Exception { |
110 | loginSysAdmin(); | 132 | loginSysAdmin(); |
111 | Tenant tenant = new Tenant(); | 133 | Tenant tenant = new Tenant(); |
@@ -16,6 +16,7 @@ | @@ -16,6 +16,7 @@ | ||
16 | package org.thingsboard.server.controller; | 16 | package org.thingsboard.server.controller; |
17 | 17 | ||
18 | import com.fasterxml.jackson.core.type.TypeReference; | 18 | import com.fasterxml.jackson.core.type.TypeReference; |
19 | +import org.apache.commons.lang3.RandomStringUtils; | ||
19 | import org.junit.After; | 20 | import org.junit.After; |
20 | import org.junit.Assert; | 21 | import org.junit.Assert; |
21 | import org.junit.Before; | 22 | import org.junit.Before; |
@@ -88,6 +89,13 @@ public abstract class BaseWidgetsBundleControllerTest extends AbstractController | @@ -88,6 +89,13 @@ public abstract class BaseWidgetsBundleControllerTest extends AbstractController | ||
88 | Assert.assertEquals(foundWidgetsBundle.getTitle(), savedWidgetsBundle.getTitle()); | 89 | Assert.assertEquals(foundWidgetsBundle.getTitle(), savedWidgetsBundle.getTitle()); |
89 | } | 90 | } |
90 | 91 | ||
92 | + @Test | ||
93 | + public void testSaveWidgetBundleWithViolationOfLengthValidation() throws Exception { | ||
94 | + WidgetsBundle widgetsBundle = new WidgetsBundle(); | ||
95 | + widgetsBundle.setTitle(RandomStringUtils.randomAlphabetic(300)); | ||
96 | + doPost("/api/widgetsBundle", widgetsBundle).andExpect(statusReason(containsString("length of title must be equal or less than 255"))); | ||
97 | + } | ||
98 | + | ||
91 | @Test | 99 | @Test |
92 | public void testUpdateWidgetsBundleFromDifferentTenant() throws Exception { | 100 | public void testUpdateWidgetsBundleFromDifferentTenant() throws Exception { |
93 | WidgetsBundle widgetsBundle = new WidgetsBundle(); | 101 | WidgetsBundle widgetsBundle = new WidgetsBundle(); |
@@ -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(); |
@@ -22,13 +22,15 @@ import com.fasterxml.jackson.databind.JsonNode; | @@ -22,13 +22,15 @@ import com.fasterxml.jackson.databind.JsonNode; | ||
22 | import io.swagger.annotations.ApiModelProperty; | 22 | import io.swagger.annotations.ApiModelProperty; |
23 | import org.thingsboard.server.common.data.id.CustomerId; | 23 | import org.thingsboard.server.common.data.id.CustomerId; |
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.validation.Length; | ||
25 | import org.thingsboard.server.common.data.validation.NoXss; | 26 | import org.thingsboard.server.common.data.validation.NoXss; |
26 | 27 | ||
27 | public class Customer extends ContactBased<CustomerId> implements HasTenantId { | 28 | public class Customer extends ContactBased<CustomerId> implements HasTenantId { |
28 | - | 29 | + |
29 | private static final long serialVersionUID = -1599722990298929275L; | 30 | private static final long serialVersionUID = -1599722990298929275L; |
30 | 31 | ||
31 | @NoXss | 32 | @NoXss |
33 | + @Length(fieldName = "title") | ||
32 | @ApiModelProperty(position = 3, value = "Title of the customer", example = "Company A") | 34 | @ApiModelProperty(position = 3, value = "Title of the customer", example = "Company A") |
33 | private String title; | 35 | private String title; |
34 | @ApiModelProperty(position = 5, required = true, value = "JSON object with Tenant Id") | 36 | @ApiModelProperty(position = 5, required = true, value = "JSON object with Tenant Id") |
@@ -41,7 +43,7 @@ public class Customer extends ContactBased<CustomerId> implements HasTenantId { | @@ -41,7 +43,7 @@ public class Customer extends ContactBased<CustomerId> implements HasTenantId { | ||
41 | public Customer(CustomerId id) { | 43 | public Customer(CustomerId id) { |
42 | super(id); | 44 | super(id); |
43 | } | 45 | } |
44 | - | 46 | + |
45 | public Customer(Customer customer) { | 47 | public Customer(Customer customer) { |
46 | super(customer); | 48 | super(customer); |
47 | this.tenantId = customer.getTenantId(); | 49 | this.tenantId = customer.getTenantId(); |
@@ -21,6 +21,7 @@ import io.swagger.annotations.ApiModelProperty; | @@ -21,6 +21,7 @@ import io.swagger.annotations.ApiModelProperty; | ||
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.DashboardId; | 22 | import org.thingsboard.server.common.data.id.DashboardId; |
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 | import javax.validation.Valid; | 27 | import javax.validation.Valid; |
@@ -32,6 +33,7 @@ public class DashboardInfo extends SearchTextBased<DashboardId> implements HasNa | @@ -32,6 +33,7 @@ public class DashboardInfo extends SearchTextBased<DashboardId> implements HasNa | ||
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 String image; | 38 | private String image; |
37 | @Valid | 39 | @Valid |
@@ -28,6 +28,7 @@ import org.thingsboard.server.common.data.id.DeviceId; | @@ -28,6 +28,7 @@ import org.thingsboard.server.common.data.id.DeviceId; | ||
28 | import org.thingsboard.server.common.data.id.DeviceProfileId; | 28 | import org.thingsboard.server.common.data.id.DeviceProfileId; |
29 | import org.thingsboard.server.common.data.id.OtaPackageId; | 29 | import org.thingsboard.server.common.data.id.OtaPackageId; |
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 | import org.thingsboard.server.common.data.validation.NoXss; | 32 | import org.thingsboard.server.common.data.validation.NoXss; |
32 | 33 | ||
33 | import java.io.ByteArrayInputStream; | 34 | import java.io.ByteArrayInputStream; |
@@ -44,10 +45,13 @@ public class Device extends SearchTextBasedWithAdditionalInfo<DeviceId> implemen | @@ -44,10 +45,13 @@ public class Device extends SearchTextBasedWithAdditionalInfo<DeviceId> implemen | ||
44 | private TenantId tenantId; | 45 | private TenantId tenantId; |
45 | private CustomerId customerId; | 46 | private CustomerId customerId; |
46 | @NoXss | 47 | @NoXss |
48 | + @Length(fieldName = "name") | ||
47 | private String name; | 49 | private String name; |
48 | @NoXss | 50 | @NoXss |
51 | + @Length(fieldName = "type") | ||
49 | private String type; | 52 | private String type; |
50 | @NoXss | 53 | @NoXss |
54 | + @Length(fieldName = "label") | ||
51 | private String label; | 55 | private String label; |
52 | private DeviceProfileId deviceProfileId; | 56 | private DeviceProfileId deviceProfileId; |
53 | private transient DeviceData deviceData; | 57 | private transient DeviceData deviceData; |
@@ -28,6 +28,7 @@ import org.thingsboard.server.common.data.id.DeviceProfileId; | @@ -28,6 +28,7 @@ import org.thingsboard.server.common.data.id.DeviceProfileId; | ||
28 | import org.thingsboard.server.common.data.id.OtaPackageId; | 28 | import org.thingsboard.server.common.data.id.OtaPackageId; |
29 | import org.thingsboard.server.common.data.id.RuleChainId; | 29 | import org.thingsboard.server.common.data.id.RuleChainId; |
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 | import org.thingsboard.server.common.data.validation.NoXss; | 32 | import org.thingsboard.server.common.data.validation.NoXss; |
32 | 33 | ||
33 | import javax.validation.Valid; | 34 | import javax.validation.Valid; |
@@ -47,6 +48,7 @@ public class DeviceProfile extends SearchTextBased<DeviceProfileId> implements H | @@ -47,6 +48,7 @@ public class DeviceProfile extends SearchTextBased<DeviceProfileId> implements H | ||
47 | @ApiModelProperty(position = 3, value = "JSON object with Tenant Id that owns the profile.", readOnly = true) | 48 | @ApiModelProperty(position = 3, value = "JSON object with Tenant Id that owns the profile.", readOnly = true) |
48 | private TenantId tenantId; | 49 | private TenantId tenantId; |
49 | @NoXss | 50 | @NoXss |
51 | + @Length(fieldName = "name") | ||
50 | @ApiModelProperty(position = 4, value = "Unique Device Profile Name in scope of Tenant.", example = "Moisture Sensor") | 52 | @ApiModelProperty(position = 4, value = "Unique Device Profile Name in scope of Tenant.", example = "Moisture Sensor") |
51 | private String name; | 53 | private String name; |
52 | @NoXss | 54 | @NoXss |
@@ -25,6 +25,7 @@ import org.thingsboard.server.common.data.id.EntityId; | @@ -25,6 +25,7 @@ import org.thingsboard.server.common.data.id.EntityId; | ||
25 | import org.thingsboard.server.common.data.id.EntityViewId; | 25 | import org.thingsboard.server.common.data.id.EntityViewId; |
26 | import org.thingsboard.server.common.data.id.TenantId; | 26 | import org.thingsboard.server.common.data.id.TenantId; |
27 | import org.thingsboard.server.common.data.objects.TelemetryEntityView; | 27 | import org.thingsboard.server.common.data.objects.TelemetryEntityView; |
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 | /** | 31 | /** |
@@ -44,9 +45,11 @@ public class EntityView extends SearchTextBasedWithAdditionalInfo<EntityViewId> | @@ -44,9 +45,11 @@ public class EntityView extends SearchTextBasedWithAdditionalInfo<EntityViewId> | ||
44 | private TenantId tenantId; | 45 | private TenantId tenantId; |
45 | private CustomerId customerId; | 46 | private CustomerId customerId; |
46 | @NoXss | 47 | @NoXss |
48 | + @Length(fieldName = "name") | ||
47 | @ApiModelProperty(position = 5, required = true, value = "Entity View name", example = "A4B72CCDFF33") | 49 | @ApiModelProperty(position = 5, required = true, value = "Entity View name", example = "A4B72CCDFF33") |
48 | private String name; | 50 | private String name; |
49 | @NoXss | 51 | @NoXss |
52 | + @Length(fieldName = "type") | ||
50 | @ApiModelProperty(position = 6, required = true, value = "Device Profile Name", example = "Temperature Sensor") | 53 | @ApiModelProperty(position = 6, required = true, value = "Device Profile Name", example = "Temperature Sensor") |
51 | private String type; | 54 | private String type; |
52 | @ApiModelProperty(position = 8, required = true, value = "Set of telemetry and attribute keys to expose via Entity View.") | 55 | @ApiModelProperty(position = 8, required = true, value = "Set of telemetry and attribute keys to expose via Entity View.") |
@@ -27,6 +27,10 @@ import org.thingsboard.server.common.data.id.OtaPackageId; | @@ -27,6 +27,10 @@ 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.ota.ChecksumAlgorithm; | 28 | import org.thingsboard.server.common.data.ota.ChecksumAlgorithm; |
29 | import org.thingsboard.server.common.data.ota.OtaPackageType; | 29 | import org.thingsboard.server.common.data.ota.OtaPackageType; |
30 | +import org.thingsboard.server.common.data.validation.Length; | ||
31 | +import org.thingsboard.server.common.data.validation.NoXss; | ||
32 | +import org.thingsboard.server.common.data.ota.ChecksumAlgorithm; | ||
33 | +import org.thingsboard.server.common.data.ota.OtaPackageType; | ||
30 | 34 | ||
31 | @ApiModel | 35 | @ApiModel |
32 | @Slf4j | 36 | @Slf4j |
@@ -42,16 +46,26 @@ public class OtaPackageInfo extends SearchTextBasedWithAdditionalInfo<OtaPackage | @@ -42,16 +46,26 @@ public class OtaPackageInfo extends SearchTextBasedWithAdditionalInfo<OtaPackage | ||
42 | private DeviceProfileId deviceProfileId; | 46 | private DeviceProfileId deviceProfileId; |
43 | @ApiModelProperty(position = 5, value = "OTA Package type.", example = "FIRMWARE", readOnly = true) | 47 | @ApiModelProperty(position = 5, value = "OTA Package type.", example = "FIRMWARE", readOnly = true) |
44 | private OtaPackageType type; | 48 | private OtaPackageType type; |
49 | + @Length(fieldName = "title") | ||
50 | + @NoXss | ||
45 | @ApiModelProperty(position = 6, value = "OTA Package title.", example = "fw", readOnly = true) | 51 | @ApiModelProperty(position = 6, value = "OTA Package title.", example = "fw", readOnly = true) |
46 | private String title; | 52 | private String title; |
53 | + @Length(fieldName = "version") | ||
54 | + @NoXss | ||
47 | @ApiModelProperty(position = 7, value = "OTA Package version.", example = "1.0", readOnly = true) | 55 | @ApiModelProperty(position = 7, value = "OTA Package version.", example = "1.0", readOnly = true) |
48 | private String version; | 56 | private String version; |
57 | + @Length(fieldName = "tag") | ||
58 | + @NoXss | ||
49 | @ApiModelProperty(position = 8, value = "OTA Package tag.", example = "fw_1.0", readOnly = true) | 59 | @ApiModelProperty(position = 8, value = "OTA Package tag.", example = "fw_1.0", readOnly = true) |
50 | private String tag; | 60 | private String tag; |
61 | + @Length(fieldName = "url") | ||
62 | + @NoXss | ||
51 | @ApiModelProperty(position = 9, value = "OTA Package url.", example = "http://thingsboard.org/fw/1", readOnly = true) | 63 | @ApiModelProperty(position = 9, value = "OTA Package url.", example = "http://thingsboard.org/fw/1", readOnly = true) |
52 | private String url; | 64 | private String url; |
53 | @ApiModelProperty(position = 10, value = "Indicates OTA Package 'has data'. Field is returned from DB ('true' if data exists or url is set). If OTA Package 'has data' is 'false' we can not assign the OTA Package to the Device or Device Profile.", example = "true", readOnly = true) | 65 | @ApiModelProperty(position = 10, value = "Indicates OTA Package 'has data'. Field is returned from DB ('true' if data exists or url is set). If OTA Package 'has data' is 'false' we can not assign the OTA Package to the Device or Device Profile.", example = "true", readOnly = true) |
54 | private boolean hasData; | 66 | private boolean hasData; |
67 | + @Length(fieldName = "file name") | ||
68 | + @NoXss | ||
55 | @ApiModelProperty(position = 11, value = "OTA Package file name.", example = "fw_1.0", readOnly = true) | 69 | @ApiModelProperty(position = 11, value = "OTA Package file name.", example = "fw_1.0", readOnly = true) |
56 | private String fileName; | 70 | private String fileName; |
57 | @ApiModelProperty(position = 12, value = "OTA Package content type.", example = "APPLICATION_OCTET_STREAM", readOnly = true) | 71 | @ApiModelProperty(position = 12, value = "OTA Package content type.", example = "APPLICATION_OCTET_STREAM", readOnly = true) |
@@ -20,6 +20,7 @@ import lombok.Data; | @@ -20,6 +20,7 @@ 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.id.TbResourceId; | 22 | import org.thingsboard.server.common.data.id.TbResourceId; |
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 | @Slf4j | 26 | @Slf4j |
@@ -30,6 +31,7 @@ public class TbResource extends TbResourceInfo { | @@ -30,6 +31,7 @@ public class TbResource extends TbResourceInfo { | ||
30 | private static final long serialVersionUID = 7379609705527272306L; | 31 | private static final long serialVersionUID = 7379609705527272306L; |
31 | 32 | ||
32 | @NoXss | 33 | @NoXss |
34 | + @Length(fieldName = "file name") | ||
33 | @ApiModelProperty(position = 8, value = "Resource file name.", example = "19.xml", readOnly = true) | 35 | @ApiModelProperty(position = 8, value = "Resource file name.", example = "19.xml", readOnly = true) |
34 | private String fileName; | 36 | private String fileName; |
35 | 37 |
@@ -23,6 +23,7 @@ import lombok.EqualsAndHashCode; | @@ -23,6 +23,7 @@ import lombok.EqualsAndHashCode; | ||
23 | import lombok.extern.slf4j.Slf4j; | 23 | import lombok.extern.slf4j.Slf4j; |
24 | import org.thingsboard.server.common.data.id.TbResourceId; | 24 | import org.thingsboard.server.common.data.id.TbResourceId; |
25 | import org.thingsboard.server.common.data.id.TenantId; | 25 | import org.thingsboard.server.common.data.id.TenantId; |
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 | @ApiModel | 29 | @ApiModel |
@@ -36,6 +37,7 @@ public class TbResourceInfo extends SearchTextBased<TbResourceId> implements Has | @@ -36,6 +37,7 @@ public class TbResourceInfo extends SearchTextBased<TbResourceId> implements Has | ||
36 | @ApiModelProperty(position = 3, value = "JSON object with Tenant Id. Tenant Id of the resource can't be changed.", readOnly = true) | 37 | @ApiModelProperty(position = 3, value = "JSON object with Tenant Id. Tenant Id of the resource can't be changed.", readOnly = true) |
37 | private TenantId tenantId; | 38 | private TenantId tenantId; |
38 | @NoXss | 39 | @NoXss |
40 | + @Length(fieldName = "title") | ||
39 | @ApiModelProperty(position = 4, value = "Resource title.", example = "BinaryAppDataContainer id=19 v1.0") | 41 | @ApiModelProperty(position = 4, value = "Resource title.", example = "BinaryAppDataContainer id=19 v1.0") |
40 | private String title; | 42 | private String title; |
41 | @ApiModelProperty(position = 5, value = "Resource type.", example = "LWM2M_MODEL", readOnly = true) | 43 | @ApiModelProperty(position = 5, value = "Resource type.", example = "LWM2M_MODEL", readOnly = true) |
@@ -23,6 +23,7 @@ import io.swagger.annotations.ApiModelProperty; | @@ -23,6 +23,7 @@ import io.swagger.annotations.ApiModelProperty; | ||
23 | import lombok.EqualsAndHashCode; | 23 | import lombok.EqualsAndHashCode; |
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.id.TenantProfileId; | 25 | import org.thingsboard.server.common.data.id.TenantProfileId; |
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 | @ApiModel | 29 | @ApiModel |
@@ -31,6 +32,7 @@ public class Tenant extends ContactBased<TenantId> implements HasTenantId { | @@ -31,6 +32,7 @@ public class Tenant extends ContactBased<TenantId> implements HasTenantId { | ||
31 | 32 | ||
32 | private static final long serialVersionUID = 8057243243859922101L; | 33 | private static final long serialVersionUID = 8057243243859922101L; |
33 | 34 | ||
35 | + @Length(fieldName = "title") | ||
34 | @NoXss | 36 | @NoXss |
35 | @ApiModelProperty(position = 3, value = "Title of the tenant", example = "Company A") | 37 | @ApiModelProperty(position = 3, value = "Title of the tenant", example = "Company A") |
36 | private String title; | 38 | private String title; |
@@ -48,7 +50,7 @@ public class Tenant extends ContactBased<TenantId> implements HasTenantId { | @@ -48,7 +50,7 @@ public class Tenant extends ContactBased<TenantId> implements HasTenantId { | ||
48 | public Tenant(TenantId id) { | 50 | public Tenant(TenantId id) { |
49 | super(id); | 51 | super(id); |
50 | } | 52 | } |
51 | - | 53 | + |
52 | public Tenant(Tenant tenant) { | 54 | public Tenant(Tenant tenant) { |
53 | super(tenant); | 55 | super(tenant); |
54 | this.title = tenant.getTitle(); | 56 | this.title = tenant.getTitle(); |
@@ -25,6 +25,7 @@ import lombok.extern.slf4j.Slf4j; | @@ -25,6 +25,7 @@ import lombok.extern.slf4j.Slf4j; | ||
25 | import org.thingsboard.server.common.data.id.TenantProfileId; | 25 | import org.thingsboard.server.common.data.id.TenantProfileId; |
26 | import org.thingsboard.server.common.data.tenant.profile.DefaultTenantProfileConfiguration; | 26 | import org.thingsboard.server.common.data.tenant.profile.DefaultTenantProfileConfiguration; |
27 | import org.thingsboard.server.common.data.tenant.profile.TenantProfileData; | 27 | import org.thingsboard.server.common.data.tenant.profile.TenantProfileData; |
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; |
@@ -42,6 +43,7 @@ public class TenantProfile extends SearchTextBased<TenantProfileId> implements H | @@ -42,6 +43,7 @@ public class TenantProfile extends SearchTextBased<TenantProfileId> implements H | ||
42 | private static final long serialVersionUID = 3021989561267192281L; | 43 | private static final long serialVersionUID = 3021989561267192281L; |
43 | 44 | ||
44 | @NoXss | 45 | @NoXss |
46 | + @Length(fieldName = "name") | ||
45 | @ApiModelProperty(position = 3, value = "Name of the tenant profile", example = "High Priority Tenants") | 47 | @ApiModelProperty(position = 3, value = "Name of the tenant profile", example = "High Priority Tenants") |
46 | private String name; | 48 | private String name; |
47 | @NoXss | 49 | @NoXss |
@@ -26,7 +26,7 @@ import org.thingsboard.server.common.data.id.EntityId; | @@ -26,7 +26,7 @@ import org.thingsboard.server.common.data.id.EntityId; | ||
26 | import org.thingsboard.server.common.data.id.TenantId; | 26 | import org.thingsboard.server.common.data.id.TenantId; |
27 | import org.thingsboard.server.common.data.id.UserId; | 27 | import org.thingsboard.server.common.data.id.UserId; |
28 | import org.thingsboard.server.common.data.security.Authority; | 28 | import org.thingsboard.server.common.data.security.Authority; |
29 | - | 29 | +import org.thingsboard.server.common.data.validation.Length; |
30 | import org.thingsboard.server.common.data.validation.NoXss; | 30 | import org.thingsboard.server.common.data.validation.NoXss; |
31 | 31 | ||
32 | @ApiModel | 32 | @ApiModel |
@@ -40,8 +40,10 @@ public class User extends SearchTextBasedWithAdditionalInfo<UserId> implements H | @@ -40,8 +40,10 @@ public class User extends SearchTextBasedWithAdditionalInfo<UserId> implements H | ||
40 | private String email; | 40 | private String email; |
41 | private Authority authority; | 41 | private Authority authority; |
42 | @NoXss | 42 | @NoXss |
43 | + @Length(fieldName = "first name") | ||
43 | private String firstName; | 44 | private String firstName; |
44 | @NoXss | 45 | @NoXss |
46 | + @Length(fieldName = "last name") | ||
45 | private String lastName; | 47 | private String lastName; |
46 | 48 | ||
47 | public User() { | 49 | public User() { |
@@ -30,6 +30,7 @@ import org.thingsboard.server.common.data.id.AlarmId; | @@ -30,6 +30,7 @@ import org.thingsboard.server.common.data.id.AlarmId; | ||
30 | import org.thingsboard.server.common.data.id.CustomerId; | 30 | import org.thingsboard.server.common.data.id.CustomerId; |
31 | import org.thingsboard.server.common.data.id.EntityId; | 31 | import org.thingsboard.server.common.data.id.EntityId; |
32 | import org.thingsboard.server.common.data.id.TenantId; | 32 | import org.thingsboard.server.common.data.id.TenantId; |
33 | +import org.thingsboard.server.common.data.validation.Length; | ||
33 | 34 | ||
34 | import java.util.List; | 35 | import java.util.List; |
35 | 36 | ||
@@ -49,6 +50,7 @@ public class Alarm extends BaseData<AlarmId> implements HasName, HasTenantId, Ha | @@ -49,6 +50,7 @@ public class Alarm extends BaseData<AlarmId> implements HasName, HasTenantId, Ha | ||
49 | private CustomerId customerId; | 50 | private CustomerId customerId; |
50 | 51 | ||
51 | @ApiModelProperty(position = 6, required = true, value = "representing type of the Alarm", example = "High Temperature Alarm") | 52 | @ApiModelProperty(position = 6, required = true, value = "representing type of the Alarm", example = "High Temperature Alarm") |
53 | + @Length(fieldName = "type") | ||
52 | private String type; | 54 | private String type; |
53 | @ApiModelProperty(position = 7, required = true, value = "JSON object with alarm originator id") | 55 | @ApiModelProperty(position = 7, required = true, value = "JSON object with alarm originator id") |
54 | private EntityId originator; | 56 | private EntityId originator; |
@@ -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.AssetId; | 26 | import org.thingsboard.server.common.data.id.AssetId; |
27 | import org.thingsboard.server.common.data.id.CustomerId; | 27 | import org.thingsboard.server.common.data.id.CustomerId; |
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 java.util.Optional; | 32 | import java.util.Optional; |
@@ -39,10 +40,13 @@ public class Asset extends SearchTextBasedWithAdditionalInfo<AssetId> implements | @@ -39,10 +40,13 @@ public class Asset extends SearchTextBasedWithAdditionalInfo<AssetId> implements | ||
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 | 51 | ||
48 | public Asset() { | 52 | public Asset() { |
@@ -28,6 +28,7 @@ import org.thingsboard.server.common.data.id.CustomerId; | @@ -28,6 +28,7 @@ import org.thingsboard.server.common.data.id.CustomerId; | ||
28 | import org.thingsboard.server.common.data.id.EdgeId; | 28 | import org.thingsboard.server.common.data.id.EdgeId; |
29 | import org.thingsboard.server.common.data.id.RuleChainId; | 29 | import org.thingsboard.server.common.data.id.RuleChainId; |
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 | @ApiModel | 33 | @ApiModel |
33 | @EqualsAndHashCode(callSuper = true) | 34 | @EqualsAndHashCode(callSuper = true) |
@@ -40,8 +41,11 @@ public class Edge extends SearchTextBasedWithAdditionalInfo<EdgeId> implements H | @@ -40,8 +41,11 @@ public class Edge extends SearchTextBasedWithAdditionalInfo<EdgeId> implements H | ||
40 | private TenantId tenantId; | 41 | private TenantId tenantId; |
41 | private CustomerId customerId; | 42 | private CustomerId customerId; |
42 | private RuleChainId rootRuleChainId; | 43 | private RuleChainId rootRuleChainId; |
44 | + @Length(fieldName = "name") | ||
43 | private String name; | 45 | private String name; |
46 | + @Length(fieldName = "type") | ||
44 | private String type; | 47 | private String type; |
48 | + @Length(fieldName = "label") | ||
45 | private String label; | 49 | private String label; |
46 | private String routingKey; | 50 | private String routingKey; |
47 | private String secret; | 51 | 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 | /** |
@@ -27,6 +26,7 @@ public class BaseAttributeKvEntry implements AttributeKvEntry { | @@ -27,6 +26,7 @@ public class BaseAttributeKvEntry implements AttributeKvEntry { | ||
27 | private static final long serialVersionUID = -6460767583563159407L; | 26 | private static final long serialVersionUID = -6460767583563159407L; |
28 | 27 | ||
29 | private final long lastUpdateTs; | 28 | private final long lastUpdateTs; |
29 | + @Valid | ||
30 | private final KvEntry kv; | 30 | private final KvEntry kv; |
31 | 31 | ||
32 | public BaseAttributeKvEntry(KvEntry kv, long lastUpdateTs) { | 32 | 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) { |
@@ -22,6 +22,7 @@ import io.swagger.annotations.ApiModelProperty; | @@ -22,6 +22,7 @@ import io.swagger.annotations.ApiModelProperty; | ||
22 | import lombok.extern.slf4j.Slf4j; | 22 | import lombok.extern.slf4j.Slf4j; |
23 | import org.thingsboard.server.common.data.SearchTextBasedWithAdditionalInfo; | 23 | import org.thingsboard.server.common.data.SearchTextBasedWithAdditionalInfo; |
24 | import org.thingsboard.server.common.data.id.EntityId; | 24 | import org.thingsboard.server.common.data.id.EntityId; |
25 | +import org.thingsboard.server.common.data.validation.Length; | ||
25 | 26 | ||
26 | import java.io.Serializable; | 27 | import java.io.Serializable; |
27 | 28 | ||
@@ -37,6 +38,7 @@ public class EntityRelation implements Serializable { | @@ -37,6 +38,7 @@ public class EntityRelation implements Serializable { | ||
37 | 38 | ||
38 | private EntityId from; | 39 | private EntityId from; |
39 | private EntityId to; | 40 | private EntityId to; |
41 | + @Length(fieldName = "type") | ||
40 | private String type; | 42 | private String type; |
41 | private RelationTypeGroup typeGroup; | 43 | private RelationTypeGroup typeGroup; |
42 | private transient JsonNode additionalInfo; | 44 | private transient JsonNode additionalInfo; |
@@ -28,6 +28,7 @@ import org.thingsboard.server.common.data.SearchTextBasedWithAdditionalInfo; | @@ -28,6 +28,7 @@ import org.thingsboard.server.common.data.SearchTextBasedWithAdditionalInfo; | ||
28 | import org.thingsboard.server.common.data.id.RuleChainId; | 28 | import org.thingsboard.server.common.data.id.RuleChainId; |
29 | import org.thingsboard.server.common.data.id.RuleNodeId; | 29 | import org.thingsboard.server.common.data.id.RuleNodeId; |
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 | import org.thingsboard.server.common.data.validation.NoXss; | 32 | import org.thingsboard.server.common.data.validation.NoXss; |
32 | 33 | ||
33 | @ApiModel | 34 | @ApiModel |
@@ -41,6 +42,7 @@ public class RuleChain extends SearchTextBasedWithAdditionalInfo<RuleChainId> im | @@ -41,6 +42,7 @@ public class RuleChain extends SearchTextBasedWithAdditionalInfo<RuleChainId> im | ||
41 | @ApiModelProperty(position = 3, required = true, value = "JSON object with Tenant Id.", readOnly = true) | 42 | @ApiModelProperty(position = 3, required = true, value = "JSON object with Tenant Id.", readOnly = true) |
42 | private TenantId tenantId; | 43 | private TenantId tenantId; |
43 | @NoXss | 44 | @NoXss |
45 | + @Length(fieldName = "name") | ||
44 | @ApiModelProperty(position = 4, required = true, value = "Rule Chain name", example = "Humidity data processing") | 46 | @ApiModelProperty(position = 4, required = true, value = "Rule Chain name", example = "Humidity data processing") |
45 | private String name; | 47 | private String name; |
46 | @ApiModelProperty(position = 5, value = "Rule Chain type. 'EDGE' rule chains are processing messages on the edge devices only.", example = "A4B72CCDFF33") | 48 | @ApiModelProperty(position = 5, value = "Rule Chain type. 'EDGE' rule chains are processing messages on the edge devices only.", example = "A4B72CCDFF33") |
@@ -26,6 +26,7 @@ import org.thingsboard.server.common.data.HasName; | @@ -26,6 +26,7 @@ import org.thingsboard.server.common.data.HasName; | ||
26 | import org.thingsboard.server.common.data.SearchTextBasedWithAdditionalInfo; | 26 | import org.thingsboard.server.common.data.SearchTextBasedWithAdditionalInfo; |
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.RuleNodeId; | 28 | import org.thingsboard.server.common.data.id.RuleNodeId; |
29 | +import org.thingsboard.server.common.data.validation.Length; | ||
29 | 30 | ||
30 | @ApiModel | 31 | @ApiModel |
31 | @Data | 32 | @Data |
@@ -37,8 +38,10 @@ public class RuleNode extends SearchTextBasedWithAdditionalInfo<RuleNodeId> impl | @@ -37,8 +38,10 @@ public class RuleNode extends SearchTextBasedWithAdditionalInfo<RuleNodeId> impl | ||
37 | 38 | ||
38 | @ApiModelProperty(position = 3, value = "JSON object with the Rule Chain Id. ", readOnly = true) | 39 | @ApiModelProperty(position = 3, value = "JSON object with the Rule Chain Id. ", readOnly = true) |
39 | private RuleChainId ruleChainId; | 40 | private RuleChainId ruleChainId; |
41 | + @Length(fieldName = "type") | ||
40 | @ApiModelProperty(position = 4, value = "Full Java Class Name of the rule node implementation. ", example = "com.mycompany.iot.rule.engine.ProcessingNode") | 42 | @ApiModelProperty(position = 4, value = "Full Java Class Name of the rule node implementation. ", example = "com.mycompany.iot.rule.engine.ProcessingNode") |
41 | private String type; | 43 | private String type; |
44 | + @Length(fieldName = "name") | ||
42 | @ApiModelProperty(position = 5, value = "User defined name of the rule node. Used on UI and for logging. ", example = "Process sensor reading") | 45 | @ApiModelProperty(position = 5, value = "User defined name of the rule node. Used on UI and for logging. ", example = "Process sensor reading") |
43 | private String name; | 46 | private String name; |
44 | @ApiModelProperty(position = 6, value = "Enable/disable debug. ", example = "false") | 47 | @ApiModelProperty(position = 6, value = "Enable/disable debug. ", example = "false") |
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} must be equal 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 | +} |
@@ -23,10 +23,9 @@ import org.thingsboard.server.common.data.HasTenantId; | @@ -23,10 +23,9 @@ import org.thingsboard.server.common.data.HasTenantId; | ||
23 | import org.thingsboard.server.common.data.SearchTextBased; | 23 | import org.thingsboard.server.common.data.SearchTextBased; |
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.id.WidgetsBundleId; | 25 | import org.thingsboard.server.common.data.id.WidgetsBundleId; |
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.util.Arrays; | ||
29 | - | ||
30 | @ApiModel | 29 | @ApiModel |
31 | public class WidgetsBundle extends SearchTextBased<WidgetsBundleId> implements HasTenantId { | 30 | public class WidgetsBundle extends SearchTextBased<WidgetsBundleId> implements HasTenantId { |
32 | 31 | ||
@@ -38,12 +37,14 @@ public class WidgetsBundle extends SearchTextBased<WidgetsBundleId> implements H | @@ -38,12 +37,14 @@ public class WidgetsBundle extends SearchTextBased<WidgetsBundleId> implements H | ||
38 | private TenantId tenantId; | 37 | private TenantId tenantId; |
39 | 38 | ||
40 | @NoXss | 39 | @NoXss |
40 | + @Length(fieldName = "alias") | ||
41 | @Getter | 41 | @Getter |
42 | @Setter | 42 | @Setter |
43 | @ApiModelProperty(position = 4, value = "Unique alias that is used in widget types as a reference widget bundle", readOnly = true) | 43 | @ApiModelProperty(position = 4, value = "Unique alias that is used in widget types as a reference widget bundle", readOnly = true) |
44 | private String alias; | 44 | private String alias; |
45 | 45 | ||
46 | @NoXss | 46 | @NoXss |
47 | + @Length(fieldName = "title") | ||
47 | @Getter | 48 | @Getter |
48 | @Setter | 49 | @Setter |
49 | @ApiModelProperty(position = 5, value = "Title used in search and UI", readOnly = true) | 50 | @ApiModelProperty(position = 5, value = "Title used in search and UI", readOnly = true) |
@@ -55,6 +56,7 @@ public class WidgetsBundle extends SearchTextBased<WidgetsBundleId> implements H | @@ -55,6 +56,7 @@ public class WidgetsBundle extends SearchTextBased<WidgetsBundleId> implements H | ||
55 | private String image; | 56 | private String image; |
56 | 57 | ||
57 | @NoXss | 58 | @NoXss |
59 | + @Length(fieldName = "description") | ||
58 | @Getter | 60 | @Getter |
59 | @Setter | 61 | @Setter |
60 | @ApiModelProperty(position = 7, value = "Description", readOnly = true) | 62 | @ApiModelProperty(position = 7, value = "Description", readOnly = true) |
@@ -41,6 +41,7 @@ import org.thingsboard.server.common.data.relation.RelationTypeGroup; | @@ -41,6 +41,7 @@ import org.thingsboard.server.common.data.relation.RelationTypeGroup; | ||
41 | import org.thingsboard.server.common.data.relation.RelationsSearchParameters; | 41 | import org.thingsboard.server.common.data.relation.RelationsSearchParameters; |
42 | import org.thingsboard.server.dao.entity.EntityService; | 42 | import org.thingsboard.server.dao.entity.EntityService; |
43 | import org.thingsboard.server.dao.exception.DataValidationException; | 43 | import org.thingsboard.server.dao.exception.DataValidationException; |
44 | +import org.thingsboard.server.dao.service.ConstraintValidator; | ||
44 | 45 | ||
45 | import javax.annotation.Nullable; | 46 | import javax.annotation.Nullable; |
46 | import java.util.ArrayList; | 47 | import java.util.ArrayList; |
@@ -559,6 +560,7 @@ public class BaseRelationService implements RelationService { | @@ -559,6 +560,7 @@ public class BaseRelationService implements RelationService { | ||
559 | if (relation == null) { | 560 | if (relation == null) { |
560 | throw new DataValidationException("Relation type should be specified!"); | 561 | throw new DataValidationException("Relation type should be specified!"); |
561 | } | 562 | } |
563 | + ConstraintValidator.validateFields(relation); | ||
562 | validate(relation.getFrom(), relation.getTo(), relation.getType(), relation.getTypeGroup()); | 564 | validate(relation.getFrom(), relation.getTo(), relation.getType(), relation.getTypeGroup()); |
563 | } | 565 | } |
564 | 566 |
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.length() <= max; | ||
35 | + } | ||
36 | + | ||
37 | + @Override | ||
38 | + public void initialize(Length constraintAnnotation) { | ||
39 | + this.max = constraintAnnotation.max(); | ||
40 | + } | ||
41 | +} |
@@ -38,6 +38,7 @@ import org.thingsboard.server.common.data.page.PageLink; | @@ -38,6 +38,7 @@ import org.thingsboard.server.common.data.page.PageLink; | ||
38 | import org.thingsboard.server.common.data.tenant.profile.DefaultTenantProfileConfiguration; | 38 | import org.thingsboard.server.common.data.tenant.profile.DefaultTenantProfileConfiguration; |
39 | import org.thingsboard.server.dao.exception.DataValidationException; | 39 | import org.thingsboard.server.dao.exception.DataValidationException; |
40 | 40 | ||
41 | +import javax.validation.ValidationException; | ||
41 | import java.nio.ByteBuffer; | 42 | import java.nio.ByteBuffer; |
42 | import java.util.ArrayList; | 43 | import java.util.ArrayList; |
43 | import java.util.Collections; | 44 | import java.util.Collections; |
@@ -673,8 +674,8 @@ public abstract class BaseOtaPackageServiceTest extends AbstractServiceTest { | @@ -673,8 +674,8 @@ public abstract class BaseOtaPackageServiceTest extends AbstractServiceTest { | ||
673 | firmwareInfo.setUrl(URL); | 674 | firmwareInfo.setUrl(URL); |
674 | firmwareInfo.setTenantId(tenantId); | 675 | firmwareInfo.setTenantId(tenantId); |
675 | 676 | ||
676 | - thrown.expect(DataValidationException.class); | ||
677 | - thrown.expectMessage("The length of title should be equal or shorter than 255"); | 677 | + thrown.expect(ValidationException.class); |
678 | + thrown.expectMessage("length of title must be equal or less than 255"); | ||
678 | 679 | ||
679 | otaPackageService.saveOtaPackageInfo(firmwareInfo, true); | 680 | otaPackageService.saveOtaPackageInfo(firmwareInfo, true); |
680 | } | 681 | } |
@@ -689,7 +690,7 @@ public abstract class BaseOtaPackageServiceTest extends AbstractServiceTest { | @@ -689,7 +690,7 @@ public abstract class BaseOtaPackageServiceTest extends AbstractServiceTest { | ||
689 | firmwareInfo.setTitle(TITLE); | 690 | firmwareInfo.setTitle(TITLE); |
690 | 691 | ||
691 | firmwareInfo.setVersion(RandomStringUtils.random(257)); | 692 | firmwareInfo.setVersion(RandomStringUtils.random(257)); |
692 | - thrown.expectMessage("The length of version should be equal or shorter than 255"); | 693 | + thrown.expectMessage("length of version must be equal or less than 255"); |
693 | 694 | ||
694 | otaPackageService.saveOtaPackageInfo(firmwareInfo, true); | 695 | otaPackageService.saveOtaPackageInfo(firmwareInfo, true); |
695 | } | 696 | } |
@@ -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 | } |
@@ -37,15 +37,15 @@ export abstract class ContactBasedComponent<T extends ContactBased<HasId>> exten | @@ -37,15 +37,15 @@ export abstract class ContactBasedComponent<T extends ContactBased<HasId>> exten | ||
37 | 37 | ||
38 | buildForm(entity: T): FormGroup { | 38 | buildForm(entity: T): FormGroup { |
39 | const entityForm = this.buildEntityForm(entity); | 39 | const entityForm = this.buildEntityForm(entity); |
40 | - entityForm.addControl('country', this.fb.control(entity ? entity.country : '', [])); | ||
41 | - entityForm.addControl('city', this.fb.control(entity ? entity.city : '', [])); | ||
42 | - entityForm.addControl('state', this.fb.control(entity ? entity.state : '', [])); | 40 | + entityForm.addControl('country', this.fb.control(entity ? entity.country : '', [Validators.maxLength(255)])); |
41 | + entityForm.addControl('city', this.fb.control(entity ? entity.city : '', [Validators.maxLength(255)])); | ||
42 | + entityForm.addControl('state', this.fb.control(entity ? entity.state : '', [Validators.maxLength(255)])); | ||
43 | entityForm.addControl('zip', this.fb.control(entity ? entity.zip : '', | 43 | entityForm.addControl('zip', this.fb.control(entity ? entity.zip : '', |
44 | this.zipValidators(entity ? entity.country : '') | 44 | this.zipValidators(entity ? entity.country : '') |
45 | )); | 45 | )); |
46 | entityForm.addControl('address', this.fb.control(entity ? entity.address : '', [])); | 46 | entityForm.addControl('address', this.fb.control(entity ? entity.address : '', [])); |
47 | entityForm.addControl('address2', this.fb.control(entity ? entity.address2 : '', [])); | 47 | entityForm.addControl('address2', this.fb.control(entity ? entity.address2 : '', [])); |
48 | - entityForm.addControl('phone', this.fb.control(entity ? entity.phone : '', [])); | 48 | + entityForm.addControl('phone', this.fb.control(entity ? entity.phone : '', [Validators.maxLength(255)])); |
49 | entityForm.addControl('email', this.fb.control(entity ? entity.email : '', [Validators.email])); | 49 | entityForm.addControl('email', this.fb.control(entity ? entity.email : '', [Validators.email])); |
50 | return entityForm; | 50 | return entityForm; |
51 | } | 51 | } |
@@ -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" |
@@ -103,7 +103,7 @@ export class DeviceProfileComponent extends EntityComponent<DeviceProfile> { | @@ -103,7 +103,7 @@ export class DeviceProfileComponent extends EntityComponent<DeviceProfile> { | ||
103 | }; | 103 | }; |
104 | const form = this.fb.group( | 104 | const form = this.fb.group( |
105 | { | 105 | { |
106 | - name: [entity ? entity.name : '', [Validators.required]], | 106 | + name: [entity ? entity.name : '', [Validators.required, Validators.maxLength(255)]], |
107 | type: [entity ? entity.type : null, [Validators.required]], | 107 | type: [entity ? entity.type : null, [Validators.required]], |
108 | image: [entity ? entity.image : null], | 108 | image: [entity ? entity.image : null], |
109 | transportType: [entity ? entity.transportType : null, [Validators.required]], | 109 | 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"> |
@@ -59,7 +59,7 @@ export class TenantProfileComponent extends EntityComponent<TenantProfile> { | @@ -59,7 +59,7 @@ export class TenantProfileComponent extends EntityComponent<TenantProfile> { | ||
59 | buildForm(entity: TenantProfile): FormGroup { | 59 | buildForm(entity: TenantProfile): FormGroup { |
60 | return this.fb.group( | 60 | return this.fb.group( |
61 | { | 61 | { |
62 | - name: [entity ? entity.name : '', [Validators.required]], | 62 | + name: [entity ? entity.name : '', [Validators.required, Validators.maxLength(255)]], |
63 | isolatedTbCore: [entity ? entity.isolatedTbCore : false, []], | 63 | isolatedTbCore: [entity ? entity.isolatedTbCore : false, []], |
64 | isolatedTbRuleEngine: [entity ? entity.isolatedTbRuleEngine : false, []], | 64 | isolatedTbRuleEngine: [entity ? entity.isolatedTbRuleEngine : false, []], |
65 | profileData: [entity && !this.isAdd ? entity.profileData : { | 65 | 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({ |
@@ -57,16 +57,14 @@ export class ResourcesLibraryComponent extends EntityComponent<Resource> impleme | @@ -57,16 +57,14 @@ export class ResourcesLibraryComponent extends EntityComponent<Resource> impleme | ||
57 | super.ngOnInit(); | 57 | super.ngOnInit(); |
58 | this.entityForm.get('resourceType').valueChanges.pipe( | 58 | this.entityForm.get('resourceType').valueChanges.pipe( |
59 | startWith(ResourceType.LWM2M_MODEL), | 59 | startWith(ResourceType.LWM2M_MODEL), |
60 | - pairwise(), | 60 | + filter(() => this.isAdd), |
61 | takeUntil(this.destroy$) | 61 | takeUntil(this.destroy$) |
62 | - ).subscribe(([previousType, type]) => { | ||
63 | - if (previousType === this.resourceType.LWM2M_MODEL) { | ||
64 | - this.entityForm.get('title').setValidators(Validators.required); | ||
65 | - this.entityForm.get('title').updateValueAndValidity({emitEvent: false}); | ||
66 | - } | 62 | + ).subscribe((type) => { |
67 | if (type === this.resourceType.LWM2M_MODEL) { | 63 | if (type === this.resourceType.LWM2M_MODEL) { |
68 | - this.entityForm.get('title').clearValidators(); | ||
69 | - this.entityForm.get('title').updateValueAndValidity({emitEvent: false}); | 64 | + this.entityForm.get('title').disable({emitEvent: false}); |
65 | + this.entityForm.patchValue({title: ''}, {emitEvent: false}); | ||
66 | + } else { | ||
67 | + this.entityForm.get('title').enable({emitEvent: false}) | ||
70 | } | 68 | } |
71 | this.entityForm.patchValue({ | 69 | this.entityForm.patchValue({ |
72 | data: null, | 70 | data: null, |
@@ -92,11 +90,8 @@ export class ResourcesLibraryComponent extends EntityComponent<Resource> impleme | @@ -92,11 +90,8 @@ export class ResourcesLibraryComponent extends EntityComponent<Resource> impleme | ||
92 | buildForm(entity: Resource): FormGroup { | 90 | buildForm(entity: Resource): FormGroup { |
93 | const form = this.fb.group( | 91 | const form = this.fb.group( |
94 | { | 92 | { |
95 | - title: [entity ? entity.title : '', []], | ||
96 | - resourceType: [{ | ||
97 | - value: entity?.resourceType ? entity.resourceType : ResourceType.LWM2M_MODEL, | ||
98 | - disabled: !this.isAdd | ||
99 | - }, [Validators.required]], | 93 | + title: [entity ? entity.title : "", [Validators.required, Validators.maxLength(255)]], |
94 | + resourceType: [entity?.resourceType ? entity.resourceType : ResourceType.LWM2M_MODEL, [Validators.required]], | ||
100 | fileName: [entity ? entity.fileName : null, [Validators.required]], | 95 | fileName: [entity ? entity.fileName : null, [Validators.required]], |
101 | } | 96 | } |
102 | ); | 97 | ); |
@@ -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"> |
@@ -66,9 +66,9 @@ export class AssetComponent extends EntityComponent<AssetInfo> { | @@ -66,9 +66,9 @@ export class AssetComponent extends EntityComponent<AssetInfo> { | ||
66 | buildForm(entity: AssetInfo): FormGroup { | 66 | buildForm(entity: AssetInfo): FormGroup { |
67 | return this.fb.group( | 67 | return this.fb.group( |
68 | { | 68 | { |
69 | - name: [entity ? entity.name : '', [Validators.required]], | ||
70 | - type: [entity ? entity.type : null, [Validators.required]], | ||
71 | - label: [entity ? entity.label : ''], | 69 | + name: [entity ? entity.name : '', [Validators.required, Validators.maxLength(255)]], |
70 | + type: [entity ? entity.type : null, [Validators.required, Validators.maxLength(255)]], | ||
71 | + label: [entity ? entity.label : '', Validators.maxLength(255)], | ||
72 | additionalInfo: this.fb.group( | 72 | additionalInfo: this.fb.group( |
73 | { | 73 | { |
74 | description: [entity && entity.additionalInfo ? entity.additionalInfo.description : ''], | 74 | 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"> |
@@ -58,7 +58,7 @@ export class CustomerComponent extends ContactBasedComponent<Customer> { | @@ -58,7 +58,7 @@ export class CustomerComponent extends ContactBasedComponent<Customer> { | ||
58 | buildEntityForm(entity: Customer): FormGroup { | 58 | buildEntityForm(entity: Customer): FormGroup { |
59 | return this.fb.group( | 59 | return this.fb.group( |
60 | { | 60 | { |
61 | - title: [entity ? entity.title : '', [Validators.required]], | 61 | + title: [entity ? entity.title : '', [Validators.required, Validators.maxLength(255)]], |
62 | additionalInfo: this.fb.group( | 62 | additionalInfo: this.fb.group( |
63 | { | 63 | { |
64 | description: [entity && entity.additionalInfo ? entity.additionalInfo.description : ''], | 64 | 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 | <div formGroupName="configuration" fxLayout="column"> | 111 | <div formGroupName="configuration" fxLayout="column"> |
109 | <mat-form-field class="mat-block"> | 112 | <mat-form-field class="mat-block"> |
@@ -80,7 +80,7 @@ export class DashboardFormComponent extends EntityComponent<Dashboard> { | @@ -80,7 +80,7 @@ export class DashboardFormComponent extends EntityComponent<Dashboard> { | ||
80 | this.updateFields(entity); | 80 | this.updateFields(entity); |
81 | return this.fb.group( | 81 | return this.fb.group( |
82 | { | 82 | { |
83 | - title: [entity ? entity.title : '', [Validators.required]], | 83 | + title: [entity ? entity.title : '', [Validators.required, Validators.maxLength(255)]], |
84 | image: [entity ? entity.image : null], | 84 | image: [entity ? entity.image : null], |
85 | mobileHide: [entity ? entity.mobileHide : false], | 85 | mobileHide: [entity ? entity.mobileHide : false], |
86 | mobileOrder: [entity ? entity.mobileOrder : null, [Validators.pattern(/^-?[0-9]+$/)]], | 86 | mobileOrder: [entity ? entity.mobileOrder : null, [Validators.pattern(/^-?[0-9]+$/)]], |
@@ -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" |
@@ -82,11 +82,11 @@ export class DeviceComponent extends EntityComponent<DeviceInfo> { | @@ -82,11 +82,11 @@ export class DeviceComponent extends EntityComponent<DeviceInfo> { | ||
82 | buildForm(entity: DeviceInfo): FormGroup { | 82 | buildForm(entity: DeviceInfo): FormGroup { |
83 | const form = this.fb.group( | 83 | const form = this.fb.group( |
84 | { | 84 | { |
85 | - name: [entity ? entity.name : '', [Validators.required]], | 85 | + name: [entity ? entity.name : '', [Validators.required, Validators.maxLength(255)]], |
86 | deviceProfileId: [entity ? entity.deviceProfileId : null, [Validators.required]], | 86 | deviceProfileId: [entity ? entity.deviceProfileId : null, [Validators.required]], |
87 | firmwareId: [entity ? entity.firmwareId : null], | 87 | firmwareId: [entity ? entity.firmwareId : null], |
88 | softwareId: [entity ? entity.softwareId : null], | 88 | softwareId: [entity ? entity.softwareId : null], |
89 | - label: [entity ? entity.label : ''], | 89 | + label: [entity ? entity.label : '', [Validators.maxLength(255)]], |
90 | deviceData: [entity ? entity.deviceData : null, [Validators.required]], | 90 | deviceData: [entity ? entity.deviceData : null, [Validators.required]], |
91 | additionalInfo: this.fb.group( | 91 | additionalInfo: this.fb.group( |
92 | { | 92 | { |
@@ -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"> |
@@ -70,9 +70,9 @@ export class EdgeComponent extends EntityComponent<EdgeInfo> { | @@ -70,9 +70,9 @@ export class EdgeComponent extends EntityComponent<EdgeInfo> { | ||
70 | buildForm(entity: EdgeInfo): FormGroup { | 70 | buildForm(entity: EdgeInfo): FormGroup { |
71 | const form = this.fb.group( | 71 | const form = this.fb.group( |
72 | { | 72 | { |
73 | - name: [entity ? entity.name : '', [Validators.required]], | ||
74 | - type: [entity?.type ? entity.type : 'default', [Validators.required]], | ||
75 | - label: [entity ? entity.label : ''], | 73 | + name: [entity ? entity.name : '', [Validators.required, Validators.maxLength(255)]], |
74 | + type: [entity?.type ? entity.type : 'default', [Validators.required, Validators.maxLength(255)]], | ||
75 | + label: [entity ? entity.label : '', Validators.maxLength(255)], | ||
76 | cloudEndpoint: [null, [Validators.required]], | 76 | cloudEndpoint: [null, [Validators.required]], |
77 | edgeLicenseKey: ['', [Validators.required]], | 77 | edgeLicenseKey: ['', [Validators.required]], |
78 | routingKey: this.fb.control({value: entity ? entity.routingKey : null, disabled: true}), | 78 | 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" |
@@ -81,8 +81,8 @@ export class EntityViewComponent extends EntityComponent<EntityViewInfo> { | @@ -81,8 +81,8 @@ export class EntityViewComponent extends EntityComponent<EntityViewInfo> { | ||
81 | buildForm(entity: EntityViewInfo): FormGroup { | 81 | buildForm(entity: EntityViewInfo): FormGroup { |
82 | return this.fb.group( | 82 | return this.fb.group( |
83 | { | 83 | { |
84 | - name: [entity ? entity.name : '', [Validators.required]], | ||
85 | - type: [entity ? entity.type : null, [Validators.required]], | 84 | + name: [entity ? entity.name : '', [Validators.required, Validators.maxLength(255)]], |
85 | + type: [entity ? entity.type : null, Validators.required], | ||
86 | entityId: [entity ? entity.entityId : null, [Validators.required]], | 86 | entityId: [entity ? entity.entityId : null, [Validators.required]], |
87 | startTimeMs: [entity ? entity.startTimeMs : null], | 87 | startTimeMs: [entity ? entity.startTimeMs : null], |
88 | endTimeMs: [entity ? entity.endTimeMs : null], | 88 | 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 | <mat-form-field class="mat-block" fxFlex style="margin-bottom: 8px"> | 83 | <mat-form-field class="mat-block" fxFlex style="margin-bottom: 8px"> |
@@ -116,7 +122,8 @@ | @@ -116,7 +122,8 @@ | ||
116 | </mat-checkbox> | 122 | </mat-checkbox> |
117 | </section> | 123 | </section> |
118 | <div fxLayout="row" fxLayoutGap.gt-xs="8px" fxLayoutGap.sm="8px" | 124 | <div fxLayout="row" fxLayoutGap.gt-xs="8px" fxLayoutGap.sm="8px" |
119 | - fxLayout.xs="column" fxLayout.md="column" *ngIf="!(isAdd && this.entityForm.get('generateChecksum').value)"> | 125 | + fxLayout.xs="column" fxLayout.md="column" |
126 | + *ngIf="!(isAdd && this.entityForm.get('generateChecksum').value)"> | ||
120 | <mat-form-field class="mat-block" fxFlex="33"> | 127 | <mat-form-field class="mat-block" fxFlex="33"> |
121 | <mat-label translate>ota-update.checksum-algorithm</mat-label> | 128 | <mat-label translate>ota-update.checksum-algorithm</mat-label> |
122 | <mat-select formControlName="checksumAlgorithm"> | 129 | <mat-select formControlName="checksumAlgorithm"> |
@@ -154,7 +161,8 @@ | @@ -154,7 +161,8 @@ | ||
154 | <input matInput formControlName="url" | 161 | <input matInput formControlName="url" |
155 | type="text" | 162 | type="text" |
156 | [required]="entityForm.get('isURL').value"> | 163 | [required]="entityForm.get('isURL').value"> |
157 | - <mat-error *ngIf="entityForm.get('url').hasError('required') || entityForm.get('url').hasError('pattern')" translate> | 164 | + <mat-error *ngIf="entityForm.get('url').hasError('required') || entityForm.get('url').hasError('pattern')" |
165 | + translate> | ||
158 | ota-update.direct-url-required | 166 | ota-update.direct-url-required |
159 | </mat-error> | 167 | </mat-error> |
160 | </mat-form-field> | 168 | </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 }} |
@@ -58,7 +58,7 @@ export class RuleChainComponent extends EntityComponent<RuleChain> { | @@ -58,7 +58,7 @@ export class RuleChainComponent extends EntityComponent<RuleChain> { | ||
58 | buildForm(entity: RuleChain): FormGroup { | 58 | buildForm(entity: RuleChain): 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 | debugMode: [entity ? entity.debugMode : false], | 62 | debugMode: [entity ? entity.debugMode : false], |
63 | additionalInfo: this.fb.group( | 63 | additionalInfo: this.fb.group( |
64 | { | 64 | { |
@@ -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" |
@@ -52,7 +52,7 @@ export class TenantComponent extends ContactBasedComponent<TenantInfo> { | @@ -52,7 +52,7 @@ export class TenantComponent extends ContactBasedComponent<TenantInfo> { | ||
52 | buildEntityForm(entity: TenantInfo): FormGroup { | 52 | buildEntityForm(entity: TenantInfo): FormGroup { |
53 | return this.fb.group( | 53 | return this.fb.group( |
54 | { | 54 | { |
55 | - title: [entity ? entity.title : '', [Validators.required]], | 55 | + title: [entity ? entity.title : '', [Validators.required, Validators.maxLength(255)]], |
56 | tenantProfileId: [entity ? entity.tenantProfileId : null, [Validators.required]], | 56 | tenantProfileId: [entity ? entity.tenantProfileId : null, [Validators.required]], |
57 | additionalInfo: this.fb.group( | 57 | additionalInfo: this.fb.group( |
58 | { | 58 | { |
@@ -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}}" |
@@ -48,7 +48,7 @@ export class WidgetsBundleComponent extends EntityComponent<WidgetsBundle> { | @@ -48,7 +48,7 @@ export class WidgetsBundleComponent extends EntityComponent<WidgetsBundle> { | ||
48 | buildForm(entity: WidgetsBundle): FormGroup { | 48 | buildForm(entity: WidgetsBundle): FormGroup { |
49 | return this.fb.group( | 49 | return this.fb.group( |
50 | { | 50 | { |
51 | - title: [entity ? entity.title : '', [Validators.required]], | 51 | + title: [entity ? entity.title : '', [Validators.required, Validators.maxLength(255)]], |
52 | image: [entity ? entity.image : ''], | 52 | image: [entity ? entity.image : ''], |
53 | description: [entity ? entity.description : '', Validators.maxLength(255)] | 53 | description: [entity ? entity.description : '', Validators.maxLength(255)] |
54 | } | 54 | } |
@@ -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 |
@@ -370,6 +370,7 @@ | @@ -370,6 +370,7 @@ | ||
370 | "management": "Asset management", | 370 | "management": "Asset management", |
371 | "view-assets": "View Assets", | 371 | "view-assets": "View Assets", |
372 | "add": "Add Asset", | 372 | "add": "Add Asset", |
373 | + "asset-type-max-length": "Asset type should be less than 256", | ||
373 | "assign-to-customer": "Assign to customer", | 374 | "assign-to-customer": "Assign to customer", |
374 | "assign-asset-to-customer": "Assign Asset(s) To Customer", | 375 | "assign-asset-to-customer": "Assign Asset(s) To Customer", |
375 | "assign-asset-to-customer-text": "Please select the assets to assign to the customer", | 376 | "assign-asset-to-customer-text": "Please select the assets to assign to the customer", |
@@ -392,6 +393,8 @@ | @@ -392,6 +393,8 @@ | ||
392 | "asset-types": "Asset types", | 393 | "asset-types": "Asset types", |
393 | "name": "Name", | 394 | "name": "Name", |
394 | "name-required": "Name is required.", | 395 | "name-required": "Name is required.", |
396 | + "name-max-length": "Name should be less than 256", | ||
397 | + "label-max-length": "Label should be less than 256", | ||
395 | "description": "Description", | 398 | "description": "Description", |
396 | "type": "Type", | 399 | "type": "Type", |
397 | "type-required": "Type is required.", | 400 | "type-required": "Type is required.", |
@@ -451,6 +454,7 @@ | @@ -451,6 +454,7 @@ | ||
451 | "scope-shared": "Shared attributes", | 454 | "scope-shared": "Shared attributes", |
452 | "add": "Add attribute", | 455 | "add": "Add attribute", |
453 | "key": "Key", | 456 | "key": "Key", |
457 | + "key-max-length": "Key should be less than 256", | ||
454 | "last-update-time": "Last update time", | 458 | "last-update-time": "Last update time", |
455 | "key-required": "Attribute key is required.", | 459 | "key-required": "Attribute key is required.", |
456 | "value": "Value", | 460 | "value": "Value", |
@@ -592,7 +596,10 @@ | @@ -592,7 +596,10 @@ | ||
592 | "address2": "Address 2", | 596 | "address2": "Address 2", |
593 | "phone": "Phone", | 597 | "phone": "Phone", |
594 | "email": "Email", | 598 | "email": "Email", |
595 | - "no-address": "No address" | 599 | + "no-address": "No address", |
600 | + "state-max-length": "State length should be less than 256", | ||
601 | + "phone-max-length": "Phone number should be less than 256", | ||
602 | + "city-max-length": "Specified city should be less than 256" | ||
596 | }, | 603 | }, |
597 | "common": { | 604 | "common": { |
598 | "username": "Username", | 605 | "username": "Username", |
@@ -648,6 +655,7 @@ | @@ -648,6 +655,7 @@ | ||
648 | "manage-dashboards": "Manage dashboards", | 655 | "manage-dashboards": "Manage dashboards", |
649 | "title": "Title", | 656 | "title": "Title", |
650 | "title-required": "Title is required.", | 657 | "title-required": "Title is required.", |
658 | + "title-max-length": "Title should be less than 256", | ||
651 | "description": "Description", | 659 | "description": "Description", |
652 | "details": "Details", | 660 | "details": "Details", |
653 | "events": "Events", | 661 | "events": "Events", |
@@ -705,6 +713,7 @@ | @@ -705,6 +713,7 @@ | ||
705 | "select-widget-subtitle": "List of available widget types", | 713 | "select-widget-subtitle": "List of available widget types", |
706 | "delete": "Delete dashboard", | 714 | "delete": "Delete dashboard", |
707 | "title-required": "Title is required.", | 715 | "title-required": "Title is required.", |
716 | + "title-max-length": "Title should be less than 256", | ||
708 | "description": "Description", | 717 | "description": "Description", |
709 | "details": "Details", | 718 | "details": "Details", |
710 | "dashboard-details": "Dashboard details", | 719 | "dashboard-details": "Dashboard details", |
@@ -891,6 +900,7 @@ | @@ -891,6 +900,7 @@ | ||
891 | "management": "Device management", | 900 | "management": "Device management", |
892 | "view-devices": "View Devices", | 901 | "view-devices": "View Devices", |
893 | "device-alias": "Device alias", | 902 | "device-alias": "Device alias", |
903 | + "device-type-max-length": "Device type should be less than 256", | ||
894 | "aliases": "Device aliases", | 904 | "aliases": "Device aliases", |
895 | "no-alias-matching": "'{{alias}}' not found.", | 905 | "no-alias-matching": "'{{alias}}' not found.", |
896 | "no-aliases-found": "No aliases found.", | 906 | "no-aliases-found": "No aliases found.", |
@@ -1003,6 +1013,8 @@ | @@ -1003,6 +1013,8 @@ | ||
1003 | "device-types": "Device types", | 1013 | "device-types": "Device types", |
1004 | "name": "Name", | 1014 | "name": "Name", |
1005 | "name-required": "Name is required.", | 1015 | "name-required": "Name is required.", |
1016 | + "name-max-length": "Name should be less than 256", | ||
1017 | + "label-max-length": "Label should be less than 256", | ||
1006 | "description": "Description", | 1018 | "description": "Description", |
1007 | "label": "Label", | 1019 | "label": "Label", |
1008 | "events": "Events", | 1020 | "events": "Events", |
@@ -1055,6 +1067,7 @@ | @@ -1055,6 +1067,7 @@ | ||
1055 | "set-default": "Make device profile default", | 1067 | "set-default": "Make device profile default", |
1056 | "delete": "Delete device profile", | 1068 | "delete": "Delete device profile", |
1057 | "copyId": "Copy device profile Id", | 1069 | "copyId": "Copy device profile Id", |
1070 | + "name-max-length": "Name should be less than 256", | ||
1058 | "new-device-profile-name": "Device profile name", | 1071 | "new-device-profile-name": "Device profile name", |
1059 | "new-device-profile-name-required": "Device profile name is required.", | 1072 | "new-device-profile-name-required": "Device profile name is required.", |
1060 | "name": "Name", | 1073 | "name": "Name", |
@@ -1416,6 +1429,9 @@ | @@ -1416,6 +1429,9 @@ | ||
1416 | "edge": "Edge", | 1429 | "edge": "Edge", |
1417 | "edge-instances": "Edge instances", | 1430 | "edge-instances": "Edge instances", |
1418 | "edge-file": "Edge file", | 1431 | "edge-file": "Edge file", |
1432 | + "name-max-length": "Name should be less than 256", | ||
1433 | + "label-max-length": "Label should be less than 256", | ||
1434 | + "type-max-length": "Type should be less than 256", | ||
1419 | "management": "Edge management", | 1435 | "management": "Edge management", |
1420 | "no-edges-matching": "No edges matching '{{entity}}' were found.", | 1436 | "no-edges-matching": "No edges matching '{{entity}}' were found.", |
1421 | "add": "Add Edge", | 1437 | "add": "Add Edge", |
@@ -1750,6 +1766,8 @@ | @@ -1750,6 +1766,8 @@ | ||
1750 | "created-time": "Created time", | 1766 | "created-time": "Created time", |
1751 | "name": "Name", | 1767 | "name": "Name", |
1752 | "name-required": "Name is required.", | 1768 | "name-required": "Name is required.", |
1769 | + "name-max-length": "Name should be less than 256", | ||
1770 | + "type-max-length": "Entity view type should be less than 256", | ||
1753 | "description": "Description", | 1771 | "description": "Description", |
1754 | "events": "Events", | 1772 | "events": "Events", |
1755 | "details": "Details", | 1773 | "details": "Details", |
@@ -2374,6 +2392,7 @@ | @@ -2374,6 +2392,7 @@ | ||
2374 | "selected-package": "{ count, plural, 1 {1 package} other {# packages} } selected", | 2392 | "selected-package": "{ count, plural, 1 {1 package} other {# packages} } selected", |
2375 | "title": "Title", | 2393 | "title": "Title", |
2376 | "title-required": "Title is required.", | 2394 | "title-required": "Title is required.", |
2395 | + "title-max-length": "Title should be less than 256", | ||
2377 | "types": { | 2396 | "types": { |
2378 | "firmware": "Firmware", | 2397 | "firmware": "Firmware", |
2379 | "software": "Software" | 2398 | "software": "Software" |
@@ -2384,6 +2403,7 @@ | @@ -2384,6 +2403,7 @@ | ||
2384 | "version-required": "Version is required.", | 2403 | "version-required": "Version is required.", |
2385 | "version-tag": "Version Tag", | 2404 | "version-tag": "Version Tag", |
2386 | "version-tag-hint": "Custom tag should match the package version reported by your device.", | 2405 | "version-tag-hint": "Custom tag should match the package version reported by your device.", |
2406 | + "version-max-length": "Version should be less than 256", | ||
2387 | "warning-after-save-no-edit": "Once the package is uploaded, you will not be able to modify title, version, device profile and package type." | 2407 | "warning-after-save-no-edit": "Once the package is uploaded, you will not be able to modify title, version, device profile and package type." |
2388 | }, | 2408 | }, |
2389 | "position": { | 2409 | "position": { |
@@ -2426,6 +2446,7 @@ | @@ -2426,6 +2446,7 @@ | ||
2426 | "delete": "Delete relation", | 2446 | "delete": "Delete relation", |
2427 | "relation-type": "Relation type", | 2447 | "relation-type": "Relation type", |
2428 | "relation-type-required": "Relation type is required.", | 2448 | "relation-type-required": "Relation type is required.", |
2449 | + "relation-type-max-length": "Relation type should be less than 256", | ||
2429 | "any-relation-type": "Any type", | 2450 | "any-relation-type": "Any type", |
2430 | "add": "Add relation", | 2451 | "add": "Add relation", |
2431 | "edit": "Edit relation", | 2452 | "edit": "Edit relation", |
@@ -2470,7 +2491,8 @@ | @@ -2470,7 +2491,8 @@ | ||
2470 | "selected-resources": "{ count, plural, 1 {1 resource} other {# resources} } selected", | 2491 | "selected-resources": "{ count, plural, 1 {1 resource} other {# resources} } selected", |
2471 | "system": "System", | 2492 | "system": "System", |
2472 | "title": "Title", | 2493 | "title": "Title", |
2473 | - "title-required": "Title is required." | 2494 | + "title-required": "Title is required.", |
2495 | + "title-max-length": "Title should be less than 256" | ||
2474 | }, | 2496 | }, |
2475 | "rulechain": { | 2497 | "rulechain": { |
2476 | "rulechain": "Rule chain", | 2498 | "rulechain": "Rule chain", |
@@ -2479,6 +2501,7 @@ | @@ -2479,6 +2501,7 @@ | ||
2479 | "delete": "Delete rule chain", | 2501 | "delete": "Delete rule chain", |
2480 | "name": "Name", | 2502 | "name": "Name", |
2481 | "name-required": "Name is required.", | 2503 | "name-required": "Name is required.", |
2504 | + "name-max-length": "Name should be less than 256", | ||
2482 | "description": "Description", | 2505 | "description": "Description", |
2483 | "add": "Add Rule Chain", | 2506 | "add": "Add Rule Chain", |
2484 | "set-root": "Make rule chain root", | 2507 | "set-root": "Make rule chain root", |
@@ -2621,6 +2644,7 @@ | @@ -2621,6 +2644,7 @@ | ||
2621 | "add-tenant-text": "Add new tenant", | 2644 | "add-tenant-text": "Add new tenant", |
2622 | "no-tenants-text": "No tenants found", | 2645 | "no-tenants-text": "No tenants found", |
2623 | "tenant-details": "Tenant details", | 2646 | "tenant-details": "Tenant details", |
2647 | + "title-max-length": "Title should be less than 256", | ||
2624 | "delete-tenant-title": "Are you sure you want to delete the tenant '{{tenantTitle}}'?", | 2648 | "delete-tenant-title": "Are you sure you want to delete the tenant '{{tenantTitle}}'?", |
2625 | "delete-tenant-text": "Be careful, after the confirmation the tenant and all related data will become unrecoverable.", | 2649 | "delete-tenant-text": "Be careful, after the confirmation the tenant and all related data will become unrecoverable.", |
2626 | "delete-tenants-title": "Are you sure you want to delete { count, plural, 1 {1 tenant} other {# tenants} }?", | 2650 | "delete-tenants-title": "Are you sure you want to delete { count, plural, 1 {1 tenant} other {# tenants} }?", |
@@ -2650,6 +2674,7 @@ | @@ -2650,6 +2674,7 @@ | ||
2650 | "edit": "Edit tenant profile", | 2674 | "edit": "Edit tenant profile", |
2651 | "tenant-profile-details": "Tenant profile details", | 2675 | "tenant-profile-details": "Tenant profile details", |
2652 | "no-tenant-profiles-text": "No tenant profiles found", | 2676 | "no-tenant-profiles-text": "No tenant profiles found", |
2677 | + "name-max-length": "Name should be less than 256", | ||
2653 | "search": "Search tenant profiles", | 2678 | "search": "Search tenant profiles", |
2654 | "selected-tenant-profiles": "{ count, plural, 1 {1 tenant profile} other {# tenant profiles} } selected", | 2679 | "selected-tenant-profiles": "{ count, plural, 1 {1 tenant profile} other {# tenant profiles} } selected", |
2655 | "no-tenant-profiles-matching": "No tenant profile matching '{{entity}}' were found.", | 2680 | "no-tenant-profiles-matching": "No tenant profile matching '{{entity}}' were found.", |
@@ -2997,6 +3022,7 @@ | @@ -2997,6 +3022,7 @@ | ||
2997 | "delete": "Delete widgets bundle", | 3022 | "delete": "Delete widgets bundle", |
2998 | "title": "Title", | 3023 | "title": "Title", |
2999 | "title-required": "Title is required.", | 3024 | "title-required": "Title is required.", |
3025 | + "title-max-length": "Title should be less than 256", | ||
3000 | "description": "Description", | 3026 | "description": "Description", |
3001 | "image-preview": "Image preview", | 3027 | "image-preview": "Image preview", |
3002 | "add-widgets-bundle-text": "Add new widgets bundle", | 3028 | "add-widgets-bundle-text": "Add new widgets bundle", |