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