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 59b63d7200..330ecc23f5 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
@@ -297,15 +297,9 @@ public class DefaultTbApiUsageStateService implements TbApiUsageStateService {
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));
- }
mailExecutor.submit(() -> {
try {
- mailService.sendApiFeatureStateEmail(apiFeature, stateValue, email, msgs[0]);
+ mailService.sendApiFeatureStateEmail(apiFeature, stateValue, email, createStateMailMessage(state, apiFeature, stateValue));
} catch (ThingsboardException e) {
log.warn("[{}] Can't send update of the API state to tenant with provided email [{}]", state.getTenantId(), email, e);
}
@@ -316,6 +310,33 @@ public class DefaultTbApiUsageStateService implements TbApiUsageStateService {
}
}
+ private ApiUsageStateMailMessage createStateMailMessage(TenantApiUsageState state, ApiFeature apiFeature, ApiUsageStateValue stateValue) {
+ StateChecker checker = getStateChecker(stateValue);
+ for (ApiUsageRecordKey apiUsageRecordKey : ApiUsageRecordKey.getKeys(apiFeature)) {
+ long threshold = state.getProfileThreshold(apiUsageRecordKey);
+ long warnThreshold = state.getProfileWarnThreshold(apiUsageRecordKey);
+ long value = state.get(apiUsageRecordKey);
+ if (checker.check(threshold, warnThreshold, value)) {
+ return new ApiUsageStateMailMessage(apiUsageRecordKey, threshold, value);
+ }
+ }
+ return null;
+ }
+
+ private StateChecker getStateChecker(ApiUsageStateValue stateValue) {
+ if (ApiUsageStateValue.ENABLED.equals(stateValue)) {
+ return (t, wt, v) -> true;
+ } else if (ApiUsageStateValue.WARNING.equals(stateValue)) {
+ return (t, wt, v) -> v < t && v >= wt;
+ } else {
+ return (t, wt, v) -> v >= t;
+ }
+ }
+
+ private interface StateChecker {
+ boolean check(long threshold, long warnThreshold, long value);
+ }
+
private void checkStartOfNextCycle() {
updateLock.lock();
try {
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 19509243ef..3045fe0cce 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
@@ -30,6 +30,7 @@ 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.ApiUsageRecordKey;
import org.thingsboard.server.common.data.ApiUsageStateMailMessage;
import org.thingsboard.server.common.data.ApiUsageStateValue;
import org.thingsboard.server.common.data.exception.ThingsboardErrorCode;
@@ -261,19 +262,36 @@ public class DefaultMailService implements MailService {
switch (stateValue) {
case ENABLED:
+ model.put("apiLabel", toEnabledValueLabel(apiFeature));
message = mergeTemplateIntoString("state.enabled.ftl", model);
break;
case WARNING:
+ model.put("apiLimitValueLabel", toDisabledValueLabel(msg.getKey(), msg.getThreshold()));
+ model.put("apiValueLabel", toDisabledValueLabel(apiFeature) + " " + toDisabledValueLabel(msg.getKey(), msg.getValue()));
message = mergeTemplateIntoString("state.warning.ftl", model);
break;
case DISABLED:
- model.put("apiLimitValueLabel", toDisabledValueLabel(apiFeature) + " " + toDisabledValueLabel(msg));
+ model.put("apiLimitValueLabel", toDisabledValueLabel(apiFeature) + " " + toDisabledValueLabel(msg.getKey(), msg.getThreshold()));
message = mergeTemplateIntoString("state.disabled.ftl", model);
break;
}
sendMail(mailSender, mailFrom, email, subject, message);
}
+ private String toEnabledValueLabel(ApiFeature apiFeature) {
+ switch (apiFeature) {
+ case DB:
+ return "save";
+ case TRANSPORT:
+ return "receive";
+ case JS:
+ case RE:
+ return "invoke";
+ default:
+ throw new RuntimeException("Not implemented!");
+ }
+ }
+
private String toDisabledValueLabel(ApiFeature apiFeature) {
switch (apiFeature) {
case DB:
@@ -288,17 +306,17 @@ public class DefaultMailService implements MailService {
}
}
- private String toDisabledValueLabel(ApiUsageStateMailMessage msg) {
- switch (msg.getKey()) {
+ private String toDisabledValueLabel(ApiUsageRecordKey key, long value) {
+ switch (key) {
case STORAGE_DP_COUNT:
case TRANSPORT_DP_COUNT:
- return (msg.getThreshold() / 1000000) + "M data points";
+ return (value / 1000000) + "M data points";
case TRANSPORT_MSG_COUNT:
- return (msg.getThreshold() / 1000000) + "M messages";
+ return (value / 1000000) + "M messages";
case JS_EXEC_COUNT:
- return (msg.getThreshold() / 1000000) + "M JavaScript functions";
+ return (value / 1000000) + "M JavaScript functions";
case RE_EXEC_COUNT:
- return (msg.getThreshold() / 1000000) + "M Rule Engine nodes";
+ return (value / 1000000) + "M Rule Engine nodes";
default:
throw new RuntimeException("Not implemented!");
}
diff --git a/application/src/main/resources/templates/state.enabled.ftl b/application/src/main/resources/templates/state.enabled.ftl
index 497b3cd780..52db9683b7 100644
--- a/application/src/main/resources/templates/state.enabled.ftl
+++ b/application/src/main/resources/templates/state.enabled.ftl
@@ -15,112 +15,141 @@
limitations under the License.
-->
-
-
+
+
-
-
-Thingsboard - Api Usage State
+
+
+ Thingsboard - Api Usage State
-
+
-
+
- |
-
-
-
-
-
-
- Thingsboard Api Usage State for tenant has been updated
- |
-
-
- |
- Thingsboard Usage state ${apiFeature} was updated to status ENABLED.
- |
-
- <#list apiUsageStateMailMessages as msg>
-
- |
- ${msg.key.apiLimitKey} = ${msg.threshold}
- |
-
-
- |
- ${msg.key.apiCountKey} = ${msg.value}
- |
-
- #list>
-
- |
- — The Thingsboard
- |
- |
-
-
-
-
+
+
+
+
+
+
+
+
+ Your ThingsBoard account feature was enabled
+ |
+
+
+ | We have enabled the ${apiFeature} for your account and ThingsBoard already able to ${apiLabel} messages.
+ |
+
+
+ | — The ThingsBoard
+ |
+
+
+
|
- |
+
+
+
diff --git a/application/src/main/resources/templates/state.warning.ftl b/application/src/main/resources/templates/state.warning.ftl
index bd4424a0b9..1a2787a9f5 100644
--- a/application/src/main/resources/templates/state.warning.ftl
+++ b/application/src/main/resources/templates/state.warning.ftl
@@ -15,112 +15,148 @@
limitations under the License.
-->
-
-
+
+
-
-
-Thingsboard - Api Usage State
+
+
+ Thingsboard - Api Usage State
-
+
-
+
- |
-
-
-
-
-
-
- Thingsboard Api Usage State for tenant has been updated
- |
-
-
- |
- Thingsboard Usage state ${apiFeature} was updated to status WARNING.
- |
-
- <#list apiUsageStateMailMessages as msg>
-
- |
- ${msg.key.apiLimitKey} = ${msg.threshold}
- |
-
-
- |
- ${msg.key.apiCountKey} = ${msg.value}
- |
-
- #list>
-
- |
- — The Thingsboard
- |
- |
-
-
-
-
+
+
+
+
+
+
+
+
+ Your ThingsBoard account feature may be disabled
+ |
+
+
+
+ Your ${apiFeature} limit (${apiLimitValueLabel}) is almost exhausted. ThingsBoard has already ${apiValueLabel}. ${apiFeature} will be disabled for your account when limit will be reached.
+ |
+
+
+ | Please contact your system administrator to resolve the issue.
+ |
+
+
+ | — The ThingsBoard
+ |
+
+
+
|
- |
+
+
+
|
|