Browse Source

Merge branch 'develop/3.4' into refactoring_tests_08

pull/6816/head
nickAS21 4 years ago
parent
commit
79483a601e
  1. 45
      application/src/main/java/org/thingsboard/server/config/ThingsboardSecurityConfiguration.java
  2. 4
      application/src/main/java/org/thingsboard/server/service/edge/rpc/sync/DefaultEdgeRequestsService.java
  3. 14
      application/src/main/java/org/thingsboard/server/service/sync/ie/DefaultEntitiesExportImportService.java
  4. 23
      application/src/main/java/org/thingsboard/server/service/sync/vc/DefaultEntitiesVersionControlService.java
  5. 8
      application/src/main/java/org/thingsboard/server/service/sync/vc/LoadEntityException.java
  6. 6
      application/src/main/java/org/thingsboard/server/service/sync/vc/data/EntitiesImportCtx.java
  7. 1
      application/src/main/resources/thingsboard.yml
  8. 21
      common/data/src/main/java/org/thingsboard/server/common/data/Dashboard.java
  9. 6
      common/data/src/main/java/org/thingsboard/server/common/data/queue/Queue.java
  10. 24
      dao/src/main/java/org/thingsboard/server/dao/service/DataValidator.java
  11. 10
      dao/src/main/java/org/thingsboard/server/dao/service/validator/QueueValidator.java
  12. 9
      dao/src/main/java/org/thingsboard/server/dao/service/validator/TenantProfileDataValidator.java
  13. 5
      dao/src/main/java/org/thingsboard/server/dao/sql/edge/JpaBaseEdgeEventDao.java
  14. 28
      dao/src/test/java/org/thingsboard/server/dao/service/BaseQueueServiceTest.java
  15. 3
      ui-ngx/src/app/modules/home/components/queue/queue-form.component.html
  16. 2
      ui-ngx/src/app/modules/home/components/queue/queue-form.component.ts
  17. 4
      ui-ngx/src/app/modules/home/pages/security/security.component.html
  18. 1
      ui-ngx/src/assets/locale/locale.constant-en_US.json

45
application/src/main/java/org/thingsboard/server/config/ThingsboardSecurityConfiguration.java

@ -24,22 +24,22 @@ import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.DefaultAuthenticationEventPublisher;
import org.springframework.security.config.annotation.ObjectPostProcessor;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.oauth2.client.web.OAuth2AuthorizationRequestResolver;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;
import org.thingsboard.server.dao.audit.AuditLogLevelFilter;
import org.thingsboard.server.dao.oauth2.OAuth2Configuration;
import org.thingsboard.server.exception.ThingsboardErrorResponseHandler;
import org.thingsboard.server.queue.util.TbCoreComponent;
@ -63,7 +63,7 @@ import java.util.List;
@EnableGlobalMethodSecurity(prePostEnabled=true)
@Order(SecurityProperties.BASIC_AUTH_ORDER)
@TbCoreComponent
public class ThingsboardSecurityConfiguration extends WebSecurityConfigurerAdapter {
public class ThingsboardSecurityConfiguration {
public static final String JWT_TOKEN_HEADER_PARAM = "X-Authorization";
public static final String JWT_TOKEN_HEADER_PARAM_V2 = "Authorization";
@ -161,16 +161,15 @@ public class ThingsboardSecurityConfiguration extends WebSecurityConfigurerAdapt
}
@Bean
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
@Override
protected void configure(AuthenticationManagerBuilder auth) {
public AuthenticationManager authenticationManager(ObjectPostProcessor<Object> objectPostProcessor) throws Exception {
DefaultAuthenticationEventPublisher eventPublisher = objectPostProcessor
.postProcess(new DefaultAuthenticationEventPublisher());
var auth = new AuthenticationManagerBuilder(objectPostProcessor);
auth.authenticationEventPublisher(eventPublisher);
auth.authenticationProvider(restAuthenticationProvider);
auth.authenticationProvider(jwtAuthenticationProvider);
auth.authenticationProvider(refreshTokenAuthenticationProvider);
return auth.build();
}
@Bean
@ -181,18 +180,20 @@ public class ThingsboardSecurityConfiguration extends WebSecurityConfigurerAdapt
@Autowired
private OAuth2AuthorizationRequestResolver oAuth2AuthorizationRequestResolver;
@Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers("/*.js","/*.css","/*.ico","/assets/**","/static/**");
@Bean
@Order(0)
SecurityFilterChain resources(HttpSecurity http) throws Exception {
http
.requestMatchers((matchers) -> matchers.antMatchers("/*.js","/*.css","/*.ico","/assets/**","/static/**"))
.authorizeHttpRequests((authorize) -> authorize.anyRequest().permitAll())
.requestCache().disable()
.securityContext().disable()
.sessionManagement().disable();
return http.build();
}
@Override
protected void configure(HttpSecurity http) throws Exception {
// http.authorizeHttpRequests((authorizeHttpRequests) ->
// authorizeHttpRequests
// .antMatchers("/*.js","/*.css","/*.ico","/assets/**","/static/**")
// .permitAll()
// );
@Bean
SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http.headers().cacheControl().and().frameOptions().disable()
.and()
.cors()
@ -234,6 +235,7 @@ public class ThingsboardSecurityConfiguration extends WebSecurityConfigurerAdapt
.successHandler(oauth2AuthenticationSuccessHandler)
.failureHandler(oauth2AuthenticationFailureHandler);
}
return http.build();
}
@Bean
@ -247,5 +249,4 @@ public class ThingsboardSecurityConfiguration extends WebSecurityConfigurerAdapt
return new CorsFilter(source);
}
}
}

4
application/src/main/java/org/thingsboard/server/service/edge/rpc/sync/DefaultEdgeRequestsService.java

@ -74,6 +74,7 @@ import org.thingsboard.server.gen.edge.v1.UserCredentialsRequestMsg;
import org.thingsboard.server.gen.edge.v1.WidgetBundleTypesRequestMsg;
import org.thingsboard.server.service.entitiy.entityview.TbEntityViewService;
import org.thingsboard.server.service.executors.DbCallbackExecutorService;
import org.thingsboard.server.service.state.DefaultDeviceStateService;
import java.util.ArrayList;
import java.util.HashMap;
@ -162,6 +163,9 @@ public class DefaultEdgeRequestsService implements EdgeRequestsService {
Map<String, Object> entityData = new HashMap<>();
ObjectNode attributes = mapper.createObjectNode();
for (AttributeKvEntry attr : ssAttributes) {
if (DefaultDeviceStateService.PERSISTENT_ATTRIBUTES.contains(attr.getKey())) {
continue;
}
if (attr.getDataType() == DataType.BOOLEAN && attr.getBooleanValue().isPresent()) {
attributes.put(attr.getKey(), attr.getBooleanValue().get());
} else if (attr.getDataType() == DataType.DOUBLE && attr.getDoubleValue().isPresent()) {

14
application/src/main/java/org/thingsboard/server/service/sync/ie/DefaultEntitiesExportImportService.java

@ -38,6 +38,8 @@ import org.thingsboard.server.service.sync.ie.exporting.EntityExportService;
import org.thingsboard.server.service.sync.ie.exporting.impl.BaseEntityExportService;
import org.thingsboard.server.service.sync.ie.exporting.impl.DefaultEntityExportService;
import org.thingsboard.server.service.sync.ie.importing.EntityImportService;
import org.thingsboard.server.service.sync.ie.importing.impl.MissingEntityException;
import org.thingsboard.server.service.sync.vc.LoadEntityException;
import org.thingsboard.server.service.sync.vc.data.EntitiesExportCtx;
import org.thingsboard.server.service.sync.vc.data.EntitiesImportCtx;
@ -95,15 +97,21 @@ public class DefaultEntitiesExportImportService implements EntitiesExportImportS
EntityImportResult<E> importResult = importService.importEntity(ctx, exportData);
ctx.putInternalId(exportData.getExternalId(), importResult.getSavedEntity().getId());
ctx.addReferenceCallback(importResult.getSaveReferencesCallback());
ctx.addReferenceCallback(exportData.getExternalId(), importResult.getSaveReferencesCallback());
ctx.addEventCallback(importResult.getSendEventsCallback());
return importResult;
}
@Override
public void saveReferencesAndRelations(EntitiesImportCtx ctx) throws ThingsboardException {
for (ThrowingRunnable saveReferencesCallback : ctx.getReferenceCallbacks()) {
saveReferencesCallback.run();
for (Map.Entry<EntityId, ThrowingRunnable> callbackEntry : ctx.getReferenceCallbacks().entrySet()) {
EntityId externalId = callbackEntry.getKey();
ThrowingRunnable saveReferencesCallback = callbackEntry.getValue();
try {
saveReferencesCallback.run();
} catch (MissingEntityException e) {
throw new LoadEntityException(externalId, e);
}
}
relationService.saveRelations(ctx.getTenantId(), new ArrayList<>(ctx.getRelations()));

23
application/src/main/java/org/thingsboard/server/service/sync/vc/DefaultEntitiesVersionControlService.java

@ -286,7 +286,7 @@ public class DefaultEntitiesVersionControlService implements EntitiesVersionCont
result.setDone(true);
return cachePut(ctx.getRequestId(), result);
} catch (LoadEntityException e) {
return cachePut(ctx.getRequestId(), onError(e.getData(), e.getCause()));
return cachePut(ctx.getRequestId(), onError(e.getExternalId(), e.getCause()));
} catch (Exception e) {
log.info("[{}] Failed to process request [{}] due to: ", ctx.getTenantId(), request, e);
return cachePut(ctx.getRequestId(), VersionLoadResult.error(EntityLoadError.runtimeError(e.getMessage())));
@ -313,7 +313,7 @@ public class DefaultEntitiesVersionControlService implements EntitiesVersionCont
.deleted(0)
.build());
} catch (Exception e) {
throw new LoadEntityException(entityData, e);
throw new LoadEntityException(entityData.getExternalId(), e);
}
}
@ -382,14 +382,14 @@ public class DefaultEntitiesVersionControlService implements EntitiesVersionCont
try {
importResult = exportImportService.importEntity(ctx, entityData);
} catch (Exception e) {
throw new LoadEntityException(entityData, e);
throw new LoadEntityException(entityData.getExternalId(), e);
}
registerResult(ctx, entityType, importResult);
if (!importResult.isUpdatedAllExternalIds()) {
ctx.getToReimport().put(entityData.getEntity().getExternalId(), new ReimportTask(reimportBackup, ctx.getSettings()));
continue;
}
registerResult(ctx, entityType, importResult);
ctx.getImportedEntities().computeIfAbsent(entityType, t -> new HashSet<>())
.add(importResult.getSavedEntity().getId());
}
@ -408,7 +408,6 @@ public class DefaultEntitiesVersionControlService implements EntitiesVersionCont
ctx.setSettings(settings);
EntityImportResult<?> importResult = exportImportService.importEntity(ctx, entityData);
registerResult(ctx, externalId.getEntityType(), importResult);
ctx.getImportedEntities().computeIfAbsent(externalId.getEntityType(), t -> new HashSet<>())
.add(importResult.getSavedEntity().getId());
} catch (Exception e) {
@ -433,20 +432,20 @@ public class DefaultEntitiesVersionControlService implements EntitiesVersionCont
});
}
private VersionLoadResult onError(EntityExportData<?> entityData, Throwable e) {
return analyze(e, entityData).orElse(VersionLoadResult.error(EntityLoadError.runtimeError(e.getMessage())));
private VersionLoadResult onError(EntityId externalId, Throwable e) {
return analyze(e, externalId).orElse(VersionLoadResult.error(EntityLoadError.runtimeError(e.getMessage())));
}
private Optional<VersionLoadResult> analyze(Throwable e, EntityExportData<?> entityData) {
private Optional<VersionLoadResult> analyze(Throwable e, EntityId externalId) {
if (e == null) {
return Optional.empty();
} else {
if (e instanceof DeviceCredentialsValidationException) {
return Optional.of(VersionLoadResult.error(EntityLoadError.credentialsError(entityData.getExternalId())));
return Optional.of(VersionLoadResult.error(EntityLoadError.credentialsError(externalId)));
} else if (e instanceof MissingEntityException) {
return Optional.of(VersionLoadResult.error(EntityLoadError.referenceEntityError(entityData.getExternalId(), ((MissingEntityException) e).getEntityId())));
return Optional.of(VersionLoadResult.error(EntityLoadError.referenceEntityError(externalId, ((MissingEntityException) e).getEntityId())));
} else {
return analyze(e.getCause(), entityData);
return analyze(e.getCause(), externalId);
}
}
}

8
application/src/main/java/org/thingsboard/server/service/sync/vc/LoadEntityException.java

@ -16,17 +16,17 @@
package org.thingsboard.server.service.sync.vc;
import lombok.Getter;
import org.thingsboard.server.common.data.sync.ie.EntityExportData;
import org.thingsboard.server.common.data.id.EntityId;
@SuppressWarnings("rawtypes")
public class LoadEntityException extends RuntimeException {
private static final long serialVersionUID = -1749719992370409504L;
@Getter
private final EntityExportData data;
private final EntityId externalId;
public LoadEntityException(EntityExportData data, Throwable cause) {
public LoadEntityException(EntityId externalId, Throwable cause) {
super(cause);
this.data = data;
this.externalId = externalId;
}
}

6
application/src/main/java/org/thingsboard/server/service/sync/vc/data/EntitiesImportCtx.java

@ -48,7 +48,7 @@ public class EntitiesImportCtx {
private final Map<EntityType, EntityTypeLoadResult> results = new HashMap<>();
private final Map<EntityType, Set<EntityId>> importedEntities = new HashMap<>();
private final Map<EntityId, ReimportTask> toReimport = new HashMap<>();
private final List<ThrowingRunnable> referenceCallbacks = new ArrayList<>();
private final Map<EntityId, ThrowingRunnable> referenceCallbacks = new HashMap<>();
private final List<ThrowingRunnable> eventCallbacks = new ArrayList<>();
private final Map<EntityId, EntityId> externalToInternalIdMap = new HashMap<>();
private final Set<EntityId> notFoundIds = new HashSet<>();
@ -119,9 +119,9 @@ public class EntitiesImportCtx {
relations.addAll(values);
}
public void addReferenceCallback(ThrowingRunnable tr) {
public void addReferenceCallback(EntityId externalId, ThrowingRunnable tr) {
if (tr != null) {
referenceCallbacks.add(tr);
referenceCallbacks.put(externalId, tr);
}
}

1
application/src/main/resources/thingsboard.yml

@ -266,7 +266,6 @@ sql:
batch_size: "${SQL_EDGE_EVENTS_BATCH_SIZE:1000}"
batch_max_delay: "${SQL_EDGE_EVENTS_BATCH_MAX_DELAY_MS:100}"
stats_print_interval_ms: "${SQL_EDGE_EVENTS_BATCH_STATS_PRINT_MS:10000}"
batch_threads: "${SQL_EDGE_EVENTS_BATCH_THREADS:3}" # batch thread count have to be a prime number like 3 or 5 to gain perfect hash distribution
# Specify whether to sort entities before batch update. Should be enabled for cluster mode to avoid deadlocks
batch_sort: "${SQL_BATCH_SORT:false}"
# Specify whether to remove null characters from strValue of attributes and timeseries before insert

21
common/data/src/main/java/org/thingsboard/server/common/data/Dashboard.java

@ -17,19 +17,18 @@ package org.thingsboard.server.common.data;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.google.common.collect.Streams;
import io.swagger.annotations.ApiModelProperty;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.Setter;
import org.thingsboard.server.common.data.id.DashboardId;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.stream.StreamSupport;
import java.util.stream.Collectors;
@EqualsAndHashCode(callSuper = true)
public class Dashboard extends DashboardInfo implements ExportableEntity<DashboardId> {
@ -86,17 +85,11 @@ public class Dashboard extends DashboardInfo implements ExportableEntity<Dashboa
private List<ObjectNode> getChildObjects(String propertyName) {
return Optional.ofNullable(configuration)
.map(config -> config.get(propertyName))
.filter(node -> !node.isEmpty())
.map(node -> (ObjectNode) node)
.map(object -> {
List<ObjectNode> widgets = new ArrayList<>(object.size());
object.forEach(child -> {
if (child.isObject()) {
widgets.add((ObjectNode) child);
}
});
return widgets;
})
.filter(node -> !node.isEmpty() && (node.isObject() || node.isArray()))
.map(node -> Streams.stream(node.elements())
.filter(JsonNode::isObject)
.map(jsonNode -> (ObjectNode) jsonNode)
.collect(Collectors.toList()))
.orElse(Collections.emptyList());
}

6
common/data/src/main/java/org/thingsboard/server/common/data/queue/Queue.java

@ -22,11 +22,17 @@ import org.thingsboard.server.common.data.SearchTextBasedWithAdditionalInfo;
import org.thingsboard.server.common.data.id.QueueId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.tenant.profile.TenantProfileQueueConfiguration;
import org.thingsboard.server.common.data.validation.Length;
import org.thingsboard.server.common.data.validation.NoXss;
@Data
public class Queue extends SearchTextBasedWithAdditionalInfo<QueueId> implements HasName, HasTenantId {
private TenantId tenantId;
@NoXss
@Length(fieldName = "name")
private String name;
@NoXss
@Length(fieldName = "topic")
private String topic;
private int pollInterval;
private int partitions;

24
dao/src/main/java/org/thingsboard/server/dao/service/DataValidator.java

@ -17,6 +17,7 @@ package org.thingsboard.server.dao.service;
import com.fasterxml.jackson.databind.JsonNode;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.thingsboard.server.common.data.BaseData;
import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.id.TenantId;
@ -36,6 +37,11 @@ public abstract class DataValidator<D extends BaseData<?>> {
private static final Pattern EMAIL_PATTERN =
Pattern.compile("^[A-Z0-9._%+-]+@[A-Z0-9.-]+\\.[A-Z]{2,}$", Pattern.CASE_INSENSITIVE);
private static final Pattern QUEUE_PATTERN = Pattern.compile("^[a-zA-Z0-9_.\\-]+$");
private static final String NAME = "name";
private static final String TOPIC = "topic";
// Returns old instance of the same object that is fetched during validation.
public D validate(D data, Function<D, TenantId> tenantIdFunction) {
try {
@ -134,4 +140,22 @@ public abstract class DataValidator<D extends BaseData<?>> {
}
}
protected static void validateQueueName(String name) {
validateQueueNameOrTopic(name, NAME);
}
protected static void validateQueueTopic(String topic) {
validateQueueNameOrTopic(topic, TOPIC);
}
private static void validateQueueNameOrTopic(String value, String fieldName) {
if (StringUtils.isEmpty(value)) {
throw new DataValidationException(String.format("Queue %s should be specified!", fieldName));
}
if (!QUEUE_PATTERN.matcher(value).matches()) {
throw new DataValidationException(
String.format("Queue %s contains a character other than ASCII alphanumerics, '.', '_' and '-'!", fieldName));
}
}
}

10
dao/src/main/java/org/thingsboard/server/dao/service/validator/QueueValidator.java

@ -15,7 +15,6 @@
*/
package org.thingsboard.server.dao.service.validator;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.thingsboard.server.common.data.TenantProfile;
@ -73,12 +72,9 @@ public class QueueValidator extends DataValidator<Queue> {
}
}
if (StringUtils.isEmpty(queue.getName())) {
throw new DataValidationException("Queue name should be specified!");
}
if (StringUtils.isBlank(queue.getTopic())) {
throw new DataValidationException("Queue topic should be non empty and without spaces!");
}
validateQueueName(queue.getName());
validateQueueTopic(queue.getTopic());
if (queue.getPollInterval() < 1) {
throw new DataValidationException("Queue poll interval should be more then 0!");
}

9
dao/src/main/java/org/thingsboard/server/dao/service/validator/TenantProfileDataValidator.java

@ -107,12 +107,9 @@ public class TenantProfileDataValidator extends DataValidator<TenantProfile> {
}
private void validateQueueConfiguration(TenantProfileQueueConfiguration queue) {
if (StringUtils.isEmpty(queue.getName())) {
throw new DataValidationException("Queue name should be specified!");
}
if (StringUtils.isBlank(queue.getTopic())) {
throw new DataValidationException("Queue topic should be non empty and without spaces!");
}
validateQueueName(queue.getName());
validateQueueTopic(queue.getTopic());
if (queue.getPollInterval() < 1) {
throw new DataValidationException("Queue poll interval should be more then 0!");
}

5
dao/src/main/java/org/thingsboard/server/dao/sql/edge/JpaBaseEdgeEventDao.java

@ -72,9 +72,6 @@ public class JpaBaseEdgeEventDao extends JpaAbstractSearchTextDao<EdgeEventEntit
@Value("${sql.edge_events.stats_print_interval_ms:10000}")
private long statsPrintIntervalMs;
@Value("${sql.edge_events.batch_threads:3}")
private int batchThreads;
private TbSqlBlockingQueueWrapper<EdgeEventEntity> queue;
@Autowired
@ -110,7 +107,7 @@ public class JpaBaseEdgeEventDao extends JpaAbstractSearchTextDao<EdgeEventEntit
return NULL_UUID.hashCode();
}
};
queue = new TbSqlBlockingQueueWrapper<>(params, hashcodeFunction, batchThreads, statsFactory);
queue = new TbSqlBlockingQueueWrapper<>(params, hashcodeFunction, 1, statsFactory);
queue.init(logExecutor, v -> edgeEventInsertRepository.save(v),
Comparator.comparing(EdgeEventEntity::getTs)
);

28
dao/src/test/java/org/thingsboard/server/dao/service/BaseQueueServiceTest.java

@ -152,6 +152,20 @@ public abstract class BaseQueueServiceTest extends AbstractServiceTest {
queueService.saveQueue(queue);
}
@Test(expected = DataValidationException.class)
public void testSaveQueueWithInvalidName() {
Queue queue = new Queue();
queue.setTenantId(tenantId);
queue.setName("Test 1");
queue.setTopic("tb_rule_engine.test");
queue.setPollInterval(25);
queue.setPartitions(1);
queue.setPackProcessingTimeout(2000);
queue.setSubmitStrategy(createTestSubmitStrategy());
queue.setProcessingStrategy(createTestProcessingStrategy());
queueService.saveQueue(queue);
}
@Test(expected = DataValidationException.class)
public void testSaveQueueWithEmptyTopic() {
Queue queue = new Queue();
@ -165,6 +179,20 @@ public abstract class BaseQueueServiceTest extends AbstractServiceTest {
queueService.saveQueue(queue);
}
@Test(expected = DataValidationException.class)
public void testSaveQueueWithInvalidTopic() {
Queue queue = new Queue();
queue.setTenantId(tenantId);
queue.setName("Test");
queue.setTopic("tb rule engine test");
queue.setPollInterval(25);
queue.setPartitions(1);
queue.setPackProcessingTimeout(2000);
queue.setSubmitStrategy(createTestSubmitStrategy());
queue.setProcessingStrategy(createTestProcessingStrategy());
queueService.saveQueue(queue);
}
@Test(expected = DataValidationException.class)
public void testSaveQueueWithEmptyPollInterval() {
Queue queue = new Queue();

3
ui-ngx/src/app/modules/home/components/queue/queue-form.component.html

@ -26,6 +26,9 @@
<mat-error *ngIf="queueFormGroup.get('name').hasError('unique')">
{{ 'queue.name-unique' | translate }}
</mat-error>
<mat-error *ngIf="queueFormGroup.get('name').hasError('pattern')">
{{ 'queue.name-pattern' | translate }}
</mat-error>
</mat-form-field>
<mat-accordion class="queue-strategy" [multi]="true">
<mat-expansion-panel [expanded]="true">

2
ui-ngx/src/app/modules/home/components/queue/queue-form.component.ts

@ -99,7 +99,7 @@ export class QueueFormComponent implements ControlValueAccessor, OnInit, OnDestr
ngOnInit() {
this.queueFormGroup = this.fb.group(
{
name: ['', [Validators.required]],
name: ['', [Validators.required, Validators.pattern(/^[a-zA-Z0-9_.\-]+$/)]],
pollInterval: [25, [Validators.min(1), Validators.required]],
partitions: [10, [Validators.min(1), Validators.required]],
consumerPerPartition: [false, []],

4
ui-ngx/src/app/modules/home/pages/security/security.component.html

@ -38,9 +38,9 @@
<div fxLayout="row" fxLayout.xs="column" fxLayoutGap="25px" fxLayoutGap.xs="0">
<div fxFlex="290px" fxFlex.sm="250px" fxFlex.xs="100">
<h3 class="card-title" translate>profile.change-password</h3>
<mat-form-field class="mat-block same-color" hideRequiredMarker appearance="fill" color="primary">
<mat-form-field class="mat-block same-color" appearance="fill" color="primary">
<mat-label translate>profile.current-password</mat-label>
<input matInput type="password" name="current-password" formControlName="currentPassword" autocomplete="current-password" required/>
<input matInput type="password" name="current-password" formControlName="currentPassword" autocomplete="current-password"/>
<tb-toggle-password [fxShow]="changePassword.get('currentPassword').dirty || changePassword.get('currentPassword').touched" matSuffix></tb-toggle-password>
<mat-error *ngIf="changePassword.get('currentPassword').hasError('differencePassword')">
{{ 'security.password-requirement.incorrect-password-try-again' | translate }}

1
ui-ngx/src/assets/locale/locale.constant-en_US.json

@ -2928,6 +2928,7 @@
"name": "Name",
"name-required": "Queue name is required!",
"name-unique": "Queue name is not unique!",
"name-pattern": "Queue name contains a character other than ASCII alphanumerics, '.', '_' and '-'!",
"queue-required": "Queue is required!",
"topic-required": "Queue topic is required!",
"poll-interval-required": "Poll interval is required!",

Loading…
Cancel
Save