Commit 1c79480b332c20151c9d99acef82f3059522617a

Authored by YevhenBondarenko
Committed by Andrew Shvayka
1 parent 449cb594

created sendApiFeatureStateEmail

... ... @@ -17,21 +17,21 @@ package org.thingsboard.server.service.apiusage;
17 17
18 18 import com.google.common.util.concurrent.FutureCallback;
19 19 import lombok.extern.slf4j.Slf4j;
  20 +import org.apache.commons.lang3.StringUtils;
20 21 import org.checkerframework.checker.nullness.qual.Nullable;
21 22 import org.springframework.beans.factory.annotation.Autowired;
22 23 import org.springframework.beans.factory.annotation.Value;
23   -import org.springframework.boot.context.event.ApplicationReadyEvent;
24 24 import org.springframework.context.annotation.Lazy;
25   -import org.springframework.context.event.EventListener;
26   -import org.springframework.core.annotation.Order;
27   -import org.springframework.data.util.Pair;
28 25 import org.springframework.stereotype.Service;
  26 +import org.thingsboard.rule.engine.api.MailService;
29 27 import org.thingsboard.server.common.data.ApiFeature;
30 28 import org.thingsboard.server.common.data.ApiUsageRecordKey;
31 29 import org.thingsboard.server.common.data.ApiUsageState;
  30 +import org.thingsboard.server.common.data.ApiUsageStateMailMessage;
32 31 import org.thingsboard.server.common.data.ApiUsageStateValue;
33 32 import org.thingsboard.server.common.data.Tenant;
34 33 import org.thingsboard.server.common.data.TenantProfile;
  34 +import org.thingsboard.server.common.data.exception.ThingsboardException;
35 35 import org.thingsboard.server.common.data.id.ApiUsageStateId;
36 36 import org.thingsboard.server.common.data.id.TenantId;
37 37 import org.thingsboard.server.common.data.id.TenantProfileId;
... ... @@ -45,6 +45,7 @@ import org.thingsboard.server.common.data.tenant.profile.TenantProfileData;
45 45 import org.thingsboard.server.common.msg.queue.ServiceType;
46 46 import org.thingsboard.server.common.msg.queue.TbCallback;
47 47 import org.thingsboard.server.common.msg.tools.SchedulerUtils;
  48 +import org.thingsboard.server.dao.tenant.TbTenantProfileCache;
48 49 import org.thingsboard.server.dao.tenant.TenantService;
49 50 import org.thingsboard.server.dao.timeseries.TimeseriesService;
50 51 import org.thingsboard.server.dao.usagerecord.ApiUsageStateService;
... ... @@ -54,14 +55,11 @@ import org.thingsboard.server.queue.common.TbProtoQueueMsg;
54 55 import org.thingsboard.server.queue.discovery.PartitionChangeEvent;
55 56 import org.thingsboard.server.queue.discovery.PartitionService;
56 57 import org.thingsboard.server.queue.scheduler.SchedulerComponent;
57   -import org.thingsboard.server.queue.util.TbCoreComponent;
58   -import org.thingsboard.server.dao.tenant.TbTenantProfileCache;
59 58 import org.thingsboard.server.service.queue.TbClusterService;
60 59 import org.thingsboard.server.service.telemetry.InternalTelemetryService;
61 60
62 61 import javax.annotation.PostConstruct;
63 62 import java.util.ArrayList;
64   -import java.util.HashMap;
65 63 import java.util.HashSet;
66 64 import java.util.List;
67 65 import java.util.Map;
... ... @@ -94,6 +92,7 @@ public class DefaultTbApiUsageStateService implements TbApiUsageStateService {
94 92 private final ApiUsageStateService apiUsageStateService;
95 93 private final SchedulerComponent scheduler;
96 94 private final TbTenantProfileCache tenantProfileCache;
  95 + private final MailService mailService;
97 96
98 97 @Lazy
99 98 @Autowired
... ... @@ -118,7 +117,7 @@ public class DefaultTbApiUsageStateService implements TbApiUsageStateService {
118 117 TimeseriesService tsService,
119 118 ApiUsageStateService apiUsageStateService,
120 119 SchedulerComponent scheduler,
121   - TbTenantProfileCache tenantProfileCache) {
  120 + TbTenantProfileCache tenantProfileCache, MailService mailService) {
122 121 this.clusterService = clusterService;
123 122 this.partitionService = partitionService;
124 123 this.tenantService = tenantService;
... ... @@ -126,6 +125,7 @@ public class DefaultTbApiUsageStateService implements TbApiUsageStateService {
126 125 this.apiUsageStateService = apiUsageStateService;
127 126 this.scheduler = scheduler;
128 127 this.tenantProfileCache = tenantProfileCache;
  128 + this.mailService = mailService;
129 129 }
130 130
131 131 @PostConstruct
... ... @@ -286,7 +286,26 @@ public class DefaultTbApiUsageStateService implements TbApiUsageStateService {
286 286 List<TsKvEntry> stateTelemetry = new ArrayList<>();
287 287 result.forEach(((apiFeature, aState) -> stateTelemetry.add(new BasicTsKvEntry(ts, new StringDataEntry(apiFeature.getApiStateKey(), aState.name())))));
288 288 tsWsService.saveAndNotifyInternal(state.getTenantId(), state.getApiUsageState().getId(), stateTelemetry, VOID_CALLBACK);
289   - //TODO: notify tenant admin via email!
  289 +
  290 + String email = tenantService.findTenantById(state.getTenantId()).getEmail();
  291 +
  292 + if (StringUtils.isNotEmpty(email)) {
  293 + result.forEach((apiFeature, stateValue) -> {
  294 + ApiUsageRecordKey[] keys = ApiUsageRecordKey.getKeys(apiFeature);
  295 + ApiUsageStateMailMessage[] msgs = new ApiUsageStateMailMessage[keys.length];
  296 + for (int i = 0; i < keys.length; i++) {
  297 + ApiUsageRecordKey key = keys[i];
  298 + msgs[i] = new ApiUsageStateMailMessage(key, state.getProfileThreshold(key), state.get(key));
  299 + }
  300 + try {
  301 + mailService.sendApiFeatureStateEmail(apiFeature, stateValue, email, msgs);
  302 + } catch (ThingsboardException e) {
  303 + log.warn("[{}] Can't send update of the API state to tenant with provided email [{}]", state.getTenantId(), email, e);
  304 + }
  305 + });
  306 + } else {
  307 + log.warn("[{}] Can't send update of the API state to tenant with empty email!", state.getTenantId());
  308 + }
290 309 }
291 310
292 311 private void checkStartOfNextCycle() {
... ...
... ... @@ -29,6 +29,9 @@ import org.springframework.stereotype.Service;
29 29 import org.springframework.ui.freemarker.FreeMarkerTemplateUtils;
30 30 import org.thingsboard.rule.engine.api.MailService;
31 31 import org.thingsboard.server.common.data.AdminSettings;
  32 +import org.thingsboard.server.common.data.ApiFeature;
  33 +import org.thingsboard.server.common.data.ApiUsageStateMailMessage;
  34 +import org.thingsboard.server.common.data.ApiUsageStateValue;
32 35 import org.thingsboard.server.common.data.exception.ThingsboardErrorCode;
33 36 import org.thingsboard.server.common.data.exception.ThingsboardException;
34 37 import org.thingsboard.server.common.data.id.EntityId;
... ... @@ -246,6 +249,32 @@ public class DefaultMailService implements MailService {
246 249 sendMail(mailSender, mailFrom, email, subject, message);
247 250 }
248 251
  252 + @Override
  253 + public void sendApiFeatureStateEmail(ApiFeature apiFeature, ApiUsageStateValue stateValue, String email, ApiUsageStateMailMessage[] stateMailMessages) throws ThingsboardException {
  254 + String subject = messages.getMessage("api.usage.state", null, Locale.US);
  255 +
  256 + Map<String, Object> model = new HashMap<>();
  257 + model.put("apiFeature", apiFeature.getApiStateKey());
  258 + model.put("apiUsageStateMailMessages", stateMailMessages);
  259 +
  260 + model.put(TARGET_EMAIL, email);
  261 +
  262 + String message = null;
  263 +
  264 + switch (stateValue) {
  265 + case ENABLED:
  266 + message = mergeTemplateIntoString("state.enabled.ftl", model);
  267 + break;
  268 + case WARNING:
  269 + message = mergeTemplateIntoString("state.warning.ftl", model);
  270 + break;
  271 + case DISABLED:
  272 + message = mergeTemplateIntoString("state.disabled.ftl", model);
  273 + break;
  274 + }
  275 + sendMail(mailSender, mailFrom, email, subject, message);
  276 + }
  277 +
249 278 private void sendMail(JavaMailSenderImpl mailSender,
250 279 String mailFrom, String email,
251 280 String subject, String message) throws ThingsboardException {
... ...
... ... @@ -3,4 +3,5 @@ activation.subject=Your account activation on Thingsboard
3 3 account.activated.subject=Thingsboard - your account has been activated
4 4 reset.password.subject=Thingsboard - Password reset has been requested
5 5 password.was.reset.subject=Thingsboard - your account password has been reset
6   -account.lockout.subject=Thingsboard - User account has been lockout
\ No newline at end of file
  6 +account.lockout.subject=Thingsboard - User account has been lockout
  7 +api.usage.state=Thingsboard - Api Usage State for tenant has been updated
\ No newline at end of file
... ...
  1 +<#--
  2 +
  3 + Copyright © 2016-2020 The Thingsboard Authors
  4 +
  5 + Licensed under the Apache License, Version 2.0 (the "License");
  6 + you may not use this file except in compliance with the License.
  7 + You may obtain a copy of the License at
  8 +
  9 + http://www.apache.org/licenses/LICENSE-2.0
  10 +
  11 + Unless required by applicable law or agreed to in writing, software
  12 + distributed under the License is distributed on an "AS IS" BASIS,
  13 + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14 + See the License for the specific language governing permissions and
  15 + limitations under the License.
  16 +
  17 +-->
  18 +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
  19 +<html xmlns="http://www.w3.org/1999/xhtml" style="font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 14px; margin: 0;">
  20 +<head>
  21 +<meta name="viewport" content="width=device-width" />
  22 +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
  23 +<title>Thingsboard - Api Usage State</title>
  24 +
  25 +
  26 +<style type="text/css">
  27 +img {
  28 +max-width: 100%;
  29 +}
  30 +body {
  31 +-webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none; width: 100% !important; height: 100%; line-height: 1.6em;
  32 +}
  33 +body {
  34 +background-color: #f6f6f6;
  35 +}
  36 +@media only screen and (max-width: 640px) {
  37 + body {
  38 + padding: 0 !important;
  39 + }
  40 + h1 {
  41 + font-weight: 800 !important; margin: 20px 0 5px !important;
  42 + }
  43 + h2 {
  44 + font-weight: 800 !important; margin: 20px 0 5px !important;
  45 + }
  46 + h3 {
  47 + font-weight: 800 !important; margin: 20px 0 5px !important;
  48 + }
  49 + h4 {
  50 + font-weight: 800 !important; margin: 20px 0 5px !important;
  51 + }
  52 + h1 {
  53 + font-size: 22px !important;
  54 + }
  55 + h2 {
  56 + font-size: 18px !important;
  57 + }
  58 + h3 {
  59 + font-size: 16px !important;
  60 + }
  61 + .container {
  62 + padding: 0 !important; width: 100% !important;
  63 + }
  64 + .content {
  65 + padding: 0 !important;
  66 + }
  67 + .content-wrap {
  68 + padding: 10px !important;
  69 + }
  70 + .invoice {
  71 + width: 100% !important;
  72 + }
  73 +}
  74 +</style>
  75 +</head>
  76 +
  77 +<body itemscope itemtype="http://schema.org/EmailMessage" style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; -webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none; width: 100% !important; height: 100%; line-height: 1.6em; background-color: #f6f6f6; margin: 0;" bgcolor="#f6f6f6">
  78 +
  79 +<table class="body-wrap" style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; width: 100%; background-color: #f6f6f6; margin: 0;" bgcolor="#f6f6f6"><tr style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; margin: 0;"><td style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; vertical-align: top; margin: 0;" valign="top"></td>
  80 + <td class="container" width="600" style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; vertical-align: top; display: block !important; max-width: 600px !important; clear: both !important; margin: 0 auto;" valign="top">
  81 + <div class="content" style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; max-width: 600px; display: block; margin: 0 auto; padding: 20px;">
  82 + <table class="main" width="100%" cellpadding="0" cellspacing="0" itemprop="action" itemscope itemtype="http://schema.org/ConfirmAction" style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; border-radius: 3px; background-color: #fff; margin: 0; border: 1px solid #e9e9e9;" bgcolor="#fff"><tr style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; margin: 0;"><td class="content-wrap" style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; vertical-align: top; margin: 0; padding: 20px;" valign="top">
  83 + <meta itemprop="name" content="Confirm Email" style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; margin: 0;" /><table width="100%" cellpadding="0" cellspacing="0" style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; margin: 0;">
  84 + <tr style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; margin: 0;">
  85 + <td class="content-block" style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; color: #348eda; box-sizing: border-box; font-size: 14px; vertical-align: top; margin: 0; padding: 0 0 20px;" valign="top">
  86 + <h2>Thingsboard Api Usage State for tenant has been updated</h2>
  87 + </td>
  88 + </tr>
  89 + <tr style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; margin: 0;">
  90 + <td class="content-block" style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; vertical-align: top; margin: 0; padding: 0 0 20px;" valign="top">
  91 + Thingsboard Usage state ${apiFeature} was updated to status DISABLED.
  92 + </td>
  93 + </tr>
  94 + <#list apiUsageStateMailMessages as msg>
  95 + <tr>
  96 + <td>
  97 + ${msg.key.apiLimitKey} = ${msg.threshold}
  98 + </td>
  99 + </tr>
  100 + <tr>
  101 + <td>
  102 + ${msg.key.apiCountKey} = ${msg.value}
  103 + </td>
  104 + </tr>
  105 + </#list>
  106 + <tr style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; margin: 0;">
  107 + <td class="content-block" style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; vertical-align: top; margin: 0; padding: 0 0 20px;" valign="top">
  108 + &mdash; The Thingsboard
  109 + </td>
  110 + </tr></table></td>
  111 + </tr>
  112 + </table>
  113 + <div class="footer" style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; width: 100%; clear: both; color: #999; margin: 0; padding: 20px;">
  114 + <table width="100%" style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; margin: 0;">
  115 + <tr style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; margin: 0;">
  116 + <td class="aligncenter content-block" style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 12px; vertical-align: top; color: #999; text-align: center; margin: 0; padding: 0 0 20px;" align="center" valign="top">This email was sent to <a href="mailto:${targetEmail}" style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 12px; color: #999; text-decoration: underline; margin: 0;">${targetEmail}</a> by Thingsboard.</td>
  117 + </tr>
  118 + </table>
  119 + </div>
  120 + </div>
  121 + </td>
  122 + <td style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; vertical-align: top; margin: 0;" valign="top"></td>
  123 + </tr>
  124 +</table>
  125 +</body>
  126 +</html>
... ...
  1 +<#--
  2 +
  3 + Copyright © 2016-2020 The Thingsboard Authors
  4 +
  5 + Licensed under the Apache License, Version 2.0 (the "License");
  6 + you may not use this file except in compliance with the License.
  7 + You may obtain a copy of the License at
  8 +
  9 + http://www.apache.org/licenses/LICENSE-2.0
  10 +
  11 + Unless required by applicable law or agreed to in writing, software
  12 + distributed under the License is distributed on an "AS IS" BASIS,
  13 + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14 + See the License for the specific language governing permissions and
  15 + limitations under the License.
  16 +
  17 +-->
  18 +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
  19 +<html xmlns="http://www.w3.org/1999/xhtml" style="font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 14px; margin: 0;">
  20 +<head>
  21 +<meta name="viewport" content="width=device-width" />
  22 +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
  23 +<title>Thingsboard - Api Usage State</title>
  24 +
  25 +
  26 +<style type="text/css">
  27 +img {
  28 +max-width: 100%;
  29 +}
  30 +body {
  31 +-webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none; width: 100% !important; height: 100%; line-height: 1.6em;
  32 +}
  33 +body {
  34 +background-color: #f6f6f6;
  35 +}
  36 +@media only screen and (max-width: 640px) {
  37 + body {
  38 + padding: 0 !important;
  39 + }
  40 + h1 {
  41 + font-weight: 800 !important; margin: 20px 0 5px !important;
  42 + }
  43 + h2 {
  44 + font-weight: 800 !important; margin: 20px 0 5px !important;
  45 + }
  46 + h3 {
  47 + font-weight: 800 !important; margin: 20px 0 5px !important;
  48 + }
  49 + h4 {
  50 + font-weight: 800 !important; margin: 20px 0 5px !important;
  51 + }
  52 + h1 {
  53 + font-size: 22px !important;
  54 + }
  55 + h2 {
  56 + font-size: 18px !important;
  57 + }
  58 + h3 {
  59 + font-size: 16px !important;
  60 + }
  61 + .container {
  62 + padding: 0 !important; width: 100% !important;
  63 + }
  64 + .content {
  65 + padding: 0 !important;
  66 + }
  67 + .content-wrap {
  68 + padding: 10px !important;
  69 + }
  70 + .invoice {
  71 + width: 100% !important;
  72 + }
  73 +}
  74 +</style>
  75 +</head>
  76 +
  77 +<body itemscope itemtype="http://schema.org/EmailMessage" style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; -webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none; width: 100% !important; height: 100%; line-height: 1.6em; background-color: #f6f6f6; margin: 0;" bgcolor="#f6f6f6">
  78 +
  79 +<table class="body-wrap" style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; width: 100%; background-color: #f6f6f6; margin: 0;" bgcolor="#f6f6f6"><tr style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; margin: 0;"><td style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; vertical-align: top; margin: 0;" valign="top"></td>
  80 + <td class="container" width="600" style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; vertical-align: top; display: block !important; max-width: 600px !important; clear: both !important; margin: 0 auto;" valign="top">
  81 + <div class="content" style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; max-width: 600px; display: block; margin: 0 auto; padding: 20px;">
  82 + <table class="main" width="100%" cellpadding="0" cellspacing="0" itemprop="action" itemscope itemtype="http://schema.org/ConfirmAction" style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; border-radius: 3px; background-color: #fff; margin: 0; border: 1px solid #e9e9e9;" bgcolor="#fff"><tr style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; margin: 0;"><td class="content-wrap" style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; vertical-align: top; margin: 0; padding: 20px;" valign="top">
  83 + <meta itemprop="name" content="Confirm Email" style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; margin: 0;" /><table width="100%" cellpadding="0" cellspacing="0" style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; margin: 0;">
  84 + <tr style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; margin: 0;">
  85 + <td class="content-block" style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; color: #348eda; box-sizing: border-box; font-size: 14px; vertical-align: top; margin: 0; padding: 0 0 20px;" valign="top">
  86 + <h2>Thingsboard Api Usage State for tenant has been updated</h2>
  87 + </td>
  88 + </tr>
  89 + <tr style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; margin: 0 ;">
  90 + <td class="content-block" style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; vertical-align: top; margin: 0; padding: 0 0 20px;" valign="top">
  91 + Thingsboard Usage state ${apiFeature} was updated to status ENABLED.
  92 + </td>
  93 + </tr>
  94 + <#list apiUsageStateMailMessages as msg>
  95 + <tr>
  96 + <td>
  97 + ${msg.key.apiLimitKey} = ${msg.threshold}
  98 + </td>
  99 + </tr>
  100 + <tr>
  101 + <td>
  102 + ${msg.key.apiCountKey} = ${msg.value}
  103 + </td>
  104 + </tr>
  105 + </#list>
  106 + <tr style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; margin: 0;">
  107 + <td class="content-block" style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; vertical-align: top; margin: 0; padding: 0 0 20px;" valign="top">
  108 + &mdash; The Thingsboard
  109 + </td>
  110 + </tr></table></td>
  111 + </tr>
  112 + </table>
  113 + <div class="footer" style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; width: 100%; clear: both; color: #999; margin: 0; padding: 20px;">
  114 + <table width="100%" style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; margin: 0;">
  115 + <tr style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; margin: 0;">
  116 + <td class="aligncenter content-block" style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 12px; vertical-align: top; color: #999; text-align: center; margin: 0; padding: 0 0 20px;" align="center" valign="top">This email was sent to <a href="mailto:${targetEmail}" style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 12px; color: #999; text-decoration: underline; margin: 0;">${targetEmail}</a> by Thingsboard.</td>
  117 + </tr>
  118 + </table>
  119 + </div>
  120 + </div>
  121 + </td>
  122 + <td style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; vertical-align: top; margin: 0;" valign="top"></td>
  123 + </tr>
  124 +</table>
  125 +</body>
  126 +</html>
... ...
  1 +<#--
  2 +
  3 + Copyright © 2016-2020 The Thingsboard Authors
  4 +
  5 + Licensed under the Apache License, Version 2.0 (the "License");
  6 + you may not use this file except in compliance with the License.
  7 + You may obtain a copy of the License at
  8 +
  9 + http://www.apache.org/licenses/LICENSE-2.0
  10 +
  11 + Unless required by applicable law or agreed to in writing, software
  12 + distributed under the License is distributed on an "AS IS" BASIS,
  13 + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14 + See the License for the specific language governing permissions and
  15 + limitations under the License.
  16 +
  17 +-->
  18 +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
  19 +<html xmlns="http://www.w3.org/1999/xhtml" style="font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 14px; margin: 0;">
  20 +<head>
  21 +<meta name="viewport" content="width=device-width" />
  22 +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
  23 +<title>Thingsboard - Api Usage State</title>
  24 +
  25 +
  26 +<style type="text/css">
  27 +img {
  28 +max-width: 100%;
  29 +}
  30 +body {
  31 +-webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none; width: 100% !important; height: 100%; line-height: 1.6em;
  32 +}
  33 +body {
  34 +background-color: #f6f6f6;
  35 +}
  36 +@media only screen and (max-width: 640px) {
  37 + body {
  38 + padding: 0 !important;
  39 + }
  40 + h1 {
  41 + font-weight: 800 !important; margin: 20px 0 5px !important;
  42 + }
  43 + h2 {
  44 + font-weight: 800 !important; margin: 20px 0 5px !important;
  45 + }
  46 + h3 {
  47 + font-weight: 800 !important; margin: 20px 0 5px !important;
  48 + }
  49 + h4 {
  50 + font-weight: 800 !important; margin: 20px 0 5px !important;
  51 + }
  52 + h1 {
  53 + font-size: 22px !important;
  54 + }
  55 + h2 {
  56 + font-size: 18px !important;
  57 + }
  58 + h3 {
  59 + font-size: 16px !important;
  60 + }
  61 + .container {
  62 + padding: 0 !important; width: 100% !important;
  63 + }
  64 + .content {
  65 + padding: 0 !important;
  66 + }
  67 + .content-wrap {
  68 + padding: 10px !important;
  69 + }
  70 + .invoice {
  71 + width: 100% !important;
  72 + }
  73 +}
  74 +</style>
  75 +</head>
  76 +
  77 +<body itemscope itemtype="http://schema.org/EmailMessage" style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; -webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none; width: 100% !important; height: 100%; line-height: 1.6em; background-color: #f6f6f6; margin: 0;" bgcolor="#f6f6f6">
  78 +
  79 +<table class="body-wrap" style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; width: 100%; background-color: #f6f6f6; margin: 0;" bgcolor="#f6f6f6"><tr style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; margin: 0;"><td style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; vertical-align: top; margin: 0;" valign="top"></td>
  80 + <td class="container" width="600" style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; vertical-align: top; display: block !important; max-width: 600px !important; clear: both !important; margin: 0 auto;" valign="top">
  81 + <div class="content" style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; max-width: 600px; display: block; margin: 0 auto; padding: 20px;">
  82 + <table class="main" width="100%" cellpadding="0" cellspacing="0" itemprop="action" itemscope itemtype="http://schema.org/ConfirmAction" style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; border-radius: 3px; background-color: #fff; margin: 0; border: 1px solid #e9e9e9;" bgcolor="#fff"><tr style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; margin: 0;"><td class="content-wrap" style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; vertical-align: top; margin: 0; padding: 20px;" valign="top">
  83 + <meta itemprop="name" content="Confirm Email" style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; margin: 0;" /><table width="100%" cellpadding="0" cellspacing="0" style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; margin: 0;">
  84 + <tr style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; margin: 0;">
  85 + <td class="content-block" style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; color: #348eda; box-sizing: border-box; font-size: 14px; vertical-align: top; margin: 0; padding: 0 0 20px;" valign="top">
  86 + <h2>Thingsboard Api Usage State for tenant has been updated</h2>
  87 + </td>
  88 + </tr>
  89 + <tr style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; margin: 0;">
  90 + <td class="content-block" style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; vertical-align: top; margin: 0; padding: 0 0 20px;" valign="top">
  91 + Thingsboard Usage state ${apiFeature} was updated to status WARNING.
  92 + </td>
  93 + </tr>
  94 + <#list apiUsageStateMailMessages as msg>
  95 + <tr>
  96 + <td>
  97 + ${msg.key.apiLimitKey} = ${msg.threshold}
  98 + </td>
  99 + </tr>
  100 + <tr>
  101 + <td>
  102 + ${msg.key.apiCountKey} = ${msg.value}
  103 + </td>
  104 + </tr>
  105 + </#list>
  106 + <tr style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; margin: 0;">
  107 + <td class="content-block" style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; vertical-align: top; margin: 0; padding: 0 0 20px;" valign="top">
  108 + &mdash; The Thingsboard
  109 + </td>
  110 + </tr></table></td>
  111 + </tr>
  112 + </table>
  113 + <div class="footer" style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; width: 100%; clear: both; color: #999; margin: 0; padding: 20px;">
  114 + <table width="100%" style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; margin: 0;">
  115 + <tr style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; margin: 0;">
  116 + <td class="aligncenter content-block" style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 12px; vertical-align: top; color: #999; text-align: center; margin: 0; padding: 0 0 20px;" align="center" valign="top">This email was sent to <a href="mailto:${targetEmail}" style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 12px; color: #999; text-decoration: underline; margin: 0;">${targetEmail}</a> by Thingsboard.</td>
  117 + </tr>
  118 + </table>
  119 + </div>
  120 + </div>
  121 + </td>
  122 + <td style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; vertical-align: top; margin: 0;" valign="top"></td>
  123 + </tr>
  124 +</table>
  125 +</body>
  126 +</html>
... ...
  1 +/**
  2 + * Copyright © 2016-2020 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.thingsboard.server.common.data;
  17 +
  18 +import lombok.Data;
  19 +
  20 +@Data
  21 +public class ApiUsageStateMailMessage {
  22 + private final ApiUsageRecordKey key;
  23 + private final long threshold;
  24 + private final long value;
  25 +}
... ...
... ... @@ -16,6 +16,9 @@
16 16 package org.thingsboard.rule.engine.api;
17 17
18 18 import com.fasterxml.jackson.databind.JsonNode;
  19 +import org.thingsboard.server.common.data.ApiFeature;
  20 +import org.thingsboard.server.common.data.ApiUsageStateMailMessage;
  21 +import org.thingsboard.server.common.data.ApiUsageStateValue;
19 22 import org.thingsboard.server.common.data.exception.ThingsboardException;
20 23
21 24 import javax.mail.MessagingException;
... ... @@ -39,4 +42,6 @@ public interface MailService {
39 42 void send(String from, String to, String cc, String bcc, String subject, String body) throws MessagingException;
40 43
41 44 void sendAccountLockoutEmail( String lockoutEmail, String email, Integer maxFailedLoginAttempts) throws ThingsboardException;
  45 +
  46 + void sendApiFeatureStateEmail(ApiFeature apiFeature, ApiUsageStateValue stateValue, String email, ApiUsageStateMailMessage[] stateMailMessages) throws ThingsboardException;
42 47 }
... ...