diff --git a/application/src/main/java/org/thingsboard/server/controller/NotificationController.java b/application/src/main/java/org/thingsboard/server/controller/NotificationController.java index a7072f6a9d..7fac0fe393 100644 --- a/application/src/main/java/org/thingsboard/server/controller/NotificationController.java +++ b/application/src/main/java/org/thingsboard/server/controller/NotificationController.java @@ -298,7 +298,7 @@ public class NotificationController extends BaseController { if (targetType == NotificationTargetType.PLATFORM_USERS) { PageData recipients = notificationTargetService.findRecipientsForNotificationTargetConfig(user.getTenantId(), (PlatformUsersNotificationTargetConfig) target.getConfiguration(), new PageLink(recipientsPreviewSize, 0, null, - new SortOrder("createdTime", SortOrder.Direction.DESC))); + SortOrder.byCreatedTimeDesc)); recipientsCount = (int) recipients.getTotalElements(); recipientsPart = recipients.getData().stream().map(r -> (NotificationRecipient) r).collect(Collectors.toList()); } else { @@ -451,7 +451,7 @@ public class NotificationController extends BaseController { @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") public UserNotificationSettings getUserNotificationSettings(@AuthenticationPrincipal SecurityUser user) { return notificationSettingsService.getUserNotificationSettings(user.getTenantId(), - userService.findUserById(user.getTenantId(), user.getId())); + userService.findUserById(user.getTenantId(), user.getId()), true); } } diff --git a/application/src/main/java/org/thingsboard/server/service/notification/DefaultNotificationCenter.java b/application/src/main/java/org/thingsboard/server/service/notification/DefaultNotificationCenter.java index 71a842b441..8f6a6dc177 100644 --- a/application/src/main/java/org/thingsboard/server/service/notification/DefaultNotificationCenter.java +++ b/application/src/main/java/org/thingsboard/server/service/notification/DefaultNotificationCenter.java @@ -37,7 +37,6 @@ import org.thingsboard.server.common.data.notification.NotificationRequestConfig import org.thingsboard.server.common.data.notification.NotificationRequestStats; import org.thingsboard.server.common.data.notification.NotificationRequestStatus; import org.thingsboard.server.common.data.notification.NotificationStatus; -import org.thingsboard.server.common.data.notification.NotificationType; import org.thingsboard.server.common.data.notification.info.RuleOriginatedNotificationInfo; import org.thingsboard.server.common.data.notification.settings.NotificationSettings; import org.thingsboard.server.common.data.notification.settings.UserNotificationSettings; @@ -240,10 +239,9 @@ public class DefaultNotificationCenter extends AbstractSubscriptionService imple if (ctx.getStats().contains(deliveryMethod, recipient.getId())) { throw new AlreadySentException(); } - if (recipient instanceof User) { - NotificationType notificationType = ctx.getNotificationTemplate().getNotificationType(); - UserNotificationSettings settings = notificationSettingsService.getUserNotificationSettings(ctx.getTenantId(), (User) recipient); - Set enabledDeliveryMethods = settings.getEnabledDeliveryMethods(notificationType); + if (recipient instanceof User && ctx.getRequest().getRuleId() != null) { + UserNotificationSettings settings = notificationSettingsService.getUserNotificationSettings(ctx.getTenantId(), (User) recipient, false); + Set enabledDeliveryMethods = settings.getEnabledDeliveryMethods(ctx.getRequest().getRuleId()); if (!enabledDeliveryMethods.contains(deliveryMethod)) { throw new RuntimeException("User disabled " + deliveryMethod.getName() + " notifications of this type"); } diff --git a/common/dao-api/src/main/java/org/thingsboard/server/dao/notification/NotificationSettingsService.java b/common/dao-api/src/main/java/org/thingsboard/server/dao/notification/NotificationSettingsService.java index bb53b1a828..33771ab71e 100644 --- a/common/dao-api/src/main/java/org/thingsboard/server/dao/notification/NotificationSettingsService.java +++ b/common/dao-api/src/main/java/org/thingsboard/server/dao/notification/NotificationSettingsService.java @@ -29,7 +29,7 @@ public interface NotificationSettingsService { void saveUserNotificationSettings(TenantId tenantId, UserId userId, UserNotificationSettings settings); - UserNotificationSettings getUserNotificationSettings(TenantId tenantId, User user); + UserNotificationSettings getUserNotificationSettings(TenantId tenantId, User user, boolean format); void createDefaultNotificationConfigs(TenantId tenantId); diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/notification/settings/UserNotificationSettings.java b/common/data/src/main/java/org/thingsboard/server/common/data/notification/settings/UserNotificationSettings.java index efe5194585..9e2f2740ab 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/notification/settings/UserNotificationSettings.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/notification/settings/UserNotificationSettings.java @@ -18,47 +18,55 @@ package org.thingsboard.server.common.data.notification.settings; import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.Data; +import org.thingsboard.server.common.data.id.NotificationRuleId; import org.thingsboard.server.common.data.notification.NotificationDeliveryMethod; -import org.thingsboard.server.common.data.notification.NotificationType; -import org.thingsboard.server.common.data.util.CollectionsUtil; +import org.thingsboard.server.common.data.notification.rule.NotificationRule; +import javax.validation.Valid; +import javax.validation.constraints.NotNull; import java.util.Collections; -import java.util.Map; +import java.util.List; import java.util.Set; +import java.util.UUID; @Data public class UserNotificationSettings { - private final Map prefs; + @NotNull + @Valid + private final List prefs; + + public static final UserNotificationSettings DEFAULT = new UserNotificationSettings(Collections.emptyList()); @JsonCreator - public UserNotificationSettings(@JsonProperty("prefs") Map prefs) { + public UserNotificationSettings(@JsonProperty("prefs") List prefs) { this.prefs = prefs; } - public static final UserNotificationSettings DEFAULT = new UserNotificationSettings(Collections.emptyMap()); - - public Set getEnabledDeliveryMethods(NotificationType notificationType) { - NotificationTypePrefs prefs; - if (this.prefs == null || (prefs = this.prefs.get(notificationType)) == null) { - return NotificationDeliveryMethod.values; - } - if (prefs.isEnabled()) { - Set deliveryMethods = prefs.getEnabledDeliveryMethods(); - if (CollectionsUtil.isNotEmpty(deliveryMethods)) { - return deliveryMethods; - } else { - return NotificationDeliveryMethod.values; - } - } else { - return Collections.emptySet(); - } + public Set getEnabledDeliveryMethods(NotificationRuleId ruleId) { + return prefs.stream() + .filter(pref -> pref.getRuleId().equals(ruleId.getId())).findFirst() + .map(pref -> pref.isEnabled() ? pref.getEnabledDeliveryMethods() : Collections.emptySet()) + .orElse(NotificationDeliveryMethod.values); } @Data - public static class NotificationTypePrefs { + public static class NotificationPref { + @NotNull + private UUID ruleId; + private String ruleName; private boolean enabled; + @NotNull private Set enabledDeliveryMethods; + + public static NotificationPref createDefault(NotificationRule rule) { + NotificationPref pref = new NotificationPref(); + pref.setRuleId(rule.getUuidId()); + pref.setRuleName(rule.getName()); + pref.setEnabled(true); + pref.setEnabledDeliveryMethods(NotificationDeliveryMethod.values); + return pref; + } } } diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/page/SortOrder.java b/common/data/src/main/java/org/thingsboard/server/common/data/page/SortOrder.java index 5c540995aa..b99cb93eed 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/page/SortOrder.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/page/SortOrder.java @@ -36,4 +36,6 @@ public class SortOrder { ASC, DESC } + public static final SortOrder byCreatedTimeDesc = new SortOrder("createdTime", Direction.DESC); + } diff --git a/dao/src/main/java/org/thingsboard/server/dao/notification/DefaultNotificationSettingsService.java b/dao/src/main/java/org/thingsboard/server/dao/notification/DefaultNotificationSettingsService.java index 90ccd095d6..af9687840a 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/notification/DefaultNotificationSettingsService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/notification/DefaultNotificationSettingsService.java @@ -20,6 +20,7 @@ import com.fasterxml.jackson.databind.node.ObjectNode; import lombok.RequiredArgsConstructor; import org.springframework.cache.annotation.CacheEvict; import org.springframework.cache.annotation.Cacheable; +import org.springframework.data.domain.Sort; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Propagation; import org.springframework.transaction.annotation.Transactional; @@ -30,8 +31,10 @@ import org.thingsboard.server.common.data.User; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.id.UserId; import org.thingsboard.server.common.data.notification.NotificationType; +import org.thingsboard.server.common.data.notification.rule.NotificationRule; import org.thingsboard.server.common.data.notification.settings.NotificationSettings; import org.thingsboard.server.common.data.notification.settings.UserNotificationSettings; +import org.thingsboard.server.common.data.notification.settings.UserNotificationSettings.NotificationPref; import org.thingsboard.server.common.data.notification.targets.NotificationTarget; import org.thingsboard.server.common.data.notification.targets.platform.AffectedTenantAdministratorsFilter; import org.thingsboard.server.common.data.notification.targets.platform.AffectedUserFilter; @@ -43,12 +46,19 @@ import org.thingsboard.server.common.data.notification.targets.platform.TenantAd import org.thingsboard.server.common.data.notification.targets.platform.UsersFilter; import org.thingsboard.server.common.data.notification.targets.platform.UsersFilterType; import org.thingsboard.server.common.data.page.PageLink; +import org.thingsboard.server.common.data.page.SortOrder; import org.thingsboard.server.dao.settings.AdminSettingsService; import org.thingsboard.server.dao.user.UserService; +import java.util.ArrayList; import java.util.Collections; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.Optional; +import java.util.UUID; + +import static java.util.function.Predicate.not; @Service @RequiredArgsConstructor @@ -57,6 +67,7 @@ public class DefaultNotificationSettingsService implements NotificationSettingsS private final AdminSettingsService adminSettingsService; private final NotificationTargetService notificationTargetService; private final NotificationTemplateService notificationTemplateService; + private final NotificationRuleService notificationRuleService; private final DefaultNotifications defaultNotifications; private final UserService userService; @@ -98,13 +109,42 @@ public class DefaultNotificationSettingsService implements NotificationSettingsS } @Override - public UserNotificationSettings getUserNotificationSettings(TenantId tenantId, User user) { - // TODO: decide whether to use user_settings or store it in the additionalInfo not to make more DB requests - JsonNode notificationSettings = user.getAdditionalInfo().get("notificationSettings"); - if (notificationSettings == null || notificationSettings.isNull()) { - return UserNotificationSettings.DEFAULT; + public UserNotificationSettings getUserNotificationSettings(TenantId tenantId, User user, boolean format) { + UserNotificationSettings settings = Optional.ofNullable(user.getAdditionalInfo().get("notificationSettings")) + .filter(not(JsonNode::isNull)) + .map(json -> JacksonUtil.treeToValue(json, UserNotificationSettings.class)) + .orElse(null); + if (!format) { + if (settings != null) { + return settings; + } else { + return UserNotificationSettings.DEFAULT; + } + } + + Map rules = new HashMap<>(); + notificationRuleService.findNotificationRulesByTenantId(tenantId, new PageLink(Integer.MAX_VALUE, 0,null, SortOrder.byCreatedTimeDesc)) + .getData().forEach(rule -> rules.put(rule.getUuidId(), rule)); + + List prefs = new ArrayList<>(); + if (settings == null) { + rules.values().forEach(rule -> { + prefs.add(NotificationPref.createDefault(rule)); + }); + } else { + settings.getPrefs().forEach(pref -> { + NotificationRule rule = rules.remove(pref.getRuleId()); + if (rule == null) { + return; + } + pref.setRuleName(rule.getName()); + prefs.add(pref); + }); + rules.values().forEach(rule -> { + prefs.add(NotificationPref.createDefault(rule)); + }); } - return JacksonUtil.treeToValue(notificationSettings, UserNotificationSettings.class); + return new UserNotificationSettings(prefs); } @Transactional(propagation = Propagation.NOT_SUPPORTED) // so that parent transaction is not aborted on method failure