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 7fac0fe393..5949028fea 100644 --- a/application/src/main/java/org/thingsboard/server/controller/NotificationController.java +++ b/application/src/main/java/org/thingsboard/server/controller/NotificationController.java @@ -443,8 +443,7 @@ public class NotificationController extends BaseController { @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") public UserNotificationSettings saveUserNotificationSettings(@RequestBody @Valid UserNotificationSettings settings, @AuthenticationPrincipal SecurityUser user) { - notificationSettingsService.saveUserNotificationSettings(user.getTenantId(), user.getId(), settings); - return settings; + return notificationSettingsService.saveUserNotificationSettings(user.getTenantId(), user.getId(), settings); } @GetMapping("/notification/settings/user") 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 b379957e0f..21105950a4 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 @@ -242,10 +242,9 @@ public class DefaultNotificationCenter extends AbstractSubscriptionService imple ctx.getStats().reportProcessed(deliveryMethod, recipient.getId()); } - if (recipient instanceof User && ctx.getRequest().getRuleId() != null) { + if (recipient instanceof User) { UserNotificationSettings settings = notificationSettingsService.getUserNotificationSettings(ctx.getTenantId(), (User) recipient, false); - Set enabledDeliveryMethods = settings.getEnabledDeliveryMethods(ctx.getNotificationType()); - if (!enabledDeliveryMethods.contains(deliveryMethod)) { + if (!settings.isEnabled(ctx.getNotificationType(), deliveryMethod)) { throw new RuntimeException("User disabled " + deliveryMethod.getName() + " notifications of this type"); } } diff --git a/application/src/test/java/org/thingsboard/server/service/notification/NotificationApiTest.java b/application/src/test/java/org/thingsboard/server/service/notification/NotificationApiTest.java index 89b77fcf99..e9c0000565 100644 --- a/application/src/test/java/org/thingsboard/server/service/notification/NotificationApiTest.java +++ b/application/src/test/java/org/thingsboard/server/service/notification/NotificationApiTest.java @@ -62,7 +62,6 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.Set; import java.util.UUID; import java.util.concurrent.TimeUnit; @@ -479,15 +478,27 @@ public class NotificationApiTest extends AbstractNotificationApiTest { public void testUserNotificationSettings() throws Exception { var entityActionNotificationPref = new UserNotificationSettings.NotificationPref(); entityActionNotificationPref.setEnabled(true); - entityActionNotificationPref.setEnabledDeliveryMethods(Set.of(NotificationDeliveryMethod.WEB)); + entityActionNotificationPref.setEnabledDeliveryMethods(Map.of( + NotificationDeliveryMethod.WEB, true, + NotificationDeliveryMethod.SMS, false, + NotificationDeliveryMethod.EMAIL, false + )); var entitiesLimitNotificationPref = new UserNotificationSettings.NotificationPref(); entitiesLimitNotificationPref.setEnabled(true); - entitiesLimitNotificationPref.setEnabledDeliveryMethods(Set.of(NotificationDeliveryMethod.SMS)); + entitiesLimitNotificationPref.setEnabledDeliveryMethods(Map.of( + NotificationDeliveryMethod.SMS, true, + NotificationDeliveryMethod.WEB, false, + NotificationDeliveryMethod.EMAIL, false + )); var apiUsageLimitNotificationPref = new UserNotificationSettings.NotificationPref(); apiUsageLimitNotificationPref.setEnabled(false); - apiUsageLimitNotificationPref.setEnabledDeliveryMethods(Set.of(NotificationDeliveryMethod.WEB)); + apiUsageLimitNotificationPref.setEnabledDeliveryMethods(Map.of( + NotificationDeliveryMethod.WEB, true, + NotificationDeliveryMethod.SMS, false, + NotificationDeliveryMethod.EMAIL, false + )); UserNotificationSettings settings = new UserNotificationSettings(Map.of( NotificationType.ENTITY_ACTION, entityActionNotificationPref, 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 33771ab71e..5c956e6b70 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 @@ -27,7 +27,7 @@ public interface NotificationSettingsService { NotificationSettings findNotificationSettings(TenantId tenantId); - void saveUserNotificationSettings(TenantId tenantId, UserId userId, UserNotificationSettings settings); + UserNotificationSettings saveUserNotificationSettings(TenantId tenantId, UserId userId, UserNotificationSettings settings); UserNotificationSettings getUserNotificationSettings(TenantId tenantId, User user, boolean format); 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 b7af57238b..0ad7cc6d78 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 @@ -29,6 +29,7 @@ import javax.validation.constraints.NotNull; import java.util.Collections; import java.util.Map; import java.util.Set; +import java.util.stream.Collectors; @Data public class UserNotificationSettings { @@ -39,39 +40,42 @@ public class UserNotificationSettings { public static final UserNotificationSettings DEFAULT = new UserNotificationSettings(Collections.emptyMap()); - private static final Set deliveryMethods = NotificationTargetType.PLATFORM_USERS.getSupportedDeliveryMethods(); + public static final Set deliveryMethods = NotificationTargetType.PLATFORM_USERS.getSupportedDeliveryMethods(); @JsonCreator public UserNotificationSettings(@JsonProperty("prefs") Map prefs) { this.prefs = prefs; } - public Set getEnabledDeliveryMethods(NotificationType notificationType) { + public boolean isEnabled(NotificationType notificationType, NotificationDeliveryMethod deliveryMethod) { NotificationPref pref = prefs.get(notificationType); - if (pref != null) { - return pref.isEnabled() ? pref.getEnabledDeliveryMethods() : Collections.emptySet(); - } else { - return deliveryMethods; + if (pref == null) { + return true; } + if (!pref.isEnabled()) { + return false; + } + return pref.getEnabledDeliveryMethods().getOrDefault(deliveryMethod, true); } @Data public static class NotificationPref { private boolean enabled; @NotNull - private Set enabledDeliveryMethods; + private Map enabledDeliveryMethods; public static NotificationPref createDefault() { NotificationPref pref = new NotificationPref(); pref.setEnabled(true); - pref.setEnabledDeliveryMethods(deliveryMethods); + pref.setEnabledDeliveryMethods(deliveryMethods.stream().collect(Collectors.toMap(v -> v, v -> true))); return pref; } @JsonIgnore @AssertTrue(message = "Only email, Web and SMS delivery methods are allowed") public boolean isValid() { - return deliveryMethods.containsAll(enabledDeliveryMethods); + return enabledDeliveryMethods.entrySet().stream() + .allMatch(entry -> deliveryMethods.contains(entry.getKey()) && entry.getValue() != null); } } 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 8fd15e6cd0..cec5a91db5 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 @@ -49,6 +49,7 @@ import org.thingsboard.server.dao.user.UserService; import java.util.Collections; import java.util.EnumMap; +import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Optional; @@ -95,12 +96,13 @@ public class DefaultNotificationSettingsService implements NotificationSettingsS } @Override - public void saveUserNotificationSettings(TenantId tenantId, UserId userId, UserNotificationSettings settings) { + public UserNotificationSettings saveUserNotificationSettings(TenantId tenantId, UserId userId, UserNotificationSettings settings) { User user = userService.findUserById(tenantId, userId); ObjectNode additionalInfo = (ObjectNode) Optional.ofNullable(user.getAdditionalInfo()).orElseGet(JacksonUtil::newObjectNode); additionalInfo.set(USER_SETTINGS_KEY, JacksonUtil.valueToTree(settings)); user.setAdditionalInfo(additionalInfo); userService.saveUser(user); + return formatUserNotificationSettings(settings); } @Override @@ -108,20 +110,32 @@ public class DefaultNotificationSettingsService implements NotificationSettingsS UserNotificationSettings settings = Optional.ofNullable(user.getAdditionalInfo().get(USER_SETTINGS_KEY)) .filter(not(JsonNode::isNull)) .map(json -> JacksonUtil.treeToValue(json, UserNotificationSettings.class)) - .orElse(null); - if (!format) { - return Optional.ofNullable(settings).orElse(UserNotificationSettings.DEFAULT); + .orElse(UserNotificationSettings.DEFAULT); + if (format) { + settings = formatUserNotificationSettings(settings); } + return settings; + } + private UserNotificationSettings formatUserNotificationSettings(UserNotificationSettings settings) { Map prefs = new EnumMap<>(NotificationType.class); if (settings != null) { prefs.putAll(settings.getPrefs()); } NotificationPref defaultPref = NotificationPref.createDefault(); for (NotificationType notificationType : NotificationType.values()) { - prefs.putIfAbsent(notificationType, defaultPref); + NotificationPref pref = prefs.get(notificationType); + if (pref == null) { + prefs.put(notificationType, defaultPref); + } else { + var enabledDeliveryMethods = new LinkedHashMap<>(pref.getEnabledDeliveryMethods()); + // in case a new delivery method was added to the platform + UserNotificationSettings.deliveryMethods.forEach(deliveryMethod -> { + enabledDeliveryMethods.putIfAbsent(deliveryMethod, true); + }); + pref.setEnabledDeliveryMethods(enabledDeliveryMethods); + } } - prefs.remove(NotificationType.GENERAL); return new UserNotificationSettings(prefs); }