Browse Source

Merge pull request #8464 from thingsboard/improvements/notification-system

Notifications deduplication; upgrade improvements
pull/8483/head
Andrew Shvayka 3 years ago
committed by GitHub
parent
commit
86743b907a
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      application/src/main/java/org/thingsboard/server/controller/AdminController.java
  2. 22
      application/src/main/java/org/thingsboard/server/service/install/DefaultSystemDataLoaderService.java
  3. 43
      application/src/main/java/org/thingsboard/server/service/notification/rule/DefaultNotificationRuleProcessor.java
  4. 8
      application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/NewPlatformVersionTriggerProcessor.java
  5. 2
      application/src/main/java/org/thingsboard/server/service/state/DefaultDeviceStateService.java
  6. 6
      application/src/main/java/org/thingsboard/server/service/sync/vc/DefaultEntitiesVersionControlService.java
  7. 3
      application/src/main/resources/thingsboard.yml
  8. 2
      application/src/test/java/org/thingsboard/server/service/notification/AbstractNotificationApiTest.java
  9. 34
      application/src/test/java/org/thingsboard/server/service/notification/NotificationRuleApiTest.java
  10. 2
      common/dao-api/src/main/java/org/thingsboard/server/dao/notification/NotificationTargetService.java
  11. 1
      common/data/src/main/java/org/thingsboard/server/common/data/CacheConstants.java
  12. 15
      common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/NotificationRuleTriggerType.java
  13. 35
      common/data/src/main/java/org/thingsboard/server/common/data/sync/vc/VcUtils.java
  14. 2
      dao/src/main/java/org/thingsboard/server/dao/notification/DefaultNotificationSettingsService.java
  15. 5
      dao/src/main/java/org/thingsboard/server/dao/notification/DefaultNotificationTargetService.java
  16. 2
      dao/src/main/java/org/thingsboard/server/dao/notification/DefaultNotifications.java
  17. 3
      dao/src/main/java/org/thingsboard/server/dao/notification/NotificationTargetDao.java
  18. 5
      dao/src/main/java/org/thingsboard/server/dao/sql/notification/JpaNotificationTargetDao.java
  19. 2
      dao/src/main/java/org/thingsboard/server/dao/sql/notification/NotificationTargetRepository.java

2
application/src/main/java/org/thingsboard/server/controller/AdminController.java

@ -51,6 +51,7 @@ import org.thingsboard.server.common.data.sms.config.TestSmsRequest;
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.settings.AdminSettingsService;
import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.security.auth.jwt.settings.JwtSettingsService;
@ -305,6 +306,7 @@ public class AdminController extends BaseController {
@PreAuthorize("hasAuthority('TENANT_ADMIN')")
@PostMapping("/autoCommitSettings")
public AutoCommitSettings saveAutoCommitSettings(@RequestBody AutoCommitSettings settings) throws ThingsboardException {
settings.values().forEach(config -> VcUtils.checkBranchName(config.getBranch()));
accessControlService.checkPermission(getCurrentUser(), Resource.VERSION_CONTROL, Operation.WRITE);
return autoCommitSettingsService.save(getTenantId(), settings);
}

22
application/src/main/java/org/thingsboard/server/service/install/DefaultSystemDataLoaderService.java

@ -21,6 +21,7 @@ import com.google.common.util.concurrent.FutureCallback;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import lombok.Getter;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
@ -110,6 +111,8 @@ import java.util.List;
import java.util.TreeMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
@Service
@Profile("install")
@ -682,18 +685,29 @@ public class DefaultSystemDataLoaderService implements SystemDataLoaderService {
}
@Override
@SneakyThrows
public void createDefaultNotificationConfigs() {
log.info("Creating default notification configs for system admin");
if (notificationTargetService.findNotificationTargetsByTenantId(TenantId.SYS_TENANT_ID, new PageLink(1)).getTotalElements() == 0) {
if (notificationTargetService.countNotificationTargetsByTenantId(TenantId.SYS_TENANT_ID) == 0) {
notificationSettingsService.createDefaultNotificationConfigs(TenantId.SYS_TENANT_ID);
}
PageDataIterable<TenantId> tenants = new PageDataIterable<>(tenantService::findTenantsIds, 500);
ExecutorService executor = Executors.newFixedThreadPool(Math.max(Runtime.getRuntime().availableProcessors(), 4));
log.info("Creating default notification configs for all tenants");
AtomicInteger count = new AtomicInteger();
for (TenantId tenantId : tenants) {
if (notificationTargetService.findNotificationTargetsByTenantId(tenantId, new PageLink(1)).getTotalElements() == 0) {
notificationSettingsService.createDefaultNotificationConfigs(tenantId);
}
executor.submit(() -> {
if (notificationTargetService.countNotificationTargetsByTenantId(tenantId) == 0) {
notificationSettingsService.createDefaultNotificationConfigs(tenantId);
int n = count.incrementAndGet();
if (n % 500 == 0) {
log.info("{} tenants processed", n);
}
}
});
}
executor.shutdown();
executor.awaitTermination(Integer.MAX_VALUE, TimeUnit.SECONDS);
}
}

43
application/src/main/java/org/thingsboard/server/service/notification/rule/DefaultNotificationRuleProcessor.java

@ -15,13 +15,17 @@
*/
package org.thingsboard.server.service.notification.rule;
import lombok.Data;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.Cache;
import org.springframework.cache.CacheManager;
import org.springframework.context.annotation.Lazy;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Service;
import org.thingsboard.rule.engine.api.NotificationCenter;
import org.thingsboard.server.common.data.CacheConstants;
import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.id.NotificationRequestId;
@ -49,6 +53,8 @@ import org.thingsboard.server.service.notification.rule.cache.NotificationRulesC
import org.thingsboard.server.service.notification.rule.trigger.NotificationRuleTriggerProcessor;
import org.thingsboard.server.service.notification.rule.trigger.RuleEngineMsgNotificationRuleTriggerProcessor;
import javax.annotation.PostConstruct;
import java.io.Serializable;
import java.util.Collection;
import java.util.EnumMap;
import java.util.HashMap;
@ -71,9 +77,19 @@ public class DefaultNotificationRuleProcessor implements NotificationRuleProcess
@Autowired @Lazy
private NotificationCenter notificationCenter;
private final NotificationExecutorService notificationExecutor;
private final CacheManager cacheManager;
private Cache sentNotifications;
private final Map<NotificationRuleTriggerType, NotificationRuleTriggerProcessor> triggerProcessors = new EnumMap<>(NotificationRuleTriggerType.class);
@PostConstruct
private void init() {
sentNotifications = cacheManager.getCache(CacheConstants.SENT_NOTIFICATIONS_CACHE);
if (sentNotifications == null) {
throw new IllegalStateException("Sent notifications cache is not set up");
}
}
@Override
public void process(NotificationRuleTrigger trigger) {
NotificationRuleTriggerType triggerType = trigger.getType();
@ -126,6 +142,9 @@ public class DefaultNotificationRuleProcessor implements NotificationRuleProcess
log.debug("[{}] Rate limit for notification requests per rule was exceeded (rule '{}')", rule.getTenantId(), rule.getName());
return;
}
if (trigger.getType().isDeduplicate() && alreadySent(rule.getId(), trigger)) {
return;
}
NotificationInfo notificationInfo = constructNotificationInfo(trigger, triggerConfig);
rule.getRecipientsConfig().getTargetsTable().forEach((delay, targets) -> {
@ -175,6 +194,23 @@ public class DefaultNotificationRuleProcessor implements NotificationRuleProcess
return triggerProcessors.get(triggerConfig.getTriggerType()).constructNotificationInfo(trigger);
}
private boolean alreadySent(NotificationRuleId ruleId, NotificationRuleTrigger trigger) {
String key = ruleId + "_" + trigger.getOriginatorEntityId();
SentNotification sent = sentNotifications.get(key, SentNotification.class);
boolean alreadySent;
if (sent != null && sent.getTrigger().equals(trigger)) {
alreadySent = true;
log.debug("Notification for {} trigger was already sent, ignoring", trigger.getType());
// updating cache anyway so that the value is not removed by ttl
} else {
alreadySent = false;
sent = new SentNotification(trigger);
}
log.trace("[{}] Putting to sentNotifications cache: {}", ruleId, trigger);
sentNotifications.put(key, sent);
return alreadySent;
}
@EventListener(ComponentLifecycleMsg.class)
public void onNotificationRuleDeleted(ComponentLifecycleMsg componentLifecycleMsg) {
if (componentLifecycleMsg.getEvent() != ComponentLifecycleEvent.DELETED ||
@ -209,4 +245,11 @@ public class DefaultNotificationRuleProcessor implements NotificationRuleProcess
RuleEngineMsgTrigger.msgTypeToTriggerType = ruleEngineMsgTypeToTriggerType;
}
@Data
private static class SentNotification implements Serializable {
private static final long serialVersionUID = 38973480405095422L;
private final NotificationRuleTrigger trigger;
}
}

8
application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/NewPlatformVersionTriggerProcessor.java

@ -18,26 +18,18 @@ package org.thingsboard.server.service.notification.rule.trigger;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.thingsboard.server.common.data.UpdateMessage;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.notification.info.NewPlatformVersionNotificationInfo;
import org.thingsboard.server.common.data.notification.info.RuleOriginatedNotificationInfo;
import org.thingsboard.server.common.data.notification.rule.trigger.NewPlatformVersionNotificationRuleTriggerConfig;
import org.thingsboard.server.common.data.notification.rule.trigger.NotificationRuleTriggerType;
import org.thingsboard.server.common.msg.notification.trigger.NewPlatformVersionTrigger;
import org.thingsboard.server.common.msg.queue.ServiceType;
import org.thingsboard.server.queue.discovery.PartitionService;
@Service
@RequiredArgsConstructor
public class NewPlatformVersionTriggerProcessor implements NotificationRuleTriggerProcessor<NewPlatformVersionTrigger, NewPlatformVersionNotificationRuleTriggerConfig> {
private final PartitionService partitionService;
@Override
public boolean matchesFilter(NewPlatformVersionTrigger trigger, NewPlatformVersionNotificationRuleTriggerConfig triggerConfig) {
if (!partitionService.isMyPartition(ServiceType.TB_CORE, TenantId.SYS_TENANT_ID, TenantId.SYS_TENANT_ID)) {
return false;
}
return trigger.getUpdateInfo().isUpdateAvailable();
}

2
application/src/main/java/org/thingsboard/server/service/state/DefaultDeviceStateService.java

@ -473,7 +473,7 @@ public class DefaultDeviceStateService extends AbstractPartitionBasedService<Dev
apiUsageReportClient.report(tenantId, null, ApiUsageRecordKey.ACTIVE_DEVICES, active);
apiUsageReportClient.report(tenantId, null, ApiUsageRecordKey.INACTIVE_DEVICES, inactive);
if (active > 0) {
log.info("[{}] Active devices: {}, inactive devices: {}", tenantId, active, inactive);
log.debug("[{}] Active devices: {}, inactive devices: {}", tenantId, active, inactive);
}
});
} catch (Throwable t) {

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

@ -22,6 +22,7 @@ import com.google.common.util.concurrent.MoreExecutors;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.support.TransactionTemplate;
@ -32,7 +33,6 @@ import org.thingsboard.common.util.ThingsBoardExecutors;
import org.thingsboard.server.cache.TbTransactionalCache;
import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.ExportableEntity;
import org.thingsboard.server.common.data.StringUtils;
import org.thingsboard.server.common.data.User;
import org.thingsboard.server.common.data.audit.ActionType;
import org.thingsboard.server.common.data.exception.ThingsboardErrorCode;
@ -101,6 +101,7 @@ import java.util.function.Function;
import java.util.stream.Collectors;
import static com.google.common.util.concurrent.Futures.transform;
import static org.thingsboard.server.common.data.sync.vc.VcUtils.checkBranchName;
@Service
@TbCoreComponent
@ -138,6 +139,7 @@ public class DefaultEntitiesVersionControlService implements EntitiesVersionCont
@SuppressWarnings("UnstableApiUsage")
@Override
public ListenableFuture<UUID> saveEntitiesVersion(User user, VersionCreateRequest request) throws Exception {
checkBranchName(request.getBranch());
var pendingCommit = gitServiceQueue.prepareCommit(user, request);
DonAsynchron.withCallback(pendingCommit, commit -> {
cachePut(commit.getTxId(), new VersionCreationResult());
@ -504,6 +506,7 @@ public class DefaultEntitiesVersionControlService implements EntitiesVersionCont
@Override
public ListenableFuture<RepositorySettings> saveVersionControlSettings(TenantId tenantId, RepositorySettings versionControlSettings) {
checkBranchName(versionControlSettings.getDefaultBranch());
var restoredSettings = this.repositorySettingsService.restore(tenantId, versionControlSettings);
try {
var future = gitServiceQueue.initRepository(tenantId, restoredSettings);
@ -525,6 +528,7 @@ public class DefaultEntitiesVersionControlService implements EntitiesVersionCont
@Override
public ListenableFuture<Void> checkVersionControlAccess(TenantId tenantId, RepositorySettings settings) throws ThingsboardException {
checkBranchName(settings.getDefaultBranch());
settings = this.repositorySettingsService.restore(tenantId, settings);
try {
return gitServiceQueue.testRepository(tenantId, settings);

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

@ -449,6 +449,9 @@ cache:
notificationSettings:
timeToLiveInMinutes: "${CACHE_SPECS_NOTIFICATION_SETTINGS_TTL:10}"
maxSize: "${CACHE_SPECS_NOTIFICATION_SETTINGS_MAX_SIZE:1000}"
sentNotifications:
timeToLiveInMinutes: "${CACHE_SPECS_SENT_NOTIFICATIONS_TTL:1440}"
maxSize: "${CACHE_SPECS_SENT_NOTIFICATIONS_MAX_SIZE:10000}"
attributes:
timeToLiveInMinutes: "${CACHE_SPECS_ATTRIBUTES_TTL:1440}"
maxSize: "${CACHE_SPECS_ATTRIBUTES_MAX_SIZE:100000}"

2
application/src/test/java/org/thingsboard/server/service/notification/AbstractNotificationApiTest.java

@ -204,7 +204,7 @@ public abstract class AbstractNotificationApiTest extends AbstractControllerTest
NotificationTemplate template = createNotificationTemplate(NotificationType.valueOf(triggerConfig.getTriggerType().toString()), subject, text, NotificationDeliveryMethod.WEB);
NotificationRule rule = new NotificationRule();
rule.setName(triggerConfig.getTriggerType() + " [" + Arrays.toString(targets) + "]");
rule.setName(triggerConfig.getTriggerType() + " " + Arrays.toString(targets));
rule.setTemplateId(template.getId());
rule.setTriggerType(triggerConfig.getTriggerType());
rule.setTriggerConfig(triggerConfig);

34
application/src/test/java/org/thingsboard/server/service/notification/NotificationRuleApiTest.java

@ -28,6 +28,7 @@ import org.thingsboard.server.common.data.DataConstants;
import org.thingsboard.server.common.data.Device;
import org.thingsboard.server.common.data.DeviceProfile;
import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.UpdateMessage;
import org.thingsboard.server.common.data.User;
import org.thingsboard.server.common.data.alarm.Alarm;
import org.thingsboard.server.common.data.alarm.AlarmSearchStatus;
@ -55,6 +56,7 @@ import org.thingsboard.server.common.data.notification.rule.trigger.AlarmNotific
import org.thingsboard.server.common.data.notification.rule.trigger.AlarmNotificationRuleTriggerConfig.AlarmAction;
import org.thingsboard.server.common.data.notification.rule.trigger.EntitiesLimitNotificationRuleTriggerConfig;
import org.thingsboard.server.common.data.notification.rule.trigger.EntityActionNotificationRuleTriggerConfig;
import org.thingsboard.server.common.data.notification.rule.trigger.NewPlatformVersionNotificationRuleTriggerConfig;
import org.thingsboard.server.common.data.notification.rule.trigger.NotificationRuleTriggerType;
import org.thingsboard.server.common.data.notification.targets.NotificationTarget;
import org.thingsboard.server.common.data.notification.template.NotificationTemplate;
@ -66,9 +68,11 @@ import org.thingsboard.server.common.data.query.FilterPredicateValue;
import org.thingsboard.server.common.data.rule.RuleChain;
import org.thingsboard.server.common.data.rule.RuleChainMetaData;
import org.thingsboard.server.common.data.security.Authority;
import org.thingsboard.server.common.msg.notification.trigger.NewPlatformVersionTrigger;
import org.thingsboard.server.dao.notification.NotificationRequestService;
import org.thingsboard.server.dao.rule.RuleChainService;
import org.thingsboard.server.dao.service.DaoSqlTest;
import org.thingsboard.server.queue.notification.NotificationRuleProcessor;
import org.thingsboard.server.service.apiusage.limits.LimitedApi;
import org.thingsboard.server.service.apiusage.limits.RateLimitService;
import org.thingsboard.server.service.telemetry.AlarmSubscriptionService;
@ -102,6 +106,8 @@ public class NotificationRuleApiTest extends AbstractNotificationApiTest {
private RateLimitService rateLimitService;
@Autowired
private RuleChainService ruleChainService;
@Autowired
private NotificationRuleProcessor notificationRuleProcessor;
@Before
public void beforeEach() throws Exception {
@ -433,6 +439,34 @@ public class NotificationRuleApiTest extends AbstractNotificationApiTest {
assertThat(getWsClient().getLastCountUpdate().getTotalUnreadCount()).isEqualTo(notificationRequestsLimit);
}
@Test
public void testNotificationsDeduplication() throws Exception {
loginSysAdmin();
NewPlatformVersionNotificationRuleTriggerConfig triggerConfig = new NewPlatformVersionNotificationRuleTriggerConfig();
createNotificationRule(triggerConfig, "Test", "Test", createNotificationTarget(tenantAdminUserId).getId());
loginTenantAdmin();
assertThat(getMyNotifications(false, 100)).size().isZero();
for (int i = 1; i <= 10; i++) {
notificationRuleProcessor.process(NewPlatformVersionTrigger.builder()
.updateInfo(new UpdateMessage(true, "test", "test",
"test", "test", "test"))
.build());
TimeUnit.MILLISECONDS.sleep(300);
}
TimeUnit.SECONDS.sleep(5);
assertThat(getMyNotifications(false, 100)).size().isOne();
notificationRuleProcessor.process(NewPlatformVersionTrigger.builder()
.updateInfo(new UpdateMessage(true, "CHANGED", "test",
"test", "test", "test"))
.build());
await().atMost(5, TimeUnit.SECONDS)
.untilAsserted(() -> {
assertThat(getMyNotifications(false, 100)).size().isEqualTo(2);
});
}
private <R> R checkNotificationAfter(Callable<R> action, BiConsumer<Notification, R> check) throws Exception {
if (getWsClient().getLastDataUpdate() == null) {
getWsClient().subscribeForUnreadNotifications(10).waitForReply(true);

2
common/dao-api/src/main/java/org/thingsboard/server/dao/notification/NotificationTargetService.java

@ -50,4 +50,6 @@ public interface NotificationTargetService {
void deleteNotificationTargetsByTenantId(TenantId tenantId);
long countNotificationTargetsByTenantId(TenantId tenantId);
}

1
common/data/src/main/java/org/thingsboard/server/common/data/CacheConstants.java

@ -30,6 +30,7 @@ public class CacheConstants {
public static final String TENANTS_EXIST_CACHE = "tenantsExist";
public static final String DEVICE_PROFILE_CACHE = "deviceProfiles";
public static final String NOTIFICATION_SETTINGS_CACHE = "notificationSettings";
public static final String SENT_NOTIFICATIONS_CACHE = "sentNotifications";
public static final String ASSET_PROFILE_CACHE = "assetProfiles";
public static final String ATTRIBUTES_CACHE = "attributes";

15
common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/NotificationRuleTriggerType.java

@ -16,8 +16,10 @@
package org.thingsboard.server.common.data.notification.rule.trigger;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
@Getter
@RequiredArgsConstructor
public enum NotificationRuleTriggerType {
ENTITY_ACTION,
@ -26,18 +28,15 @@ public enum NotificationRuleTriggerType {
ALARM_ASSIGNMENT,
DEVICE_ACTIVITY,
RULE_ENGINE_COMPONENT_LIFECYCLE_EVENT,
NEW_PLATFORM_VERSION(false),
ENTITIES_LIMIT(false),
API_USAGE_LIMIT(false);
NEW_PLATFORM_VERSION(false, true),
ENTITIES_LIMIT(false, false),
API_USAGE_LIMIT(false, false);
private final boolean tenantLevel;
NotificationRuleTriggerType(boolean tenantLevel) {
this.tenantLevel = tenantLevel;
}
private final boolean deduplicate;
NotificationRuleTriggerType() {
this(true);
this(true, false);
}
}

35
common/data/src/main/java/org/thingsboard/server/common/data/sync/vc/VcUtils.java

@ -0,0 +1,35 @@
/**
* 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.common.data.sync.vc;
import org.apache.commons.lang3.StringUtils;
public class VcUtils {
private VcUtils() {}
public static void checkBranchName(String branch) {
if (StringUtils.isEmpty(branch)) return;
boolean invalid = StringUtils.containsWhitespace(branch) ||
StringUtils.containsAny(branch, "..", "~", "^", ":", "\\") ||
StringUtils.endsWithAny(branch, "/", ".lock");
if (invalid) {
throw new IllegalArgumentException("Branch name is invalid");
}
}
}

2
dao/src/main/java/org/thingsboard/server/dao/notification/DefaultNotificationSettingsService.java

@ -98,7 +98,7 @@ public class DefaultNotificationSettingsService implements NotificationSettingsS
defaultNotifications.create(tenantId, DefaultNotifications.apiFeatureDisabledForSysadmin, sysAdmins.getId());
defaultNotifications.create(tenantId, DefaultNotifications.apiFeatureDisabledForTenant, affectedTenantAdmins.getId());
defaultNotifications.create(tenantId, DefaultNotifications.newPlatformVersion, sysAdmins.getId(), tenantAdmins.getId());
defaultNotifications.create(tenantId, DefaultNotifications.newPlatformVersion, sysAdmins.getId());
return;
}

5
dao/src/main/java/org/thingsboard/server/dao/notification/DefaultNotificationTargetService.java

@ -192,6 +192,11 @@ public class DefaultNotificationTargetService extends AbstractEntityService impl
notificationTargetDao.removeByTenantId(tenantId);
}
@Override
public long countNotificationTargetsByTenantId(TenantId tenantId) {
return notificationTargetDao.countByTenantId(tenantId);
}
@Override
public Optional<HasId<?>> findEntity(TenantId tenantId, EntityId entityId) {
return Optional.ofNullable(findNotificationTargetById(tenantId, new NotificationTargetId(entityId.getId())));

2
dao/src/main/java/org/thingsboard/server/dao/notification/DefaultNotifications.java

@ -143,7 +143,7 @@ public class DefaultNotifications {
.rule(DefaultRule.builder()
.name("New platform version")
.triggerConfig(new NewPlatformVersionNotificationRuleTriggerConfig())
.description("Send notification to system admins and tenant admins when new platform version is available")
.description("Send notification to system admins when new platform version is available")
.build())
.build();

3
dao/src/main/java/org/thingsboard/server/dao/notification/NotificationTargetDao.java

@ -22,10 +22,11 @@ import org.thingsboard.server.common.data.notification.targets.NotificationTarge
import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.PageLink;
import org.thingsboard.server.dao.Dao;
import org.thingsboard.server.dao.TenantEntityDao;
import java.util.List;
public interface NotificationTargetDao extends Dao<NotificationTarget> {
public interface NotificationTargetDao extends Dao<NotificationTarget>, TenantEntityDao {
PageData<NotificationTarget> findByTenantIdAndPageLink(TenantId tenantId, PageLink pageLink);

5
dao/src/main/java/org/thingsboard/server/dao/sql/notification/JpaNotificationTargetDao.java

@ -71,6 +71,11 @@ public class JpaNotificationTargetDao extends JpaAbstractDao<NotificationTargetE
notificationTargetRepository.deleteByTenantId(tenantId.getId());
}
@Override
public Long countByTenantId(TenantId tenantId) {
return notificationTargetRepository.countByTenantId(tenantId.getId());
}
@Override
protected Class<NotificationTargetEntity> getEntityClass() {
return NotificationTargetEntity.class;

2
dao/src/main/java/org/thingsboard/server/dao/sql/notification/NotificationTargetRepository.java

@ -50,4 +50,6 @@ public interface NotificationTargetRepository extends JpaRepository<Notification
@Transactional
void deleteByTenantId(UUID tenantId);
long countByTenantId(UUID tenantId);
}

Loading…
Cancel
Save