diff --git a/application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/NewPlatformVersionTriggerProcessor.java b/application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/NewPlatformVersionTriggerProcessor.java index 9706862ed4..cb44e7b3ef 100644 --- a/application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/NewPlatformVersionTriggerProcessor.java +++ b/application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/NewPlatformVersionTriggerProcessor.java @@ -15,16 +15,15 @@ */ package org.thingsboard.server.service.notification.rule.trigger; -import com.fasterxml.jackson.core.type.TypeReference; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; -import org.thingsboard.common.util.JacksonUtil; +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.msg.notification.trigger.NewPlatformVersionTrigger; 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; @@ -36,17 +35,21 @@ public class NewPlatformVersionTriggerProcessor implements NotificationRuleTrigg @Override public boolean matchesFilter(NewPlatformVersionTrigger trigger, NewPlatformVersionNotificationRuleTriggerConfig triggerConfig) { - // todo: don't send repetitive notification after platform restart? - if (!partitionService.resolve(ServiceType.TB_CORE, TenantId.SYS_TENANT_ID, TenantId.SYS_TENANT_ID).isMyPartition()) { + if (!partitionService.isMyPartition(ServiceType.TB_CORE, TenantId.SYS_TENANT_ID, TenantId.SYS_TENANT_ID)) { return false; } - return trigger.getMessage().isUpdateAvailable(); + return trigger.getUpdateInfo().isUpdateAvailable(); } @Override public RuleOriginatedNotificationInfo constructNotificationInfo(NewPlatformVersionTrigger trigger) { + UpdateMessage updateInfo = trigger.getUpdateInfo(); return NewPlatformVersionNotificationInfo.builder() - .message(JacksonUtil.convertValue(trigger.getMessage(), new TypeReference<>() {})) + .latestVersion(updateInfo.getLatestVersion()) + .latestVersionReleaseNotesUrl(updateInfo.getLatestVersionReleaseNotesUrl()) + .upgradeInstructionsUrl(updateInfo.getUpgradeInstructionsUrl()) + .currentVersion(updateInfo.getCurrentVersion()) + .currentVersionReleaseNotesUrl(updateInfo.getCurrentVersionReleaseNotesUrl()) .build(); } diff --git a/application/src/main/java/org/thingsboard/server/service/update/DefaultUpdateService.java b/application/src/main/java/org/thingsboard/server/service/update/DefaultUpdateService.java index c6a80efc53..6b41ce00ff 100644 --- a/application/src/main/java/org/thingsboard/server/service/update/DefaultUpdateService.java +++ b/application/src/main/java/org/thingsboard/server/service/update/DefaultUpdateService.java @@ -15,7 +15,6 @@ */ package org.thingsboard.server.service.update; -import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.node.ObjectNode; import lombok.extern.slf4j.Slf4j; @@ -28,6 +27,7 @@ import org.thingsboard.common.util.ThingsBoardThreadFactory; import org.thingsboard.server.common.data.UpdateMessage; import org.thingsboard.server.common.msg.notification.trigger.NewPlatformVersionTrigger; import org.thingsboard.server.common.msg.notification.NotificationRuleProcessor; +import org.thingsboard.server.queue.util.AfterStartUp; import org.thingsboard.server.queue.util.TbCoreComponent; import javax.annotation.PostConstruct; @@ -74,8 +74,8 @@ public class DefaultUpdateService implements UpdateService { private String version; private UUID instanceId = null; - @PostConstruct - private void init() { + @AfterStartUp(order = AfterStartUp.REGULAR_SERVICE) + public void init() { version = buildProperties != null ? buildProperties.getVersion() : "unknown"; updateMessage = new UpdateMessage(false, version, "", "", "", ""); if (updatesEnabled) { @@ -132,7 +132,7 @@ public class DefaultUpdateService implements UpdateService { updateMessage = restClient.postForObject(UPDATE_SERVER_BASE_URL + "/api/v2/thingsboard/updates", request, UpdateMessage.class); if (updateMessage.isUpdateAvailable() && !updateMessage.equals(prevUpdateMessage)) { notificationRuleProcessor.process(NewPlatformVersionTrigger.builder() - .message(updateMessage) + .updateInfo(updateMessage) .build()); } } catch (Exception e) { diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/notification/info/NewPlatformVersionNotificationInfo.java b/common/data/src/main/java/org/thingsboard/server/common/data/notification/info/NewPlatformVersionNotificationInfo.java index cc7133d5f4..a7edeecde4 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/notification/info/NewPlatformVersionNotificationInfo.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/notification/info/NewPlatformVersionNotificationInfo.java @@ -19,7 +19,6 @@ import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; -import org.thingsboard.server.common.data.UpdateMessage; import java.util.Map; @@ -31,11 +30,22 @@ import static org.thingsboard.server.common.data.util.CollectionsUtil.mapOf; @Builder public class NewPlatformVersionNotificationInfo implements RuleOriginatedNotificationInfo { - private Map message; + private String latestVersion; + private String latestVersionReleaseNotesUrl; + private String upgradeInstructionsUrl; + + private String currentVersion; + private String currentVersionReleaseNotesUrl; @Override public Map getTemplateData() { - return message; + return mapOf( + "latestVersion", latestVersion, + "latestVersionReleaseNotesUrl", latestVersionReleaseNotesUrl, + "upgradeInstructionsUrl", upgradeInstructionsUrl, + "currentVersion", currentVersion, + "currentVersionReleaseNotesUrl", currentVersionReleaseNotesUrl + ); } } diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/NewPlatformVersionNotificationRuleTriggerConfig.java b/common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/NewPlatformVersionNotificationRuleTriggerConfig.java index 5473288f94..230be3b9d5 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/NewPlatformVersionNotificationRuleTriggerConfig.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/NewPlatformVersionNotificationRuleTriggerConfig.java @@ -20,8 +20,6 @@ import lombok.Data; @Data public class NewPlatformVersionNotificationRuleTriggerConfig implements NotificationRuleTriggerConfig { - // TODO: don't forget to create default notification configs - @Override public NotificationRuleTriggerType getTriggerType() { return NotificationRuleTriggerType.NEW_PLATFORM_VERSION; diff --git a/common/message/src/main/java/org/thingsboard/server/common/msg/notification/trigger/NewPlatformVersionTrigger.java b/common/message/src/main/java/org/thingsboard/server/common/msg/notification/trigger/NewPlatformVersionTrigger.java index d6428b7467..0da2f0c57b 100644 --- a/common/message/src/main/java/org/thingsboard/server/common/msg/notification/trigger/NewPlatformVersionTrigger.java +++ b/common/message/src/main/java/org/thingsboard/server/common/msg/notification/trigger/NewPlatformVersionTrigger.java @@ -26,7 +26,7 @@ import org.thingsboard.server.common.data.notification.rule.trigger.Notification @Builder public class NewPlatformVersionTrigger implements NotificationRuleTrigger { - private final UpdateMessage message; + private final UpdateMessage updateInfo; @Override public NotificationRuleTriggerType getType() { 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 50a7d49f66..9438c79b62 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 @@ -46,6 +46,7 @@ import org.thingsboard.server.common.data.notification.rule.trigger.DeviceActivi import org.thingsboard.server.common.data.notification.rule.trigger.DeviceActivityNotificationRuleTriggerConfig.DeviceEvent; 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.NotificationRuleTriggerConfig; import org.thingsboard.server.common.data.notification.rule.trigger.NotificationRuleTriggerType; import org.thingsboard.server.common.data.notification.rule.trigger.RuleEngineComponentLifecycleEventNotificationRuleTriggerConfig; @@ -144,6 +145,14 @@ public class DefaultNotificationSettingsService implements NotificationSettingsS apiUsageLimitRuleTriggerConfig.setNotifyOn(Set.of(ApiUsageStateValue.WARNING, ApiUsageStateValue.DISABLED)); createRule(tenantId, "API usage limit", apiUsageLimitNotificationTemplate.getId(), apiUsageLimitRuleTriggerConfig, List.of(affectedTenantAdmins.getId(), sysAdmins.getId()), "Send notification to tenant admins and system admins when API feature usage state changed"); + + NotificationTemplate newPlatformVersionNotificationTemplate = createTemplate(tenantId, "New platform version notification", NotificationType.NEW_PLATFORM_VERSION, + "New version ${latestVersion} is available", + "Current platform version is ${currentVersion}", + null, "Open release notes", "${latestVersionReleaseNotesUrl}"); + NewPlatformVersionNotificationRuleTriggerConfig newPlatformVersionRuleTriggerConfig = new NewPlatformVersionNotificationRuleTriggerConfig(); + createRule(tenantId, "New platform version", newPlatformVersionNotificationTemplate.getId(), newPlatformVersionRuleTriggerConfig, + List.of(sysAdmins.getId(), tenantAdmins.getId()), "Send notification to system admins and tenant admins when new platform version is available"); return; } diff --git a/ui-ngx/src/app/modules/home/pages/notification/rule/rule-notification-dialog.component.html b/ui-ngx/src/app/modules/home/pages/notification/rule/rule-notification-dialog.component.html index a3e7d55b60..e9c0f80fd8 100644 --- a/ui-ngx/src/app/modules/home/pages/notification/rule/rule-notification-dialog.component.html +++ b/ui-ngx/src/app/modules/home/pages/notification/rule/rule-notification-dialog.component.html @@ -478,6 +478,20 @@ + + + {{ 'notification.new-platform-version-trigger-settings' | translate }} +
+
+ + notification.description + + +
+
+
+ diff --git a/ui-ngx/src/app/modules/home/pages/notification/rule/rule-notification-dialog.component.ts b/ui-ngx/src/app/modules/home/pages/notification/rule/rule-notification-dialog.component.ts index 8566745ecf..ae0e608224 100644 --- a/ui-ngx/src/app/modules/home/pages/notification/rule/rule-notification-dialog.component.ts +++ b/ui-ngx/src/app/modules/home/pages/notification/rule/rule-notification-dialog.component.ts @@ -94,6 +94,7 @@ export class RuleNotificationDialogComponent extends ruleEngineEventsTemplateForm: FormGroup; entitiesLimitTemplateForm: FormGroup; apiUsageLimitTemplateForm: FormGroup; + newPlatformVersionTemplateForm: FormGroup; triggerType = TriggerType; triggerTypes: TriggerType[]; @@ -294,6 +295,12 @@ export class RuleNotificationDialogComponent extends }) }); + this.newPlatformVersionTemplateForm = this.fb.group({ + triggerConfig: this.fb.group({ + + }) + }); + this.triggerTypeFormsMap = new Map([ [TriggerType.ALARM, this.alarmTemplateForm], [TriggerType.ALARM_COMMENT, this.alarmCommentTemplateForm], @@ -302,7 +309,8 @@ export class RuleNotificationDialogComponent extends [TriggerType.ALARM_ASSIGNMENT, this.alarmAssignmentTemplateForm], [TriggerType.RULE_ENGINE_COMPONENT_LIFECYCLE_EVENT, this.ruleEngineEventsTemplateForm], [TriggerType.ENTITIES_LIMIT, this.entitiesLimitTemplateForm], - [TriggerType.API_USAGE_LIMIT, this.apiUsageLimitTemplateForm] + [TriggerType.API_USAGE_LIMIT, this.apiUsageLimitTemplateForm], + [TriggerType.NEW_PLATFORM_VERSION, this.newPlatformVersionTemplateForm] ]); if (data.isAdd || data.isCopy) { @@ -433,9 +441,10 @@ export class RuleNotificationDialogComponent extends private allowTriggerTypes(): TriggerType[] { if (this.isSysAdmin()) { - return [TriggerType.ENTITIES_LIMIT, TriggerType.API_USAGE_LIMIT]; + return [TriggerType.ENTITIES_LIMIT, TriggerType.API_USAGE_LIMIT, TriggerType.NEW_PLATFORM_VERSION]; } - return Object.values(TriggerType).filter(type => type !== TriggerType.ENTITIES_LIMIT && type !== TriggerType.API_USAGE_LIMIT); + return Object.values(TriggerType).filter(type => type !== TriggerType.ENTITIES_LIMIT && type !== TriggerType.API_USAGE_LIMIT + && type !== TriggerType.NEW_PLATFORM_VERSION); } get allowEntityTypeForEntityAction(): EntityType[] { diff --git a/ui-ngx/src/app/modules/home/pages/notification/template/template-notification-dialog.component.ts b/ui-ngx/src/app/modules/home/pages/notification/template/template-notification-dialog.component.ts index 122169ed07..76a2bb1f34 100644 --- a/ui-ngx/src/app/modules/home/pages/notification/template/template-notification-dialog.component.ts +++ b/ui-ngx/src/app/modules/home/pages/notification/template/template-notification-dialog.component.ts @@ -176,9 +176,10 @@ export class TemplateNotificationDialogComponent private allowNotificationType(): NotificationType[] { if (this.isSysAdmin()) { - return [NotificationType.GENERAL, NotificationType.ENTITIES_LIMIT, NotificationType.API_USAGE_LIMIT]; + return [NotificationType.GENERAL, NotificationType.ENTITIES_LIMIT, NotificationType.API_USAGE_LIMIT, NotificationType.NEW_PLATFORM_VERSION]; } return Object.values(NotificationType) - .filter(type => type !== NotificationType.ENTITIES_LIMIT && type !== NotificationType.API_USAGE_LIMIT); + .filter(type => type !== NotificationType.ENTITIES_LIMIT && type !== NotificationType.API_USAGE_LIMIT + && type !== NotificationType.NEW_PLATFORM_VERSION); } } diff --git a/ui-ngx/src/app/shared/models/notification.models.ts b/ui-ngx/src/app/shared/models/notification.models.ts index 0969af78d4..2bb00fe745 100644 --- a/ui-ngx/src/app/shared/models/notification.models.ts +++ b/ui-ngx/src/app/shared/models/notification.models.ts @@ -442,6 +442,7 @@ export enum NotificationType { RULE_ENGINE_COMPONENT_LIFECYCLE_EVENT = 'RULE_ENGINE_COMPONENT_LIFECYCLE_EVENT', ENTITIES_LIMIT = 'ENTITIES_LIMIT', API_USAGE_LIMIT = 'API_USAGE_LIMIT', + NEW_PLATFORM_VERSION = 'NEW_PLATFORM_VERSION', RULE_ENGINE = 'RULE_ENGINE' } @@ -536,6 +537,12 @@ export const NotificationTemplateTypeTranslateMap = new Map([ @@ -564,4 +572,5 @@ export const TriggerTypeTranslationMap = new Map([ [TriggerType.RULE_ENGINE_COMPONENT_LIFECYCLE_EVENT, 'notification.trigger.rule-engine-lifecycle-event'], [TriggerType.ENTITIES_LIMIT, 'notification.trigger.entities-limit'], [TriggerType.API_USAGE_LIMIT, 'notification.trigger.api-usage-limit'], + [TriggerType.NEW_PLATFORM_VERSION, 'notification.trigger.new-platform-version'], ]); diff --git a/ui-ngx/src/assets/locale/locale.constant-en_US.json b/ui-ngx/src/assets/locale/locale.constant-en_US.json index c64ca941f2..4d6e907f32 100644 --- a/ui-ngx/src/assets/locale/locale.constant-en_US.json +++ b/ui-ngx/src/assets/locale/locale.constant-en_US.json @@ -2749,6 +2749,7 @@ "all": "All", "api-feature-hint": "If the field is empty, the trigger will be applied to all api features", "api-usage-trigger-settings": "API usage trigger settings", + "new-platform-version-trigger-settings": "New platform version trigger settings", "at-least-one-should-be-selected": "At least one should be selected", "basic-settings": "Basic settings", "button-text": "Button text", @@ -2932,7 +2933,8 @@ "entity-action": "Entity action", "general": "General", "rule-engine-lifecycle-event": "Rule engine lifecycle event", - "rule-engine": "Rule engine" + "rule-engine": "Rule engine", + "new-platform-version": "New platform version" }, "templates": "Templates", "tenant-profiles-list-rule-hint": "If the field is empty, the trigger will be applied to all tenant profiles", @@ -2949,6 +2951,7 @@ "entities-limit": "Entities limit", "entity-action": "Entity action", "rule-engine-lifecycle-event": "Rule engine lifecycle event", + "new-platform-version": "New platform version", "trigger": "Trigger", "trigger-required": "Trigger is required" },