From 1c79480b332c20151c9d99acef82f3059522617a Mon Sep 17 00:00:00 2001 From: YevhenBondarenko Date: Tue, 17 Nov 2020 17:32:47 +0200 Subject: [PATCH] created sendApiFeatureStateEmail --- .../DefaultTbApiUsageStateService.java | 37 +++-- .../service/mail/DefaultMailService.java | 29 ++++ .../main/resources/i18n/messages.properties | 3 +- .../resources/templates/state.disabled.ftl | 126 ++++++++++++++++++ .../resources/templates/state.enabled.ftl | 126 ++++++++++++++++++ .../resources/templates/state.warning.ftl | 126 ++++++++++++++++++ .../common/data/ApiUsageStateMailMessage.java | 25 ++++ .../rule/engine/api/MailService.java | 5 + 8 files changed, 467 insertions(+), 10 deletions(-) create mode 100644 application/src/main/resources/templates/state.disabled.ftl create mode 100644 application/src/main/resources/templates/state.enabled.ftl create mode 100644 application/src/main/resources/templates/state.warning.ftl create mode 100644 common/data/src/main/java/org/thingsboard/server/common/data/ApiUsageStateMailMessage.java diff --git a/application/src/main/java/org/thingsboard/server/service/apiusage/DefaultTbApiUsageStateService.java b/application/src/main/java/org/thingsboard/server/service/apiusage/DefaultTbApiUsageStateService.java index c7206712c3..9b45ffdaed 100644 --- a/application/src/main/java/org/thingsboard/server/service/apiusage/DefaultTbApiUsageStateService.java +++ b/application/src/main/java/org/thingsboard/server/service/apiusage/DefaultTbApiUsageStateService.java @@ -17,21 +17,21 @@ package org.thingsboard.server.service.apiusage; import com.google.common.util.concurrent.FutureCallback; import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; import org.checkerframework.checker.nullness.qual.Nullable; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; -import org.springframework.boot.context.event.ApplicationReadyEvent; import org.springframework.context.annotation.Lazy; -import org.springframework.context.event.EventListener; -import org.springframework.core.annotation.Order; -import org.springframework.data.util.Pair; import org.springframework.stereotype.Service; +import org.thingsboard.rule.engine.api.MailService; import org.thingsboard.server.common.data.ApiFeature; import org.thingsboard.server.common.data.ApiUsageRecordKey; import org.thingsboard.server.common.data.ApiUsageState; +import org.thingsboard.server.common.data.ApiUsageStateMailMessage; import org.thingsboard.server.common.data.ApiUsageStateValue; import org.thingsboard.server.common.data.Tenant; import org.thingsboard.server.common.data.TenantProfile; +import org.thingsboard.server.common.data.exception.ThingsboardException; import org.thingsboard.server.common.data.id.ApiUsageStateId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.id.TenantProfileId; @@ -45,6 +45,7 @@ import org.thingsboard.server.common.data.tenant.profile.TenantProfileData; import org.thingsboard.server.common.msg.queue.ServiceType; import org.thingsboard.server.common.msg.queue.TbCallback; import org.thingsboard.server.common.msg.tools.SchedulerUtils; +import org.thingsboard.server.dao.tenant.TbTenantProfileCache; import org.thingsboard.server.dao.tenant.TenantService; import org.thingsboard.server.dao.timeseries.TimeseriesService; import org.thingsboard.server.dao.usagerecord.ApiUsageStateService; @@ -54,14 +55,11 @@ import org.thingsboard.server.queue.common.TbProtoQueueMsg; import org.thingsboard.server.queue.discovery.PartitionChangeEvent; import org.thingsboard.server.queue.discovery.PartitionService; import org.thingsboard.server.queue.scheduler.SchedulerComponent; -import org.thingsboard.server.queue.util.TbCoreComponent; -import org.thingsboard.server.dao.tenant.TbTenantProfileCache; import org.thingsboard.server.service.queue.TbClusterService; import org.thingsboard.server.service.telemetry.InternalTelemetryService; import javax.annotation.PostConstruct; import java.util.ArrayList; -import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; @@ -94,6 +92,7 @@ public class DefaultTbApiUsageStateService implements TbApiUsageStateService { private final ApiUsageStateService apiUsageStateService; private final SchedulerComponent scheduler; private final TbTenantProfileCache tenantProfileCache; + private final MailService mailService; @Lazy @Autowired @@ -118,7 +117,7 @@ public class DefaultTbApiUsageStateService implements TbApiUsageStateService { TimeseriesService tsService, ApiUsageStateService apiUsageStateService, SchedulerComponent scheduler, - TbTenantProfileCache tenantProfileCache) { + TbTenantProfileCache tenantProfileCache, MailService mailService) { this.clusterService = clusterService; this.partitionService = partitionService; this.tenantService = tenantService; @@ -126,6 +125,7 @@ public class DefaultTbApiUsageStateService implements TbApiUsageStateService { this.apiUsageStateService = apiUsageStateService; this.scheduler = scheduler; this.tenantProfileCache = tenantProfileCache; + this.mailService = mailService; } @PostConstruct @@ -286,7 +286,26 @@ public class DefaultTbApiUsageStateService implements TbApiUsageStateService { List stateTelemetry = new ArrayList<>(); result.forEach(((apiFeature, aState) -> stateTelemetry.add(new BasicTsKvEntry(ts, new StringDataEntry(apiFeature.getApiStateKey(), aState.name()))))); tsWsService.saveAndNotifyInternal(state.getTenantId(), state.getApiUsageState().getId(), stateTelemetry, VOID_CALLBACK); - //TODO: notify tenant admin via email! + + String email = tenantService.findTenantById(state.getTenantId()).getEmail(); + + if (StringUtils.isNotEmpty(email)) { + result.forEach((apiFeature, stateValue) -> { + ApiUsageRecordKey[] keys = ApiUsageRecordKey.getKeys(apiFeature); + ApiUsageStateMailMessage[] msgs = new ApiUsageStateMailMessage[keys.length]; + for (int i = 0; i < keys.length; i++) { + ApiUsageRecordKey key = keys[i]; + msgs[i] = new ApiUsageStateMailMessage(key, state.getProfileThreshold(key), state.get(key)); + } + try { + mailService.sendApiFeatureStateEmail(apiFeature, stateValue, email, msgs); + } catch (ThingsboardException e) { + log.warn("[{}] Can't send update of the API state to tenant with provided email [{}]", state.getTenantId(), email, e); + } + }); + } else { + log.warn("[{}] Can't send update of the API state to tenant with empty email!", state.getTenantId()); + } } private void checkStartOfNextCycle() { diff --git a/application/src/main/java/org/thingsboard/server/service/mail/DefaultMailService.java b/application/src/main/java/org/thingsboard/server/service/mail/DefaultMailService.java index bcf541880c..1b85c73196 100644 --- a/application/src/main/java/org/thingsboard/server/service/mail/DefaultMailService.java +++ b/application/src/main/java/org/thingsboard/server/service/mail/DefaultMailService.java @@ -29,6 +29,9 @@ import org.springframework.stereotype.Service; import org.springframework.ui.freemarker.FreeMarkerTemplateUtils; import org.thingsboard.rule.engine.api.MailService; import org.thingsboard.server.common.data.AdminSettings; +import org.thingsboard.server.common.data.ApiFeature; +import org.thingsboard.server.common.data.ApiUsageStateMailMessage; +import org.thingsboard.server.common.data.ApiUsageStateValue; import org.thingsboard.server.common.data.exception.ThingsboardErrorCode; import org.thingsboard.server.common.data.exception.ThingsboardException; import org.thingsboard.server.common.data.id.EntityId; @@ -246,6 +249,32 @@ public class DefaultMailService implements MailService { sendMail(mailSender, mailFrom, email, subject, message); } + @Override + public void sendApiFeatureStateEmail(ApiFeature apiFeature, ApiUsageStateValue stateValue, String email, ApiUsageStateMailMessage[] stateMailMessages) throws ThingsboardException { + String subject = messages.getMessage("api.usage.state", null, Locale.US); + + Map model = new HashMap<>(); + model.put("apiFeature", apiFeature.getApiStateKey()); + model.put("apiUsageStateMailMessages", stateMailMessages); + + model.put(TARGET_EMAIL, email); + + String message = null; + + switch (stateValue) { + case ENABLED: + message = mergeTemplateIntoString("state.enabled.ftl", model); + break; + case WARNING: + message = mergeTemplateIntoString("state.warning.ftl", model); + break; + case DISABLED: + message = mergeTemplateIntoString("state.disabled.ftl", model); + break; + } + sendMail(mailSender, mailFrom, email, subject, message); + } + private void sendMail(JavaMailSenderImpl mailSender, String mailFrom, String email, String subject, String message) throws ThingsboardException { diff --git a/application/src/main/resources/i18n/messages.properties b/application/src/main/resources/i18n/messages.properties index a34582e132..9de9c4b789 100644 --- a/application/src/main/resources/i18n/messages.properties +++ b/application/src/main/resources/i18n/messages.properties @@ -3,4 +3,5 @@ activation.subject=Your account activation on Thingsboard account.activated.subject=Thingsboard - your account has been activated reset.password.subject=Thingsboard - Password reset has been requested password.was.reset.subject=Thingsboard - your account password has been reset -account.lockout.subject=Thingsboard - User account has been lockout \ No newline at end of file +account.lockout.subject=Thingsboard - User account has been lockout +api.usage.state=Thingsboard - Api Usage State for tenant has been updated \ No newline at end of file diff --git a/application/src/main/resources/templates/state.disabled.ftl b/application/src/main/resources/templates/state.disabled.ftl new file mode 100644 index 0000000000..c1f81da181 --- /dev/null +++ b/application/src/main/resources/templates/state.disabled.ftl @@ -0,0 +1,126 @@ +<#-- + + Copyright © 2016-2020 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. + +--> + + + + + +Thingsboard - Api Usage State + + + + + + + + + + + +
+
+ + +
+ + + + + + + + <#list apiUsageStateMailMessages as msg> + + + + + + + + + +
+

Thingsboard Api Usage State for tenant has been updated

+
+ Thingsboard Usage state ${apiFeature} was updated to status DISABLED. +
+ ${msg.key.apiLimitKey} = ${msg.threshold} +
+ ${msg.key.apiCountKey} = ${msg.value} +
+ — The Thingsboard +
+ +
+
+ + diff --git a/application/src/main/resources/templates/state.enabled.ftl b/application/src/main/resources/templates/state.enabled.ftl new file mode 100644 index 0000000000..497b3cd780 --- /dev/null +++ b/application/src/main/resources/templates/state.enabled.ftl @@ -0,0 +1,126 @@ +<#-- + + Copyright © 2016-2020 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. + +--> + + + + + +Thingsboard - Api Usage State + + + + + + + + + + + +
+
+ + +
+ + + + + + + + <#list apiUsageStateMailMessages as msg> + + + + + + + + + +
+

Thingsboard Api Usage State for tenant has been updated

+
+ Thingsboard Usage state ${apiFeature} was updated to status ENABLED. +
+ ${msg.key.apiLimitKey} = ${msg.threshold} +
+ ${msg.key.apiCountKey} = ${msg.value} +
+ — The Thingsboard +
+ +
+
+ + diff --git a/application/src/main/resources/templates/state.warning.ftl b/application/src/main/resources/templates/state.warning.ftl new file mode 100644 index 0000000000..bd4424a0b9 --- /dev/null +++ b/application/src/main/resources/templates/state.warning.ftl @@ -0,0 +1,126 @@ +<#-- + + Copyright © 2016-2020 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. + +--> + + + + + +Thingsboard - Api Usage State + + + + + + + + + + + +
+
+ + +
+ + + + + + + + <#list apiUsageStateMailMessages as msg> + + + + + + + + + +
+

Thingsboard Api Usage State for tenant has been updated

+
+ Thingsboard Usage state ${apiFeature} was updated to status WARNING. +
+ ${msg.key.apiLimitKey} = ${msg.threshold} +
+ ${msg.key.apiCountKey} = ${msg.value} +
+ — The Thingsboard +
+ +
+
+ + diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/ApiUsageStateMailMessage.java b/common/data/src/main/java/org/thingsboard/server/common/data/ApiUsageStateMailMessage.java new file mode 100644 index 0000000000..cab3789fdc --- /dev/null +++ b/common/data/src/main/java/org/thingsboard/server/common/data/ApiUsageStateMailMessage.java @@ -0,0 +1,25 @@ +/** + * Copyright © 2016-2020 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; + +import lombok.Data; + +@Data +public class ApiUsageStateMailMessage { + private final ApiUsageRecordKey key; + private final long threshold; + private final long value; +} diff --git a/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/MailService.java b/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/MailService.java index a36089107d..59b96a2e67 100644 --- a/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/MailService.java +++ b/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/MailService.java @@ -16,6 +16,9 @@ package org.thingsboard.rule.engine.api; import com.fasterxml.jackson.databind.JsonNode; +import org.thingsboard.server.common.data.ApiFeature; +import org.thingsboard.server.common.data.ApiUsageStateMailMessage; +import org.thingsboard.server.common.data.ApiUsageStateValue; import org.thingsboard.server.common.data.exception.ThingsboardException; import javax.mail.MessagingException; @@ -39,4 +42,6 @@ public interface MailService { void send(String from, String to, String cc, String bcc, String subject, String body) throws MessagingException; void sendAccountLockoutEmail( String lockoutEmail, String email, Integer maxFailedLoginAttempts) throws ThingsboardException; + + void sendApiFeatureStateEmail(ApiFeature apiFeature, ApiUsageStateValue stateValue, String email, ApiUsageStateMailMessage[] stateMailMessages) throws ThingsboardException; }