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 a88a7ee4f6..24dc41f199 100644 --- a/application/src/main/java/org/thingsboard/server/controller/NotificationController.java +++ b/application/src/main/java/org/thingsboard/server/controller/NotificationController.java @@ -271,6 +271,7 @@ public class NotificationController extends BaseController { @ApiParam(value = "Amount of the recipients to show in preview") @RequestParam(defaultValue = "20") int recipientsPreviewSize, @AuthenticationPrincipal SecurityUser user) throws ThingsboardException { + // PE: generic permission NotificationTemplate template; if (request.getTemplateId() != null) { template = checkEntityId(request.getTemplateId(), notificationTemplateService::findNotificationTemplateById, Operation.READ); @@ -386,7 +387,7 @@ public class NotificationController extends BaseController { @ApiParam(value = SORT_ORDER_DESCRIPTION) @RequestParam(required = false) String sortOrder, @AuthenticationPrincipal SecurityUser user) throws ThingsboardException { - // generic permission + // PE: generic permission PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder); return notificationRequestService.findNotificationRequestsInfosByTenantIdAndOriginatorType(user.getTenantId(), EntityType.USER, pageLink); } diff --git a/application/src/main/java/org/thingsboard/server/controller/NotificationRuleController.java b/application/src/main/java/org/thingsboard/server/controller/NotificationRuleController.java index 2afb67a8bd..4321be8122 100644 --- a/application/src/main/java/org/thingsboard/server/controller/NotificationRuleController.java +++ b/application/src/main/java/org/thingsboard/server/controller/NotificationRuleController.java @@ -161,7 +161,7 @@ public class NotificationRuleController extends BaseController { @ApiParam(value = SORT_ORDER_DESCRIPTION) @RequestParam(required = false) String sortOrder, @AuthenticationPrincipal SecurityUser user) throws ThingsboardException { - // generic permission + // PE: generic permission PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder); return notificationRuleService.findNotificationRulesInfosByTenantId(user.getTenantId(), pageLink); } diff --git a/application/src/main/java/org/thingsboard/server/controller/NotificationTargetController.java b/application/src/main/java/org/thingsboard/server/controller/NotificationTargetController.java index a4c829796b..51ed86441b 100644 --- a/application/src/main/java/org/thingsboard/server/controller/NotificationTargetController.java +++ b/application/src/main/java/org/thingsboard/server/controller/NotificationTargetController.java @@ -139,7 +139,7 @@ public class NotificationTargetController extends BaseController { @ApiParam(value = PAGE_NUMBER_DESCRIPTION, required = true) @RequestParam int page, @AuthenticationPrincipal SecurityUser user) throws ThingsboardException { - // generic permission + // PE: generic permission NotificationTargetConfig targetConfig = notificationTarget.getConfiguration(); if (targetConfig.getType() == NotificationTargetType.PLATFORM_USERS) { checkTargetUsers(user, targetConfig); @@ -159,7 +159,7 @@ public class NotificationTargetController extends BaseController { public List getNotificationTargetsByIds(@ApiParam(value = "Comma-separated list of uuids representing targets ids", required = true) @RequestParam("ids") UUID[] ids, @AuthenticationPrincipal SecurityUser user) { - // generic permission + // PE: generic permission List targetsIds = Arrays.stream(ids).map(NotificationTargetId::new).collect(Collectors.toList()); return notificationTargetService.findNotificationTargetsByTenantIdAndIds(user.getTenantId(), targetsIds); } @@ -181,7 +181,7 @@ public class NotificationTargetController extends BaseController { @ApiParam(value = SORT_ORDER_DESCRIPTION) @RequestParam(required = false) String sortOrder, @AuthenticationPrincipal SecurityUser user) throws ThingsboardException { - // generic permission + // PE: generic permission PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder); return notificationTargetService.findNotificationTargetsByTenantId(user.getTenantId(), pageLink); } @@ -199,6 +199,7 @@ public class NotificationTargetController extends BaseController { @RequestParam(required = false) String sortOrder, @RequestParam(required = false) NotificationType notificationType, @AuthenticationPrincipal SecurityUser user) throws ThingsboardException { + // PE: generic permission PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder); return notificationTargetService.findNotificationTargetsByTenantIdAndSupportedNotificationType(user.getTenantId(), notificationType, pageLink); } @@ -219,7 +220,7 @@ public class NotificationTargetController extends BaseController { if (user.isSystemAdmin()) { return; } - // generic permission for users + // PE: generic permission for users UsersFilter usersFilter = ((PlatformUsersNotificationTargetConfig) targetConfig).getUsersFilter(); switch (usersFilter.getType()) { case USER_LIST: diff --git a/application/src/main/java/org/thingsboard/server/controller/NotificationTemplateController.java b/application/src/main/java/org/thingsboard/server/controller/NotificationTemplateController.java index ab171efacf..514210ec00 100644 --- a/application/src/main/java/org/thingsboard/server/controller/NotificationTemplateController.java +++ b/application/src/main/java/org/thingsboard/server/controller/NotificationTemplateController.java @@ -150,7 +150,7 @@ public class NotificationTemplateController extends BaseController { @ApiParam(value = "Comma-separated list of notification types to filter the templates") @RequestParam(required = false) NotificationType[] notificationTypes, @AuthenticationPrincipal SecurityUser user) throws ThingsboardException { - // generic permission + // PE: generic permission PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder); if (notificationTypes == null || notificationTypes.length == 0) { notificationTypes = NotificationType.values(); @@ -180,7 +180,7 @@ public class NotificationTemplateController extends BaseController { @ApiParam(value = "Slack bot token. If absent - system Slack settings will be used") @RequestParam(required = false) String token, @AuthenticationPrincipal SecurityUser user) { - // generic permission + // PE: generic permission if (StringUtils.isEmpty(token)) { NotificationSettings settings = notificationSettingsService.findNotificationSettings(user.getTenantId()); SlackNotificationDeliveryMethodConfig slackConfig = (SlackNotificationDeliveryMethodConfig) diff --git a/application/src/main/java/org/thingsboard/server/service/action/EntityActionService.java b/application/src/main/java/org/thingsboard/server/service/action/EntityActionService.java index 99884b013d..77cc275ab2 100644 --- a/application/src/main/java/org/thingsboard/server/service/action/EntityActionService.java +++ b/application/src/main/java/org/thingsboard/server/service/action/EntityActionService.java @@ -31,9 +31,9 @@ import org.thingsboard.server.common.data.alarm.Alarm; import org.thingsboard.server.common.data.alarm.AlarmComment; import org.thingsboard.server.common.data.alarm.AlarmInfo; import org.thingsboard.server.common.data.audit.ActionType; -import org.thingsboard.server.common.data.edge.EdgeEventActionType; import org.thingsboard.server.common.data.id.CustomerId; import org.thingsboard.server.common.data.id.EntityId; +import org.thingsboard.server.common.data.id.HasId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.kv.AttributeKvEntry; import org.thingsboard.server.common.data.kv.TsKvEntry; @@ -179,7 +179,8 @@ public class EntityActionService { } } - private void processNotificationRules(TenantId tenantId, EntityId entityId, HasName entity, ActionType actionType, User user, Object... additionalInfo) { + private void processNotificationRules(TenantId tenantId, EntityId originatorId, HasName entity, ActionType actionType, User user, Object... additionalInfo) { + EntityId entityId = entity instanceof HasId ? ((HasId) entity).getId() : originatorId; switch (actionType) { case ADDED: notificationRuleProcessor.process(EntitiesLimitTrigger.builder() diff --git a/application/src/test/java/org/thingsboard/server/service/notification/NotificationRuleApiTest.java b/application/src/test/java/org/thingsboard/server/service/notification/NotificationRuleApiTest.java index 0f57d5ef14..0909510243 100644 --- a/application/src/test/java/org/thingsboard/server/service/notification/NotificationRuleApiTest.java +++ b/application/src/test/java/org/thingsboard/server/service/notification/NotificationRuleApiTest.java @@ -269,6 +269,31 @@ public class NotificationRuleApiTest extends AbstractNotificationApiTest { }); } + @Test + public void testNotificationRuleProcessing_alarmTrigger_createViaRestApi() throws Exception { + Device device = createDevice("Device with alarm", "233"); + NotificationTarget target = createNotificationTarget(tenantAdminUserId); + defaultNotifications.create(tenantId, DefaultNotifications.newAlarm, target.getId()); + defaultNotifications.create(tenantId, DefaultNotifications.entityAction, target.getId()); + notificationRulesCache.evict(tenantId); + + Alarm alarm = new Alarm(); + alarm.setSeverity(AlarmSeverity.CRITICAL); + alarm.setType("testAlarm"); + alarm.setOriginator(device.getId()); + alarm = doPost("/api/alarm", alarm, Alarm.class); + + await().atMost(15, TimeUnit.SECONDS) + .pollDelay(2, TimeUnit.SECONDS) + .untilAsserted(() -> { + List notifications = getMyNotifications(false, 10); + assertThat(notifications).hasSize(1).first().matches(notification -> { + return notification.getType() == NotificationType.ALARM && + notification.getSubject().equals("New alarm 'testAlarm'"); + }); + }); + } + @Test public void testNotificationRuleProcessing_alarmTrigger_clearRule() throws Exception { String notificationSubject = "${alarmSeverity} alarm '${alarmType}' is ${alarmStatus}"; diff --git a/common/script/script-api/src/main/java/org/thingsboard/script/api/tbel/TbDate.java b/common/script/script-api/src/main/java/org/thingsboard/script/api/tbel/TbDate.java index 084bc25c1f..87a6e1e0ed 100644 --- a/common/script/script-api/src/main/java/org/thingsboard/script/api/tbel/TbDate.java +++ b/common/script/script-api/src/main/java/org/thingsboard/script/api/tbel/TbDate.java @@ -94,7 +94,10 @@ public class TbDate implements Serializable, Cloneable { } public ZonedDateTime getZonedDateTime() { - return instant.atZone(zoneIdUTC); + return getZonedDateTime(zoneIdUTC); + } + public ZonedDateTime getZonedDateTime(ZoneId zoneId) { + return instant.atZone(zoneId); } public LocalDateTime getLocalDateTime() { @@ -149,13 +152,20 @@ public class TbDate implements Serializable, Cloneable { public String toString(String localeStr, String optionsStr) { return toLocaleString(localeStr, optionsStr, (locale, options) -> DateTimeFormatter.ofLocalizedDateTime(FormatStyle.FULL, FormatStyle.FULL).withLocale(locale)); } - public String toISOZonedDateTimeString() { + public String toZonedDateTimeString() { return getZonedDateTime().toString(); } - public String toISOZonedDateTimeString(DateTimeFormatter formatter) { + public String toZonedDateTimeString(DateTimeFormatter formatter) { return getZonedDateTime().format(formatter); } + public String toZonedDateTimeString(String zoneIdStr) { + return getZonedDateTime(ZoneId.of(zoneIdStr)).toString(); + } + public String toZonedDateTimeString(DateTimeFormatter formatter, String zoneIdStr) { + return getZonedDateTime(ZoneId.of(zoneIdStr)).format(formatter); + } + public String toLocaleDateString() { return toLocaleDateString(localeUTC.getLanguage()); } diff --git a/common/script/script-api/src/test/java/org/thingsboard/script/api/tbel/TbDateTest.java b/common/script/script-api/src/test/java/org/thingsboard/script/api/tbel/TbDateTest.java index 1c2c5bde1c..d3951dce0a 100644 --- a/common/script/script-api/src/test/java/org/thingsboard/script/api/tbel/TbDateTest.java +++ b/common/script/script-api/src/test/java/org/thingsboard/script/api/tbel/TbDateTest.java @@ -30,7 +30,6 @@ import org.thingsboard.common.util.JacksonUtil; import java.time.DateTimeException; import java.time.ZoneId; import java.time.format.DateTimeFormatter; -import java.time.format.DateTimeParseException; import java.util.ArrayList; import java.util.List; import java.util.Locale; @@ -374,19 +373,34 @@ class TbDateTest { TbDate d1 = new TbDate(23, 9, 7, 8, 4, 5, "+04:00"); TbDate d2 = new TbDate(23, 9, 7, 8, 4, 5, "-03:00"); - Assert.assertEquals("2023-09-07T04:04:05Z[UTC]", d1.toISOZonedDateTimeString()); - Assert.assertEquals("2023-09-07T04:04:05Z", d1.toISOZonedDateTimeString(DateTimeFormatter.ISO_OFFSET_DATE_TIME)); - Assert.assertEquals("2023-09-07T04:04:05Z[UTC]", d1.toISOZonedDateTimeString(DateTimeFormatter.ISO_ZONED_DATE_TIME)); - Assert.assertEquals("2023-09-07T04:04:05", d1.toISOZonedDateTimeString(DateTimeFormatter.ISO_LOCAL_DATE_TIME)); - Assert.assertEquals("Thu, 7 Sep 2023 04:04:05 GMT", d1.toISOZonedDateTimeString(DateTimeFormatter.RFC_1123_DATE_TIME)); - Assert.assertEquals("2023-09-07T04:04:05Z", d1.toISOZonedDateTimeString(DateTimeFormatter.ISO_INSTANT)); - - Assert.assertEquals("2023-09-07T11:04:05Z[UTC]", d2.toISOZonedDateTimeString()); - Assert.assertEquals("2023-09-07T11:04:05Z", d2.toISOZonedDateTimeString(DateTimeFormatter.ISO_OFFSET_DATE_TIME)); - Assert.assertEquals("2023-09-07T11:04:05Z[UTC]", d2.toISOZonedDateTimeString(DateTimeFormatter.ISO_ZONED_DATE_TIME)); - Assert.assertEquals("2023-09-07T11:04:05", d2.toISOZonedDateTimeString(DateTimeFormatter.ISO_LOCAL_DATE_TIME)); - Assert.assertEquals("Thu, 7 Sep 2023 11:04:05 GMT", d2.toISOZonedDateTimeString(DateTimeFormatter.RFC_1123_DATE_TIME)); - Assert.assertEquals("2023-09-07T11:04:05Z", d2.toISOZonedDateTimeString(DateTimeFormatter.ISO_INSTANT)); + Assert.assertEquals("2023-09-07T04:04:05Z[UTC]", d1.toZonedDateTimeString()); + Assert.assertEquals("2023-09-07T04:04:05Z", d1.toZonedDateTimeString(DateTimeFormatter.ISO_OFFSET_DATE_TIME)); + Assert.assertEquals("2023-09-07T04:04:05Z[UTC]", d1.toZonedDateTimeString(DateTimeFormatter.ISO_ZONED_DATE_TIME)); + Assert.assertEquals("2023-09-07T04:04:05", d1.toZonedDateTimeString(DateTimeFormatter.ISO_LOCAL_DATE_TIME)); + Assert.assertEquals("Thu, 7 Sep 2023 04:04:05 GMT", d1.toZonedDateTimeString(DateTimeFormatter.RFC_1123_DATE_TIME)); + Assert.assertEquals("2023-09-07T04:04:05Z", d1.toZonedDateTimeString(DateTimeFormatter.ISO_INSTANT)); + + Assert.assertEquals("2023-09-07T11:04:05Z[UTC]", d2.toZonedDateTimeString()); + Assert.assertEquals("2023-09-07T11:04:05Z", d2.toZonedDateTimeString(DateTimeFormatter.ISO_OFFSET_DATE_TIME)); + Assert.assertEquals("2023-09-07T11:04:05Z[UTC]", d2.toZonedDateTimeString(DateTimeFormatter.ISO_ZONED_DATE_TIME)); + Assert.assertEquals("2023-09-07T11:04:05", d2.toZonedDateTimeString(DateTimeFormatter.ISO_LOCAL_DATE_TIME)); + Assert.assertEquals("Thu, 7 Sep 2023 11:04:05 GMT", d2.toZonedDateTimeString(DateTimeFormatter.RFC_1123_DATE_TIME)); + Assert.assertEquals("2023-09-07T11:04:05Z", d2.toZonedDateTimeString(DateTimeFormatter.ISO_INSTANT)); + } + + @Test + void TestZoneDateTimeFormatterToString () { + TbDate d1 = new TbDate(23, 9, 7, 8, 4, 5, "-04:00"); + Assert.assertEquals("2023-09-07T12:04:05Z[UTC]", d1.toZonedDateTimeString()); + Assert.assertEquals("2023-09-07T12:04:05Z", d1.toZonedDateTimeString(DateTimeFormatter.ISO_INSTANT,"America/New_York")); + Assert.assertEquals("2023-09-07T08:04:05-04:00", d1.toZonedDateTimeString(DateTimeFormatter.ISO_OFFSET_DATE_TIME,"America/New_York")); + Assert.assertEquals("2023-09-07T08:04:05-04:00[America/New_York]", d1.toZonedDateTimeString("America/New_York")); + Assert.assertEquals("Thu, 7 Sep 2023 08:04:05 -0400", d1.toZonedDateTimeString(DateTimeFormatter.RFC_1123_DATE_TIME,"America/New_York")); + + Assert.assertEquals("2023-09-07T14:04:05+02:00[Europe/Berlin]", d1.toZonedDateTimeString("Europe/Berlin")); + Assert.assertEquals("2023-09-07T14:04:05+02:00", d1.toZonedDateTimeString(DateTimeFormatter.ISO_OFFSET_DATE_TIME,"Europe/Berlin")); + Assert.assertEquals("2023-09-08T02:04:05+14:00[Etc/GMT-14]", d1.toZonedDateTimeString("Etc/GMT-14")); + Assert.assertEquals("2023-09-07T00:04:05-12:00[Etc/GMT+12]", d1.toZonedDateTimeString("Etc/GMT+12")); } @Test