added sms disabled feature for tenant profile configuration
This commit is contained in:
parent
07ff1ab44a
commit
a6c52809cd
@ -42,6 +42,7 @@ import org.thingsboard.server.common.data.AdminSettings;
|
||||
import org.thingsboard.server.common.data.FeaturesInfo;
|
||||
import org.thingsboard.server.common.data.SystemInfo;
|
||||
import org.thingsboard.server.common.data.UpdateMessage;
|
||||
import org.thingsboard.server.common.data.audit.ActionType;
|
||||
import org.thingsboard.server.common.data.exception.ThingsboardException;
|
||||
import org.thingsboard.server.common.data.id.TenantId;
|
||||
import org.thingsboard.server.common.data.security.model.JwtPair;
|
||||
@ -52,6 +53,7 @@ import org.thingsboard.server.common.data.sync.vc.AutoCommitSettings;
|
||||
import org.thingsboard.server.common.data.sync.vc.RepositorySettings;
|
||||
import org.thingsboard.server.common.data.sync.vc.RepositorySettingsInfo;
|
||||
import org.thingsboard.server.common.data.sync.vc.VcUtils;
|
||||
import org.thingsboard.server.dao.audit.AuditLogService;
|
||||
import org.thingsboard.server.dao.settings.AdminSettingsService;
|
||||
import org.thingsboard.server.queue.util.TbCoreComponent;
|
||||
import org.thingsboard.server.service.security.auth.jwt.settings.JwtSettingsService;
|
||||
@ -86,6 +88,7 @@ public class AdminController extends BaseController {
|
||||
private final TbAutoCommitSettingsService autoCommitSettingsService;
|
||||
private final UpdateService updateService;
|
||||
private final SystemInfoService systemInfoService;
|
||||
private final AuditLogService auditLogService;
|
||||
|
||||
@ApiOperation(value = "Get the Administration Settings object using key (getAdminSettings)",
|
||||
notes = "Get the Administration Settings object using specified string key. Referencing non-existing key will cause an error." + SYSTEM_AUTHORITY_PARAGRAPH)
|
||||
@ -202,8 +205,15 @@ public class AdminController extends BaseController {
|
||||
public void sendTestSms(
|
||||
@ApiParam(value = "A JSON value representing the Test SMS request.")
|
||||
@RequestBody TestSmsRequest testSmsRequest) throws ThingsboardException {
|
||||
accessControlService.checkPermission(getCurrentUser(), Resource.ADMIN_SETTINGS, Operation.READ);
|
||||
SecurityUser user = getCurrentUser();
|
||||
accessControlService.checkPermission(user, Resource.ADMIN_SETTINGS, Operation.READ);
|
||||
try {
|
||||
smsService.sendTestSms(testSmsRequest);
|
||||
auditLogService.logEntityAction(user.getTenantId(), user.getCustomerId(), user.getId(), user.getName(), user.getId(), user, ActionType.SMS_SENT, null, testSmsRequest.getNumberTo());
|
||||
} catch (ThingsboardException e) {
|
||||
auditLogService.logEntityAction(user.getTenantId(), user.getCustomerId(), user.getId(), user.getName(), user.getId(), user, ActionType.SMS_SENT, e, testSmsRequest.getNumberTo());
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
@ApiOperation(value = "Get repository settings (getRepositorySettings)",
|
||||
|
||||
@ -55,6 +55,10 @@ public class TenantApiUsageState extends BaseApiUsageState {
|
||||
return tenantProfileData.getConfiguration().getProfileThreshold(key);
|
||||
}
|
||||
|
||||
public boolean getProfileFeatureEnabled(ApiUsageRecordKey key) {
|
||||
return tenantProfileData.getConfiguration().getProfileFeatureEnabled(key);
|
||||
}
|
||||
|
||||
public long getProfileWarnThreshold(ApiUsageRecordKey key) {
|
||||
return tenantProfileData.getConfiguration().getWarnThreshold(key);
|
||||
}
|
||||
@ -63,9 +67,11 @@ public class TenantApiUsageState extends BaseApiUsageState {
|
||||
ApiUsageStateValue featureValue = ApiUsageStateValue.ENABLED;
|
||||
for (ApiUsageRecordKey recordKey : ApiUsageRecordKey.getKeys(feature)) {
|
||||
long value = get(recordKey);
|
||||
boolean featureEnabled = getProfileFeatureEnabled(recordKey);
|
||||
long threshold = getProfileThreshold(recordKey);
|
||||
long warnThreshold = getProfileWarnThreshold(recordKey);
|
||||
ApiUsageStateValue tmpValue;
|
||||
if (featureEnabled) {
|
||||
if (threshold == 0 || value == 0 || value < warnThreshold) {
|
||||
tmpValue = ApiUsageStateValue.ENABLED;
|
||||
} else if (value < threshold) {
|
||||
@ -73,6 +79,9 @@ public class TenantApiUsageState extends BaseApiUsageState {
|
||||
} else {
|
||||
tmpValue = ApiUsageStateValue.DISABLED;
|
||||
}
|
||||
} else {
|
||||
tmpValue = ApiUsageStateValue.DISABLED;
|
||||
}
|
||||
featureValue = ApiUsageStateValue.toMoreRestricted(featureValue, tmpValue);
|
||||
}
|
||||
return setFeatureValue(feature, featureValue) ? Pair.of(feature, featureValue) : null;
|
||||
|
||||
@ -20,12 +20,14 @@ import org.springframework.stereotype.Service;
|
||||
import org.thingsboard.rule.engine.api.SmsService;
|
||||
import org.thingsboard.rule.engine.api.util.TbNodeUtils;
|
||||
import org.thingsboard.server.common.data.User;
|
||||
import org.thingsboard.server.common.data.audit.ActionType;
|
||||
import org.thingsboard.server.common.data.exception.ThingsboardErrorCode;
|
||||
import org.thingsboard.server.common.data.exception.ThingsboardException;
|
||||
import org.thingsboard.server.common.data.id.TenantId;
|
||||
import org.thingsboard.server.common.data.security.model.mfa.account.SmsTwoFaAccountConfig;
|
||||
import org.thingsboard.server.common.data.security.model.mfa.provider.SmsTwoFaProviderConfig;
|
||||
import org.thingsboard.server.common.data.security.model.mfa.provider.TwoFaProviderType;
|
||||
import org.thingsboard.server.dao.audit.AuditLogService;
|
||||
import org.thingsboard.server.queue.util.TbCoreComponent;
|
||||
import org.thingsboard.server.service.security.model.SecurityUser;
|
||||
|
||||
@ -36,10 +38,12 @@ import java.util.Map;
|
||||
public class SmsTwoFaProvider extends OtpBasedTwoFaProvider<SmsTwoFaProviderConfig, SmsTwoFaAccountConfig> {
|
||||
|
||||
private final SmsService smsService;
|
||||
private final AuditLogService auditLogService;
|
||||
|
||||
public SmsTwoFaProvider(CacheManager cacheManager, SmsService smsService) {
|
||||
public SmsTwoFaProvider(CacheManager cacheManager, SmsService smsService, AuditLogService auditLogService) {
|
||||
super(cacheManager);
|
||||
this.smsService = smsService;
|
||||
this.auditLogService = auditLogService;
|
||||
}
|
||||
|
||||
|
||||
@ -56,8 +60,13 @@ public class SmsTwoFaProvider extends OtpBasedTwoFaProvider<SmsTwoFaProviderConf
|
||||
);
|
||||
String message = TbNodeUtils.processTemplate(providerConfig.getSmsVerificationMessageTemplate(), messageData);
|
||||
String phoneNumber = accountConfig.getPhoneNumber();
|
||||
|
||||
try {
|
||||
smsService.sendSms(user.getTenantId(), user.getCustomerId(), new String[]{phoneNumber}, message);
|
||||
auditLogService.logEntityAction(user.getTenantId(), user.getCustomerId(), user.getId(), user.getName(), user.getId(), user, ActionType.SMS_SENT, null, phoneNumber);
|
||||
} catch (ThingsboardException e) {
|
||||
auditLogService.logEntityAction(user.getTenantId(), user.getCustomerId(), user.getId(), user.getName(), user.getId(), user, ActionType.SMS_SENT, e, phoneNumber);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@ -34,6 +34,7 @@ import org.thingsboard.server.common.data.sms.config.TestSmsRequest;
|
||||
import org.thingsboard.server.common.stats.TbApiUsageReportClient;
|
||||
import org.thingsboard.server.dao.settings.AdminSettingsService;
|
||||
import org.thingsboard.server.service.apiusage.TbApiUsageStateService;
|
||||
import org.thingsboard.server.service.transport.DefaultTransportApiService;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
import javax.annotation.PreDestroy;
|
||||
@ -86,7 +87,7 @@ public class DefaultSmsService implements SmsService {
|
||||
}
|
||||
}
|
||||
|
||||
private int sendSms(String numberTo, String message) throws ThingsboardException {
|
||||
protected int sendSms(String numberTo, String message) throws ThingsboardException {
|
||||
if (this.smsSender == null) {
|
||||
throw new ThingsboardException("Unable to send SMS: no SMS provider configured!", ThingsboardErrorCode.GENERAL);
|
||||
}
|
||||
@ -130,7 +131,9 @@ public class DefaultSmsService implements SmsService {
|
||||
|
||||
private int sendSms(SmsSender smsSender, String numberTo, String message) throws ThingsboardException {
|
||||
try {
|
||||
return smsSender.sendSms(numberTo, message);
|
||||
int sentSms = smsSender.sendSms(numberTo, message);
|
||||
log.trace("Successfully sent sms to number: {}", numberTo);
|
||||
return sentSms;
|
||||
} catch (Exception e) {
|
||||
throw handleException(e);
|
||||
}
|
||||
|
||||
@ -0,0 +1,164 @@
|
||||
/**
|
||||
* Copyright © 2016-2023 The Thingsboard Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.thingsboard.server.service.sms;
|
||||
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
import com.fasterxml.jackson.databind.node.ObjectNode;
|
||||
import org.junit.After;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.mock.mockito.SpyBean;
|
||||
import org.springframework.test.context.TestPropertySource;
|
||||
import org.testcontainers.shaded.org.apache.commons.lang3.RandomStringUtils;
|
||||
import org.thingsboard.common.util.JacksonUtil;
|
||||
import org.thingsboard.server.common.data.AdminSettings;
|
||||
import org.thingsboard.server.common.data.FeaturesInfo;
|
||||
import org.thingsboard.server.common.data.TenantProfile;
|
||||
import org.thingsboard.server.common.data.id.TenantId;
|
||||
import org.thingsboard.server.common.data.page.PageData;
|
||||
import org.thingsboard.server.common.data.page.PageLink;
|
||||
import org.thingsboard.server.common.data.tenant.profile.DefaultTenantProfileConfiguration;
|
||||
import org.thingsboard.server.common.data.tenant.profile.TenantProfileConfiguration;
|
||||
import org.thingsboard.server.common.data.tenant.profile.TenantProfileData;
|
||||
import org.thingsboard.server.controller.AbstractControllerTest;
|
||||
import org.thingsboard.server.dao.service.DaoSqlTest;
|
||||
import org.thingsboard.server.dao.settings.AdminSettingsService;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.doReturn;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||
|
||||
@DaoSqlTest
|
||||
@TestPropertySource(properties = {
|
||||
"usage.stats.report.enabled=true",
|
||||
"usage.stats.report.interval=1",
|
||||
})
|
||||
public class DefaultSmsServiceTest extends AbstractControllerTest {
|
||||
@SpyBean
|
||||
private DefaultSmsService defaultSmsService;
|
||||
@Autowired
|
||||
private AdminSettingsService adminSettingsService;
|
||||
|
||||
private TenantProfile tenantProfile;
|
||||
|
||||
@Before
|
||||
public void before() throws Exception {
|
||||
loginSysAdmin();
|
||||
prepareSmsSystemSetting();
|
||||
}
|
||||
|
||||
@After
|
||||
public void after() throws Exception {
|
||||
saveTenantProfileWitConfiguration(tenantProfile, new DefaultTenantProfileConfiguration());
|
||||
adminSettingsService.deleteAdminSettingsByTenantIdAndKey(TenantId.SYS_TENANT_ID, "sms");
|
||||
resetTokens();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLimitSmsMessagingByTenantProfileSettings() throws Exception {
|
||||
tenantProfile = getDefaultTenantProfile();
|
||||
|
||||
DefaultTenantProfileConfiguration config = createTenantProfileConfigurationWithSmsLimits(10, true);
|
||||
saveTenantProfileWitConfiguration(tenantProfile, config);
|
||||
|
||||
for (int i = 0; i < 10; i++) {
|
||||
doReturn(1).when(defaultSmsService).sendSms(any(), any());
|
||||
defaultSmsService.sendSms(tenantId, null, new String[]{RandomStringUtils.randomNumeric(10)}, "Message");
|
||||
}
|
||||
|
||||
//wait 1 sec so that api usage state is updated
|
||||
TimeUnit.SECONDS.sleep(1);
|
||||
assertThrows(RuntimeException.class, () -> {
|
||||
defaultSmsService.sendSms(tenantId, null, new String[]{RandomStringUtils.randomNumeric(10)}, "Message");
|
||||
}, "SMS sending is disabled due to API limits!");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLimitSmsMessagingIfSmsDisabled() throws Exception {
|
||||
tenantProfile = getDefaultTenantProfile();
|
||||
|
||||
DefaultTenantProfileConfiguration config = createTenantProfileConfigurationWithSmsLimits(0, false);
|
||||
saveTenantProfileWitConfiguration(tenantProfile, config);
|
||||
|
||||
TimeUnit.SECONDS.sleep(1);
|
||||
assertThrows(RuntimeException.class, () -> {
|
||||
defaultSmsService.sendSms(tenantId, null, new String[]{RandomStringUtils.randomNumeric(10)}, "Message");
|
||||
}, "SMS sending is disabled due to API limits!");
|
||||
|
||||
//enable sms messaging
|
||||
DefaultTenantProfileConfiguration config2 = createTenantProfileConfigurationWithSmsLimits(0, true);
|
||||
saveTenantProfileWitConfiguration(tenantProfile, config2);
|
||||
TimeUnit.SECONDS.sleep(1);
|
||||
|
||||
for (int i = 0; i < 10; i++) {
|
||||
doReturn(1).when(defaultSmsService).sendSms(any(), any());
|
||||
defaultSmsService.sendSms(tenantId, null, new String[]{RandomStringUtils.randomNumeric(10)}, "Message");
|
||||
}
|
||||
}
|
||||
|
||||
private TenantProfile getDefaultTenantProfile() throws Exception {
|
||||
|
||||
PageLink pageLink = new PageLink(17);
|
||||
PageData<TenantProfile> pageData = doGetTypedWithPageLink("/api/tenantProfiles?",
|
||||
new TypeReference<>(){}, pageLink);
|
||||
Assert.assertFalse(pageData.hasNext());
|
||||
Assert.assertEquals(1, pageData.getTotalElements());
|
||||
List<TenantProfile> tenantProfiles = new ArrayList<>(pageData.getData());
|
||||
|
||||
Optional<TenantProfile> optionalDefaultProfile = tenantProfiles.stream().filter(TenantProfile::isDefault).reduce((a, b) -> null);
|
||||
Assert.assertTrue(optionalDefaultProfile.isPresent());
|
||||
|
||||
return optionalDefaultProfile.get();
|
||||
}
|
||||
|
||||
private DefaultTenantProfileConfiguration createTenantProfileConfigurationWithSmsLimits(Integer maxSms, Boolean smsEnabled) {
|
||||
DefaultTenantProfileConfiguration.DefaultTenantProfileConfigurationBuilder builder = DefaultTenantProfileConfiguration.builder();
|
||||
builder.maxSms(maxSms);
|
||||
builder.smsEnabled(smsEnabled);
|
||||
return builder.build();
|
||||
|
||||
}
|
||||
|
||||
private void saveTenantProfileWitConfiguration(TenantProfile tenantProfile, TenantProfileConfiguration tenantProfileConfiguration) {
|
||||
TenantProfileData tenantProfileData = tenantProfile.getProfileData();
|
||||
tenantProfileData.setConfiguration(tenantProfileConfiguration);
|
||||
TenantProfile savedTenantProfile = doPost("/api/tenantProfile", tenantProfile, TenantProfile.class);
|
||||
Assert.assertNotNull(savedTenantProfile);
|
||||
}
|
||||
|
||||
private void prepareSmsSystemSetting() throws Exception {
|
||||
if (doGet("/api/admin/settings/sms").andReturn().getResponse().getStatus() == 404) {
|
||||
AdminSettings adminSettings = new AdminSettings();
|
||||
ObjectNode value = JacksonUtil.newObjectNode();
|
||||
value.put("numberFrom", "+12543223870");
|
||||
value.put("accountSid", "testAcc");
|
||||
value.put("accountToken", "testToken");
|
||||
value.put("type", "TWILIO");
|
||||
adminSettings.setKey("sms");
|
||||
adminSettings.setJsonValue(value);
|
||||
|
||||
doPost("/api/admin/settings", adminSettings).andExpect(status().isOk());
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -38,6 +38,7 @@ public class UsageInfo {
|
||||
private long maxEmails;
|
||||
private long sms;
|
||||
private long maxSms;
|
||||
private boolean smsEnabled;
|
||||
private long alarms;
|
||||
private long maxAlarms;
|
||||
}
|
||||
@ -53,7 +53,8 @@ public enum ActionType {
|
||||
UNASSIGNED_FROM_EDGE(false),
|
||||
ADDED_COMMENT(false),
|
||||
UPDATED_COMMENT(false),
|
||||
DELETED_COMMENT(false);
|
||||
DELETED_COMMENT(false),
|
||||
SMS_SENT(false);
|
||||
|
||||
private final boolean isRead;
|
||||
|
||||
|
||||
@ -57,6 +57,7 @@ public class DefaultTenantProfileConfiguration implements TenantProfileConfigura
|
||||
private long maxDPStorageDays;
|
||||
private int maxRuleNodeExecutionsPerMessage;
|
||||
private long maxEmails;
|
||||
private Boolean smsEnabled;
|
||||
private long maxSms;
|
||||
private long maxCreatedAlarms;
|
||||
|
||||
@ -105,6 +106,16 @@ public class DefaultTenantProfileConfiguration implements TenantProfileConfigura
|
||||
return 0L;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getProfileFeatureEnabled(ApiUsageRecordKey key) {
|
||||
switch (key) {
|
||||
case SMS_EXEC_COUNT:
|
||||
return smsEnabled == null || smsEnabled;
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getWarnThreshold(ApiUsageRecordKey key) {
|
||||
return (long) (getProfileThreshold(key) * (warnThreshold > 0.0 ? warnThreshold : 0.8));
|
||||
|
||||
@ -37,6 +37,9 @@ public interface TenantProfileConfiguration {
|
||||
@JsonIgnore
|
||||
long getProfileThreshold(ApiUsageRecordKey key);
|
||||
|
||||
@JsonIgnore
|
||||
boolean getProfileFeatureEnabled(ApiUsageRecordKey key);
|
||||
|
||||
@JsonIgnore
|
||||
long getWarnThreshold(ApiUsageRecordKey key);
|
||||
|
||||
|
||||
@ -326,6 +326,10 @@ public class AuditLogServiceImpl implements AuditLogService {
|
||||
actionData.put("unassignedEdgeId", strEdgeId);
|
||||
actionData.put("unassignedEdgeName", strEdgeName);
|
||||
break;
|
||||
case SMS_SENT:
|
||||
String number = extractParameter(String.class, 0, additionalInfo);
|
||||
actionData.put("recipientNumber", number);
|
||||
break;
|
||||
}
|
||||
return actionData;
|
||||
}
|
||||
|
||||
@ -69,6 +69,7 @@ public class BasicUsageInfoService implements UsageInfoService {
|
||||
usageInfo.setMaxJsExecutions(profileConfiguration.getMaxJSExecutions());
|
||||
usageInfo.setMaxEmails(profileConfiguration.getMaxEmails());
|
||||
usageInfo.setMaxSms(profileConfiguration.getMaxSms());
|
||||
usageInfo.setSmsEnabled(profileConfiguration.getSmsEnabled());
|
||||
ApiUsageState apiUsageState = apiUsageStateService.findTenantApiUsageState(tenantId);
|
||||
if (apiUsageState != null) {
|
||||
Collection<String> keys = Arrays.asList(
|
||||
|
||||
@ -253,7 +253,22 @@
|
||||
<legend class="group-title">
|
||||
{{ 'tenant-profile.alarms-and-notifications' | translate }} <span translate>tenant-profile.unlimited</span>
|
||||
</legend>
|
||||
<div class="fields-element" fxFlex fxLayout="row" fxLayout.xs="column" fxLayoutGap.gt-xs="16px">
|
||||
<mat-slide-toggle class="slide-toggle-element" fxFlex formControlName="smsEnabled">
|
||||
{{ 'tenant-profile.sms-enabled' | translate }}
|
||||
</mat-slide-toggle>
|
||||
<mat-form-field *ngIf="defaultTenantProfileConfigurationFormGroup.get('smsEnabled').value" fxFlex class="mat-block" appearance="fill">
|
||||
<mat-label translate>tenant-profile.max-sms</mat-label>
|
||||
<input matInput required min="0" step="1"
|
||||
formControlName="maxSms"
|
||||
type="number">
|
||||
<mat-error *ngIf="defaultTenantProfileConfigurationFormGroup.get('maxSms').hasError('required')">
|
||||
{{ 'tenant-profile.max-sms-required' | translate}}
|
||||
</mat-error>
|
||||
<mat-error *ngIf="defaultTenantProfileConfigurationFormGroup.get('maxSms').hasError('min')">
|
||||
{{ 'tenant-profile.max-sms-range' | translate}}
|
||||
</mat-error>
|
||||
</mat-form-field>
|
||||
<div fxFlex fxLayout="row" fxLayout.xs="column" fxLayoutGap.gt-xs="16px">
|
||||
<mat-form-field fxFlex class="mat-block" appearance="fill">
|
||||
<mat-label translate>tenant-profile.max-emails</mat-label>
|
||||
<input matInput required min="0" step="1"
|
||||
@ -279,21 +294,6 @@
|
||||
</mat-error>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div fxFlex fxLayout="row" fxLayout.xs="column" fxLayoutGap.gt-xs="16px">
|
||||
<mat-form-field fxFlex class="mat-block" appearance="fill">
|
||||
<mat-label translate>tenant-profile.max-sms</mat-label>
|
||||
<input matInput required min="0" step="1"
|
||||
formControlName="maxSms"
|
||||
type="number">
|
||||
<mat-error *ngIf="defaultTenantProfileConfigurationFormGroup.get('maxSms').hasError('required')">
|
||||
{{ 'tenant-profile.max-sms-required' | translate}}
|
||||
</mat-error>
|
||||
<mat-error *ngIf="defaultTenantProfileConfigurationFormGroup.get('maxSms').hasError('min')">
|
||||
{{ 'tenant-profile.max-sms-range' | translate}}
|
||||
</mat-error>
|
||||
</mat-form-field>
|
||||
<div fxFlex></div>
|
||||
</div>
|
||||
</fieldset>
|
||||
|
||||
<fieldset class="fields-group">
|
||||
|
||||
@ -18,6 +18,10 @@
|
||||
padding-top: 15px;
|
||||
}
|
||||
|
||||
.slide-toggle-element {
|
||||
margin: 7px 0 13px;
|
||||
}
|
||||
|
||||
.group-title > span {
|
||||
color: rgba(0, 0, 0, 0.54);
|
||||
}
|
||||
|
||||
@ -14,7 +14,7 @@
|
||||
/// limitations under the License.
|
||||
///
|
||||
|
||||
import { Component, forwardRef, Input, OnInit } from '@angular/core';
|
||||
import { Component, forwardRef, Input, OnDestroy, OnInit } from '@angular/core';
|
||||
import { ControlValueAccessor, UntypedFormBuilder, UntypedFormGroup, NG_VALUE_ACCESSOR, Validators } from '@angular/forms';
|
||||
import { Store } from '@ngrx/store';
|
||||
import { AppState } from '@app/core/core.state';
|
||||
@ -22,6 +22,8 @@ import { coerceBooleanProperty } from '@angular/cdk/coercion';
|
||||
import { DefaultTenantProfileConfiguration, TenantProfileConfiguration } from '@shared/models/tenant.model';
|
||||
import { isDefinedAndNotNull } from '@core/utils';
|
||||
import { RateLimitsType } from './rate-limits/rate-limits.models';
|
||||
import { takeUntil } from 'rxjs/operators';
|
||||
import { Subject } from 'rxjs';
|
||||
|
||||
@Component({
|
||||
selector: 'tb-default-tenant-profile-configuration',
|
||||
@ -33,11 +35,12 @@ import { RateLimitsType } from './rate-limits/rate-limits.models';
|
||||
multi: true
|
||||
}]
|
||||
})
|
||||
export class DefaultTenantProfileConfigurationComponent implements ControlValueAccessor, OnInit {
|
||||
export class DefaultTenantProfileConfigurationComponent implements ControlValueAccessor, OnInit, OnDestroy {
|
||||
|
||||
defaultTenantProfileConfigurationFormGroup: UntypedFormGroup;
|
||||
|
||||
private requiredValue: boolean;
|
||||
private destroy$ = new Subject<void>();
|
||||
get required(): boolean {
|
||||
return this.requiredValue;
|
||||
}
|
||||
@ -81,7 +84,8 @@ export class DefaultTenantProfileConfigurationComponent implements ControlValueA
|
||||
maxDPStorageDays: [null, [Validators.required, Validators.min(0)]],
|
||||
maxRuleNodeExecutionsPerMessage: [null, [Validators.required, Validators.min(0)]],
|
||||
maxEmails: [null, [Validators.required, Validators.min(0)]],
|
||||
maxSms: [null, [Validators.required, Validators.min(0)]],
|
||||
maxSms: [null, []],
|
||||
smsEnabled: [null, []],
|
||||
maxCreatedAlarms: [null, [Validators.required, Validators.min(0)]],
|
||||
defaultStorageTtlDays: [null, [Validators.required, Validators.min(0)]],
|
||||
alarmsTtlDays: [null, [Validators.required, Validators.min(0)]],
|
||||
@ -100,11 +104,33 @@ export class DefaultTenantProfileConfigurationComponent implements ControlValueA
|
||||
wsUpdatesPerSessionRateLimit: [null, []],
|
||||
cassandraQueryTenantRateLimitsConfiguration: [null, []]
|
||||
});
|
||||
|
||||
this.defaultTenantProfileConfigurationFormGroup.get('smsEnabled').valueChanges.pipe(
|
||||
takeUntil(this.destroy$)
|
||||
).subscribe((value: boolean) => {
|
||||
this.maxSmsValidation(value);
|
||||
}
|
||||
);
|
||||
|
||||
this.defaultTenantProfileConfigurationFormGroup.valueChanges.subscribe(() => {
|
||||
this.updateModel();
|
||||
});
|
||||
}
|
||||
|
||||
private maxSmsValidation(smsEnabled: boolean) {
|
||||
if (smsEnabled) {
|
||||
this.defaultTenantProfileConfigurationFormGroup.get('maxSms').addValidators([Validators.required, Validators.min(0)]);
|
||||
} else {
|
||||
this.defaultTenantProfileConfigurationFormGroup.get('maxSms').clearValidators();
|
||||
}
|
||||
this.defaultTenantProfileConfigurationFormGroup.get('maxSms').updateValueAndValidity({emitEvent: false});
|
||||
}
|
||||
|
||||
ngOnDestroy(): void {
|
||||
this.destroy$.next();
|
||||
this.destroy$.complete();
|
||||
}
|
||||
|
||||
registerOnChange(fn: any): void {
|
||||
this.propagateChange = fn;
|
||||
}
|
||||
@ -126,6 +152,7 @@ export class DefaultTenantProfileConfigurationComponent implements ControlValueA
|
||||
|
||||
writeValue(value: DefaultTenantProfileConfiguration | null): void {
|
||||
if (isDefinedAndNotNull(value)) {
|
||||
this.maxSmsValidation(value.smsEnabled);
|
||||
this.defaultTenantProfileConfigurationFormGroup.patchValue(value, {emitEvent: false});
|
||||
}
|
||||
}
|
||||
|
||||
@ -62,7 +62,8 @@ export enum ActionType {
|
||||
TIMESERIES_UPDATED = 'TIMESERIES_UPDATED',
|
||||
TIMESERIES_DELETED = 'TIMESERIES_DELETED',
|
||||
ASSIGNED_TO_EDGE = 'ASSIGNED_TO_EDGE',
|
||||
UNASSIGNED_FROM_EDGE = 'UNASSIGNED_FROM_EDGE'
|
||||
UNASSIGNED_FROM_EDGE = 'UNASSIGNED_FROM_EDGE',
|
||||
SMS_SENT = 'SMS_SENT'
|
||||
}
|
||||
|
||||
export enum ActionStatus {
|
||||
@ -105,7 +106,8 @@ export const actionTypeTranslations = new Map<ActionType, string>(
|
||||
[ActionType.TIMESERIES_UPDATED, 'audit-log.type-timeseries-updated'],
|
||||
[ActionType.TIMESERIES_DELETED, 'audit-log.type-timeseries-deleted'],
|
||||
[ActionType.ASSIGNED_TO_EDGE, 'audit-log.type-assigned-to-edge'],
|
||||
[ActionType.UNASSIGNED_FROM_EDGE, 'audit-log.type-unassigned-from-edge']
|
||||
[ActionType.UNASSIGNED_FROM_EDGE, 'audit-log.type-unassigned-from-edge'],
|
||||
[ActionType.SMS_SENT, 'audit-log.type-sms-sent'],
|
||||
]
|
||||
);
|
||||
|
||||
|
||||
@ -54,6 +54,7 @@ export interface DefaultTenantProfileConfiguration {
|
||||
maxRuleNodeExecutionsPerMessage: number;
|
||||
maxEmails: number;
|
||||
maxSms: number;
|
||||
smsEnabled: boolean;
|
||||
maxCreatedAlarms: number;
|
||||
|
||||
tenantServerRestLimitsConfiguration: string;
|
||||
@ -105,6 +106,7 @@ export function createTenantProfileConfiguration(type: TenantProfileType): Tenan
|
||||
maxRuleNodeExecutionsPerMessage: 0,
|
||||
maxEmails: 0,
|
||||
maxSms: 0,
|
||||
smsEnabled: true,
|
||||
maxCreatedAlarms: 0,
|
||||
tenantServerRestLimitsConfiguration: '',
|
||||
customerServerRestLimitsConfiguration: '',
|
||||
|
||||
@ -807,7 +807,8 @@
|
||||
"type-provision-success": "Device provisioned",
|
||||
"type-provision-failure": "Device provisioning was failed",
|
||||
"type-timeseries-updated": "Telemetry updated",
|
||||
"type-timeseries-deleted": "Telemetry deleted"
|
||||
"type-timeseries-deleted": "Telemetry deleted",
|
||||
"type-sms-sent": "SMS sent"
|
||||
},
|
||||
"confirm-on-exit": {
|
||||
"message": "You have unsaved changes. Are you sure you want to leave this page?",
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user