From 53e7ead94cafaef58b34774c52e4994ed466225f Mon Sep 17 00:00:00 2001 From: Sergey Matvienko Date: Thu, 22 Dec 2022 17:22:37 +0100 Subject: [PATCH 01/28] log node fix: for new LogRuleNode MVEL script ignored as it considered standard, because the JS script was standard. Test added for any new script type --- .../thingsboard/rule/engine/action/TbLogNode.java | 15 ++++++++++++++- .../rule/engine/action/TbLogNodeTest.java | 12 ++++++++++++ 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbLogNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbLogNode.java index 5943800a14..7bb388e7a3 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbLogNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbLogNode.java @@ -32,6 +32,8 @@ import org.thingsboard.server.common.data.plugin.ComponentType; import org.thingsboard.server.common.data.script.ScriptLanguage; import org.thingsboard.server.common.msg.TbMsg; +import java.util.Objects; + @Slf4j @RuleNode( type = ComponentType.ACTION, @@ -54,7 +56,7 @@ public class TbLogNode implements TbNode { @Override public void init(TbContext ctx, TbNodeConfiguration configuration) throws TbNodeException { this.config = TbNodeUtils.convert(configuration, TbLogNodeConfiguration.class); - this.standard = new TbLogNodeConfiguration().defaultConfiguration().getJsScript().equals(config.getJsScript()); + this.standard = isStandard(config); this.scriptEngine = this.standard ? null : ctx.createScriptEngine(config.getScriptLang(), ScriptLanguage.TBEL.equals(config.getScriptLang()) ? config.getTbelScript() : config.getJsScript()); } @@ -83,6 +85,17 @@ public class TbLogNode implements TbNode { }, MoreExecutors.directExecutor()); //usually js responses runs on js callback executor } + boolean isStandard(TbLogNodeConfiguration conf) { + Objects.requireNonNull(conf, "node config is null"); + final TbLogNodeConfiguration defaultConfig = new TbLogNodeConfiguration().defaultConfiguration(); + switch (conf.getScriptLang()) { + case JS: return defaultConfig.getJsScript().equals(conf.getJsScript()); + case TBEL: return defaultConfig.getTbelScript().equals(conf.getTbelScript()); + } + log.warn("No rule to define isStandard script for script language [{}], assuming that is non-standard", conf.getScriptLang()); + return false; + } + void logStandard(TbContext ctx, TbMsg msg) { log.info(toLogMessage(msg)); ctx.tellSuccess(msg); diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/action/TbLogNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/action/TbLogNodeTest.java index fd1a5af6c1..8e1a648b83 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/action/TbLogNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/action/TbLogNodeTest.java @@ -18,6 +18,7 @@ package org.thingsboard.rule.engine.action; import lombok.extern.slf4j.Slf4j; import org.junit.jupiter.api.Test; import org.thingsboard.server.common.data.id.TenantId; +import org.thingsboard.server.common.data.script.ScriptLanguage; import org.thingsboard.server.common.msg.TbMsg; import org.thingsboard.server.common.msg.TbMsgMetaData; @@ -61,6 +62,7 @@ public class TbLogNodeTest { "Incoming metadata:\n" + "{}"); } + @Test void givenNullDataMsg_whenToLog_thenReturnString() { TbLogNode node = new TbLogNode(); @@ -77,4 +79,14 @@ public class TbLogNodeTest { "{}"); } + @Test + void givenDefaultConfig_whenIsStandardForEachScriptLanguage_thenTrue() { + TbLogNode node = new TbLogNode(); + for (ScriptLanguage scriptLanguage : ScriptLanguage.values()) { + TbLogNodeConfiguration config = new TbLogNodeConfiguration().defaultConfiguration(); + config.setScriptLang(scriptLanguage); + assertThat(node.isStandard(config)).as("Script is standard for language " + scriptLanguage).isTrue(); + } + } + } From f590bf64fcd0b4b52b1961b250f30cc1798e84f0 Mon Sep 17 00:00:00 2001 From: Seraphym-Tuhai Date: Wed, 8 Mar 2023 14:10:51 +0200 Subject: [PATCH 02/28] fix tests after update on UI --- .../msa/ui/pages/CustomerPageElements.java | 14 ++--- .../msa/ui/pages/CustomerPageHelper.java | 6 +++ .../msa/ui/pages/DashboardPageHelper.java | 6 +-- .../ui/pages/OpenRuleChainPageElements.java | 7 +-- .../msa/ui/pages/OpenRuleChainPageHelper.java | 5 +- .../msa/ui/pages/OtherPageElements.java | 17 +++--- .../msa/ui/pages/OtherPageElementsHelper.java | 52 +++++-------------- .../msa/ui/pages/RuleChainsPageElements.java | 2 +- .../CreateAssetProfileTest.java | 2 +- .../customerSmoke/CustomerEditMenuTest.java | 24 ++++----- .../customerSmoke/DeleteCustomerTest.java | 4 +- .../DeleteSeveralCustomerTest.java | 10 ++-- .../ManageCustomersAssetsTest.java | 2 +- .../ManageCustomersDashboardsTest.java | 2 +- .../ManageCustomersUsersTest.java | 2 +- .../CreateDeviceProfileTest.java | 2 +- .../CreateRuleChainImportTest.java | 11 ++-- .../ruleChainsSmoke/DeleteRuleChainTest.java | 4 +- .../DeleteSeveralRuleChainsTest.java | 10 ++-- 19 files changed, 75 insertions(+), 107 deletions(-) diff --git a/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/ui/pages/CustomerPageElements.java b/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/ui/pages/CustomerPageElements.java index de9e9d5bac..7caf109bc0 100644 --- a/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/ui/pages/CustomerPageElements.java +++ b/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/ui/pages/CustomerPageElements.java @@ -32,17 +32,17 @@ public class CustomerPageElements extends OtherPageElementsHelper { private static final String TITLES = "//mat-cell[contains(@class,'cdk-column-title')]/span"; protected static final String EDIT_MENU_DASHBOARD_FIELD = "//input[@formcontrolname='dashboard']"; private static final String EDIT_MENU_DASHBOARD = "//div[@class='cdk-overlay-pane']//span/span"; - private static final String MANAGE_CUSTOMERS_USERS_BTN = ENTITY + "/../..//mat-icon[contains(text(),' account_circle')]/../.."; - private static final String MANAGE_CUSTOMERS_ASSETS_BTN = ENTITY + "/../..//mat-icon[contains(text(),' domain')]/../.."; - private static final String MANAGE_CUSTOMERS_DEVICES_BTN = ENTITY + "/../..//mat-icon[contains(text(),' devices_other')]/../.."; - private static final String MANAGE_CUSTOMERS_DASHBOARDS_BTN = ENTITY + "/../..//mat-icon[contains(text(),' dashboard')]/../.."; - private static final String MANAGE_CUSTOMERS_EDGE_BTN = ENTITY + "/../..//mat-icon[contains(text(),' router')]/../.."; + private static final String MANAGE_CUSTOMERS_USERS_BTN = ENTITY + "/ancestor::mat-row//mat-icon[contains(text(),' account_circle')]"; + private static final String MANAGE_CUSTOMERS_ASSETS_BTN = ENTITY + "/ancestor::mat-row//mat-icon[contains(text(),' domain')]/parent::button"; + private static final String MANAGE_CUSTOMERS_DEVICES_BTN = ENTITY + "/ancestor::mat-row//mat-icon[contains(text(),'devices_other')]/parent::button"; + private static final String MANAGE_CUSTOMERS_DASHBOARDS_BTN = ENTITY + "/ancestor::mat-row//mat-icon[contains(text(),'dashboard')]/parent::button"; + private static final String MANAGE_CUSTOMERS_EDGE_BTN = ENTITY + "/ancestor::mat-row//mat-icon[contains(text(),'router')]/parent::button"; private static final String ADD_USER_EMAIL = "//tb-add-user-dialog//input[@formcontrolname='email']"; private static final String ACTIVATE_WINDOW_OK_BTN = "//span[contains(text(),'OK')]"; private static final String USER_LOGIN_BTN = "//mat-icon[@data-mat-icon-name='login']"; private static final String USERS_WIDGET = "//tb-widget"; private static final String SELECT_COUNTRY_MENU = "//mat-form-field//mat-select[@formcontrolname='country']"; - private static final String COUNTRIES = "//span[@class='mat-option-text']"; + private static final String COUNTRIES = "//span[@class='mdc-list-item__primary-text']"; protected static final String INPUT_FIELD = "//input[@formcontrolname='%s']"; protected static final String INPUT_FIELD_NAME_TITLE = "title"; private static final String INPUT_FIELD_NAME_CITY = "city"; @@ -54,7 +54,7 @@ public class CustomerPageElements extends OtherPageElementsHelper { private static final String INPUT_FIELD_NAME_NUMBER = "phoneNumber"; private static final String INPUT_FIELD_NAME_ASSIGNED_LIST = "entity"; private static final String ASSIGNED_BTN = "//button[@type='submit']"; - private static final String HIDE_HOME_DASHBOARD_TOOLBAR = "//mat-checkbox[@formcontrolname='homeDashboardHideToolbar']/label"; + private static final String HIDE_HOME_DASHBOARD_TOOLBAR = "//mat-checkbox[@formcontrolname='homeDashboardHideToolbar']//label"; private static final String FILTER_BTN = "//tb-filters-edit"; private static final String TIME_BTN = "//tb-timewindow"; private static final String CUSTOMER_ICON_HEADER = "//tb-breadcrumb//span[contains(text(),'Customer %s')]"; diff --git a/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/ui/pages/CustomerPageHelper.java b/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/ui/pages/CustomerPageHelper.java index d657388354..26303d3e3a 100644 --- a/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/ui/pages/CustomerPageHelper.java +++ b/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/ui/pages/CustomerPageHelper.java @@ -17,6 +17,7 @@ package org.thingsboard.server.msa.ui.pages; import lombok.extern.slf4j.Slf4j; import org.openqa.selenium.By; +import org.openqa.selenium.Keys; import org.openqa.selenium.WebDriver; import org.openqa.selenium.support.ui.ExpectedConditions; @@ -156,4 +157,9 @@ public class CustomerPageHelper extends CustomerPageElements { public void addCustomerViewEnterName(CharSequence keysToEnter) { enterText(titleFieldAddEntityView(), keysToEnter); } + + public void enterPhoneNumber(String number) { + phoneNumberEntityView().sendKeys(number); + phoneNumberEntityView().sendKeys(Keys.TAB); + } } diff --git a/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/ui/pages/DashboardPageHelper.java b/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/ui/pages/DashboardPageHelper.java index e6ec13fd1f..6449cf0cbb 100644 --- a/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/ui/pages/DashboardPageHelper.java +++ b/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/ui/pages/DashboardPageHelper.java @@ -33,8 +33,8 @@ public class DashboardPageHelper extends DashboardPageElements { } public void assignedCustomer(String title) { - manageAssignedEntityListField().click(); - manageAssignedEntity(title).click(); - manageAssignedUpdateBtn().click(); + jsClick(manageAssignedEntityListField()); + jsClick(manageAssignedEntity(title)); + jsClick(manageAssignedUpdateBtn()); } } diff --git a/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/ui/pages/OpenRuleChainPageElements.java b/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/ui/pages/OpenRuleChainPageElements.java index 9a51392690..6fd114ad1d 100644 --- a/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/ui/pages/OpenRuleChainPageElements.java +++ b/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/ui/pages/OpenRuleChainPageElements.java @@ -24,8 +24,7 @@ public class OpenRuleChainPageElements extends AbstractBasePage { super(driver); } - private static final String DONE_BTN = "//mat-icon[contains(text(),'done')]/../.."; - private static final String DONE_BTN_DISABLE = "//mat-icon[contains(text(),'done')]/../parent::button[@disabled='true']"; + private static final String DONE_BTN = "//mat-icon[contains(text(),'done')]/parent::button"; private static final String INPUT_NODE = "//div[@class='tb-rule-node tb-input-type']"; private static final String HEAD_RULE_CHAIN_NAME = "//div[@class='tb-breadcrumb']/span[2]"; @@ -37,10 +36,6 @@ public class OpenRuleChainPageElements extends AbstractBasePage { return waitUntilVisibilityOfElementLocated(HEAD_RULE_CHAIN_NAME); } - public String getDoneBtnDisable() { - return DONE_BTN_DISABLE; - } - public WebElement doneBtn() { return waitUntilElementToBeClickable(DONE_BTN); } diff --git a/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/ui/pages/OpenRuleChainPageHelper.java b/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/ui/pages/OpenRuleChainPageHelper.java index 1a87102687..7bba9586dc 100644 --- a/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/ui/pages/OpenRuleChainPageHelper.java +++ b/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/ui/pages/OpenRuleChainPageHelper.java @@ -16,6 +16,7 @@ package org.thingsboard.server.msa.ui.pages; import org.openqa.selenium.WebDriver; +import org.openqa.selenium.WebElement; public class OpenRuleChainPageHelper extends OpenRuleChainPageElements { public OpenRuleChainPageHelper(WebDriver driver) { @@ -32,7 +33,7 @@ public class OpenRuleChainPageHelper extends OpenRuleChainPageElements { return headName; } - public void waitUntilDoneBtnDisable() { - waitUntilVisibilityOfElementLocated(getDoneBtnDisable()); + public void waitUntilBtnDisable(WebElement element) { + waitUntilAttributeContains(element, "disabled", "true"); } } diff --git a/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/ui/pages/OtherPageElements.java b/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/ui/pages/OtherPageElements.java index 99e737dba1..7cb5da3bc6 100644 --- a/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/ui/pages/OtherPageElements.java +++ b/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/ui/pages/OtherPageElements.java @@ -28,7 +28,7 @@ public class OtherPageElements extends AbstractBasePage { } protected static final String ENTITY = "//mat-row//span[contains(text(),'%s')]"; - protected static final String DELETE_BTN = ENTITY + "/../..//mat-icon[contains(text(),' delete')]/../.."; + protected static final String DELETE_BTN = ENTITY + "/ancestor::mat-row//mat-icon[contains(text(),'delete')]/ancestor::button"; protected static final String DETAILS_BTN = ENTITY + "/../..//mat-icon[contains(text(),'edit')]/../.."; private static final String ENTITY_COUNT = "//div[@class='mat-paginator-range-label']"; private static final String WARNING_DELETE_POPUP_YES = "//tb-confirm-dialog//button[2]"; @@ -37,11 +37,11 @@ public class OtherPageElements extends AbstractBasePage { private static final String HELP_BTN = "//mat-icon[contains(text(),'help')]/ancestor::button"; private static final String CHECKBOX = "//mat-row//span[contains(text(),'%s')]/../..//mat-checkbox"; private static final String CHECKBOXES = "//tbody//mat-checkbox"; - private static final String DELETE_SELECTED_BTN = "//span[contains(text(),'selected')]//..//mat-icon/../.."; + private static final String DELETE_SELECTED_BTN = "//div[@class='mat-toolbar-tools']//mat-icon[contains(text(),'delete')]/parent::button"; private static final String DELETE_BTNS = "//mat-icon[contains(text(),' delete')]/../.."; private static final String MARKS_CHECKBOX = "//mat-row[contains (@class,'mat-selected')]//mat-checkbox[contains(@class, 'checked')]"; private static final String SELECT_ALL_CHECKBOX = "//thead//mat-checkbox"; - private static final String ALL_ENTITY = "//mat-row[@class='mat-row cdk-row mat-row-select ng-star-inserted']"; + private static final String ALL_ENTITY = "//mat-row[@class='mat-mdc-row mdc-data-table__row cdk-row mat-row-select ng-star-inserted']"; private static final String EDIT_PENCIL_BTN = "//tb-details-panel//mat-icon[contains(text(),'edit')]/ancestor::button"; private static final String NAME_FIELD_EDIT_VIEW = "//input[@formcontrolname='name']"; private static final String HEADER_NAME_VIEW = "//header//div[@class='tb-details-title']/span"; @@ -50,14 +50,13 @@ public class OtherPageElements extends AbstractBasePage { private static final String DESCRIPTION_ADD_ENTITY_VIEW = "//tb-add-entity-dialog//textarea"; private static final String DEBUG_CHECKBOX_EDIT = "//mat-checkbox[@formcontrolname='debugMode']"; private static final String DEBUG_CHECKBOX_VIEW = "//mat-checkbox[@formcontrolname='debugMode']//input"; - private static final String CLOSE_ENTITY_VIEW_BTN = "//header//mat-icon[contains(text(),'close')]/../.."; - private static final String SEARCH_BTN = "//mat-toolbar//mat-icon[contains(text(),'search')]/.." + - "/parent::button[@class='mat-focus-indicator mat-tooltip-trigger mat-icon-button mat-button-base ng-star-inserted']"; + private static final String CLOSE_ENTITY_VIEW_BTN = "//header//mat-icon[contains(text(),'close')]/parent::button"; + private static final String SEARCH_BTN = "//mat-toolbar//mat-icon[contains(text(),'search')]/ancestor::button[contains(@class,'ng-star')]"; private static final String SORT_BY_NAME_BTN = "//div[contains(text(),'Name')]"; private static final String SORT_BY_TITLE_BTN = "//div[contains(text(),'Title')]"; private static final String SORT_BY_TIME_BTN = "//div[contains(text(),'Created time')]/.."; private static final String CREATED_TIME = "//tbody[@role='rowgroup']//mat-cell[2]/span"; - private static final String PLUS_BTN = "//mat-icon[contains(text(),'add')]/../parent::button"; + private static final String PLUS_BTN = "//mat-icon[contains(text(),'add')]/ancestor::button"; private static final String CREATE_VIEW_ADD_BTN = "//span[contains(text(),'Add')]/.."; private static final String WARNING_MESSAGE = "//tb-snack-bar-component/div/div"; private static final String ERROR_MESSAGE = "//mat-error"; @@ -66,7 +65,7 @@ public class OtherPageElements extends AbstractBasePage { private static final String ENTITY_FROM_LIST = "//div[@role='listbox']/mat-option//span[contains(text(),'%s')]"; protected static final String ADD_ENTITY_VIEW = "//tb-add-entity-dialog"; protected static final String STATE_CONTROLLER = "//tb-entity-state-controller"; - private static final String SEARCH_FIELD = "//input[contains (@data-placeholder,'Search')]"; + private static final String SEARCH_FIELD = "//input[contains (@placeholder,'Search')]"; private static final String BROWSE_FILE = "//input[@class='file-input']"; private static final String IMPORT_BROWSE_FILE = "//mat-dialog-container//span[contains(text(),'Import')]/.."; private static final String IMPORTING_FILE = "//div[contains(text(),'%s')]"; @@ -158,7 +157,7 @@ public class OtherPageElements extends AbstractBasePage { } public WebElement debugCheckboxView() { - return waitUntilVisibilityOfElementLocated(DEBUG_CHECKBOX_VIEW); + return waitUntilPresenceOfElementLocated(DEBUG_CHECKBOX_VIEW); } public WebElement closeEntityViewBtn() { diff --git a/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/ui/pages/OtherPageElementsHelper.java b/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/ui/pages/OtherPageElementsHelper.java index 45a0dddc98..815e118a9b 100644 --- a/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/ui/pages/OtherPageElementsHelper.java +++ b/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/ui/pages/OtherPageElementsHelper.java @@ -62,48 +62,22 @@ public class OtherPageElementsHelper extends OtherPageElements { } public String deleteRuleChainTrash(String entityName) { - String s = ""; - if (deleteBtn(entityName) != null) { - deleteBtn(entityName).click(); - warningPopUpYesBtn().click(); - return entityName; - } else { - for (int i = 0; i < deleteBtns().size(); i++) { - if (deleteBtns().get(i).isEnabled()) { - deleteBtns().get(i).click(); - warningPopUpYesBtn().click(); - if (elementIsNotPresent(getWarningMessage())) { - s = driver.findElements(By.xpath(getDeleteBtns() - + "/../../../mat-cell/following-sibling::mat-cell/following-sibling::mat-cell[contains(@class,'cdk-column-name')]/span")).get(i).getText(); - break; - } - } - } - return s; - } + deleteBtn(entityName).click(); + warningPopUpYesBtn().click(); + return entityName; } public String deleteSelected(String entityName) { - String s = ""; - if (deleteBtn(entityName) != null) { - checkBox(entityName).click(); - deleteSelectedBtn().click(); - warningPopUpYesBtn().click(); - return entityName; - } else { - for (int i = 0; i < checkBoxes().size(); i++) { - if (checkBoxes().get(i).isDisplayed()) { - s = driver.findElements(By.xpath(getCheckboxes() + "/../../mat-cell/following-sibling::mat-cell/following-sibling::mat-cell[contains(@class,'cdk-column-name')]/span")).get(i).getText(); - checkBox(s).click(); - deleteSelectedBtn().click(); - warningPopUpYesBtn().click(); - if (elementIsNotPresent(getWarningMessage())) { - break; - } - } - } - return s; - } + checkBox(entityName).click(); + jsClick(deleteSelectedBtn()); + warningPopUpYesBtn().click(); + return entityName; + } + + public void deleteSelected(int countOfCheckBoxes) { + clickOnCheckBoxes(countOfCheckBoxes); + jsClick(deleteSelectedBtn()); + warningPopUpYesBtn().click(); } public void searchEntity(String namePath) { diff --git a/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/ui/pages/RuleChainsPageElements.java b/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/ui/pages/RuleChainsPageElements.java index b34c5ccb86..1f0073bfbe 100644 --- a/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/ui/pages/RuleChainsPageElements.java +++ b/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/ui/pages/RuleChainsPageElements.java @@ -25,7 +25,7 @@ public class RuleChainsPageElements extends OtherPageElementsHelper { super(driver); } - private static final String MAKE_ROOT_BTN = ENTITY + "/../..//mat-icon[contains(text(),' flag')]/../.."; + private static final String MAKE_ROOT_BTN = ENTITY + "/ancestor::mat-row//mat-icon[contains(text(),'flag')]/ancestor::button"; private static final String ROOT = ENTITY + "/../..//mat-icon[text() = 'check_box']"; private static final String ROOT_DISABLE = ENTITY + "/../..//mat-icon[text() = 'check_box_outline_blank']"; private static final String CREATED_TIME = ENTITY + "/../..//mat-cell/span[contains(text(),'%s')]"; diff --git a/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/ui/tests/assetProfileSmoke/CreateAssetProfileTest.java b/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/ui/tests/assetProfileSmoke/CreateAssetProfileTest.java index 5f06cd1f8d..98e5e036dd 100644 --- a/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/ui/tests/assetProfileSmoke/CreateAssetProfileTest.java +++ b/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/ui/tests/assetProfileSmoke/CreateAssetProfileTest.java @@ -167,7 +167,7 @@ public class CreateAssetProfileTest extends AbstractDriverBaseTest { String urlPath = "docs/user-guide/asset-profiles/"; sideBarMenuView.openAssetProfiles(); - profilesPage.allEntity().get(0).click(); + profilesPage.profileNames().get(0).click(); profilesPage.goToProfileHelpPage(); Assert.assertTrue(urlContains(urlPath)); diff --git a/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/ui/tests/customerSmoke/CustomerEditMenuTest.java b/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/ui/tests/customerSmoke/CustomerEditMenuTest.java index c67ed9d2cd..f579779927 100644 --- a/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/ui/tests/customerSmoke/CustomerEditMenuTest.java +++ b/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/ui/tests/customerSmoke/CustomerEditMenuTest.java @@ -137,14 +137,14 @@ public class CustomerEditMenuTest extends AbstractDriverBaseTest { dashboardPage.assignedCustomer(customerName); sideBarMenuView.customerBtn().click(); customerPage.entity(customerName).click(); - customerPage.editPencilBtn().click(); + jsClick(customerPage.editPencilBtn()); customerPage.chooseDashboard(); customerPage.doneBtnEditView().click(); customerPage.setDashboardFromView(); customerPage.closeEntityViewBtn().click(); - customerPage.manageCustomersUserBtn(customerName).click(); + jsClick(customerPage.manageCustomersUserBtn(customerName)); customerPage.createCustomersUser(); - customerPage.userLoginBtn().click(); + jsClick(customerPage.userLoginBtn()); Assert.assertNotNull(customerPage.usersWidget()); Assert.assertTrue(customerPage.usersWidget().isDisplayed()); @@ -163,14 +163,14 @@ public class CustomerEditMenuTest extends AbstractDriverBaseTest { customerPage.assignedDashboard(); sideBarMenuView.customerBtn().click(); customerPage.entity(customerName).click(); - customerPage.editPencilBtn().click(); + jsClick(customerPage.editPencilBtn()); customerPage.chooseDashboard(); customerPage.doneBtnEditView().click(); customerPage.setDashboardFromView(); customerPage.closeEntityViewBtn().click(); - customerPage.manageCustomersUserBtn(customerName).click(); + jsClick(customerPage.manageCustomersUserBtn(customerName)); customerPage.createCustomersUser(); - customerPage.userLoginBtn().click(); + jsClick(customerPage.userLoginBtn()); Assert.assertNotNull(customerPage.usersWidget()); Assert.assertTrue(customerPage.usersWidget().isDisplayed()); @@ -189,15 +189,15 @@ public class CustomerEditMenuTest extends AbstractDriverBaseTest { customerPage.assignedDashboard(); sideBarMenuView.customerBtn().click(); customerPage.entity(customerName).click(); - customerPage.editPencilBtn().click(); + jsClick(customerPage.editPencilBtn()); customerPage.chooseDashboard(); customerPage.hideHomeDashboardToolbarCheckbox().click(); customerPage.doneBtnEditView().click(); customerPage.setDashboardFromView(); customerPage.closeEntityViewBtn().click(); - customerPage.manageCustomersUserBtn(customerName).click(); + jsClick(customerPage.manageCustomersUserBtn(customerName)); customerPage.createCustomersUser(); - customerPage.userLoginBtn().click(); + jsClick(customerPage.userLoginBtn()); Assert.assertNotNull(customerPage.usersWidget()); Assert.assertTrue(customerPage.usersWidget().isDisplayed()); @@ -233,11 +233,9 @@ public class CustomerEditMenuTest extends AbstractDriverBaseTest { sideBarMenuView.customerBtn().click(); customerPage.entityTitles().get(0).click(); customerPage.editPencilBtn().click(); - customerPage.phoneNumberEntityView().sendKeys(number); - boolean doneBtnIsEnable = customerPage.doneBtnEditViewVisible().isEnabled(); - customerPage.doneBtnEditViewVisible().click(); + customerPage.enterPhoneNumber(number); - Assert.assertFalse(doneBtnIsEnable); + Assert.assertFalse(customerPage.doneBtnEditViewVisible().isEnabled()); Assert.assertNotNull(customerPage.errorMessage()); Assert.assertTrue(customerPage.errorMessage().isDisplayed()); Assert.assertEquals(customerPage.errorMessage().getText(), PHONE_NUMBER_ERROR_MESSAGE); diff --git a/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/ui/tests/customerSmoke/DeleteCustomerTest.java b/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/ui/tests/customerSmoke/DeleteCustomerTest.java index 4372799f33..e1ec330e87 100644 --- a/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/ui/tests/customerSmoke/DeleteCustomerTest.java +++ b/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/ui/tests/customerSmoke/DeleteCustomerTest.java @@ -77,9 +77,9 @@ public class DeleteCustomerTest extends AbstractDriverBaseTest { sideBarMenuView.customerBtn().click(); customerPage.entity(customerName).click(); - customerPage.customerViewDeleteBtn().click(); + jsClick(customerPage.customerViewDeleteBtn()); customerPage.warningPopUpYesBtn().click(); - customerPage.refreshBtn().click(); + jsClick(customerPage.refreshBtn()); Assert.assertTrue(customerPage.entityIsNotPresent(customerName)); } diff --git a/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/ui/tests/customerSmoke/DeleteSeveralCustomerTest.java b/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/ui/tests/customerSmoke/DeleteSeveralCustomerTest.java index a32a9304b2..d87cd98105 100644 --- a/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/ui/tests/customerSmoke/DeleteSeveralCustomerTest.java +++ b/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/ui/tests/customerSmoke/DeleteSeveralCustomerTest.java @@ -49,9 +49,7 @@ public class DeleteSeveralCustomerTest extends AbstractDriverBaseTest { testRestClient.postCustomer(defaultCustomerPrototype(title2)); sideBarMenuView.customerBtn().click(); - customerPage.clickOnCheckBoxes(2); - customerPage.deleteSelectedBtn().click(); - customerPage.warningPopUpYesBtn().click(); + customerPage.deleteSelected(2); customerPage.refreshBtn().click(); Assert.assertTrue(customerPage.customerIsNotPresent(title1)); @@ -63,7 +61,7 @@ public class DeleteSeveralCustomerTest extends AbstractDriverBaseTest { public void selectAllCustomers() { sideBarMenuView.customerBtn().click(); customerPage.selectAllCheckBox().click(); - customerPage.deleteSelectedBtn().click(); + jsClick(customerPage.deleteSelectedBtn()); Assert.assertNotNull(customerPage.warningPopUpTitle()); Assert.assertTrue(customerPage.warningPopUpTitle().isDisplayed()); @@ -79,9 +77,7 @@ public class DeleteSeveralCustomerTest extends AbstractDriverBaseTest { testRestClient.postCustomer(defaultCustomerPrototype(title2)); sideBarMenuView.customerBtn().click(); - customerPage.clickOnCheckBoxes(2); - customerPage.deleteSelectedBtn().click(); - customerPage.warningPopUpYesBtn().click(); + customerPage.deleteSelected(2); Assert.assertTrue(customerPage.customerIsNotPresent(title1)); Assert.assertTrue(customerPage.customerIsNotPresent(title2)); diff --git a/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/ui/tests/customerSmoke/ManageCustomersAssetsTest.java b/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/ui/tests/customerSmoke/ManageCustomersAssetsTest.java index 90528f0d89..2b4538ba3e 100644 --- a/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/ui/tests/customerSmoke/ManageCustomersAssetsTest.java +++ b/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/ui/tests/customerSmoke/ManageCustomersAssetsTest.java @@ -56,7 +56,7 @@ public class ManageCustomersAssetsTest extends AbstractDriverBaseTest { sideBarMenuView.customerBtn().click(); customerPage.setCustomerName(); customerPage.entity(customerPage.getCustomerName()).click(); - customerPage.manageCustomersAssetsBtnView().click(); + jsClick(customerPage.manageCustomersAssetsBtnView()); Assert.assertTrue(urlContains(manage.toLowerCase())); Assert.assertNotNull(customerPage.customerAssetsIconHeader()); diff --git a/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/ui/tests/customerSmoke/ManageCustomersDashboardsTest.java b/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/ui/tests/customerSmoke/ManageCustomersDashboardsTest.java index 27b5ecb1aa..19f2031ec2 100644 --- a/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/ui/tests/customerSmoke/ManageCustomersDashboardsTest.java +++ b/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/ui/tests/customerSmoke/ManageCustomersDashboardsTest.java @@ -55,7 +55,7 @@ public class ManageCustomersDashboardsTest extends AbstractDriverBaseTest { sideBarMenuView.customerBtn().click(); customerPage.setCustomerName(); customerPage.entity(customerPage.getCustomerName()).click(); - customerPage.manageCustomersDashboardsBtnView().click(); + jsClick(customerPage.manageCustomersDashboardsBtnView()); Assert.assertTrue(urlContains(manage.toLowerCase())); Assert.assertNotNull(customerPage.customerDashboardIconHeader()); diff --git a/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/ui/tests/customerSmoke/ManageCustomersUsersTest.java b/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/ui/tests/customerSmoke/ManageCustomersUsersTest.java index faa7cde0fb..7b67351a63 100644 --- a/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/ui/tests/customerSmoke/ManageCustomersUsersTest.java +++ b/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/ui/tests/customerSmoke/ManageCustomersUsersTest.java @@ -42,7 +42,7 @@ public class ManageCustomersUsersTest extends AbstractDriverBaseTest { public void openWindowByRightCornerBtn() { sideBarMenuView.customerBtn().click(); customerPage.setCustomerName(); - customerPage.manageCustomersUserBtn(customerPage.getCustomerName()).click(); + jsClick(customerPage.manageCustomersUserBtn(customerPage.getCustomerName())); Assert.assertTrue(urlContains("user")); Assert.assertNotNull(customerPage.customerUserIconHeader()); diff --git a/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/ui/tests/deviceProfileSmoke/CreateDeviceProfileTest.java b/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/ui/tests/deviceProfileSmoke/CreateDeviceProfileTest.java index 9fc7e3ae77..4d7fc0220c 100644 --- a/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/ui/tests/deviceProfileSmoke/CreateDeviceProfileTest.java +++ b/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/ui/tests/deviceProfileSmoke/CreateDeviceProfileTest.java @@ -173,7 +173,7 @@ public class CreateDeviceProfileTest extends AbstractDriverBaseTest { String urlPath = "docs/user-guide/device-profiles/"; sideBarMenuView.openDeviceProfiles(); - profilesPage.allEntity().get(0).click(); + profilesPage.profileNames().get(0).click(); profilesPage.goToProfileHelpPage(); Assert.assertTrue(urlContains(urlPath)); diff --git a/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/ui/tests/ruleChainsSmoke/CreateRuleChainImportTest.java b/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/ui/tests/ruleChainsSmoke/CreateRuleChainImportTest.java index d30c7799dd..a9603680dc 100644 --- a/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/ui/tests/ruleChainsSmoke/CreateRuleChainImportTest.java +++ b/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/ui/tests/ruleChainsSmoke/CreateRuleChainImportTest.java @@ -16,6 +16,7 @@ package org.thingsboard.server.msa.ui.tests.ruleChainsSmoke; import io.qameta.allure.Description; +import org.openqa.selenium.WebElement; import org.testng.Assert; import org.testng.annotations.AfterMethod; import org.testng.annotations.BeforeMethod; @@ -100,8 +101,9 @@ public class CreateRuleChainImportTest extends AbstractDriverBaseTest { ruleChainsPage.openImportRuleChainView(); ruleChainsPage.browseFile().sendKeys(absolutePathToFileImportRuleChain); ruleChainsPage.importBrowseFileBtn().click(); - openRuleChainPage.doneBtn().click(); - openRuleChainPage.waitUntilDoneBtnDisable(); + WebElement doneBtn = openRuleChainPage.doneBtn(); + doneBtn.click(); + //openRuleChainPage.waitUntilBtnDisable(doneBtn); ruleChainName = IMPORT_RULE_CHAIN_NAME; sideBarMenuView.ruleChainsBtn().click(); @@ -120,8 +122,9 @@ public class CreateRuleChainImportTest extends AbstractDriverBaseTest { ruleChainsPage.openImportRuleChainView(); ruleChainsPage.browseFile().sendKeys(absolutePathToFileImportRuleChain); ruleChainsPage.importBrowseFileBtn().click(); - openRuleChainPage.doneBtn().click(); - openRuleChainPage.waitUntilDoneBtnDisable(); + WebElement doneBtn = openRuleChainPage.doneBtn(); + doneBtn.click(); + //openRuleChainPage.waitUntilBtnDisable(doneBtn); sideBarMenuView.ruleChainsBtn().click(); boolean entityNotNull = ruleChainsPage.entity(ruleChainName) != null; diff --git a/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/ui/tests/ruleChainsSmoke/DeleteRuleChainTest.java b/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/ui/tests/ruleChainsSmoke/DeleteRuleChainTest.java index 8a1be66505..d18f0db38b 100644 --- a/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/ui/tests/ruleChainsSmoke/DeleteRuleChainTest.java +++ b/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/ui/tests/ruleChainsSmoke/DeleteRuleChainTest.java @@ -76,7 +76,7 @@ public class DeleteRuleChainTest extends AbstractDriverBaseTest { sideBarMenuView.ruleChainsBtn().click(); ruleChainsPage.detailsBtn(ENTITY_NAME).click(); String deletedRuleChain = ruleChainsPage.deleteRuleChainFromView(ruleChainName); - ruleChainsPage.refreshBtn().click(); + jsClick(ruleChainsPage.refreshBtn()); Assert.assertTrue(ruleChainsPage.entityIsNotPresent(deletedRuleChain)); } @@ -145,7 +145,7 @@ public class DeleteRuleChainTest extends AbstractDriverBaseTest { sideBarMenuView.ruleChainsBtn().click(); ruleChainsPage.detailsBtn(deletedRuleChain).click(); - ruleChainsPage.deleteBtnFromView().click(); + jsClick(ruleChainsPage.deleteBtnFromView()); ruleChainsPage.warningPopUpYesBtn().click(); Assert.assertNotNull(ruleChainsPage.entity(deletedRuleChain)); diff --git a/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/ui/tests/ruleChainsSmoke/DeleteSeveralRuleChainsTest.java b/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/ui/tests/ruleChainsSmoke/DeleteSeveralRuleChainsTest.java index d631ed05d5..f17ab704a6 100644 --- a/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/ui/tests/ruleChainsSmoke/DeleteSeveralRuleChainsTest.java +++ b/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/ui/tests/ruleChainsSmoke/DeleteSeveralRuleChainsTest.java @@ -49,9 +49,7 @@ public class DeleteSeveralRuleChainsTest extends AbstractDriverBaseTest { testRestClient.postRuleChain(defaultRuleChainPrototype(ruleChainName)); sideBarMenuView.ruleChainsBtn().click(); - ruleChainsPage.clickOnCheckBoxes(2); - ruleChainsPage.deleteSelectedBtn().click(); - ruleChainsPage.warningPopUpYesBtn().click(); + ruleChainsPage.deleteSelected(2); ruleChainsPage.refreshBtn().click(); Assert.assertTrue(ruleChainsPage.ruleChainsIsNotPresent(ruleChainName)); @@ -66,7 +64,7 @@ public class DeleteSeveralRuleChainsTest extends AbstractDriverBaseTest { sideBarMenuView.ruleChainsBtn().click(); ruleChainsPage.selectAllCheckBox().click(); - ruleChainsPage.deleteSelectedBtn().click(); + jsClick(ruleChainsPage.deleteSelectedBtn()); ruleChainsPage.warningPopUpYesBtn().click(); ruleChainsPage.refreshBtn().click(); @@ -99,9 +97,7 @@ public class DeleteSeveralRuleChainsTest extends AbstractDriverBaseTest { testRestClient.postRuleChain(defaultRuleChainPrototype(ruleChainName)); sideBarMenuView.ruleChainsBtn().click(); - ruleChainsPage.clickOnCheckBoxes(2); - ruleChainsPage.deleteSelectedBtn().click(); - ruleChainsPage.warningPopUpYesBtn().click(); + ruleChainsPage.deleteSelected(2); Assert.assertTrue(ruleChainsPage.ruleChainsIsNotPresent(ruleChainName)); } From e99024d7eba5d3f5b4c94b8642801d8f41780b2b Mon Sep 17 00:00:00 2001 From: Seraphym-Tuhai Date: Thu, 9 Mar 2023 18:37:13 +0200 Subject: [PATCH 03/28] fix locators, fix flaky tests with ElementClickInterceptedException --- .../server/msa/ui/base/AbstractDriverBaseTest.java | 13 ++++++------- .../server/msa/ui/pages/CustomerPageHelper.java | 2 -- .../server/msa/ui/pages/RuleChainsPageElements.java | 2 +- .../tests/customerSmoke/CustomerEditMenuTest.java | 2 +- .../customerSmoke/ManageCustomersDevicesTest.java | 2 +- .../customerSmoke/ManageCustomersEdgesTest.java | 2 +- .../customerSmoke/ManageCustomersUsersTest.java | 2 +- .../ruleChainsSmoke/MakeRuleChainRootTest.java | 2 +- 8 files changed, 12 insertions(+), 15 deletions(-) diff --git a/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/ui/base/AbstractDriverBaseTest.java b/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/ui/base/AbstractDriverBaseTest.java index 29574a1942..c6db3c7bad 100644 --- a/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/ui/base/AbstractDriverBaseTest.java +++ b/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/ui/base/AbstractDriverBaseTest.java @@ -18,7 +18,6 @@ package org.thingsboard.server.msa.ui.base; import io.github.bonigarcia.wdm.WebDriverManager; import io.qameta.allure.Allure; import lombok.extern.slf4j.Slf4j; -import org.openqa.selenium.By; import org.openqa.selenium.Dimension; import org.openqa.selenium.JavascriptExecutor; import org.openqa.selenium.OutputType; @@ -48,7 +47,6 @@ import java.io.ByteArrayInputStream; import java.net.MalformedURLException; import java.net.URL; import java.time.Duration; -import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; import static org.thingsboard.server.msa.TestProperties.getBaseUiUrl; @@ -87,7 +85,7 @@ abstract public class AbstractDriverBaseTest extends AbstractContainerTest { @BeforeMethod public void open() { - openHomePage(); + openLocalhost(); } @AfterMethod @@ -101,12 +99,13 @@ abstract public class AbstractDriverBaseTest extends AbstractContainerTest { driver.quit(); } - public void openLocalhost() { - driver.get(getBaseUiUrl()); + public String getJwtTokenFromLocalStorage() { + js = (JavascriptExecutor) driver; + return (String) js.executeScript("return window.localStorage.getItem('jwt_token');"); } - public void openHomePage() { - driver.get(getBaseUiUrl() + "/home"); + public void openLocalhost() { + driver.get(getBaseUiUrl()); } public String getUrl() { diff --git a/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/ui/pages/CustomerPageHelper.java b/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/ui/pages/CustomerPageHelper.java index 26303d3e3a..e428ff8030 100644 --- a/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/ui/pages/CustomerPageHelper.java +++ b/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/ui/pages/CustomerPageHelper.java @@ -114,9 +114,7 @@ public class CustomerPageHelper extends CustomerPageElements { public void chooseDashboard() { editMenuDashboardField().click(); - sleep(0.5); editMenuDashboard().click(); - sleep(0.5); } public void createCustomersUser() { diff --git a/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/ui/pages/RuleChainsPageElements.java b/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/ui/pages/RuleChainsPageElements.java index 1f0073bfbe..c1b72efbeb 100644 --- a/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/ui/pages/RuleChainsPageElements.java +++ b/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/ui/pages/RuleChainsPageElements.java @@ -35,7 +35,7 @@ public class RuleChainsPageElements extends OtherPageElementsHelper { private static final String DELETE_RULE_CHAIN_FROM_VIEW_BTN = "//span[contains(text(),' Delete')]"; private static final String IMPORT_RULE_CHAIN_BTN = "//span[contains(text(),'Import rule chain')]"; private static final String OPEN_RULE_CHAIN_FROM_VIEW = "//span[contains(text(),'Open rule chain')]"; - private static final String MAKE_ROOT_FROM_VIEW = "(//span[contains(text(),' Make rule chain root ')]/..)[1]"; + private static final String MAKE_ROOT_FROM_VIEW = "//span[contains(text(),' Make rule chain root ')]/parent::button"; private static final String ROOT_ACTIVE_CHECKBOXES = "//mat-icon[text() = 'check_box']"; private static final String ALL_NAMES = "//mat-icon[contains(text(),'check')]/../../../mat-cell[contains(@class,'name')]/span"; diff --git a/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/ui/tests/customerSmoke/CustomerEditMenuTest.java b/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/ui/tests/customerSmoke/CustomerEditMenuTest.java index 68e22f2d7f..998aa0af06 100644 --- a/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/ui/tests/customerSmoke/CustomerEditMenuTest.java +++ b/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/ui/tests/customerSmoke/CustomerEditMenuTest.java @@ -63,7 +63,7 @@ public class CustomerEditMenuTest extends AbstractDriverBaseTest { @BeforeMethod public void reLogin() { - if (getUrl().contains("/login")) { + if (getJwtTokenFromLocalStorage() == null) { loginPage.authorizationTenant(); } } diff --git a/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/ui/tests/customerSmoke/ManageCustomersDevicesTest.java b/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/ui/tests/customerSmoke/ManageCustomersDevicesTest.java index fde5b87e52..f6a6e4c433 100644 --- a/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/ui/tests/customerSmoke/ManageCustomersDevicesTest.java +++ b/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/ui/tests/customerSmoke/ManageCustomersDevicesTest.java @@ -55,7 +55,7 @@ public class ManageCustomersDevicesTest extends AbstractDriverBaseTest { sideBarMenuView.customerBtn().click(); customerPage.setCustomerName(); customerPage.entity(customerPage.getCustomerName()).click(); - customerPage.manageCustomersDeviceBtnView().click(); + jsClick(customerPage.manageCustomersDeviceBtnView()); Assert.assertTrue(urlContains(manage.toLowerCase())); Assert.assertNotNull(customerPage.customerDevicesIconHeader()); diff --git a/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/ui/tests/customerSmoke/ManageCustomersEdgesTest.java b/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/ui/tests/customerSmoke/ManageCustomersEdgesTest.java index 184f506584..a32ab02b7a 100644 --- a/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/ui/tests/customerSmoke/ManageCustomersEdgesTest.java +++ b/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/ui/tests/customerSmoke/ManageCustomersEdgesTest.java @@ -56,7 +56,7 @@ public class ManageCustomersEdgesTest extends AbstractDriverBaseTest { sideBarMenuView.customerBtn().click(); customerPage.setCustomerName(); customerPage.entity(customerPage.getCustomerName()).click(); - customerPage.manageCustomersEdgeBtnView().click(); + jsClick(customerPage.manageCustomersEdgeBtnView()); Assert.assertTrue(urlContains("edgeInstances")); Assert.assertNotNull(customerPage.customerEdgeIconHeader()); diff --git a/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/ui/tests/customerSmoke/ManageCustomersUsersTest.java b/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/ui/tests/customerSmoke/ManageCustomersUsersTest.java index 0ac6258ab0..632f76422e 100644 --- a/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/ui/tests/customerSmoke/ManageCustomersUsersTest.java +++ b/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/ui/tests/customerSmoke/ManageCustomersUsersTest.java @@ -56,7 +56,7 @@ public class ManageCustomersUsersTest extends AbstractDriverBaseTest { sideBarMenuView.customerBtn().click(); customerPage.setCustomerName(); customerPage.entity(customerPage.getCustomerName()).click(); - customerPage.manageCustomersUserBtnView().click(); + jsClick(customerPage.manageCustomersUserBtnView()); Assert.assertTrue(urlContains("user")); Assert.assertNotNull(customerPage.customerUserIconHeader()); diff --git a/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/ui/tests/ruleChainsSmoke/MakeRuleChainRootTest.java b/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/ui/tests/ruleChainsSmoke/MakeRuleChainRootTest.java index 7ad3fad982..6b6bbc43bd 100644 --- a/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/ui/tests/ruleChainsSmoke/MakeRuleChainRootTest.java +++ b/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/ui/tests/ruleChainsSmoke/MakeRuleChainRootTest.java @@ -75,7 +75,7 @@ public class MakeRuleChainRootTest extends AbstractDriverBaseTest { ruleChainsPage.setRuleChainNameWithoutRoot(0); String ruleChain = ruleChainsPage.getRuleChainName(); ruleChainsPage.detailsBtn(ruleChain).click(); - ruleChainsPage.makeRootFromViewBtn().click(); + jsClick(ruleChainsPage.makeRootFromViewBtn()); ruleChainsPage.warningPopUpYesBtn().click(); ruleChainsPage.closeEntityViewBtn().click(); From ec4d567ecdf3728e50e3ee0d487255979af79085 Mon Sep 17 00:00:00 2001 From: Seraphym-Tuhai Date: Fri, 10 Mar 2023 09:40:50 +0200 Subject: [PATCH 04/28] temporary fix after updating google chrome --- .../thingsboard/server/msa/ui/base/AbstractDriverBaseTest.java | 1 + 1 file changed, 1 insertion(+) diff --git a/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/ui/base/AbstractDriverBaseTest.java b/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/ui/base/AbstractDriverBaseTest.java index c6db3c7bad..634bf47c14 100644 --- a/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/ui/base/AbstractDriverBaseTest.java +++ b/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/ui/base/AbstractDriverBaseTest.java @@ -71,6 +71,7 @@ abstract public class AbstractDriverBaseTest extends AbstractContainerTest { testRestClient.login(TENANT_EMAIL, TENANT_PASSWORD); ChromeOptions options = new ChromeOptions(); options.setAcceptInsecureCerts(true); + options.addArguments("-remote-allow-origins=*"); //temporary fix after updating google chrome if (instance.isActive()) { RemoteWebDriver remoteWebDriver = new RemoteWebDriver(new URL(REMOTE_WEBDRIVER_HOST), options); remoteWebDriver.setFileDetector(new LocalFileDetector()); From 0e01f1c74d267aa1da0c9361631c5ae9565682fb Mon Sep 17 00:00:00 2001 From: Volodymyr Babak Date: Fri, 10 Mar 2023 15:53:47 +0200 Subject: [PATCH 05/28] sendUpdateSharedAttributeToCloudAndValidateDeviceSubscription - timeout increased for run test stable on slow (busy) environments --- .../java/org/thingsboard/server/edge/BaseDeviceEdgeTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/application/src/test/java/org/thingsboard/server/edge/BaseDeviceEdgeTest.java b/application/src/test/java/org/thingsboard/server/edge/BaseDeviceEdgeTest.java index 98508e72ce..303e91ee80 100644 --- a/application/src/test/java/org/thingsboard/server/edge/BaseDeviceEdgeTest.java +++ b/application/src/test/java/org/thingsboard/server/edge/BaseDeviceEdgeTest.java @@ -690,7 +690,7 @@ abstract public class BaseDeviceEdgeTest extends AbstractEdgeTest { edgeImitator.sendUplinkMsg(uplinkMsgBuilder.build()); Assert.assertTrue(edgeImitator.waitForResponses()); - Assert.assertTrue(onUpdateCallback.getSubscribeLatch().await(5, TimeUnit.SECONDS)); + Assert.assertTrue(onUpdateCallback.getSubscribeLatch().await(30, TimeUnit.SECONDS)); Assert.assertEquals(JacksonUtil.OBJECT_MAPPER.createObjectNode().put(attrKey, attrValue), JacksonUtil.fromBytes(onUpdateCallback.getPayloadBytes())); From add0a342c4540ae6f678134d3dc21801b46581d0 Mon Sep 17 00:00:00 2001 From: Sergey Matvienko Date: Fri, 10 Mar 2023 16:20:21 +0100 Subject: [PATCH 06/28] EntityRegistryService: PostConstrust replaced with event listener ContextRefreshedEvent. This will guarantee that all EntityDaoService's beans created. Otherwise, the Bean may discover beans that not created yet (reproducible on dao tests) --- .../entity/DefaultEntityServiceRegistry.java | 23 +++++++++++-------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/dao/src/main/java/org/thingsboard/server/dao/entity/DefaultEntityServiceRegistry.java b/dao/src/main/java/org/thingsboard/server/dao/entity/DefaultEntityServiceRegistry.java index a8b1d97bac..a752127f91 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/entity/DefaultEntityServiceRegistry.java +++ b/dao/src/main/java/org/thingsboard/server/dao/entity/DefaultEntityServiceRegistry.java @@ -15,27 +15,31 @@ */ package org.thingsboard.server.dao.entity; +import com.google.common.collect.MapMaker; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; import org.springframework.context.ApplicationContext; +import org.springframework.context.event.ContextRefreshedEvent; +import org.springframework.context.event.EventListener; +import org.springframework.core.Ordered; +import org.springframework.core.annotation.Order; import org.springframework.stereotype.Service; import org.thingsboard.server.common.data.EntityType; -import javax.annotation.PostConstruct; -import java.util.HashMap; import java.util.Map; @Service +@RequiredArgsConstructor +@Slf4j public class DefaultEntityServiceRegistry implements EntityServiceRegistry { private final ApplicationContext applicationContext; - private final Map entityDaoServicesMap; + private final Map entityDaoServicesMap = new MapMaker().weakValues().makeMap(); - public DefaultEntityServiceRegistry(ApplicationContext applicationContext) { - this.applicationContext = applicationContext; - this.entityDaoServicesMap = new HashMap<>(); - } - - @PostConstruct + @EventListener(ContextRefreshedEvent.class) + @Order(Ordered.HIGHEST_PRECEDENCE) public void init() { + log.debug("Initializing EntityServiceRegistry on ContextRefreshedEvent"); applicationContext.getBeansOfType(EntityDaoService.class).values().forEach(entityDaoService -> { EntityType entityType = entityDaoService.getEntityType(); entityDaoServicesMap.put(entityType, entityDaoService); @@ -43,6 +47,7 @@ public class DefaultEntityServiceRegistry implements EntityServiceRegistry { entityDaoServicesMap.put(EntityType.RULE_NODE, entityDaoService); } }); + log.debug("Initialized EntityServiceRegistry total [{}] entries", entityDaoServicesMap.size()); } @Override From 9904c9ccc2f1c180b6750041169bbdabaefbc181 Mon Sep 17 00:00:00 2001 From: Oleksandra Matviienko Date: Fri, 10 Mar 2023 17:40:26 +0100 Subject: [PATCH 07/28] uncommon dependency refactoring in AbstractServiceTest in dao package --- .../dao/service/AbstractServiceTest.java | 83 ------------------- .../service/BaseAdminSettingsServiceTest.java | 5 ++ .../service/BaseAlarmCommentServiceTest.java | 12 ++- .../dao/service/BaseAlarmServiceTest.java | 23 ++++- .../service/BaseApiUsageStateServiceTest.java | 5 ++ .../service/BaseAssetProfileServiceTest.java | 8 ++ .../dao/service/BaseAssetServiceTest.java | 8 ++ .../dao/service/BaseCustomerServiceTest.java | 6 ++ .../dao/service/BaseDashboardServiceTest.java | 13 ++- .../BaseDeviceCredentialsServiceTest.java | 8 ++ .../service/BaseDeviceProfileServiceTest.java | 11 +++ .../dao/service/BaseDeviceServiceTest.java | 20 +++++ .../dao/service/BaseEdgeEventServiceTest.java | 9 +- .../dao/service/BaseEdgeServiceTest.java | 11 +++ .../BaseEntityServiceRegistryTest.java | 2 +- .../dao/service/BaseEntityServiceTest.java | 24 ++++-- .../service/BaseOtaPackageServiceTest.java | 14 ++++ .../dao/service/BaseQueueServiceTest.java | 8 ++ .../dao/service/BaseRelationServiceTest.java | 5 ++ .../dao/service/BaseRuleChainServiceTest.java | 8 ++ .../service/BaseTenantProfileServiceTest.java | 5 ++ .../dao/service/BaseTenantServiceTest.java | 75 +++++++++++------ .../dao/service/BaseUserServiceTest.java | 8 ++ .../service/BaseWidgetTypeServiceTest.java | 8 ++ .../service/BaseWidgetsBundleServiceTest.java | 5 ++ .../service/event/BaseEventServiceTest.java | 6 ++ .../timeseries/BaseTimeseriesServiceTest.java | 10 +++ 27 files changed, 278 insertions(+), 122 deletions(-) diff --git a/dao/src/test/java/org/thingsboard/server/dao/service/AbstractServiceTest.java b/dao/src/test/java/org/thingsboard/server/dao/service/AbstractServiceTest.java index 7f1f5e9ca0..282e07caa1 100644 --- a/dao/src/test/java/org/thingsboard/server/dao/service/AbstractServiceTest.java +++ b/dao/src/test/java/org/thingsboard/server/dao/service/AbstractServiceTest.java @@ -100,92 +100,9 @@ public abstract class AbstractServiceTest { public static final TenantId SYSTEM_TENANT_ID = TenantId.SYS_TENANT_ID; - @Autowired - protected UserService userService; - - @Autowired - protected ApiUsageStateService apiUsageStateService; - - @Autowired - protected AdminSettingsService adminSettingsService; - @Autowired protected TenantService tenantService; - @Autowired - protected CustomerService customerService; - - @Autowired - protected DeviceService deviceService; - - @Autowired - protected AssetService assetService; - - @Autowired - protected EntityViewService entityViewService; - - @Autowired - protected EntityService entityService; - - @Autowired - protected DeviceCredentialsService deviceCredentialsService; - - @Autowired - protected WidgetsBundleService widgetsBundleService; - - @Autowired - protected WidgetTypeService widgetTypeService; - - @Autowired - protected DashboardService dashboardService; - - @Autowired - protected TimeseriesService tsService; - - @Autowired - protected EventService eventService; - - @Autowired - protected RelationService relationService; - - @Autowired - protected AlarmService alarmService; - @Autowired - protected AlarmCommentService alarmCommentService; - - @Autowired - protected RuleChainService ruleChainService; - - @Autowired - protected EdgeService edgeService; - - @Autowired - protected EdgeEventService edgeEventService; - - @Autowired - private ComponentDescriptorService componentDescriptorService; - - @Autowired - protected TenantProfileService tenantProfileService; - - @Autowired - protected DeviceProfileService deviceProfileService; - - @Autowired - protected AssetProfileService assetProfileService; - - @Autowired - protected ResourceService resourceService; - - @Autowired - protected OtaPackageService otaPackageService; - - @Autowired - protected RpcService rpcService; - - @Autowired - protected QueueService queueService; - public class IdComparator implements Comparator { @Override public int compare(D o1, D o2) { diff --git a/dao/src/test/java/org/thingsboard/server/dao/service/BaseAdminSettingsServiceTest.java b/dao/src/test/java/org/thingsboard/server/dao/service/BaseAdminSettingsServiceTest.java index c839b8ed69..3b8659f93c 100644 --- a/dao/src/test/java/org/thingsboard/server/dao/service/BaseAdminSettingsServiceTest.java +++ b/dao/src/test/java/org/thingsboard/server/dao/service/BaseAdminSettingsServiceTest.java @@ -20,11 +20,16 @@ import com.fasterxml.jackson.databind.node.ObjectNode; import org.junit.Assert; import org.junit.Test; import org.junit.jupiter.api.Assertions; +import org.springframework.beans.factory.annotation.Autowired; import org.thingsboard.server.common.data.AdminSettings; import org.thingsboard.server.dao.exception.DataValidationException; +import org.thingsboard.server.dao.settings.AdminSettingsService; public abstract class BaseAdminSettingsServiceTest extends AbstractServiceTest { + @Autowired + AdminSettingsService adminSettingsService; + @Test public void testFindAdminSettingsByKey() { AdminSettings adminSettings = adminSettingsService.findAdminSettingsByKey(SYSTEM_TENANT_ID, "general"); diff --git a/dao/src/test/java/org/thingsboard/server/dao/service/BaseAlarmCommentServiceTest.java b/dao/src/test/java/org/thingsboard/server/dao/service/BaseAlarmCommentServiceTest.java index 688793d6c6..8448650dcf 100644 --- a/dao/src/test/java/org/thingsboard/server/dao/service/BaseAlarmCommentServiceTest.java +++ b/dao/src/test/java/org/thingsboard/server/dao/service/BaseAlarmCommentServiceTest.java @@ -20,6 +20,7 @@ import org.junit.After; import org.junit.Assert; import org.junit.Before; import org.junit.Test; +import org.springframework.beans.factory.annotation.Autowired; import org.testcontainers.shaded.org.apache.commons.lang3.RandomStringUtils; import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.server.common.data.Tenant; @@ -28,13 +29,15 @@ import org.thingsboard.server.common.data.alarm.Alarm; import org.thingsboard.server.common.data.alarm.AlarmComment; import org.thingsboard.server.common.data.alarm.AlarmCommentInfo; import org.thingsboard.server.common.data.alarm.AlarmSeverity; -import org.thingsboard.server.common.data.alarm.AlarmStatus; import org.thingsboard.server.common.data.id.AssetId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.id.UserId; import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageLink; import org.thingsboard.server.common.data.security.Authority; +import org.thingsboard.server.dao.alarm.AlarmCommentService; +import org.thingsboard.server.dao.alarm.AlarmService; +import org.thingsboard.server.dao.user.UserService; import java.util.UUID; import java.util.concurrent.ExecutionException; @@ -43,6 +46,13 @@ import static org.thingsboard.server.common.data.alarm.AlarmCommentType.OTHER; public abstract class BaseAlarmCommentServiceTest extends AbstractServiceTest { + @Autowired + AlarmService alarmService; + @Autowired + AlarmCommentService alarmCommentService; + @Autowired + UserService userService; + public static final String TEST_ALARM = "TEST_ALARM"; private TenantId tenantId; private Alarm alarm; diff --git a/dao/src/test/java/org/thingsboard/server/dao/service/BaseAlarmServiceTest.java b/dao/src/test/java/org/thingsboard/server/dao/service/BaseAlarmServiceTest.java index b7f5135533..f914bc63f7 100644 --- a/dao/src/test/java/org/thingsboard/server/dao/service/BaseAlarmServiceTest.java +++ b/dao/src/test/java/org/thingsboard/server/dao/service/BaseAlarmServiceTest.java @@ -20,6 +20,7 @@ import org.junit.After; import org.junit.Assert; import org.junit.Before; import org.junit.Test; +import org.springframework.beans.factory.annotation.Autowired; import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.server.common.data.Customer; import org.thingsboard.server.common.data.Device; @@ -38,7 +39,6 @@ import org.thingsboard.server.common.data.asset.Asset; import org.thingsboard.server.common.data.id.AssetId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.page.PageData; -import org.thingsboard.server.common.data.page.PageLink; import org.thingsboard.server.common.data.page.SortOrder; import org.thingsboard.server.common.data.page.TimePageLink; import org.thingsboard.server.common.data.query.AlarmData; @@ -52,7 +52,12 @@ import org.thingsboard.server.common.data.relation.EntityRelation; import org.thingsboard.server.common.data.relation.RelationTypeGroup; import org.thingsboard.server.common.data.security.Authority; import org.thingsboard.server.dao.alarm.AlarmApiCallResult; -import org.thingsboard.server.dao.alarm.AlarmOperationResult; +import org.thingsboard.server.dao.alarm.AlarmService; +import org.thingsboard.server.dao.asset.AssetService; +import org.thingsboard.server.dao.customer.CustomerService; +import org.thingsboard.server.dao.device.DeviceService; +import org.thingsboard.server.dao.relation.RelationService; +import org.thingsboard.server.dao.user.UserService; import java.util.Arrays; import java.util.Collections; @@ -61,8 +66,20 @@ import java.util.concurrent.ExecutionException; public abstract class BaseAlarmServiceTest extends AbstractServiceTest { - public static final String TEST_ALARM = "TEST_ALARM"; + @Autowired + AlarmService alarmService; + @Autowired + AssetService assetService; + @Autowired + CustomerService customerService; + @Autowired + DeviceService deviceService; + @Autowired + RelationService relationService; + @Autowired + UserService userService; + public static final String TEST_ALARM = "TEST_ALARM"; private static final String TEST_TENANT_EMAIL = "testtenant@thingsboard.org"; private static final String TEST_TENANT_FIRST_NAME = "testtenantfirstname"; private static final String TEST_TENANT_LAST_NAME = "testtenantlastname"; diff --git a/dao/src/test/java/org/thingsboard/server/dao/service/BaseApiUsageStateServiceTest.java b/dao/src/test/java/org/thingsboard/server/dao/service/BaseApiUsageStateServiceTest.java index 2ea7147a65..2c325654a1 100644 --- a/dao/src/test/java/org/thingsboard/server/dao/service/BaseApiUsageStateServiceTest.java +++ b/dao/src/test/java/org/thingsboard/server/dao/service/BaseApiUsageStateServiceTest.java @@ -19,14 +19,19 @@ import org.junit.After; import org.junit.Assert; import org.junit.Before; import org.junit.Test; +import org.springframework.beans.factory.annotation.Autowired; import org.thingsboard.server.common.data.ApiUsageStateValue; import org.thingsboard.server.common.data.Tenant; import org.thingsboard.server.common.data.ApiUsageState; import org.thingsboard.server.common.data.id.TenantId; +import org.thingsboard.server.dao.usagerecord.ApiUsageStateService; public abstract class BaseApiUsageStateServiceTest extends AbstractServiceTest { + @Autowired + ApiUsageStateService apiUsageStateService; + private TenantId tenantId; @Before diff --git a/dao/src/test/java/org/thingsboard/server/dao/service/BaseAssetProfileServiceTest.java b/dao/src/test/java/org/thingsboard/server/dao/service/BaseAssetProfileServiceTest.java index 091b309269..90f68b0207 100644 --- a/dao/src/test/java/org/thingsboard/server/dao/service/BaseAssetProfileServiceTest.java +++ b/dao/src/test/java/org/thingsboard/server/dao/service/BaseAssetProfileServiceTest.java @@ -24,6 +24,7 @@ import org.junit.Assert; import org.junit.Before; import org.junit.Test; import org.junit.jupiter.api.Assertions; +import org.springframework.beans.factory.annotation.Autowired; import org.thingsboard.common.util.ThingsBoardThreadFactory; import org.thingsboard.server.common.data.Tenant; import org.thingsboard.server.common.data.asset.Asset; @@ -32,6 +33,8 @@ import org.thingsboard.server.common.data.asset.AssetProfileInfo; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageLink; +import org.thingsboard.server.dao.asset.AssetProfileService; +import org.thingsboard.server.dao.asset.AssetService; import org.thingsboard.server.dao.exception.DataValidationException; import java.util.ArrayList; @@ -46,6 +49,11 @@ public abstract class BaseAssetProfileServiceTest extends AbstractServiceTest { private IdComparator idComparator = new IdComparator<>(); private IdComparator assetProfileInfoIdComparator = new IdComparator<>(); + @Autowired + AssetProfileService assetProfileService; + @Autowired + AssetService assetService; + private TenantId tenantId; @Before diff --git a/dao/src/test/java/org/thingsboard/server/dao/service/BaseAssetServiceTest.java b/dao/src/test/java/org/thingsboard/server/dao/service/BaseAssetServiceTest.java index 108fcb70d9..ab81764015 100644 --- a/dao/src/test/java/org/thingsboard/server/dao/service/BaseAssetServiceTest.java +++ b/dao/src/test/java/org/thingsboard/server/dao/service/BaseAssetServiceTest.java @@ -21,6 +21,7 @@ import org.junit.Assert; import org.junit.Before; import org.junit.Test; import org.junit.jupiter.api.Assertions; +import org.springframework.beans.factory.annotation.Autowired; import org.thingsboard.server.common.data.Customer; import org.thingsboard.server.common.data.EntitySubtype; import org.thingsboard.server.common.data.StringUtils; @@ -31,6 +32,8 @@ import org.thingsboard.server.common.data.id.CustomerId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageLink; +import org.thingsboard.server.dao.asset.AssetService; +import org.thingsboard.server.dao.customer.CustomerService; import org.thingsboard.server.dao.exception.DataValidationException; import java.util.ArrayList; @@ -41,6 +44,11 @@ import static org.thingsboard.server.dao.model.ModelConstants.NULL_UUID; public abstract class BaseAssetServiceTest extends AbstractServiceTest { + @Autowired + AssetService assetService; + @Autowired + CustomerService customerService; + private IdComparator idComparator = new IdComparator<>(); private TenantId tenantId; diff --git a/dao/src/test/java/org/thingsboard/server/dao/service/BaseCustomerServiceTest.java b/dao/src/test/java/org/thingsboard/server/dao/service/BaseCustomerServiceTest.java index 18bf036495..46a28cf36e 100644 --- a/dao/src/test/java/org/thingsboard/server/dao/service/BaseCustomerServiceTest.java +++ b/dao/src/test/java/org/thingsboard/server/dao/service/BaseCustomerServiceTest.java @@ -25,6 +25,7 @@ import org.junit.Assert; import org.junit.Before; import org.junit.Test; import org.junit.jupiter.api.Assertions; +import org.springframework.beans.factory.annotation.Autowired; import org.thingsboard.common.util.ThingsBoardExecutors; import org.thingsboard.server.common.data.Customer; import org.thingsboard.server.common.data.StringUtils; @@ -32,6 +33,7 @@ import org.thingsboard.server.common.data.Tenant; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageLink; +import org.thingsboard.server.dao.customer.CustomerService; import org.thingsboard.server.dao.exception.DataValidationException; import java.util.ArrayList; @@ -41,6 +43,10 @@ import java.util.concurrent.TimeUnit; import static org.assertj.core.api.Assertions.assertThat; public abstract class BaseCustomerServiceTest extends AbstractServiceTest { + + @Autowired + CustomerService customerService; + static final int TIMEOUT = 30; ListeningExecutorService executor; diff --git a/dao/src/test/java/org/thingsboard/server/dao/service/BaseDashboardServiceTest.java b/dao/src/test/java/org/thingsboard/server/dao/service/BaseDashboardServiceTest.java index 4dc28a210a..9305e55450 100644 --- a/dao/src/test/java/org/thingsboard/server/dao/service/BaseDashboardServiceTest.java +++ b/dao/src/test/java/org/thingsboard/server/dao/service/BaseDashboardServiceTest.java @@ -21,6 +21,7 @@ import org.junit.Assert; import org.junit.Before; import org.junit.Test; import org.junit.jupiter.api.Assertions; +import org.springframework.beans.factory.annotation.Autowired; import org.thingsboard.server.common.data.Customer; import org.thingsboard.server.common.data.Dashboard; import org.thingsboard.server.common.data.DashboardInfo; @@ -33,6 +34,9 @@ import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageLink; import org.thingsboard.server.common.data.page.SortOrder; +import org.thingsboard.server.dao.customer.CustomerService; +import org.thingsboard.server.dao.dashboard.DashboardService; +import org.thingsboard.server.dao.edge.EdgeService; import org.thingsboard.server.dao.exception.DataValidationException; import java.io.IOException; @@ -42,7 +46,14 @@ import java.util.List; import java.util.concurrent.ExecutionException; public abstract class BaseDashboardServiceTest extends AbstractServiceTest { - + + @Autowired + CustomerService customerService; + @Autowired + DashboardService dashboardService; + @Autowired + EdgeService edgeService; + private IdComparator idComparator = new IdComparator<>(); private TenantId tenantId; diff --git a/dao/src/test/java/org/thingsboard/server/dao/service/BaseDeviceCredentialsServiceTest.java b/dao/src/test/java/org/thingsboard/server/dao/service/BaseDeviceCredentialsServiceTest.java index f3e052b3e9..e06c55b5d6 100644 --- a/dao/src/test/java/org/thingsboard/server/dao/service/BaseDeviceCredentialsServiceTest.java +++ b/dao/src/test/java/org/thingsboard/server/dao/service/BaseDeviceCredentialsServiceTest.java @@ -21,6 +21,7 @@ import org.junit.Assert; import org.junit.Before; import org.junit.Test; import org.junit.jupiter.api.Assertions; +import org.springframework.beans.factory.annotation.Autowired; import org.thingsboard.server.common.data.Device; import org.thingsboard.server.common.data.Tenant; import org.thingsboard.server.common.data.id.DeviceCredentialsId; @@ -28,10 +29,17 @@ import org.thingsboard.server.common.data.id.DeviceId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.security.DeviceCredentials; import org.thingsboard.server.common.data.security.DeviceCredentialsType; +import org.thingsboard.server.dao.device.DeviceCredentialsService; +import org.thingsboard.server.dao.device.DeviceService; import org.thingsboard.server.dao.exception.DataValidationException; public abstract class BaseDeviceCredentialsServiceTest extends AbstractServiceTest { + @Autowired + DeviceCredentialsService deviceCredentialsService; + @Autowired + DeviceService deviceService; + private TenantId tenantId; @Before diff --git a/dao/src/test/java/org/thingsboard/server/dao/service/BaseDeviceProfileServiceTest.java b/dao/src/test/java/org/thingsboard/server/dao/service/BaseDeviceProfileServiceTest.java index 77a8a479f2..bb2caa41fd 100644 --- a/dao/src/test/java/org/thingsboard/server/dao/service/BaseDeviceProfileServiceTest.java +++ b/dao/src/test/java/org/thingsboard/server/dao/service/BaseDeviceProfileServiceTest.java @@ -25,6 +25,7 @@ import org.junit.Before; import org.junit.Ignore; import org.junit.Test; import org.junit.jupiter.api.Assertions; +import org.springframework.beans.factory.annotation.Autowired; import org.thingsboard.common.util.ThingsBoardThreadFactory; import org.thingsboard.server.common.data.Device; import org.thingsboard.server.common.data.DeviceProfile; @@ -36,7 +37,10 @@ import org.thingsboard.server.common.data.ota.ChecksumAlgorithm; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageLink; +import org.thingsboard.server.dao.device.DeviceProfileService; +import org.thingsboard.server.dao.device.DeviceService; import org.thingsboard.server.dao.exception.DataValidationException; +import org.thingsboard.server.dao.ota.OtaPackageService; import java.nio.ByteBuffer; import java.util.ArrayList; @@ -52,6 +56,13 @@ import static org.thingsboard.server.common.data.ota.OtaPackageType.FIRMWARE; public abstract class BaseDeviceProfileServiceTest extends AbstractServiceTest { + @Autowired + DeviceProfileService deviceProfileService; + @Autowired + DeviceService deviceService; + @Autowired + OtaPackageService otaPackageService; + private IdComparator idComparator = new IdComparator<>(); private IdComparator deviceProfileInfoIdComparator = new IdComparator<>(); diff --git a/dao/src/test/java/org/thingsboard/server/dao/service/BaseDeviceServiceTest.java b/dao/src/test/java/org/thingsboard/server/dao/service/BaseDeviceServiceTest.java index 010f56235f..0fdefa7e16 100644 --- a/dao/src/test/java/org/thingsboard/server/dao/service/BaseDeviceServiceTest.java +++ b/dao/src/test/java/org/thingsboard/server/dao/service/BaseDeviceServiceTest.java @@ -23,6 +23,7 @@ import org.junit.Rule; import org.junit.Test; import org.junit.jupiter.api.Assertions; import org.junit.rules.ExpectedException; +import org.springframework.beans.factory.annotation.Autowired; import org.thingsboard.server.common.data.Customer; import org.thingsboard.server.common.data.Device; import org.thingsboard.server.common.data.DeviceInfo; @@ -40,7 +41,13 @@ import org.thingsboard.server.common.data.page.PageLink; import org.thingsboard.server.common.data.security.DeviceCredentials; import org.thingsboard.server.common.data.security.DeviceCredentialsType; import org.thingsboard.server.common.data.tenant.profile.DefaultTenantProfileConfiguration; +import org.thingsboard.server.dao.customer.CustomerService; +import org.thingsboard.server.dao.device.DeviceCredentialsService; +import org.thingsboard.server.dao.device.DeviceProfileService; +import org.thingsboard.server.dao.device.DeviceService; import org.thingsboard.server.dao.exception.DataValidationException; +import org.thingsboard.server.dao.ota.OtaPackageService; +import org.thingsboard.server.dao.tenant.TenantProfileService; import java.nio.ByteBuffer; import java.util.ArrayList; @@ -52,6 +59,19 @@ import static org.thingsboard.server.dao.model.ModelConstants.NULL_UUID; public abstract class BaseDeviceServiceTest extends AbstractServiceTest { + @Autowired + CustomerService customerService; + @Autowired + DeviceCredentialsService deviceCredentialsService; + @Autowired + DeviceProfileService deviceProfileService; + @Autowired + DeviceService deviceService; + @Autowired + OtaPackageService otaPackageService; + @Autowired + TenantProfileService tenantProfileService; + private IdComparator idComparator = new IdComparator<>(); private TenantId tenantId; diff --git a/dao/src/test/java/org/thingsboard/server/dao/service/BaseEdgeEventServiceTest.java b/dao/src/test/java/org/thingsboard/server/dao/service/BaseEdgeEventServiceTest.java index 3bd47cc991..3b942dab5f 100644 --- a/dao/src/test/java/org/thingsboard/server/dao/service/BaseEdgeEventServiceTest.java +++ b/dao/src/test/java/org/thingsboard/server/dao/service/BaseEdgeEventServiceTest.java @@ -21,6 +21,7 @@ import com.google.common.util.concurrent.ListenableFuture; import org.junit.Assert; import org.junit.Before; import org.junit.Test; +import org.springframework.beans.factory.annotation.Autowired; import org.thingsboard.server.common.data.edge.EdgeEvent; import org.thingsboard.server.common.data.edge.EdgeEventActionType; import org.thingsboard.server.common.data.edge.EdgeEventType; @@ -32,20 +33,20 @@ import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.SortOrder; import org.thingsboard.server.common.data.page.TimePageLink; +import org.thingsboard.server.dao.edge.EdgeEventService; import java.io.IOException; import java.text.ParseException; -import java.time.LocalDateTime; -import java.time.Month; -import java.time.ZoneOffset; import java.util.ArrayList; import java.util.List; -import java.util.concurrent.TimeUnit; import static org.apache.commons.lang3.time.DateFormatUtils.ISO_DATETIME_TIME_ZONE_FORMAT; public abstract class BaseEdgeEventServiceTest extends AbstractServiceTest { + @Autowired + EdgeEventService edgeEventService; + long timeBeforeStartTime; long startTime; long eventTime; diff --git a/dao/src/test/java/org/thingsboard/server/dao/service/BaseEdgeServiceTest.java b/dao/src/test/java/org/thingsboard/server/dao/service/BaseEdgeServiceTest.java index 70d41f4681..7ed318f58f 100644 --- a/dao/src/test/java/org/thingsboard/server/dao/service/BaseEdgeServiceTest.java +++ b/dao/src/test/java/org/thingsboard/server/dao/service/BaseEdgeServiceTest.java @@ -22,6 +22,7 @@ import org.junit.Assert; import org.junit.Before; import org.junit.Test; import org.junit.jupiter.api.Assertions; +import org.springframework.beans.factory.annotation.Autowired; import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.server.common.data.Customer; import org.thingsboard.server.common.data.EntitySubtype; @@ -36,7 +37,10 @@ import org.thingsboard.server.common.data.rule.RuleChain; import org.thingsboard.server.common.data.rule.RuleChainMetaData; import org.thingsboard.server.common.data.rule.RuleChainType; import org.thingsboard.server.common.data.rule.RuleNode; +import org.thingsboard.server.dao.customer.CustomerService; +import org.thingsboard.server.dao.edge.EdgeService; import org.thingsboard.server.dao.exception.DataValidationException; +import org.thingsboard.server.dao.rule.RuleChainService; import java.util.ArrayList; import java.util.Arrays; @@ -47,6 +51,13 @@ import static org.thingsboard.server.dao.model.ModelConstants.NULL_UUID; public abstract class BaseEdgeServiceTest extends AbstractServiceTest { + @Autowired + CustomerService customerService; + @Autowired + EdgeService edgeService; + @Autowired + RuleChainService ruleChainService; + private IdComparator idComparator = new IdComparator<>(); private TenantId tenantId; diff --git a/dao/src/test/java/org/thingsboard/server/dao/service/BaseEntityServiceRegistryTest.java b/dao/src/test/java/org/thingsboard/server/dao/service/BaseEntityServiceRegistryTest.java index 81a512dc95..87b6bbdd80 100644 --- a/dao/src/test/java/org/thingsboard/server/dao/service/BaseEntityServiceRegistryTest.java +++ b/dao/src/test/java/org/thingsboard/server/dao/service/BaseEntityServiceRegistryTest.java @@ -28,7 +28,7 @@ import org.thingsboard.server.dao.rule.RuleChainService; public abstract class BaseEntityServiceRegistryTest extends AbstractServiceTest { @Autowired - private EntityServiceRegistry entityServiceRegistry; + EntityServiceRegistry entityServiceRegistry; @Test public void givenAllEntityTypes_whenGetServiceByEntityTypeCalled_thenAllBeansExists() { diff --git a/dao/src/test/java/org/thingsboard/server/dao/service/BaseEntityServiceTest.java b/dao/src/test/java/org/thingsboard/server/dao/service/BaseEntityServiceTest.java index 7c80bef095..75dc250e63 100644 --- a/dao/src/test/java/org/thingsboard/server/dao/service/BaseEntityServiceTest.java +++ b/dao/src/test/java/org/thingsboard/server/dao/service/BaseEntityServiceTest.java @@ -73,8 +73,13 @@ import org.thingsboard.server.common.data.relation.EntityRelation; import org.thingsboard.server.common.data.relation.EntitySearchDirection; import org.thingsboard.server.common.data.relation.RelationEntityTypeFilter; import org.thingsboard.server.common.data.relation.RelationTypeGroup; +import org.thingsboard.server.dao.asset.AssetService; import org.thingsboard.server.dao.attributes.AttributesService; +import org.thingsboard.server.dao.device.DeviceService; +import org.thingsboard.server.dao.edge.EdgeService; +import org.thingsboard.server.dao.entity.EntityService; import org.thingsboard.server.dao.model.sqlts.ts.TsKvEntity; +import org.thingsboard.server.dao.relation.RelationService; import org.thingsboard.server.dao.sql.relation.RelationRepository; import org.thingsboard.server.dao.timeseries.TimeseriesService; @@ -100,15 +105,24 @@ public abstract class BaseEntityServiceTest extends AbstractServiceTest { static final int ENTITY_COUNT = 5; @Autowired - private AttributesService attributesService; - + AssetService assetService; + @Autowired + AttributesService attributesService; + @Autowired + DeviceService deviceService; + @Autowired + EdgeService edgeService; @Autowired - private TimeseriesService timeseriesService; + EntityService entityService; + @Autowired + RelationRepository relationRepository; + @Autowired + RelationService relationService; + @Autowired + TimeseriesService timeseriesService; private TenantId tenantId; - @Autowired - private RelationRepository relationRepository; @Before public void before() { diff --git a/dao/src/test/java/org/thingsboard/server/dao/service/BaseOtaPackageServiceTest.java b/dao/src/test/java/org/thingsboard/server/dao/service/BaseOtaPackageServiceTest.java index c89e7c4b69..22396e25a9 100644 --- a/dao/src/test/java/org/thingsboard/server/dao/service/BaseOtaPackageServiceTest.java +++ b/dao/src/test/java/org/thingsboard/server/dao/service/BaseOtaPackageServiceTest.java @@ -22,6 +22,7 @@ import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; +import org.springframework.beans.factory.annotation.Autowired; import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.server.common.data.Device; import org.thingsboard.server.common.data.DeviceProfile; @@ -36,7 +37,11 @@ import org.thingsboard.server.common.data.ota.ChecksumAlgorithm; import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageLink; import org.thingsboard.server.common.data.tenant.profile.DefaultTenantProfileConfiguration; +import org.thingsboard.server.dao.device.DeviceProfileService; +import org.thingsboard.server.dao.device.DeviceService; import org.thingsboard.server.dao.exception.DataValidationException; +import org.thingsboard.server.dao.ota.OtaPackageService; +import org.thingsboard.server.dao.tenant.TenantProfileService; import java.nio.ByteBuffer; import java.util.ArrayList; @@ -64,6 +69,15 @@ public abstract class BaseOtaPackageServiceTest extends AbstractServiceTest { private DeviceProfileId deviceProfileId; + @Autowired + DeviceProfileService deviceProfileService; + @Autowired + DeviceService deviceService; + @Autowired + OtaPackageService otaPackageService; + @Autowired + TenantProfileService tenantProfileService; + @Before public void before() { Tenant tenant = new Tenant(); diff --git a/dao/src/test/java/org/thingsboard/server/dao/service/BaseQueueServiceTest.java b/dao/src/test/java/org/thingsboard/server/dao/service/BaseQueueServiceTest.java index af2f067c2e..3890aa257c 100644 --- a/dao/src/test/java/org/thingsboard/server/dao/service/BaseQueueServiceTest.java +++ b/dao/src/test/java/org/thingsboard/server/dao/service/BaseQueueServiceTest.java @@ -20,6 +20,7 @@ import org.junit.Assert; import org.junit.Before; import org.junit.Test; import org.junit.jupiter.api.Assertions; +import org.springframework.beans.factory.annotation.Autowired; import org.thingsboard.server.common.data.DataConstants; import org.thingsboard.server.common.data.Tenant; import org.thingsboard.server.common.data.TenantProfile; @@ -35,6 +36,8 @@ import org.thingsboard.server.common.data.queue.SubmitStrategyType; import org.thingsboard.server.common.data.tenant.profile.TenantProfileData; import org.thingsboard.server.common.data.tenant.profile.TenantProfileQueueConfiguration; import org.thingsboard.server.dao.exception.DataValidationException; +import org.thingsboard.server.dao.queue.QueueService; +import org.thingsboard.server.dao.tenant.TenantProfileService; import java.util.ArrayList; import java.util.Collections; @@ -42,6 +45,11 @@ import java.util.List; public abstract class BaseQueueServiceTest extends AbstractServiceTest { + @Autowired + TenantProfileService tenantProfileService; + @Autowired + QueueService queueService; + private IdComparator idComparator = new IdComparator<>(); private TenantId tenantId; diff --git a/dao/src/test/java/org/thingsboard/server/dao/service/BaseRelationServiceTest.java b/dao/src/test/java/org/thingsboard/server/dao/service/BaseRelationServiceTest.java index c920b86bd5..d60a896aec 100644 --- a/dao/src/test/java/org/thingsboard/server/dao/service/BaseRelationServiceTest.java +++ b/dao/src/test/java/org/thingsboard/server/dao/service/BaseRelationServiceTest.java @@ -23,6 +23,7 @@ import org.junit.Assert; import org.junit.Before; import org.junit.Test; import org.junit.jupiter.api.Assertions; +import org.springframework.beans.factory.annotation.Autowired; import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.id.AssetId; import org.thingsboard.server.common.data.id.DeviceId; @@ -33,6 +34,7 @@ import org.thingsboard.server.common.data.relation.RelationEntityTypeFilter; import org.thingsboard.server.common.data.relation.RelationTypeGroup; import org.thingsboard.server.common.data.relation.RelationsSearchParameters; import org.thingsboard.server.dao.exception.DataValidationException; +import org.thingsboard.server.dao.relation.RelationService; import java.util.ArrayList; import java.util.Collections; @@ -42,6 +44,9 @@ import java.util.concurrent.ExecutionException; public abstract class BaseRelationServiceTest extends AbstractServiceTest { + @Autowired + RelationService relationService; + @Before public void before() { } diff --git a/dao/src/test/java/org/thingsboard/server/dao/service/BaseRuleChainServiceTest.java b/dao/src/test/java/org/thingsboard/server/dao/service/BaseRuleChainServiceTest.java index 16901119a6..e21138d25c 100644 --- a/dao/src/test/java/org/thingsboard/server/dao/service/BaseRuleChainServiceTest.java +++ b/dao/src/test/java/org/thingsboard/server/dao/service/BaseRuleChainServiceTest.java @@ -22,6 +22,7 @@ import org.junit.Assert; import org.junit.Before; import org.junit.Test; import org.junit.jupiter.api.Assertions; +import org.springframework.beans.factory.annotation.Autowired; import org.thingsboard.server.common.data.StringUtils; import org.thingsboard.server.common.data.Tenant; import org.thingsboard.server.common.data.edge.Edge; @@ -34,7 +35,9 @@ import org.thingsboard.server.common.data.rule.RuleChain; import org.thingsboard.server.common.data.rule.RuleChainMetaData; import org.thingsboard.server.common.data.rule.RuleChainType; import org.thingsboard.server.common.data.rule.RuleNode; +import org.thingsboard.server.dao.edge.EdgeService; import org.thingsboard.server.dao.exception.DataValidationException; +import org.thingsboard.server.dao.rule.RuleChainService; import java.io.IOException; import java.util.ArrayList; @@ -46,6 +49,11 @@ import java.util.List; */ public abstract class BaseRuleChainServiceTest extends AbstractServiceTest { + @Autowired + EdgeService edgeService; + @Autowired + RuleChainService ruleChainService; + private IdComparator idComparator = new IdComparator<>(); private IdComparator ruleNodeIdComparator = new IdComparator<>(); diff --git a/dao/src/test/java/org/thingsboard/server/dao/service/BaseTenantProfileServiceTest.java b/dao/src/test/java/org/thingsboard/server/dao/service/BaseTenantProfileServiceTest.java index 926f680e40..becb148b82 100644 --- a/dao/src/test/java/org/thingsboard/server/dao/service/BaseTenantProfileServiceTest.java +++ b/dao/src/test/java/org/thingsboard/server/dao/service/BaseTenantProfileServiceTest.java @@ -20,6 +20,7 @@ import org.junit.After; import org.junit.Assert; import org.junit.Test; import org.junit.jupiter.api.Assertions; +import org.springframework.beans.factory.annotation.Autowired; import org.thingsboard.server.common.data.DataConstants; import org.thingsboard.server.common.data.EntityInfo; import org.thingsboard.server.common.data.Tenant; @@ -36,6 +37,7 @@ import org.thingsboard.server.common.data.tenant.profile.DefaultTenantProfileCon import org.thingsboard.server.common.data.tenant.profile.TenantProfileData; import org.thingsboard.server.common.data.tenant.profile.TenantProfileQueueConfiguration; import org.thingsboard.server.dao.exception.DataValidationException; +import org.thingsboard.server.dao.tenant.TenantProfileService; import java.util.ArrayList; import java.util.Collections; @@ -44,6 +46,9 @@ import java.util.stream.Collectors; public abstract class BaseTenantProfileServiceTest extends AbstractServiceTest { + @Autowired + TenantProfileService tenantProfileService; + private IdComparator idComparator = new IdComparator<>(); private IdComparator tenantProfileInfoIdComparator = new IdComparator<>(); diff --git a/dao/src/test/java/org/thingsboard/server/dao/service/BaseTenantServiceTest.java b/dao/src/test/java/org/thingsboard/server/dao/service/BaseTenantServiceTest.java index 3f8c33c5e7..00aac94585 100644 --- a/dao/src/test/java/org/thingsboard/server/dao/service/BaseTenantServiceTest.java +++ b/dao/src/test/java/org/thingsboard/server/dao/service/BaseTenantServiceTest.java @@ -23,24 +23,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.mock.mockito.SpyBean; import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.server.cache.TbTransactionalCache; -import org.thingsboard.server.common.data.Customer; -import org.thingsboard.server.common.data.Dashboard; -import org.thingsboard.server.common.data.DashboardInfo; -import org.thingsboard.server.common.data.Device; -import org.thingsboard.server.common.data.DeviceProfile; -import org.thingsboard.server.common.data.DeviceProfileType; -import org.thingsboard.server.common.data.DeviceTransportType; -import org.thingsboard.server.common.data.EntityView; -import org.thingsboard.server.common.data.OtaPackage; -import org.thingsboard.server.common.data.OtaPackageInfo; -import org.thingsboard.server.common.data.ResourceType; -import org.thingsboard.server.common.data.StringUtils; -import org.thingsboard.server.common.data.TbResource; -import org.thingsboard.server.common.data.TbResourceInfo; -import org.thingsboard.server.common.data.Tenant; -import org.thingsboard.server.common.data.TenantInfo; -import org.thingsboard.server.common.data.TenantProfile; -import org.thingsboard.server.common.data.User; +import org.thingsboard.server.common.data.*; import org.thingsboard.server.common.data.asset.Asset; import org.thingsboard.server.common.data.device.profile.DeviceProfileData; import org.thingsboard.server.common.data.device.profile.MqttDeviceProfileTransportConfiguration; @@ -54,8 +37,23 @@ import org.thingsboard.server.common.data.rule.RuleChain; import org.thingsboard.server.common.data.rule.RuleChainType; import org.thingsboard.server.common.data.security.Authority; import org.thingsboard.server.common.data.widget.WidgetsBundle; +import org.thingsboard.server.dao.asset.AssetService; +import org.thingsboard.server.dao.customer.CustomerService; +import org.thingsboard.server.dao.dashboard.DashboardService; +import org.thingsboard.server.dao.device.DeviceProfileService; +import org.thingsboard.server.dao.device.DeviceService; +import org.thingsboard.server.dao.edge.EdgeService; +import org.thingsboard.server.dao.entityview.EntityViewService; import org.thingsboard.server.dao.exception.DataValidationException; +import org.thingsboard.server.dao.ota.OtaPackageService; +import org.thingsboard.server.dao.resource.ResourceService; +import org.thingsboard.server.dao.rpc.RpcService; +import org.thingsboard.server.dao.rule.RuleChainService; import org.thingsboard.server.dao.tenant.TenantDao; +import org.thingsboard.server.dao.tenant.TenantProfileService; +import org.thingsboard.server.dao.usagerecord.ApiUsageStateService; +import org.thingsboard.server.dao.user.UserService; +import org.thingsboard.server.dao.widget.WidgetsBundleService; import java.util.ArrayList; import java.util.Collections; @@ -69,16 +67,45 @@ import static org.mockito.Mockito.verify; public abstract class BaseTenantServiceTest extends AbstractServiceTest { - private IdComparator idComparator = new IdComparator<>(); - @SpyBean - protected TenantDao tenantDao; + TenantDao tenantDao; @Autowired - protected TbTransactionalCache cache; - + ApiUsageStateService apiUsageStateService; + @Autowired + AssetService assetService; + @Autowired + CustomerService customerService; + @Autowired + DashboardService dashboardService; + @Autowired + DeviceProfileService deviceProfileService; + @Autowired + DeviceService deviceService; + @Autowired + EdgeService edgeService; + @Autowired + EntityViewService entityViewService; @Autowired - protected TbTransactionalCache existsTenantCache; + OtaPackageService otaPackageService; + @Autowired + ResourceService resourceService; + @Autowired + RpcService rpcService; + @Autowired + RuleChainService ruleChainService; + @Autowired + TbTransactionalCache existsTenantCache; + @Autowired + TbTransactionalCache cache; + @Autowired + TenantProfileService tenantProfileService; + @Autowired + UserService userService; + @Autowired + WidgetsBundleService widgetsBundleService; + + private final IdComparator idComparator = new IdComparator<>(); @Test public void testSaveTenant() { diff --git a/dao/src/test/java/org/thingsboard/server/dao/service/BaseUserServiceTest.java b/dao/src/test/java/org/thingsboard/server/dao/service/BaseUserServiceTest.java index 49ececc8e4..7698c2d129 100644 --- a/dao/src/test/java/org/thingsboard/server/dao/service/BaseUserServiceTest.java +++ b/dao/src/test/java/org/thingsboard/server/dao/service/BaseUserServiceTest.java @@ -20,6 +20,7 @@ import org.junit.Assert; import org.junit.Before; import org.junit.Test; import org.junit.jupiter.api.Assertions; +import org.springframework.beans.factory.annotation.Autowired; import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.server.common.data.Customer; import org.thingsboard.server.common.data.StringUtils; @@ -33,7 +34,9 @@ import org.thingsboard.server.common.data.page.PageLink; import org.thingsboard.server.common.data.security.Authority; import org.thingsboard.server.common.data.security.UserCredentials; import org.thingsboard.server.common.data.security.UserSettings; +import org.thingsboard.server.dao.customer.CustomerService; import org.thingsboard.server.dao.exception.DataValidationException; +import org.thingsboard.server.dao.user.UserService; import java.util.ArrayList; import java.util.Collections; @@ -41,6 +44,11 @@ import java.util.List; public abstract class BaseUserServiceTest extends AbstractServiceTest { + @Autowired + CustomerService customerService; + @Autowired + UserService userService; + private IdComparator idComparator = new IdComparator<>(); private TenantId tenantId; diff --git a/dao/src/test/java/org/thingsboard/server/dao/service/BaseWidgetTypeServiceTest.java b/dao/src/test/java/org/thingsboard/server/dao/service/BaseWidgetTypeServiceTest.java index 04cc1d8412..ba5d149910 100644 --- a/dao/src/test/java/org/thingsboard/server/dao/service/BaseWidgetTypeServiceTest.java +++ b/dao/src/test/java/org/thingsboard/server/dao/service/BaseWidgetTypeServiceTest.java @@ -23,6 +23,7 @@ import org.junit.Assert; import org.junit.Before; import org.junit.Test; import org.junit.jupiter.api.Assertions; +import org.springframework.beans.factory.annotation.Autowired; import org.thingsboard.server.common.data.Tenant; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.widget.WidgetType; @@ -30,6 +31,8 @@ import org.thingsboard.server.common.data.widget.WidgetTypeDetails; import org.thingsboard.server.common.data.widget.WidgetsBundle; import org.thingsboard.server.dao.exception.DataValidationException; import org.thingsboard.server.dao.model.ModelConstants; +import org.thingsboard.server.dao.widget.WidgetTypeService; +import org.thingsboard.server.dao.widget.WidgetsBundleService; import java.io.IOException; import java.util.ArrayList; @@ -38,6 +41,11 @@ import java.util.List; public abstract class BaseWidgetTypeServiceTest extends AbstractServiceTest { + @Autowired + WidgetsBundleService widgetsBundleService; + @Autowired + WidgetTypeService widgetTypeService; + private IdComparator idComparator = new IdComparator<>(); private TenantId tenantId; diff --git a/dao/src/test/java/org/thingsboard/server/dao/service/BaseWidgetsBundleServiceTest.java b/dao/src/test/java/org/thingsboard/server/dao/service/BaseWidgetsBundleServiceTest.java index c28f5face7..dd1b92263b 100644 --- a/dao/src/test/java/org/thingsboard/server/dao/service/BaseWidgetsBundleServiceTest.java +++ b/dao/src/test/java/org/thingsboard/server/dao/service/BaseWidgetsBundleServiceTest.java @@ -21,6 +21,7 @@ import org.junit.Assert; import org.junit.Before; import org.junit.Test; import org.junit.jupiter.api.Assertions; +import org.springframework.beans.factory.annotation.Autowired; import org.thingsboard.server.common.data.Tenant; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.page.PageData; @@ -28,6 +29,7 @@ import org.thingsboard.server.common.data.page.PageLink; import org.thingsboard.server.common.data.widget.WidgetsBundle; import org.thingsboard.server.dao.exception.DataValidationException; import org.thingsboard.server.dao.model.ModelConstants; +import org.thingsboard.server.dao.widget.WidgetsBundleService; import java.io.IOException; import java.util.ArrayList; @@ -36,6 +38,9 @@ import java.util.List; public abstract class BaseWidgetsBundleServiceTest extends AbstractServiceTest { + @Autowired + WidgetsBundleService widgetsBundleService; + private IdComparator idComparator = new IdComparator<>(); private TenantId tenantId; diff --git a/dao/src/test/java/org/thingsboard/server/dao/service/event/BaseEventServiceTest.java b/dao/src/test/java/org/thingsboard/server/dao/service/event/BaseEventServiceTest.java index 4b0cf9a1b1..1b0825aff3 100644 --- a/dao/src/test/java/org/thingsboard/server/dao/service/event/BaseEventServiceTest.java +++ b/dao/src/test/java/org/thingsboard/server/dao/service/event/BaseEventServiceTest.java @@ -19,6 +19,7 @@ import com.datastax.oss.driver.api.core.uuid.Uuids; import org.junit.Assert; import org.junit.Before; import org.junit.Test; +import org.springframework.beans.factory.annotation.Autowired; import org.thingsboard.server.common.data.EventInfo; import org.thingsboard.server.common.data.event.Event; import org.thingsboard.server.common.data.event.EventType; @@ -31,6 +32,7 @@ import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.SortOrder; import org.thingsboard.server.common.data.page.TimePageLink; +import org.thingsboard.server.dao.event.EventService; import org.thingsboard.server.dao.service.AbstractServiceTest; import java.text.ParseException; @@ -39,6 +41,10 @@ import java.util.List; import static org.apache.commons.lang3.time.DateFormatUtils.ISO_DATETIME_TIME_ZONE_FORMAT; public abstract class BaseEventServiceTest extends AbstractServiceTest { + + @Autowired + EventService eventService; + long timeBeforeStartTime; long startTime; long eventTime; diff --git a/dao/src/test/java/org/thingsboard/server/dao/service/timeseries/BaseTimeseriesServiceTest.java b/dao/src/test/java/org/thingsboard/server/dao/service/timeseries/BaseTimeseriesServiceTest.java index 924f515143..962dc7e246 100644 --- a/dao/src/test/java/org/thingsboard/server/dao/service/timeseries/BaseTimeseriesServiceTest.java +++ b/dao/src/test/java/org/thingsboard/server/dao/service/timeseries/BaseTimeseriesServiceTest.java @@ -21,6 +21,7 @@ import org.junit.After; import org.junit.Assert; import org.junit.Before; import org.junit.Test; +import org.springframework.beans.factory.annotation.Autowired; import org.thingsboard.server.common.data.EntityView; import org.thingsboard.server.common.data.Tenant; import org.thingsboard.server.common.data.id.DeviceId; @@ -39,7 +40,9 @@ import org.thingsboard.server.common.data.kv.ReadTsKvQueryResult; import org.thingsboard.server.common.data.kv.StringDataEntry; import org.thingsboard.server.common.data.kv.TsKvEntry; import org.thingsboard.server.common.data.objects.TelemetryEntityView; +import org.thingsboard.server.dao.entityview.EntityViewService; import org.thingsboard.server.dao.service.AbstractServiceTest; +import org.thingsboard.server.dao.timeseries.TimeseriesService; import java.util.ArrayList; import java.util.Arrays; @@ -59,6 +62,13 @@ import static org.junit.Assert.assertNotNull; @Slf4j public abstract class BaseTimeseriesServiceTest extends AbstractServiceTest { + + @Autowired + TimeseriesService tsService; + + @Autowired + EntityViewService entityViewService; + static final int MAX_TIMEOUT = 30; private static final String STRING_KEY = "stringKey"; From 67b0d24910e478af1894efc69931431c6e5f113e Mon Sep 17 00:00:00 2001 From: OleksandraMatviienko Date: Fri, 10 Mar 2023 21:16:18 +0100 Subject: [PATCH 08/28] the creation and deletion of a tenant moved to the AbstractServiceTest --- .../dao/service/AbstractServiceTest.java | 45 ++++++----------- .../service/BaseAlarmCommentServiceTest.java | 10 ---- .../dao/service/BaseAlarmServiceTest.java | 21 -------- .../service/BaseApiUsageStateServiceTest.java | 20 -------- .../service/BaseAssetProfileServiceTest.java | 20 -------- .../dao/service/BaseAssetServiceTest.java | 34 ------------- .../dao/service/BaseCustomerServiceTest.java | 19 +------ .../dao/service/BaseDashboardServiceTest.java | 42 ---------------- .../BaseDeviceCredentialsServiceTest.java | 20 -------- .../service/BaseDeviceProfileServiceTest.java | 21 -------- .../dao/service/BaseDeviceServiceTest.java | 19 ------- .../dao/service/BaseEdgeServiceTest.java | 34 ------------- .../dao/service/BaseEntityServiceTest.java | 21 -------- .../service/BaseOtaPackageServiceTest.java | 9 ---- .../dao/service/BaseQueueServiceTest.java | 2 +- .../dao/service/BaseRuleChainServiceTest.java | 26 ---------- .../service/BaseTenantProfileServiceTest.java | 9 ++++ .../dao/service/BaseTenantServiceTest.java | 3 +- .../dao/service/BaseUserServiceTest.java | 49 ++----------------- .../service/BaseWidgetTypeServiceTest.java | 19 ------- .../service/BaseWidgetsBundleServiceTest.java | 39 --------------- 21 files changed, 34 insertions(+), 448 deletions(-) diff --git a/dao/src/test/java/org/thingsboard/server/dao/service/AbstractServiceTest.java b/dao/src/test/java/org/thingsboard/server/dao/service/AbstractServiceTest.java index 282e07caa1..55f3bb58c8 100644 --- a/dao/src/test/java/org/thingsboard/server/dao/service/AbstractServiceTest.java +++ b/dao/src/test/java/org/thingsboard/server/dao/service/AbstractServiceTest.java @@ -18,6 +18,8 @@ package org.thingsboard.server.dao.service; import com.datastax.oss.driver.api.core.uuid.Uuids; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; +import org.junit.After; +import org.junit.Before; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; @@ -47,44 +49,17 @@ import org.thingsboard.server.common.data.id.HasId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.ota.ChecksumAlgorithm; import org.thingsboard.server.common.data.ota.OtaPackageType; -import org.thingsboard.server.dao.alarm.AlarmCommentService; -import org.thingsboard.server.dao.alarm.AlarmService; -import org.thingsboard.server.dao.asset.AssetProfileService; -import org.thingsboard.server.dao.asset.AssetService; import org.thingsboard.server.dao.audit.AuditLogLevelFilter; import org.thingsboard.server.dao.audit.AuditLogLevelMask; import org.thingsboard.server.dao.audit.AuditLogLevelProperties; -import org.thingsboard.server.dao.component.ComponentDescriptorService; -import org.thingsboard.server.dao.customer.CustomerService; -import org.thingsboard.server.dao.dashboard.DashboardService; -import org.thingsboard.server.dao.device.DeviceCredentialsService; -import org.thingsboard.server.dao.device.DeviceProfileService; -import org.thingsboard.server.dao.device.DeviceService; -import org.thingsboard.server.dao.edge.EdgeEventService; -import org.thingsboard.server.dao.edge.EdgeService; -import org.thingsboard.server.dao.entity.EntityService; -import org.thingsboard.server.dao.entityview.EntityViewService; -import org.thingsboard.server.dao.event.EventService; -import org.thingsboard.server.dao.ota.OtaPackageService; -import org.thingsboard.server.dao.queue.QueueService; -import org.thingsboard.server.dao.relation.RelationService; -import org.thingsboard.server.dao.resource.ResourceService; -import org.thingsboard.server.dao.rpc.RpcService; -import org.thingsboard.server.dao.rule.RuleChainService; -import org.thingsboard.server.dao.settings.AdminSettingsService; -import org.thingsboard.server.dao.tenant.TenantProfileService; import org.thingsboard.server.dao.tenant.TenantService; -import org.thingsboard.server.dao.timeseries.TimeseriesService; -import org.thingsboard.server.dao.usagerecord.ApiUsageStateService; -import org.thingsboard.server.dao.user.UserService; -import org.thingsboard.server.dao.widget.WidgetTypeService; -import org.thingsboard.server.dao.widget.WidgetsBundleService; import java.io.IOException; import java.nio.ByteBuffer; import java.util.Comparator; import java.util.HashMap; import java.util.Map; +import java.util.UUID; import static org.junit.Assert.assertNotNull; @@ -103,6 +78,18 @@ public abstract class AbstractServiceTest { @Autowired protected TenantService tenantService; + protected TenantId tenantId; + + @Before + public void beforeAbstractService() { + tenantId = createTenant(); + } + + @After + public void afterAbstractService() { + tenantService.deleteTenants(); + } + public class IdComparator implements Comparator { @Override public int compare(D o1, D o2) { @@ -187,7 +174,7 @@ public abstract class AbstractServiceTest { public TenantId createTenant() { Tenant tenant = new Tenant(); - tenant.setTitle("My tenant " + Uuids.timeBased()); + tenant.setTitle("My tenant " + UUID.randomUUID()); Tenant savedTenant = tenantService.saveTenant(tenant); assertNotNull(savedTenant); return savedTenant.getId(); diff --git a/dao/src/test/java/org/thingsboard/server/dao/service/BaseAlarmCommentServiceTest.java b/dao/src/test/java/org/thingsboard/server/dao/service/BaseAlarmCommentServiceTest.java index 8448650dcf..1144ec6513 100644 --- a/dao/src/test/java/org/thingsboard/server/dao/service/BaseAlarmCommentServiceTest.java +++ b/dao/src/test/java/org/thingsboard/server/dao/service/BaseAlarmCommentServiceTest.java @@ -23,14 +23,12 @@ import org.junit.Test; import org.springframework.beans.factory.annotation.Autowired; import org.testcontainers.shaded.org.apache.commons.lang3.RandomStringUtils; import org.thingsboard.common.util.JacksonUtil; -import org.thingsboard.server.common.data.Tenant; import org.thingsboard.server.common.data.User; import org.thingsboard.server.common.data.alarm.Alarm; import org.thingsboard.server.common.data.alarm.AlarmComment; import org.thingsboard.server.common.data.alarm.AlarmCommentInfo; import org.thingsboard.server.common.data.alarm.AlarmSeverity; import org.thingsboard.server.common.data.id.AssetId; -import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.id.UserId; import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageLink; @@ -54,18 +52,11 @@ public abstract class BaseAlarmCommentServiceTest extends AbstractServiceTest { UserService userService; public static final String TEST_ALARM = "TEST_ALARM"; - private TenantId tenantId; private Alarm alarm; private User user; @Before public void before() { - Tenant tenant = new Tenant(); - tenant.setTitle("My tenant"); - Tenant savedTenant = tenantService.saveTenant(tenant); - Assert.assertNotNull(savedTenant); - tenantId = savedTenant.getId(); - alarm = Alarm.builder().tenantId(tenantId).originator(new AssetId(Uuids.timeBased())) .type(TEST_ALARM) .severity(AlarmSeverity.CRITICAL) @@ -84,7 +75,6 @@ public abstract class BaseAlarmCommentServiceTest extends AbstractServiceTest { @After public void after() { alarmService.deleteAlarm(tenantId, alarm.getId()); - tenantService.deleteTenant(tenantId); } diff --git a/dao/src/test/java/org/thingsboard/server/dao/service/BaseAlarmServiceTest.java b/dao/src/test/java/org/thingsboard/server/dao/service/BaseAlarmServiceTest.java index f914bc63f7..73a489ab68 100644 --- a/dao/src/test/java/org/thingsboard/server/dao/service/BaseAlarmServiceTest.java +++ b/dao/src/test/java/org/thingsboard/server/dao/service/BaseAlarmServiceTest.java @@ -16,15 +16,12 @@ package org.thingsboard.server.dao.service; import com.datastax.oss.driver.api.core.uuid.Uuids; -import org.junit.After; import org.junit.Assert; -import org.junit.Before; import org.junit.Test; import org.springframework.beans.factory.annotation.Autowired; import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.server.common.data.Customer; import org.thingsboard.server.common.data.Device; -import org.thingsboard.server.common.data.Tenant; import org.thingsboard.server.common.data.User; import org.thingsboard.server.common.data.alarm.Alarm; import org.thingsboard.server.common.data.alarm.AlarmCreateOrUpdateActiveRequest; @@ -37,7 +34,6 @@ import org.thingsboard.server.common.data.alarm.AlarmStatus; import org.thingsboard.server.common.data.alarm.AlarmUpdateRequest; import org.thingsboard.server.common.data.asset.Asset; import org.thingsboard.server.common.data.id.AssetId; -import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.SortOrder; import org.thingsboard.server.common.data.page.TimePageLink; @@ -84,23 +80,6 @@ public abstract class BaseAlarmServiceTest extends AbstractServiceTest { private static final String TEST_TENANT_FIRST_NAME = "testtenantfirstname"; private static final String TEST_TENANT_LAST_NAME = "testtenantlastname"; - private TenantId tenantId; - - @Before - public void before() { - Tenant tenant = new Tenant(); - tenant.setTitle("My tenant"); - Tenant savedTenant = tenantService.saveTenant(tenant); - Assert.assertNotNull(savedTenant); - tenantId = savedTenant.getId(); - } - - @After - public void after() { - tenantService.deleteTenant(tenantId); - } - - @Test public void testSaveAndFetchAlarm() throws ExecutionException, InterruptedException { AssetId parentId = new AssetId(Uuids.timeBased()); diff --git a/dao/src/test/java/org/thingsboard/server/dao/service/BaseApiUsageStateServiceTest.java b/dao/src/test/java/org/thingsboard/server/dao/service/BaseApiUsageStateServiceTest.java index 2c325654a1..2ee2f74b3e 100644 --- a/dao/src/test/java/org/thingsboard/server/dao/service/BaseApiUsageStateServiceTest.java +++ b/dao/src/test/java/org/thingsboard/server/dao/service/BaseApiUsageStateServiceTest.java @@ -15,15 +15,11 @@ */ package org.thingsboard.server.dao.service; -import org.junit.After; import org.junit.Assert; -import org.junit.Before; import org.junit.Test; import org.springframework.beans.factory.annotation.Autowired; import org.thingsboard.server.common.data.ApiUsageStateValue; -import org.thingsboard.server.common.data.Tenant; import org.thingsboard.server.common.data.ApiUsageState; -import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.dao.usagerecord.ApiUsageStateService; @@ -32,22 +28,6 @@ public abstract class BaseApiUsageStateServiceTest extends AbstractServiceTest { @Autowired ApiUsageStateService apiUsageStateService; - private TenantId tenantId; - - @Before - public void before() { - Tenant tenant = new Tenant(); - tenant.setTitle("My tenant"); - Tenant savedTenant = tenantService.saveTenant(tenant); - Assert.assertNotNull(savedTenant); - tenantId = savedTenant.getId(); - } - - @After - public void after() { - tenantService.deleteTenant(tenantId); - } - @Test public void testFindApiUsageStateByTenantId() { ApiUsageState apiUsageState = apiUsageStateService.findTenantApiUsageState(tenantId); diff --git a/dao/src/test/java/org/thingsboard/server/dao/service/BaseAssetProfileServiceTest.java b/dao/src/test/java/org/thingsboard/server/dao/service/BaseAssetProfileServiceTest.java index 90f68b0207..df0cb464fc 100644 --- a/dao/src/test/java/org/thingsboard/server/dao/service/BaseAssetProfileServiceTest.java +++ b/dao/src/test/java/org/thingsboard/server/dao/service/BaseAssetProfileServiceTest.java @@ -19,18 +19,14 @@ import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.ListeningExecutorService; import com.google.common.util.concurrent.MoreExecutors; -import org.junit.After; import org.junit.Assert; -import org.junit.Before; import org.junit.Test; import org.junit.jupiter.api.Assertions; import org.springframework.beans.factory.annotation.Autowired; import org.thingsboard.common.util.ThingsBoardThreadFactory; -import org.thingsboard.server.common.data.Tenant; import org.thingsboard.server.common.data.asset.Asset; import org.thingsboard.server.common.data.asset.AssetProfile; import org.thingsboard.server.common.data.asset.AssetProfileInfo; -import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageLink; import org.thingsboard.server.dao.asset.AssetProfileService; @@ -54,22 +50,6 @@ public abstract class BaseAssetProfileServiceTest extends AbstractServiceTest { @Autowired AssetService assetService; - private TenantId tenantId; - - @Before - public void before() { - Tenant tenant = new Tenant(); - tenant.setTitle("My tenant"); - Tenant savedTenant = tenantService.saveTenant(tenant); - Assert.assertNotNull(savedTenant); - tenantId = savedTenant.getId(); - } - - @After - public void after() { - tenantService.deleteTenant(tenantId); - } - @Test public void testSaveAssetProfile() { AssetProfile assetProfile = this.createAssetProfile(tenantId, "Asset Profile"); diff --git a/dao/src/test/java/org/thingsboard/server/dao/service/BaseAssetServiceTest.java b/dao/src/test/java/org/thingsboard/server/dao/service/BaseAssetServiceTest.java index ab81764015..9f4c8fe363 100644 --- a/dao/src/test/java/org/thingsboard/server/dao/service/BaseAssetServiceTest.java +++ b/dao/src/test/java/org/thingsboard/server/dao/service/BaseAssetServiceTest.java @@ -16,9 +16,7 @@ package org.thingsboard.server.dao.service; import com.datastax.oss.driver.api.core.uuid.Uuids; -import org.junit.After; import org.junit.Assert; -import org.junit.Before; import org.junit.Test; import org.junit.jupiter.api.Assertions; import org.springframework.beans.factory.annotation.Autowired; @@ -51,22 +49,6 @@ public abstract class BaseAssetServiceTest extends AbstractServiceTest { private IdComparator idComparator = new IdComparator<>(); - private TenantId tenantId; - - @Before - public void before() { - Tenant tenant = new Tenant(); - tenant.setTitle("My tenant"); - Tenant savedTenant = tenantService.saveTenant(tenant); - Assert.assertNotNull(savedTenant); - tenantId = savedTenant.getId(); - } - - @After - public void after() { - tenantService.deleteTenant(tenantId); - } - @Test public void testSaveAsset() { Asset asset = new Asset(); @@ -228,12 +210,6 @@ public abstract class BaseAssetServiceTest extends AbstractServiceTest { @Test public void testFindAssetsByTenantId() { - Tenant tenant = new Tenant(); - tenant.setTitle("Test tenant"); - tenant = tenantService.saveTenant(tenant); - - TenantId tenantId = tenant.getId(); - List assets = new ArrayList<>(); for (int i=0;i<178;i++) { Asset asset = new Asset(); @@ -265,8 +241,6 @@ public abstract class BaseAssetServiceTest extends AbstractServiceTest { pageData = assetService.findAssetsByTenantId(tenantId, pageLink); Assert.assertFalse(pageData.hasNext()); Assert.assertTrue(pageData.getData().isEmpty()); - - tenantService.deleteTenant(tenantId); } @Test @@ -427,12 +401,6 @@ public abstract class BaseAssetServiceTest extends AbstractServiceTest { @Test public void testFindAssetsByTenantIdAndCustomerId() { - Tenant tenant = new Tenant(); - tenant.setTitle("Test tenant"); - tenant = tenantService.saveTenant(tenant); - - TenantId tenantId = tenant.getId(); - Customer customer = new Customer(); customer.setTitle("Test customer"); customer.setTenantId(tenantId); @@ -471,8 +439,6 @@ public abstract class BaseAssetServiceTest extends AbstractServiceTest { pageData = assetService.findAssetInfosByTenantIdAndCustomerId(tenantId, customerId, pageLink); Assert.assertFalse(pageData.hasNext()); Assert.assertTrue(pageData.getData().isEmpty()); - - tenantService.deleteTenant(tenantId); } @Test diff --git a/dao/src/test/java/org/thingsboard/server/dao/service/BaseCustomerServiceTest.java b/dao/src/test/java/org/thingsboard/server/dao/service/BaseCustomerServiceTest.java index 46a28cf36e..371d8abb99 100644 --- a/dao/src/test/java/org/thingsboard/server/dao/service/BaseCustomerServiceTest.java +++ b/dao/src/test/java/org/thingsboard/server/dao/service/BaseCustomerServiceTest.java @@ -51,24 +51,14 @@ public abstract class BaseCustomerServiceTest extends AbstractServiceTest { ListeningExecutorService executor; - private TenantId tenantId; - @Before public void before() { executor = MoreExecutors.listeningDecorator(ThingsBoardExecutors.newWorkStealingPool(8, getClass())); - - Tenant tenant = new Tenant(); - tenant.setTitle("My tenant"); - Tenant savedTenant = tenantService.saveTenant(tenant); - Assert.assertNotNull(savedTenant); - tenantId = savedTenant.getId(); - } + } @After public void after() { executor.shutdownNow(); - - tenantService.deleteTenant(tenantId); } @Test @@ -158,11 +148,6 @@ public abstract class BaseCustomerServiceTest extends AbstractServiceTest { @Test public void testFindCustomersByTenantId() throws Exception { - Tenant tenant = new Tenant(); - tenant.setTitle("Test tenant"); - tenant = tenantService.saveTenant(tenant); - - TenantId tenantId = tenant.getId(); List> futures = new ArrayList<>(135); for (int i = 0; i < 135; i++) { @@ -193,8 +178,6 @@ public abstract class BaseCustomerServiceTest extends AbstractServiceTest { pageData = customerService.findCustomersByTenantId(tenantId, pageLink); Assert.assertFalse(pageData.hasNext()); Assert.assertTrue(pageData.getData().isEmpty()); - - tenantService.deleteTenant(tenantId); } @Test diff --git a/dao/src/test/java/org/thingsboard/server/dao/service/BaseDashboardServiceTest.java b/dao/src/test/java/org/thingsboard/server/dao/service/BaseDashboardServiceTest.java index 9305e55450..7ccd5e6211 100644 --- a/dao/src/test/java/org/thingsboard/server/dao/service/BaseDashboardServiceTest.java +++ b/dao/src/test/java/org/thingsboard/server/dao/service/BaseDashboardServiceTest.java @@ -16,9 +16,7 @@ package org.thingsboard.server.dao.service; import com.datastax.oss.driver.api.core.uuid.Uuids; -import org.junit.After; import org.junit.Assert; -import org.junit.Before; import org.junit.Test; import org.junit.jupiter.api.Assertions; import org.springframework.beans.factory.annotation.Autowired; @@ -56,22 +54,6 @@ public abstract class BaseDashboardServiceTest extends AbstractServiceTest { private IdComparator idComparator = new IdComparator<>(); - private TenantId tenantId; - - @Before - public void before() { - Tenant tenant = new Tenant(); - tenant.setTitle("My tenant"); - Tenant savedTenant = tenantService.saveTenant(tenant); - Assert.assertNotNull(savedTenant); - tenantId = savedTenant.getId(); - } - - @After - public void after() { - tenantService.deleteTenant(tenantId); - } - @Test public void testSaveDashboard() throws IOException { Dashboard dashboard = new Dashboard(); @@ -187,12 +169,6 @@ public abstract class BaseDashboardServiceTest extends AbstractServiceTest { @Test public void testFindDashboardsByTenantId() { - Tenant tenant = new Tenant(); - tenant.setTitle("Test tenant"); - tenant = tenantService.saveTenant(tenant); - - TenantId tenantId = tenant.getId(); - List dashboards = new ArrayList<>(); for (int i=0;i<165;i++) { Dashboard dashboard = new Dashboard(); @@ -223,18 +199,10 @@ public abstract class BaseDashboardServiceTest extends AbstractServiceTest { pageData = dashboardService.findDashboardsByTenantId(tenantId, pageLink); Assert.assertFalse(pageData.hasNext()); Assert.assertTrue(pageData.getData().isEmpty()); - - tenantService.deleteTenant(tenantId); } @Test public void testFindMobileDashboardsByTenantId() { - Tenant tenant = new Tenant(); - tenant.setTitle("Test tenant"); - tenant = tenantService.saveTenant(tenant); - - TenantId tenantId = tenant.getId(); - List mobileDashboards = new ArrayList<>(); for (int i=0;i<165;i++) { Dashboard dashboard = new Dashboard(); @@ -283,8 +251,6 @@ public abstract class BaseDashboardServiceTest extends AbstractServiceTest { pageData = dashboardService.findMobileDashboardsByTenantId(tenantId, pageLink); Assert.assertFalse(pageData.hasNext()); Assert.assertTrue(pageData.getData().isEmpty()); - - tenantService.deleteTenant(tenantId); } @Test @@ -364,12 +330,6 @@ public abstract class BaseDashboardServiceTest extends AbstractServiceTest { @Test public void testFindDashboardsByTenantIdAndCustomerId() throws ExecutionException, InterruptedException { - Tenant tenant = new Tenant(); - tenant.setTitle("Test tenant"); - tenant = tenantService.saveTenant(tenant); - - TenantId tenantId = tenant.getId(); - Customer customer = new Customer(); customer.setTitle("Test customer"); customer.setTenantId(tenantId); @@ -407,8 +367,6 @@ public abstract class BaseDashboardServiceTest extends AbstractServiceTest { pageData = dashboardService.findDashboardsByTenantIdAndCustomerId(tenantId, customerId, pageLink); Assert.assertFalse(pageData.hasNext()); Assert.assertTrue(pageData.getData().isEmpty()); - - tenantService.deleteTenant(tenantId); } @Test diff --git a/dao/src/test/java/org/thingsboard/server/dao/service/BaseDeviceCredentialsServiceTest.java b/dao/src/test/java/org/thingsboard/server/dao/service/BaseDeviceCredentialsServiceTest.java index e06c55b5d6..4512a5fa4f 100644 --- a/dao/src/test/java/org/thingsboard/server/dao/service/BaseDeviceCredentialsServiceTest.java +++ b/dao/src/test/java/org/thingsboard/server/dao/service/BaseDeviceCredentialsServiceTest.java @@ -16,17 +16,13 @@ package org.thingsboard.server.dao.service; import com.datastax.oss.driver.api.core.uuid.Uuids; -import org.junit.After; import org.junit.Assert; -import org.junit.Before; import org.junit.Test; import org.junit.jupiter.api.Assertions; import org.springframework.beans.factory.annotation.Autowired; import org.thingsboard.server.common.data.Device; -import org.thingsboard.server.common.data.Tenant; import org.thingsboard.server.common.data.id.DeviceCredentialsId; import org.thingsboard.server.common.data.id.DeviceId; -import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.security.DeviceCredentials; import org.thingsboard.server.common.data.security.DeviceCredentialsType; import org.thingsboard.server.dao.device.DeviceCredentialsService; @@ -40,22 +36,6 @@ public abstract class BaseDeviceCredentialsServiceTest extends AbstractServiceTe @Autowired DeviceService deviceService; - private TenantId tenantId; - - @Before - public void before() { - Tenant tenant = new Tenant(); - tenant.setTitle("My tenant"); - Tenant savedTenant = tenantService.saveTenant(tenant); - Assert.assertNotNull(savedTenant); - tenantId = savedTenant.getId(); - } - - @After - public void after() { - tenantService.deleteTenant(tenantId); - } - @Test public void testCreateDeviceCredentials() { DeviceCredentials deviceCredentials = new DeviceCredentials(); diff --git a/dao/src/test/java/org/thingsboard/server/dao/service/BaseDeviceProfileServiceTest.java b/dao/src/test/java/org/thingsboard/server/dao/service/BaseDeviceProfileServiceTest.java index bb2caa41fd..cdfa73fac9 100644 --- a/dao/src/test/java/org/thingsboard/server/dao/service/BaseDeviceProfileServiceTest.java +++ b/dao/src/test/java/org/thingsboard/server/dao/service/BaseDeviceProfileServiceTest.java @@ -19,9 +19,7 @@ import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.ListeningExecutorService; import com.google.common.util.concurrent.MoreExecutors; -import org.junit.After; import org.junit.Assert; -import org.junit.Before; import org.junit.Ignore; import org.junit.Test; import org.junit.jupiter.api.Assertions; @@ -32,9 +30,7 @@ import org.thingsboard.server.common.data.DeviceProfile; import org.thingsboard.server.common.data.DeviceProfileInfo; import org.thingsboard.server.common.data.DeviceTransportType; import org.thingsboard.server.common.data.OtaPackage; -import org.thingsboard.server.common.data.Tenant; import org.thingsboard.server.common.data.ota.ChecksumAlgorithm; -import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageLink; import org.thingsboard.server.dao.device.DeviceProfileService; @@ -48,7 +44,6 @@ import java.util.Collections; import java.util.List; import java.util.concurrent.ExecutionException; import java.util.concurrent.Executors; -import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; import static org.assertj.core.api.Assertions.assertThat; @@ -66,22 +61,6 @@ public abstract class BaseDeviceProfileServiceTest extends AbstractServiceTest { private IdComparator idComparator = new IdComparator<>(); private IdComparator deviceProfileInfoIdComparator = new IdComparator<>(); - private TenantId tenantId; - - @Before - public void before() { - Tenant tenant = new Tenant(); - tenant.setTitle("My tenant"); - Tenant savedTenant = tenantService.saveTenant(tenant); - Assert.assertNotNull(savedTenant); - tenantId = savedTenant.getId(); - } - - @After - public void after() { - tenantService.deleteTenant(tenantId); - } - @Test public void testSaveDeviceProfile() { DeviceProfile deviceProfile = this.createDeviceProfile(tenantId, "Device Profile"); diff --git a/dao/src/test/java/org/thingsboard/server/dao/service/BaseDeviceServiceTest.java b/dao/src/test/java/org/thingsboard/server/dao/service/BaseDeviceServiceTest.java index 0fdefa7e16..ddd3553194 100644 --- a/dao/src/test/java/org/thingsboard/server/dao/service/BaseDeviceServiceTest.java +++ b/dao/src/test/java/org/thingsboard/server/dao/service/BaseDeviceServiceTest.java @@ -73,13 +73,10 @@ public abstract class BaseDeviceServiceTest extends AbstractServiceTest { TenantProfileService tenantProfileService; private IdComparator idComparator = new IdComparator<>(); - - private TenantId tenantId; private TenantId anotherTenantId; @Before public void before() { - tenantId = createTenant(); anotherTenantId = createTenant(); } @@ -409,12 +406,6 @@ public abstract class BaseDeviceServiceTest extends AbstractServiceTest { @Test public void testFindDevicesByTenantId() { - Tenant tenant = new Tenant(); - tenant.setTitle("Test tenant"); - tenant = tenantService.saveTenant(tenant); - - TenantId tenantId = tenant.getId(); - List devices = new ArrayList<>(); for (int i = 0; i < 178; i++) { Device device = new Device(); @@ -446,8 +437,6 @@ public abstract class BaseDeviceServiceTest extends AbstractServiceTest { pageData = deviceService.findDevicesByTenantId(tenantId, pageLink); Assert.assertFalse(pageData.hasNext()); Assert.assertTrue(pageData.getData().isEmpty()); - - tenantService.deleteTenant(tenantId); } @Test @@ -608,12 +597,6 @@ public abstract class BaseDeviceServiceTest extends AbstractServiceTest { @Test public void testFindDevicesByTenantIdAndCustomerId() { - Tenant tenant = new Tenant(); - tenant.setTitle("Test tenant"); - tenant = tenantService.saveTenant(tenant); - - TenantId tenantId = tenant.getId(); - Customer customer = new Customer(); customer.setTitle("Test customer"); customer.setTenantId(tenantId); @@ -652,8 +635,6 @@ public abstract class BaseDeviceServiceTest extends AbstractServiceTest { pageData = deviceService.findDeviceInfosByTenantIdAndCustomerId(tenantId, customerId, pageLink); Assert.assertFalse(pageData.hasNext()); Assert.assertTrue(pageData.getData().isEmpty()); - - tenantService.deleteTenant(tenantId); } @Test diff --git a/dao/src/test/java/org/thingsboard/server/dao/service/BaseEdgeServiceTest.java b/dao/src/test/java/org/thingsboard/server/dao/service/BaseEdgeServiceTest.java index 7ed318f58f..9b307b2f8c 100644 --- a/dao/src/test/java/org/thingsboard/server/dao/service/BaseEdgeServiceTest.java +++ b/dao/src/test/java/org/thingsboard/server/dao/service/BaseEdgeServiceTest.java @@ -17,9 +17,7 @@ package org.thingsboard.server.dao.service; import com.datastax.oss.driver.api.core.uuid.Uuids; import com.fasterxml.jackson.databind.node.ObjectNode; -import org.junit.After; import org.junit.Assert; -import org.junit.Before; import org.junit.Test; import org.junit.jupiter.api.Assertions; import org.springframework.beans.factory.annotation.Autowired; @@ -60,22 +58,6 @@ public abstract class BaseEdgeServiceTest extends AbstractServiceTest { private IdComparator idComparator = new IdComparator<>(); - private TenantId tenantId; - - @Before - public void before() { - Tenant tenant = new Tenant(); - tenant.setTitle("My tenant"); - Tenant savedTenant = tenantService.saveTenant(tenant); - Assert.assertNotNull(savedTenant); - tenantId = savedTenant.getId(); - } - - @After - public void after() { - tenantService.deleteTenant(tenantId); - } - @Test public void testSaveEdge() { Edge edge = constructEdge("My edge", "default"); @@ -215,12 +197,6 @@ public abstract class BaseEdgeServiceTest extends AbstractServiceTest { @Test public void testFindEdgesByTenantId() { - Tenant tenant = new Tenant(); - tenant.setTitle("Test tenant"); - tenant = tenantService.saveTenant(tenant); - - TenantId tenantId = tenant.getId(); - List edges = new ArrayList<>(); for (int i = 0; i < 178; i++) { Edge edge = constructEdge(tenantId, "Edge " + i, "default"); @@ -249,8 +225,6 @@ public abstract class BaseEdgeServiceTest extends AbstractServiceTest { pageData = edgeService.findEdgesByTenantId(tenantId, pageLink); Assert.assertFalse(pageData.hasNext()); Assert.assertTrue(pageData.getData().isEmpty()); - - tenantService.deleteTenant(tenantId); } @Test @@ -399,12 +373,6 @@ public abstract class BaseEdgeServiceTest extends AbstractServiceTest { @Test public void testFindEdgesByTenantIdAndCustomerId() { - Tenant tenant = new Tenant(); - tenant.setTitle("Test tenant"); - tenant = tenantService.saveTenant(tenant); - - TenantId tenantId = tenant.getId(); - Customer customer = new Customer(); customer.setTitle("Test customer"); customer.setTenantId(tenantId); @@ -440,8 +408,6 @@ public abstract class BaseEdgeServiceTest extends AbstractServiceTest { pageData = edgeService.findEdgesByTenantIdAndCustomerId(tenantId, customerId, pageLink); Assert.assertFalse(pageData.hasNext()); Assert.assertTrue(pageData.getData().isEmpty()); - - tenantService.deleteTenant(tenantId); } @Test diff --git a/dao/src/test/java/org/thingsboard/server/dao/service/BaseEntityServiceTest.java b/dao/src/test/java/org/thingsboard/server/dao/service/BaseEntityServiceTest.java index 75dc250e63..1af63c0ed7 100644 --- a/dao/src/test/java/org/thingsboard/server/dao/service/BaseEntityServiceTest.java +++ b/dao/src/test/java/org/thingsboard/server/dao/service/BaseEntityServiceTest.java @@ -21,9 +21,7 @@ import com.google.common.util.concurrent.ListenableFuture; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.RandomUtils; import org.hamcrest.Matchers; -import org.junit.After; import org.junit.Assert; -import org.junit.Before; import org.junit.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.jdbc.core.ResultSetExtractor; @@ -31,7 +29,6 @@ import org.thingsboard.server.common.data.DataConstants; import org.thingsboard.server.common.data.Device; import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.StringUtils; -import org.thingsboard.server.common.data.Tenant; import org.thingsboard.server.common.data.asset.Asset; import org.thingsboard.server.common.data.edge.Edge; import org.thingsboard.server.common.data.id.CustomerId; @@ -121,24 +118,6 @@ public abstract class BaseEntityServiceTest extends AbstractServiceTest { @Autowired TimeseriesService timeseriesService; - private TenantId tenantId; - - - @Before - public void before() { - Tenant tenant = new Tenant(); - tenant.setTitle("My tenant"); - Tenant savedTenant = tenantService.saveTenant(tenant); - Assert.assertNotNull(savedTenant); - tenantId = savedTenant.getId(); - } - - @After - public void after() { - tenantService.deleteTenant(tenantId); - } - - @Test public void testCountEntitiesByQuery() throws InterruptedException { List devices = new ArrayList<>(); diff --git a/dao/src/test/java/org/thingsboard/server/dao/service/BaseOtaPackageServiceTest.java b/dao/src/test/java/org/thingsboard/server/dao/service/BaseOtaPackageServiceTest.java index 22396e25a9..0458a09e31 100644 --- a/dao/src/test/java/org/thingsboard/server/dao/service/BaseOtaPackageServiceTest.java +++ b/dao/src/test/java/org/thingsboard/server/dao/service/BaseOtaPackageServiceTest.java @@ -29,7 +29,6 @@ import org.thingsboard.server.common.data.DeviceProfile; import org.thingsboard.server.common.data.OtaPackage; import org.thingsboard.server.common.data.OtaPackageInfo; import org.thingsboard.server.common.data.StringUtils; -import org.thingsboard.server.common.data.Tenant; import org.thingsboard.server.common.data.TenantProfile; import org.thingsboard.server.common.data.id.DeviceProfileId; import org.thingsboard.server.common.data.id.TenantId; @@ -65,8 +64,6 @@ public abstract class BaseOtaPackageServiceTest extends AbstractServiceTest { private final IdComparator idComparator = new IdComparator<>(); - private TenantId tenantId; - private DeviceProfileId deviceProfileId; @Autowired @@ -80,12 +77,6 @@ public abstract class BaseOtaPackageServiceTest extends AbstractServiceTest { @Before public void before() { - Tenant tenant = new Tenant(); - tenant.setTitle("My tenant"); - Tenant savedTenant = tenantService.saveTenant(tenant); - Assert.assertNotNull(savedTenant); - tenantId = savedTenant.getId(); - DeviceProfile deviceProfile = this.createDeviceProfile(tenantId, "Device Profile"); DeviceProfile savedDeviceProfile = deviceProfileService.saveDeviceProfile(deviceProfile); Assert.assertNotNull(savedDeviceProfile); diff --git a/dao/src/test/java/org/thingsboard/server/dao/service/BaseQueueServiceTest.java b/dao/src/test/java/org/thingsboard/server/dao/service/BaseQueueServiceTest.java index 3890aa257c..9d2c2bac5a 100644 --- a/dao/src/test/java/org/thingsboard/server/dao/service/BaseQueueServiceTest.java +++ b/dao/src/test/java/org/thingsboard/server/dao/service/BaseQueueServiceTest.java @@ -91,7 +91,7 @@ public abstract class BaseQueueServiceTest extends AbstractServiceTest { Tenant tenant = new Tenant(); tenant.setTitle("My tenant"); - tenant.setTenantProfileId(tenantProfileId); + tenant.setTenantProfileId(tenantProfileId); //custom profile Tenant savedTenant = tenantService.saveTenant(tenant); Assert.assertNotNull(savedTenant); tenantId = savedTenant.getId(); diff --git a/dao/src/test/java/org/thingsboard/server/dao/service/BaseRuleChainServiceTest.java b/dao/src/test/java/org/thingsboard/server/dao/service/BaseRuleChainServiceTest.java index e21138d25c..e3c5234942 100644 --- a/dao/src/test/java/org/thingsboard/server/dao/service/BaseRuleChainServiceTest.java +++ b/dao/src/test/java/org/thingsboard/server/dao/service/BaseRuleChainServiceTest.java @@ -17,9 +17,7 @@ package org.thingsboard.server.dao.service; import com.datastax.oss.driver.api.core.uuid.Uuids; import com.fasterxml.jackson.databind.ObjectMapper; -import org.junit.After; import org.junit.Assert; -import org.junit.Before; import org.junit.Test; import org.junit.jupiter.api.Assertions; import org.springframework.beans.factory.annotation.Autowired; @@ -57,22 +55,6 @@ public abstract class BaseRuleChainServiceTest extends AbstractServiceTest { private IdComparator idComparator = new IdComparator<>(); private IdComparator ruleNodeIdComparator = new IdComparator<>(); - private TenantId tenantId; - - @Before - public void before() { - Tenant tenant = new Tenant(); - tenant.setTitle("My tenant"); - Tenant savedTenant = tenantService.saveTenant(tenant); - Assert.assertNotNull(savedTenant); - tenantId = savedTenant.getId(); - } - - @After - public void after() { - tenantService.deleteTenant(tenantId); - } - @Test public void testSaveRuleChain() throws IOException { RuleChain ruleChain = new RuleChain(); @@ -141,12 +123,6 @@ public abstract class BaseRuleChainServiceTest extends AbstractServiceTest { @Test public void testFindRuleChainsByTenantId() { - Tenant tenant = new Tenant(); - tenant.setTitle("Test tenant"); - tenant = tenantService.saveTenant(tenant); - - TenantId tenantId = tenant.getId(); - List ruleChains = new ArrayList<>(); for (int i = 0; i < 165; i++) { RuleChain ruleChain = new RuleChain(); @@ -177,8 +153,6 @@ public abstract class BaseRuleChainServiceTest extends AbstractServiceTest { pageData = ruleChainService.findTenantRuleChainsByType(tenantId, RuleChainType.CORE, pageLink); Assert.assertFalse(pageData.hasNext()); Assert.assertTrue(pageData.getData().isEmpty()); - - tenantService.deleteTenant(tenantId); } @Test diff --git a/dao/src/test/java/org/thingsboard/server/dao/service/BaseTenantProfileServiceTest.java b/dao/src/test/java/org/thingsboard/server/dao/service/BaseTenantProfileServiceTest.java index becb148b82..6d41da2965 100644 --- a/dao/src/test/java/org/thingsboard/server/dao/service/BaseTenantProfileServiceTest.java +++ b/dao/src/test/java/org/thingsboard/server/dao/service/BaseTenantProfileServiceTest.java @@ -18,6 +18,7 @@ package org.thingsboard.server.dao.service; import com.fasterxml.jackson.databind.node.NullNode; import org.junit.After; import org.junit.Assert; +import org.junit.Before; import org.junit.Test; import org.junit.jupiter.api.Assertions; import org.springframework.beans.factory.annotation.Autowired; @@ -52,6 +53,14 @@ public abstract class BaseTenantProfileServiceTest extends AbstractServiceTest { private IdComparator idComparator = new IdComparator<>(); private IdComparator tenantProfileInfoIdComparator = new IdComparator<>(); + @Before + public void before() { + //this test requires no Tenants in the database + tenantId = null; + tenantService.deleteTenants(); + tenantProfileService.deleteTenantProfiles(TenantId.SYS_TENANT_ID); + } + @After public void after() { tenantProfileService.deleteTenantProfiles(TenantId.SYS_TENANT_ID); diff --git a/dao/src/test/java/org/thingsboard/server/dao/service/BaseTenantServiceTest.java b/dao/src/test/java/org/thingsboard/server/dao/service/BaseTenantServiceTest.java index 00aac94585..938272c0a8 100644 --- a/dao/src/test/java/org/thingsboard/server/dao/service/BaseTenantServiceTest.java +++ b/dao/src/test/java/org/thingsboard/server/dao/service/BaseTenantServiceTest.java @@ -177,6 +177,7 @@ public abstract class BaseTenantServiceTest extends AbstractServiceTest { @Test public void testFindTenants() { + tenantService.deleteTenants(); List tenants = new ArrayList<>(); PageLink pageLink = new PageLink(17); PageData pageData = tenantService.findTenants(pageLink); @@ -291,7 +292,7 @@ public abstract class BaseTenantServiceTest extends AbstractServiceTest { @Test public void testFindTenantInfos() { - + tenantService.deleteTenants(); List tenants = new ArrayList<>(); PageLink pageLink = new PageLink(17); PageData pageData = tenantService.findTenantInfos(pageLink); diff --git a/dao/src/test/java/org/thingsboard/server/dao/service/BaseUserServiceTest.java b/dao/src/test/java/org/thingsboard/server/dao/service/BaseUserServiceTest.java index 7698c2d129..14917f6807 100644 --- a/dao/src/test/java/org/thingsboard/server/dao/service/BaseUserServiceTest.java +++ b/dao/src/test/java/org/thingsboard/server/dao/service/BaseUserServiceTest.java @@ -15,7 +15,6 @@ */ package org.thingsboard.server.dao.service; -import org.junit.After; import org.junit.Assert; import org.junit.Before; import org.junit.Test; @@ -51,17 +50,10 @@ public abstract class BaseUserServiceTest extends AbstractServiceTest { private IdComparator idComparator = new IdComparator<>(); - private TenantId tenantId; private UserSettings userSettings; @Before public void before() { - Tenant tenant = new Tenant(); - tenant.setTitle("My tenant"); - Tenant savedTenant = tenantService.saveTenant(tenant); - Assert.assertNotNull(savedTenant); - tenantId = savedTenant.getId(); - User tenantAdmin = new User(); tenantAdmin.setAuthority(Authority.TENANT_ADMIN); tenantAdmin.setTenantId(tenantId); @@ -83,11 +75,6 @@ public abstract class BaseUserServiceTest extends AbstractServiceTest { userSettings = createUserSettings(customerUser.getId()); } - @After - public void after() { - tenantService.deleteTenant(tenantId); - } - @Test public void testFindUserByEmail() { User user = userService.findUserByEmail(SYSTEM_TENANT_ID, "sysadmin@thingsboard.org"); @@ -217,17 +204,13 @@ public abstract class BaseUserServiceTest extends AbstractServiceTest { Assert.assertEquals(1, users.size()); Assert.assertEquals(tenantAdminUser, users.get(0)); - Tenant tenant = new Tenant(); - tenant.setTitle("Test tenant"); - tenant = tenantService.saveTenant(tenant); - - TenantId tenantId = tenant.getId(); + TenantId secondTenantId = createTenant(); List tenantAdmins = new ArrayList<>(); for (int i = 0; i < 124; i++) { User user = new User(); user.setAuthority(Authority.TENANT_ADMIN); - user.setTenantId(tenantId); + user.setTenantId(secondTenantId); user.setEmail("testTenant" + i + "@thingsboard.org"); tenantAdmins.add(userService.saveUser(user)); } @@ -235,7 +218,7 @@ public abstract class BaseUserServiceTest extends AbstractServiceTest { List loadedTenantAdmins = new ArrayList<>(); PageLink pageLink = new PageLink(33); do { - pageData = userService.findTenantAdmins(tenantId, pageLink); + pageData = userService.findTenantAdmins(secondTenantId, pageLink); loadedTenantAdmins.addAll(pageData.getData()); if (pageData.hasNext()) { pageLink = pageLink.nextPageLink(); @@ -247,10 +230,10 @@ public abstract class BaseUserServiceTest extends AbstractServiceTest { Assert.assertEquals(tenantAdmins, loadedTenantAdmins); - tenantService.deleteTenant(tenantId); + tenantService.deleteTenant(secondTenantId); pageLink = new PageLink(33); - pageData = userService.findTenantAdmins(tenantId, pageLink); + pageData = userService.findTenantAdmins(secondTenantId, pageLink); Assert.assertFalse(pageData.hasNext()); Assert.assertTrue(pageData.getData().isEmpty()); @@ -258,12 +241,6 @@ public abstract class BaseUserServiceTest extends AbstractServiceTest { @Test public void testFindTenantAdminsByEmail() { - Tenant tenant = new Tenant(); - tenant.setTitle("Test tenant"); - tenant = tenantService.saveTenant(tenant); - - TenantId tenantId = tenant.getId(); - String email1 = "testEmail1"; List tenantAdminsEmail1 = new ArrayList<>(); @@ -340,8 +317,6 @@ public abstract class BaseUserServiceTest extends AbstractServiceTest { pageData = userService.findTenantAdmins(tenantId, pageLink); Assert.assertFalse(pageData.hasNext()); Assert.assertEquals(0, pageData.getData().size()); - - tenantService.deleteTenant(tenantId); } @Test @@ -354,12 +329,6 @@ public abstract class BaseUserServiceTest extends AbstractServiceTest { Assert.assertEquals(1, users.size()); Assert.assertEquals(customerUser, users.get(0)); - Tenant tenant = new Tenant(); - tenant.setTitle("Test tenant"); - tenant = tenantService.saveTenant(tenant); - - TenantId tenantId = tenant.getId(); - Customer customer = new Customer(); customer.setTitle("Test customer"); customer.setTenantId(tenantId); @@ -402,12 +371,6 @@ public abstract class BaseUserServiceTest extends AbstractServiceTest { @Test public void testFindCustomerUsersByEmail() { - Tenant tenant = new Tenant(); - tenant.setTitle("Test tenant"); - tenant = tenantService.saveTenant(tenant); - - TenantId tenantId = tenant.getId(); - Customer customer = new Customer(); customer.setTitle("Test customer"); customer.setTenantId(tenantId); @@ -493,8 +456,6 @@ public abstract class BaseUserServiceTest extends AbstractServiceTest { pageData = userService.findCustomerUsers(tenantId, customerId, pageLink); Assert.assertFalse(pageData.hasNext()); Assert.assertEquals(0, pageData.getData().size()); - - tenantService.deleteTenant(tenantId); } private UserSettings createUserSettings(UserId userId) { diff --git a/dao/src/test/java/org/thingsboard/server/dao/service/BaseWidgetTypeServiceTest.java b/dao/src/test/java/org/thingsboard/server/dao/service/BaseWidgetTypeServiceTest.java index ba5d149910..b04053f6d9 100644 --- a/dao/src/test/java/org/thingsboard/server/dao/service/BaseWidgetTypeServiceTest.java +++ b/dao/src/test/java/org/thingsboard/server/dao/service/BaseWidgetTypeServiceTest.java @@ -18,13 +18,10 @@ package org.thingsboard.server.dao.service; import com.datastax.oss.driver.api.core.uuid.Uuids; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; -import org.junit.After; import org.junit.Assert; -import org.junit.Before; import org.junit.Test; import org.junit.jupiter.api.Assertions; import org.springframework.beans.factory.annotation.Autowired; -import org.thingsboard.server.common.data.Tenant; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.widget.WidgetType; import org.thingsboard.server.common.data.widget.WidgetTypeDetails; @@ -48,22 +45,6 @@ public abstract class BaseWidgetTypeServiceTest extends AbstractServiceTest { private IdComparator idComparator = new IdComparator<>(); - private TenantId tenantId; - - @Before - public void before() { - Tenant tenant = new Tenant(); - tenant.setTitle("My tenant"); - Tenant savedTenant = tenantService.saveTenant(tenant); - Assert.assertNotNull(savedTenant); - tenantId = savedTenant.getId(); - } - - @After - public void after() { - tenantService.deleteTenant(tenantId); - } - @Test public void testSaveWidgetType() throws IOException { WidgetsBundle widgetsBundle = new WidgetsBundle(); diff --git a/dao/src/test/java/org/thingsboard/server/dao/service/BaseWidgetsBundleServiceTest.java b/dao/src/test/java/org/thingsboard/server/dao/service/BaseWidgetsBundleServiceTest.java index dd1b92263b..8f04eaec62 100644 --- a/dao/src/test/java/org/thingsboard/server/dao/service/BaseWidgetsBundleServiceTest.java +++ b/dao/src/test/java/org/thingsboard/server/dao/service/BaseWidgetsBundleServiceTest.java @@ -16,13 +16,10 @@ package org.thingsboard.server.dao.service; import com.datastax.oss.driver.api.core.uuid.Uuids; -import org.junit.After; import org.junit.Assert; -import org.junit.Before; import org.junit.Test; import org.junit.jupiter.api.Assertions; import org.springframework.beans.factory.annotation.Autowired; -import org.thingsboard.server.common.data.Tenant; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageLink; @@ -43,22 +40,6 @@ public abstract class BaseWidgetsBundleServiceTest extends AbstractServiceTest { private IdComparator idComparator = new IdComparator<>(); - private TenantId tenantId; - - @Before - public void before() { - Tenant tenant = new Tenant(); - tenant.setTitle("My tenant"); - Tenant savedTenant = tenantService.saveTenant(tenant); - Assert.assertNotNull(savedTenant); - tenantId = savedTenant.getId(); - } - - @After - public void after() { - tenantService.deleteTenant(tenantId); - } - @Test public void testSaveWidgetsBundle() throws IOException { WidgetsBundle widgetsBundle = new WidgetsBundle(); @@ -254,11 +235,6 @@ public abstract class BaseWidgetsBundleServiceTest extends AbstractServiceTest { @Test public void testFindTenantWidgetsBundlesByTenantId() { - Tenant tenant = new Tenant(); - tenant.setTitle("Test tenant"); - tenant = tenantService.saveTenant(tenant); - - TenantId tenantId = tenant.getId(); List widgetsBundles = new ArrayList<>(); for (int i=0;i<127;i++) { @@ -291,7 +267,6 @@ public abstract class BaseWidgetsBundleServiceTest extends AbstractServiceTest { Assert.assertFalse(pageData.hasNext()); Assert.assertTrue(pageData.getData().isEmpty()); - tenantService.deleteTenant(tenantId); } @Test @@ -299,11 +274,6 @@ public abstract class BaseWidgetsBundleServiceTest extends AbstractServiceTest { List systemWidgetsBundles = widgetsBundleService.findSystemWidgetsBundles(tenantId); - Tenant tenant = new Tenant(); - tenant.setTitle("Test tenant"); - tenant = tenantService.saveTenant(tenant); - - TenantId tenantId = tenant.getId(); TenantId systemTenantId = TenantId.fromUUID(ModelConstants.NULL_UUID); List createdWidgetsBundles = new ArrayList<>(); @@ -376,8 +346,6 @@ public abstract class BaseWidgetsBundleServiceTest extends AbstractServiceTest { Collections.sort(loadedWidgetsBundles, idComparator); Assert.assertEquals(systemWidgetsBundles, loadedWidgetsBundles); - - tenantService.deleteTenant(tenantId); } @Test @@ -385,11 +353,6 @@ public abstract class BaseWidgetsBundleServiceTest extends AbstractServiceTest { List systemWidgetsBundles = widgetsBundleService.findSystemWidgetsBundles(tenantId); - Tenant tenant = new Tenant(); - tenant.setTitle("Test tenant"); - tenant = tenantService.saveTenant(tenant); - - TenantId tenantId = tenant.getId(); TenantId systemTenantId = TenantId.fromUUID(ModelConstants.NULL_UUID); List createdWidgetsBundles = new ArrayList<>(); @@ -437,8 +400,6 @@ public abstract class BaseWidgetsBundleServiceTest extends AbstractServiceTest { Collections.sort(loadedWidgetsBundles, idComparator); Assert.assertEquals(systemWidgetsBundles, loadedWidgetsBundles); - - tenantService.deleteTenant(tenantId); } } From 378ae47acbafa4c95b330b5ec0a61c09f407f2ae Mon Sep 17 00:00:00 2001 From: ViacheslavKlimov Date: Mon, 13 Mar 2023 10:41:40 +0200 Subject: [PATCH 09/28] Alarm comments rule trigger config, NotificationInfo stateEntityId --- .../trigger/AlarmCommentTriggerProcessor.java | 16 ++++++++++++++-- .../rule/trigger/AlarmTriggerProcessor.java | 13 ++++++++----- .../trigger/EntityActionTriggerProcessor.java | 3 +-- .../notification/NotificationRuleApiTest.java | 7 ++++--- .../common/data/alarm/AlarmStatusFilter.java | 18 +++++++++++------- .../info/AlarmCommentNotificationInfo.java | 17 ++++++++++++++++- .../info/AlarmNotificationInfo.java | 5 +++++ .../info/DeviceInactivityNotificationInfo.java | 7 +++++++ .../info/EntityActionNotificationInfo.java | 12 ++++++++---- .../notification/info/NotificationInfo.java | 5 +++++ ...omponentLifecycleEventNotificationInfo.java | 5 +++++ .../RuleEngineOriginatedNotificationInfo.java | 5 +++++ ...rmCommentNotificationRuleTriggerConfig.java | 8 ++++++++ .../AlarmNotificationRuleTriggerConfig.java | 4 ++-- .../sql/query/DefaultAlarmQueryRepository.java | 7 +------ 15 files changed, 100 insertions(+), 32 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/AlarmCommentTriggerProcessor.java b/application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/AlarmCommentTriggerProcessor.java index 7a1ef3949b..28a03830bf 100644 --- a/application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/AlarmCommentTriggerProcessor.java +++ b/application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/AlarmCommentTriggerProcessor.java @@ -19,18 +19,27 @@ import org.springframework.stereotype.Service; import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.server.common.data.alarm.Alarm; import org.thingsboard.server.common.data.alarm.AlarmComment; +import org.thingsboard.server.common.data.alarm.AlarmStatusFilter; import org.thingsboard.server.common.data.notification.info.AlarmCommentNotificationInfo; import org.thingsboard.server.common.data.notification.info.NotificationInfo; import org.thingsboard.server.common.data.notification.rule.trigger.AlarmCommentNotificationRuleTriggerConfig; import org.thingsboard.server.common.data.notification.rule.trigger.NotificationRuleTriggerType; import org.thingsboard.server.common.msg.TbMsg; +import static org.apache.commons.collections.CollectionUtils.isEmpty; + @Service public class AlarmCommentTriggerProcessor implements NotificationRuleTriggerProcessor { @Override public boolean matchesFilter(TbMsg ruleEngineMsg, AlarmCommentNotificationRuleTriggerConfig triggerConfig) { - return ruleEngineMsg.getMetaData().getValue("comment") != null; + if (ruleEngineMsg.getMetaData().getValue("comment") == null) { + return false; + } + Alarm alarm = JacksonUtil.fromString(ruleEngineMsg.getData(), Alarm.class); + return (isEmpty(triggerConfig.getAlarmTypes()) || triggerConfig.getAlarmTypes().contains(alarm.getType())) && + (isEmpty(triggerConfig.getAlarmSeverities()) || triggerConfig.getAlarmSeverities().contains(alarm.getSeverity())) && + (isEmpty(triggerConfig.getAlarmStatuses()) || AlarmStatusFilter.from(triggerConfig.getAlarmStatuses()).matches(alarm)); } @Override @@ -39,8 +48,11 @@ public class AlarmCommentTriggerProcessor implements NotificationRuleTriggerProc Alarm alarm = JacksonUtil.fromString(ruleEngineMsg.getData(), Alarm.class); return AlarmCommentNotificationInfo.builder() .comment(comment.getComment().get("text").asText()) + .alarmId(alarm.getUuidId()) .alarmType(alarm.getType()) - .alarmId(comment.getAlarmId().getId()) + .alarmOriginator(alarm.getOriginator()) + .alarmSeverity(alarm.getSeverity()) + .alarmStatus(alarm.getStatus()) .build(); } diff --git a/application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/AlarmTriggerProcessor.java b/application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/AlarmTriggerProcessor.java index d5e3660782..9f226ca352 100644 --- a/application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/AlarmTriggerProcessor.java +++ b/application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/AlarmTriggerProcessor.java @@ -17,9 +17,9 @@ package org.thingsboard.server.service.notification.rule.trigger; import lombok.Builder; import lombok.Data; -import org.apache.commons.collections.CollectionUtils; import org.springframework.stereotype.Service; import org.thingsboard.server.common.data.alarm.Alarm; +import org.thingsboard.server.common.data.alarm.AlarmStatusFilter; import org.thingsboard.server.common.data.notification.info.AlarmNotificationInfo; import org.thingsboard.server.common.data.notification.info.NotificationInfo; import org.thingsboard.server.common.data.notification.rule.trigger.AlarmNotificationRuleTriggerConfig; @@ -27,14 +27,17 @@ import org.thingsboard.server.common.data.notification.rule.trigger.AlarmNotific import org.thingsboard.server.common.data.notification.rule.trigger.NotificationRuleTriggerType; import org.thingsboard.server.service.notification.rule.trigger.AlarmTriggerProcessor.AlarmTriggerObject; +import static org.apache.commons.collections.CollectionUtils.isEmpty; +import static org.apache.commons.collections.CollectionUtils.isNotEmpty; + @Service public class AlarmTriggerProcessor implements NotificationRuleTriggerProcessor { @Override public boolean matchesFilter(AlarmTriggerObject triggerObject, AlarmNotificationRuleTriggerConfig triggerConfig) { Alarm alarm = triggerObject.getAlarm(); - return (CollectionUtils.isEmpty(triggerConfig.getAlarmTypes()) || triggerConfig.getAlarmTypes().contains(alarm.getType())) && - (CollectionUtils.isEmpty(triggerConfig.getAlarmSeverities()) || triggerConfig.getAlarmSeverities().contains(alarm.getSeverity())); + return (isEmpty(triggerConfig.getAlarmTypes()) || triggerConfig.getAlarmTypes().contains(alarm.getType())) && + (isEmpty(triggerConfig.getAlarmSeverities()) || triggerConfig.getAlarmSeverities().contains(alarm.getSeverity())); } @Override @@ -45,8 +48,8 @@ public class AlarmTriggerProcessor implements NotificationRuleTriggerProcessor wsClient.registerWaitForUpdate()); - alarmSubscriptionService.ackAlarm(tenantId, alarm.getId(), System.currentTimeMillis()); + alarmSubscriptionService.acknowledgeAlarm(tenantId, alarm.getId(), System.currentTimeMillis()); AlarmStatus expectedStatus = AlarmStatus.ACTIVE_ACK; AlarmSeverity expectedSeverity = AlarmSeverity.CRITICAL; clients.values().forEach(wsClient -> { @@ -270,7 +271,7 @@ public class NotificationRuleApiTest extends AbstractNotificationApiTest { triggerConfig.setAlarmSeverities(null); AlarmNotificationRuleTriggerConfig.ClearRule clearRule = new AlarmNotificationRuleTriggerConfig.ClearRule(); - clearRule.setAlarmStatus(AlarmStatus.CLEARED_UNACK); + clearRule.setAlarmStatuses(Set.of(AlarmSearchStatus.CLEARED, AlarmSearchStatus.UNACK)); triggerConfig.setClearRule(clearRule); notificationRule.setTriggerConfig(triggerConfig); @@ -308,7 +309,7 @@ public class NotificationRuleApiTest extends AbstractNotificationApiTest { assertThat(scheduledNotificationRequest).extracting(NotificationRequest::getInfo).isEqualTo(notification.getInfo()); getWsClient().registerWaitForUpdate(); - alarmSubscriptionService.clearAlarm(tenantId, alarm.getId(), null, System.currentTimeMillis()); + alarmSubscriptionService.clearAlarm(tenantId, alarm.getId(), System.currentTimeMillis(), null); getWsClient().waitForUpdate(true); notification = getWsClient().getLastDataUpdate().getNotifications().iterator().next(); assertThat(notification.getSubject()).isEqualTo("CRITICAL alarm '" + alarmType + "' is CLEARED_UNACK"); diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/alarm/AlarmStatusFilter.java b/common/data/src/main/java/org/thingsboard/server/common/data/alarm/AlarmStatusFilter.java index c8f40fa048..50b02327cb 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/alarm/AlarmStatusFilter.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/alarm/AlarmStatusFilter.java @@ -15,7 +15,7 @@ */ package org.thingsboard.server.common.data.alarm; -import java.util.List; +import java.util.Collection; import java.util.Optional; public class AlarmStatusFilter { @@ -94,19 +94,19 @@ public class AlarmStatusFilter { } - public static AlarmStatusFilter fromList(List list) { - if (list == null || list.isEmpty() || list.contains(AlarmSearchStatus.ANY)) { + public static AlarmStatusFilter from(Collection statuses) { + if (statuses == null || statuses.isEmpty() || statuses.contains(AlarmSearchStatus.ANY)) { return EMPTY; } - boolean clearFilter = list.contains(AlarmSearchStatus.CLEARED); - boolean activeFilter = list.contains(AlarmSearchStatus.ACTIVE); + boolean clearFilter = statuses.contains(AlarmSearchStatus.CLEARED); + boolean activeFilter = statuses.contains(AlarmSearchStatus.ACTIVE); Optional clear = Optional.empty(); if (clearFilter && !activeFilter || !clearFilter && activeFilter) { clear = Optional.of(clearFilter); } - boolean ackFilter = list.contains(AlarmSearchStatus.ACK); - boolean unackFilter = list.contains(AlarmSearchStatus.UNACK); + boolean ackFilter = statuses.contains(AlarmSearchStatus.ACK); + boolean unackFilter = statuses.contains(AlarmSearchStatus.UNACK); Optional ack = Optional.empty(); if (ackFilter && !unackFilter || !ackFilter && unackFilter) { ack = Optional.of(ackFilter); @@ -114,5 +114,9 @@ public class AlarmStatusFilter { return new AlarmStatusFilter(clear, ack); } + public boolean matches(Alarm alarm) { + return ackFilter.map(ackFilter -> ackFilter.equals(alarm.isAcknowledged())).orElse(true) && + clearFilter.map(clearedFilter -> clearedFilter.equals(alarm.isCleared())).orElse(true); + } } diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/notification/info/AlarmCommentNotificationInfo.java b/common/data/src/main/java/org/thingsboard/server/common/data/notification/info/AlarmCommentNotificationInfo.java index 0a8b97ba64..20764f56f4 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/notification/info/AlarmCommentNotificationInfo.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/notification/info/AlarmCommentNotificationInfo.java @@ -19,6 +19,9 @@ import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; +import org.thingsboard.server.common.data.alarm.AlarmSeverity; +import org.thingsboard.server.common.data.alarm.AlarmStatus; +import org.thingsboard.server.common.data.id.EntityId; import java.util.Map; import java.util.UUID; @@ -32,14 +35,26 @@ public class AlarmCommentNotificationInfo implements NotificationInfo { private String comment; private String alarmType; private UUID alarmId; + private EntityId alarmOriginator; + private AlarmSeverity alarmSeverity; + private AlarmStatus alarmStatus; @Override public Map getTemplateData() { return Map.of( "comment", comment, "alarmType", alarmType, - "alarmId", alarmId.toString() + "alarmId", alarmId.toString(), + "alarmSeverity", alarmSeverity.toString(), + "alarmStatus", alarmStatus.toString(), + "alarmOriginatorEntityType", alarmOriginator.getEntityType().toString(), + "alarmOriginatorId", alarmOriginator.getId().toString() ); } + @Override + public EntityId getStateEntityId() { + return alarmOriginator; + } + } diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/notification/info/AlarmNotificationInfo.java b/common/data/src/main/java/org/thingsboard/server/common/data/notification/info/AlarmNotificationInfo.java index 73785c2af6..4f387e3d86 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/notification/info/AlarmNotificationInfo.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/notification/info/AlarmNotificationInfo.java @@ -57,4 +57,9 @@ public class AlarmNotificationInfo implements RuleOriginatedNotificationInfo { ); } + @Override + public EntityId getStateEntityId() { + return alarmOriginator; + } + } diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/notification/info/DeviceInactivityNotificationInfo.java b/common/data/src/main/java/org/thingsboard/server/common/data/notification/info/DeviceInactivityNotificationInfo.java index 7ad3e14896..8a2d6941a0 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/notification/info/DeviceInactivityNotificationInfo.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/notification/info/DeviceInactivityNotificationInfo.java @@ -20,6 +20,8 @@ import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; import org.thingsboard.server.common.data.id.CustomerId; +import org.thingsboard.server.common.data.id.DeviceId; +import org.thingsboard.server.common.data.id.EntityId; import java.util.Map; import java.util.UUID; @@ -49,4 +51,9 @@ public class DeviceInactivityNotificationInfo implements RuleOriginatedNotificat ); } + @Override + public EntityId getStateEntityId() { + return new DeviceId(deviceId); + } + } diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/notification/info/EntityActionNotificationInfo.java b/common/data/src/main/java/org/thingsboard/server/common/data/notification/info/EntityActionNotificationInfo.java index 77a906c35f..60061d3a78 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/notification/info/EntityActionNotificationInfo.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/notification/info/EntityActionNotificationInfo.java @@ -19,9 +19,9 @@ import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; -import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.audit.ActionType; import org.thingsboard.server.common.data.id.CustomerId; +import org.thingsboard.server.common.data.id.EntityId; import java.util.Map; import java.util.UUID; @@ -32,8 +32,7 @@ import java.util.UUID; @Builder public class EntityActionNotificationInfo implements RuleOriginatedNotificationInfo { - private EntityType entityType; - private UUID entityId; + private EntityId entityId; private String entityName; private ActionType actionType; private UUID originatorUserId; @@ -48,7 +47,7 @@ public class EntityActionNotificationInfo implements RuleOriginatedNotificationI @Override public Map getTemplateData() { return Map.of( - "entityType", entityType.name(), + "entityType", entityId.getEntityType().name(), "entityId", entityId.toString(), "entityName", entityName, "actionType", actionType.name().toLowerCase(), @@ -57,4 +56,9 @@ public class EntityActionNotificationInfo implements RuleOriginatedNotificationI ); } + @Override + public EntityId getStateEntityId() { + return entityId; + } + } diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/notification/info/NotificationInfo.java b/common/data/src/main/java/org/thingsboard/server/common/data/notification/info/NotificationInfo.java index 6877ba1bc9..44bdcbe52a 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/notification/info/NotificationInfo.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/notification/info/NotificationInfo.java @@ -18,6 +18,7 @@ package org.thingsboard.server.common.data.notification.info; import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonTypeInfo; +import org.thingsboard.server.common.data.id.EntityId; import java.util.Map; @@ -28,4 +29,8 @@ public interface NotificationInfo { @JsonIgnore Map getTemplateData(); + default EntityId getStateEntityId() { + return null; + } + } diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/notification/info/RuleEngineComponentLifecycleEventNotificationInfo.java b/common/data/src/main/java/org/thingsboard/server/common/data/notification/info/RuleEngineComponentLifecycleEventNotificationInfo.java index 971ee1cdee..0dc942c588 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/notification/info/RuleEngineComponentLifecycleEventNotificationInfo.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/notification/info/RuleEngineComponentLifecycleEventNotificationInfo.java @@ -53,4 +53,9 @@ public class RuleEngineComponentLifecycleEventNotificationInfo implements Notifi ); } + @Override + public EntityId getStateEntityId() { + return ruleChainId; + } + } diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/notification/info/RuleEngineOriginatedNotificationInfo.java b/common/data/src/main/java/org/thingsboard/server/common/data/notification/info/RuleEngineOriginatedNotificationInfo.java index 05f4dbb49b..924028da36 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/notification/info/RuleEngineOriginatedNotificationInfo.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/notification/info/RuleEngineOriginatedNotificationInfo.java @@ -43,4 +43,9 @@ public class RuleEngineOriginatedNotificationInfo implements NotificationInfo { return templateData; } + @Override + public EntityId getStateEntityId() { + return msgOriginator; + } + } diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/AlarmCommentNotificationRuleTriggerConfig.java b/common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/AlarmCommentNotificationRuleTriggerConfig.java index 2560aee733..f8cae97c0e 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/AlarmCommentNotificationRuleTriggerConfig.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/AlarmCommentNotificationRuleTriggerConfig.java @@ -16,10 +16,18 @@ package org.thingsboard.server.common.data.notification.rule.trigger; import lombok.Data; +import org.thingsboard.server.common.data.alarm.AlarmSearchStatus; +import org.thingsboard.server.common.data.alarm.AlarmSeverity; + +import java.util.Set; @Data public class AlarmCommentNotificationRuleTriggerConfig implements NotificationRuleTriggerConfig { + private Set alarmTypes; + private Set alarmSeverities; + private Set alarmStatuses; + @Override public NotificationRuleTriggerType getTriggerType() { return NotificationRuleTriggerType.ALARM_COMMENT; diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/AlarmNotificationRuleTriggerConfig.java b/common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/AlarmNotificationRuleTriggerConfig.java index f502bd6932..70d986cdf7 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/AlarmNotificationRuleTriggerConfig.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/AlarmNotificationRuleTriggerConfig.java @@ -16,8 +16,8 @@ package org.thingsboard.server.common.data.notification.rule.trigger; import lombok.Data; +import org.thingsboard.server.common.data.alarm.AlarmSearchStatus; import org.thingsboard.server.common.data.alarm.AlarmSeverity; -import org.thingsboard.server.common.data.alarm.AlarmStatus; import java.util.Set; @@ -35,7 +35,7 @@ public class AlarmNotificationRuleTriggerConfig implements NotificationRuleTrigg @Data public static class ClearRule { - private AlarmStatus alarmStatus; + private Set alarmStatuses; } } diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/query/DefaultAlarmQueryRepository.java b/dao/src/main/java/org/thingsboard/server/dao/sql/query/DefaultAlarmQueryRepository.java index ecf9c1c95f..4d6f39a546 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/query/DefaultAlarmQueryRepository.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/query/DefaultAlarmQueryRepository.java @@ -19,12 +19,9 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate; import org.springframework.stereotype.Repository; import org.springframework.transaction.support.TransactionTemplate; -import org.thingsboard.server.common.data.DataConstants; import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.StringUtils; -import org.thingsboard.server.common.data.alarm.AlarmSearchStatus; import org.thingsboard.server.common.data.alarm.AlarmSeverity; -import org.thingsboard.server.common.data.alarm.AlarmStatus; import org.thingsboard.server.common.data.alarm.AlarmStatusFilter; import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.TenantId; @@ -41,11 +38,9 @@ import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashMap; -import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Objects; -import java.util.Set; import java.util.stream.Collectors; @Repository @@ -248,7 +243,7 @@ public class DefaultAlarmQueryRepository implements AlarmQueryRepository { wherePart.append("a.severity in (:alarmSeverities)"); } - AlarmStatusFilter asf = AlarmStatusFilter.fromList(pageLink.getStatusList()); + AlarmStatusFilter asf = AlarmStatusFilter.from(pageLink.getStatusList()); if (asf.hasAnyFilter()) { if (asf.hasAckFilter()) { addAndIfNeeded(wherePart, addAnd); From 738fbda60b04a15d2e66e1db617bff42913cb2fb Mon Sep 17 00:00:00 2001 From: Seraphym-Tuhai Date: Mon, 13 Mar 2023 12:16:15 +0200 Subject: [PATCH 10/28] fix test on assigned dashboard --- .../server/msa/ui/pages/CustomerPageElements.java | 6 +++--- .../thingsboard/server/msa/ui/pages/CustomerPageHelper.java | 4 ++-- .../msa/ui/tests/customerSmoke/CustomerEditMenuTest.java | 6 +++--- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/ui/pages/CustomerPageElements.java b/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/ui/pages/CustomerPageElements.java index 7caf109bc0..1d69ddd5fc 100644 --- a/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/ui/pages/CustomerPageElements.java +++ b/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/ui/pages/CustomerPageElements.java @@ -31,7 +31,7 @@ public class CustomerPageElements extends OtherPageElementsHelper { private static final String CITY = ENTITY + "/../..//mat-cell[contains(@class,'city')]/span"; private static final String TITLES = "//mat-cell[contains(@class,'cdk-column-title')]/span"; protected static final String EDIT_MENU_DASHBOARD_FIELD = "//input[@formcontrolname='dashboard']"; - private static final String EDIT_MENU_DASHBOARD = "//div[@class='cdk-overlay-pane']//span/span"; + private static final String EDIT_MENU_DASHBOARD = "//div[@class='cdk-overlay-pane']//span/span[contains(text(),'%s')]"; private static final String MANAGE_CUSTOMERS_USERS_BTN = ENTITY + "/ancestor::mat-row//mat-icon[contains(text(),' account_circle')]"; private static final String MANAGE_CUSTOMERS_ASSETS_BTN = ENTITY + "/ancestor::mat-row//mat-icon[contains(text(),' domain')]/parent::button"; private static final String MANAGE_CUSTOMERS_DEVICES_BTN = ENTITY + "/ancestor::mat-row//mat-icon[contains(text(),'devices_other')]/parent::button"; @@ -104,8 +104,8 @@ public class CustomerPageElements extends OtherPageElementsHelper { return waitUntilVisibilityOfElementLocated(EDIT_MENU_DASHBOARD_FIELD); } - public WebElement editMenuDashboard() { - return waitUntilElementToBeClickable(EDIT_MENU_DASHBOARD); + public WebElement editMenuDashboard(String dashboardName) { + return waitUntilElementToBeClickable(String.format(EDIT_MENU_DASHBOARD, dashboardName)); } public WebElement phoneNumberEntityView() { diff --git a/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/ui/pages/CustomerPageHelper.java b/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/ui/pages/CustomerPageHelper.java index e428ff8030..030bf630cb 100644 --- a/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/ui/pages/CustomerPageHelper.java +++ b/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/ui/pages/CustomerPageHelper.java @@ -112,9 +112,9 @@ public class CustomerPageHelper extends CustomerPageElements { titleFieldEntityView().sendKeys(newTitle); } - public void chooseDashboard() { + public void chooseDashboard(String dashboardName) { editMenuDashboardField().click(); - editMenuDashboard().click(); + editMenuDashboard(dashboardName).click(); } public void createCustomersUser() { diff --git a/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/ui/tests/customerSmoke/CustomerEditMenuTest.java b/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/ui/tests/customerSmoke/CustomerEditMenuTest.java index 998aa0af06..76a4abb65d 100644 --- a/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/ui/tests/customerSmoke/CustomerEditMenuTest.java +++ b/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/ui/tests/customerSmoke/CustomerEditMenuTest.java @@ -148,7 +148,7 @@ public class CustomerEditMenuTest extends AbstractDriverBaseTest { sideBarMenuView.customerBtn().click(); customerPage.entity(customerName).click(); jsClick(customerPage.editPencilBtn()); - customerPage.chooseDashboard(); + customerPage.chooseDashboard(dashboardPage.getDashboardTitle()); customerPage.doneBtnEditView().click(); customerPage.setDashboardFromView(); customerPage.closeEntityViewBtn().click(); @@ -174,7 +174,7 @@ public class CustomerEditMenuTest extends AbstractDriverBaseTest { sideBarMenuView.customerBtn().click(); customerPage.entity(customerName).click(); jsClick(customerPage.editPencilBtn()); - customerPage.chooseDashboard(); + customerPage.chooseDashboard(customerPage.getDashboard()); customerPage.doneBtnEditView().click(); customerPage.setDashboardFromView(); customerPage.closeEntityViewBtn().click(); @@ -200,7 +200,7 @@ public class CustomerEditMenuTest extends AbstractDriverBaseTest { sideBarMenuView.customerBtn().click(); customerPage.entity(customerName).click(); jsClick(customerPage.editPencilBtn()); - customerPage.chooseDashboard(); + customerPage.chooseDashboard(customerPage.getDashboard()); customerPage.hideHomeDashboardToolbarCheckbox().click(); customerPage.doneBtnEditView().click(); customerPage.setDashboardFromView(); From 7a0c58a18ef8856ccd48d4e461cefcab8dd43601 Mon Sep 17 00:00:00 2001 From: Sergey Matvienko Date: Mon, 13 Mar 2023 15:38:42 +0100 Subject: [PATCH 11/28] revert entityDaoServicesMap = new HashMap<>() --- .../server/dao/entity/DefaultEntityServiceRegistry.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dao/src/main/java/org/thingsboard/server/dao/entity/DefaultEntityServiceRegistry.java b/dao/src/main/java/org/thingsboard/server/dao/entity/DefaultEntityServiceRegistry.java index a752127f91..232905e9fc 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/entity/DefaultEntityServiceRegistry.java +++ b/dao/src/main/java/org/thingsboard/server/dao/entity/DefaultEntityServiceRegistry.java @@ -15,7 +15,6 @@ */ package org.thingsboard.server.dao.entity; -import com.google.common.collect.MapMaker; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.context.ApplicationContext; @@ -26,6 +25,7 @@ import org.springframework.core.annotation.Order; import org.springframework.stereotype.Service; import org.thingsboard.server.common.data.EntityType; +import java.util.HashMap; import java.util.Map; @Service @@ -34,7 +34,7 @@ import java.util.Map; public class DefaultEntityServiceRegistry implements EntityServiceRegistry { private final ApplicationContext applicationContext; - private final Map entityDaoServicesMap = new MapMaker().weakValues().makeMap(); + private final Map entityDaoServicesMap = new HashMap<>(); @EventListener(ContextRefreshedEvent.class) @Order(Ordered.HIGHEST_PRECEDENCE) From 5cb1b7d275cc04e35df197b682e72bf7a0225f3f Mon Sep 17 00:00:00 2001 From: Oleksandra Matviienko Date: Mon, 13 Mar 2023 22:09:16 +0100 Subject: [PATCH 12/28] BaseOtaPackageServiceTest: Rule ExpectedException refactored with AssertJ Exception Assertions --- .../service/BaseOtaPackageServiceTest.java | 134 +++++++++--------- 1 file changed, 66 insertions(+), 68 deletions(-) diff --git a/dao/src/test/java/org/thingsboard/server/dao/service/BaseOtaPackageServiceTest.java b/dao/src/test/java/org/thingsboard/server/dao/service/BaseOtaPackageServiceTest.java index c89e7c4b69..c5c217a486 100644 --- a/dao/src/test/java/org/thingsboard/server/dao/service/BaseOtaPackageServiceTest.java +++ b/dao/src/test/java/org/thingsboard/server/dao/service/BaseOtaPackageServiceTest.java @@ -19,9 +19,7 @@ import com.datastax.oss.driver.api.core.uuid.Uuids; import org.junit.After; import org.junit.Assert; import org.junit.Before; -import org.junit.Rule; import org.junit.Test; -import org.junit.rules.ExpectedException; import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.server.common.data.Device; import org.thingsboard.server.common.data.DeviceProfile; @@ -44,6 +42,7 @@ import java.util.Collections; import java.util.List; import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.thingsboard.server.common.data.ota.OtaPackageType.FIRMWARE; public abstract class BaseOtaPackageServiceTest extends AbstractServiceTest { @@ -78,10 +77,6 @@ public abstract class BaseOtaPackageServiceTest extends AbstractServiceTest { deviceProfileId = savedDeviceProfile.getId(); } - @SuppressWarnings("deprecation") - @Rule - public ExpectedException thrown = ExpectedException.none(); - @After public void after() { tenantService.deleteTenant(tenantId); @@ -99,9 +94,9 @@ public abstract class BaseOtaPackageServiceTest extends AbstractServiceTest { createAndSaveFirmware(tenantId, "1"); Assert.assertEquals(1, otaPackageService.sumDataSizeByTenantId(tenantId)); - thrown.expect(DataValidationException.class); - thrown.expectMessage(String.format("Failed to create the ota package, files size limit is exhausted %d bytes!", DATA_SIZE)); - createAndSaveFirmware(tenantId, "2"); + assertThatThrownBy(() -> createAndSaveFirmware(tenantId, "2")) + .isInstanceOf(DataValidationException.class) + .hasMessageContaining("Failed to create the ota package, files size limit is exhausted %d bytes!", DATA_SIZE); } @Test @@ -243,9 +238,9 @@ public abstract class BaseOtaPackageServiceTest extends AbstractServiceTest { firmware.setChecksum(CHECKSUM); firmware.setData(DATA); - thrown.expect(DataValidationException.class); - thrown.expectMessage("OtaPackage should be assigned to tenant!"); - otaPackageService.saveOtaPackage(firmware); + assertThatThrownBy(() -> otaPackageService.saveOtaPackage(firmware)) + .isInstanceOf(DataValidationException.class) + .hasMessageContaining("OtaPackage should be assigned to tenant!"); } @Test @@ -261,9 +256,9 @@ public abstract class BaseOtaPackageServiceTest extends AbstractServiceTest { firmware.setChecksum(CHECKSUM); firmware.setData(DATA); - thrown.expect(DataValidationException.class); - thrown.expectMessage("Type should be specified!"); - otaPackageService.saveOtaPackage(firmware); + assertThatThrownBy(() -> otaPackageService.saveOtaPackage(firmware)) + .isInstanceOf(DataValidationException.class) + .hasMessageContaining("Type should be specified!"); } @Test @@ -279,9 +274,9 @@ public abstract class BaseOtaPackageServiceTest extends AbstractServiceTest { firmware.setChecksum(CHECKSUM); firmware.setData(DATA); - thrown.expect(DataValidationException.class); - thrown.expectMessage("OtaPackage title should be specified!"); - otaPackageService.saveOtaPackage(firmware); + assertThatThrownBy(() -> otaPackageService.saveOtaPackage(firmware)) + .isInstanceOf(DataValidationException.class) + .hasMessageContaining("OtaPackage title should be specified!"); } @Test @@ -297,9 +292,9 @@ public abstract class BaseOtaPackageServiceTest extends AbstractServiceTest { firmware.setChecksum(CHECKSUM); firmware.setData(DATA); - thrown.expect(DataValidationException.class); - thrown.expectMessage("OtaPackage file name should be specified!"); - otaPackageService.saveOtaPackage(firmware); + assertThatThrownBy(() -> otaPackageService.saveOtaPackage(firmware)) + .isInstanceOf(DataValidationException.class) + .hasMessageContaining("OtaPackage file name should be specified!"); } @Test @@ -315,9 +310,9 @@ public abstract class BaseOtaPackageServiceTest extends AbstractServiceTest { firmware.setChecksum(CHECKSUM); firmware.setData(DATA); - thrown.expect(DataValidationException.class); - thrown.expectMessage("OtaPackage content type should be specified!"); - otaPackageService.saveOtaPackage(firmware); + assertThatThrownBy(() -> otaPackageService.saveOtaPackage(firmware)) + .isInstanceOf(DataValidationException.class) + .hasMessageContaining("OtaPackage content type should be specified!"); } @Test @@ -333,9 +328,9 @@ public abstract class BaseOtaPackageServiceTest extends AbstractServiceTest { firmware.setChecksumAlgorithm(CHECKSUM_ALGORITHM); firmware.setChecksum(CHECKSUM); - thrown.expect(DataValidationException.class); - thrown.expectMessage("OtaPackage data should be specified!"); - otaPackageService.saveOtaPackage(firmware); + assertThatThrownBy(() -> otaPackageService.saveOtaPackage(firmware)) + .isInstanceOf(DataValidationException.class) + .hasMessageContaining("OtaPackage data should be specified!"); } @Test @@ -352,9 +347,9 @@ public abstract class BaseOtaPackageServiceTest extends AbstractServiceTest { firmware.setChecksum(CHECKSUM); firmware.setData(DATA); - thrown.expect(DataValidationException.class); - thrown.expectMessage("OtaPackage is referencing to non-existent tenant!"); - otaPackageService.saveOtaPackage(firmware); + assertThatThrownBy(() -> otaPackageService.saveOtaPackage(firmware)) + .isInstanceOf(DataValidationException.class) + .hasMessageContaining("OtaPackage is referencing to non-existent tenant!"); } @Test @@ -371,9 +366,9 @@ public abstract class BaseOtaPackageServiceTest extends AbstractServiceTest { firmware.setChecksum(CHECKSUM); firmware.setData(DATA); - thrown.expect(DataValidationException.class); - thrown.expectMessage("OtaPackage is referencing to non-existent device profile!"); - otaPackageService.saveOtaPackage(firmware); + assertThatThrownBy(() -> otaPackageService.saveOtaPackage(firmware)) + .isInstanceOf(DataValidationException.class) + .hasMessageContaining("OtaPackage is referencing to non-existent device profile!"); } @Test @@ -389,9 +384,9 @@ public abstract class BaseOtaPackageServiceTest extends AbstractServiceTest { firmware.setChecksumAlgorithm(CHECKSUM_ALGORITHM); firmware.setData(DATA); - thrown.expect(DataValidationException.class); - thrown.expectMessage("OtaPackage checksum should be specified!"); - otaPackageService.saveOtaPackage(firmware); + assertThatThrownBy(() -> otaPackageService.saveOtaPackage(firmware)) + .isInstanceOf(DataValidationException.class) + .hasMessageContaining("OtaPackage checksum should be specified!"); } @Test @@ -411,17 +406,17 @@ public abstract class BaseOtaPackageServiceTest extends AbstractServiceTest { newFirmwareInfo.setTitle(TITLE); newFirmwareInfo.setVersion(VERSION); - thrown.expect(DataValidationException.class); - thrown.expectMessage("OtaPackage with such title and version already exists!"); - otaPackageService.saveOtaPackageInfo(newFirmwareInfo, false); + assertThatThrownBy(() -> otaPackageService.saveOtaPackageInfo(newFirmwareInfo, false)) + .isInstanceOf(DataValidationException.class) + .hasMessageContaining("OtaPackage with such title and version already exists!"); } @Test public void testSaveFirmwareWithExistingTitleAndVersion() { createAndSaveFirmware(tenantId, VERSION); - thrown.expect(DataValidationException.class); - thrown.expectMessage("OtaPackage with such title and version already exists!"); - createAndSaveFirmware(tenantId, VERSION); + assertThatThrownBy(() -> createAndSaveFirmware(tenantId, VERSION)) + .isInstanceOf(DataValidationException.class) + .hasMessageContaining("OtaPackage with such title and version already exists!"); } @Test @@ -436,9 +431,9 @@ public abstract class BaseOtaPackageServiceTest extends AbstractServiceTest { Device savedDevice = deviceService.saveDevice(device); try { - thrown.expect(DataValidationException.class); - thrown.expectMessage("The otaPackage referenced by the devices cannot be deleted!"); - otaPackageService.deleteOtaPackage(tenantId, savedFirmware.getId()); + assertThatThrownBy(() -> otaPackageService.deleteOtaPackage(tenantId, savedFirmware.getId())) + .isInstanceOf(DataValidationException.class) + .hasMessageContaining("The otaPackage referenced by the devices cannot be deleted!"); } finally { deviceService.deleteDevice(tenantId, savedDevice.getId()); otaPackageService.deleteOtaPackage(tenantId, savedFirmware.getId()); @@ -448,12 +443,12 @@ public abstract class BaseOtaPackageServiceTest extends AbstractServiceTest { @Test public void testUpdateDeviceProfileId() { OtaPackage savedFirmware = createAndSaveFirmware(tenantId, VERSION); + savedFirmware.setDeviceProfileId(null); try { - thrown.expect(DataValidationException.class); - thrown.expectMessage("Updating otaPackage deviceProfile is prohibited!"); - savedFirmware.setDeviceProfileId(null); - otaPackageService.saveOtaPackage(savedFirmware); + assertThatThrownBy(() -> otaPackageService.saveOtaPackage(savedFirmware)) + .isInstanceOf(DataValidationException.class) + .hasMessageContaining("Updating otaPackage deviceProfile is prohibited!"); } finally { otaPackageService.deleteOtaPackage(tenantId, savedFirmware.getId()); } @@ -482,9 +477,9 @@ public abstract class BaseOtaPackageServiceTest extends AbstractServiceTest { deviceProfileService.saveDeviceProfile(savedDeviceProfile); try { - thrown.expect(DataValidationException.class); - thrown.expectMessage("The otaPackage referenced by the device profile cannot be deleted!"); - otaPackageService.deleteOtaPackage(tenantId, savedFirmware.getId()); + assertThatThrownBy(() -> otaPackageService.deleteOtaPackage(tenantId, savedFirmware.getId())) + .isInstanceOf(DataValidationException.class) + .hasMessageContaining("The otaPackage referenced by the device profile cannot be deleted!"); } finally { deviceProfileService.deleteDeviceProfile(tenantId, savedDeviceProfile.getId()); } @@ -636,12 +631,18 @@ public abstract class BaseOtaPackageServiceTest extends AbstractServiceTest { firmwareInfo.setType(FIRMWARE); firmwareInfo.setTitle(TITLE); firmwareInfo.setVersion(VERSION); + firmwareInfo.setUrl(" "); - thrown.expect(DataValidationException.class); - thrown.expectMessage("Ota package URL should be specified!"); - otaPackageService.saveOtaPackageInfo(firmwareInfo, true); + assertThatThrownBy(() -> otaPackageService.saveOtaPackageInfo(firmwareInfo, true)) + .as("firmwareInfo url set whitespaces") + .isInstanceOf(DataValidationException.class) + .hasMessageContaining("Ota package URL should be specified!"); + firmwareInfo.setUrl(""); - otaPackageService.saveOtaPackageInfo(firmwareInfo, true); + assertThatThrownBy(() -> otaPackageService.saveOtaPackageInfo(firmwareInfo, true)) + .as("firmwareInfo url is empty") + .isInstanceOf(DataValidationException.class) + .hasMessageContaining("Ota package URL should be specified!"); } @Test @@ -655,12 +656,10 @@ public abstract class BaseOtaPackageServiceTest extends AbstractServiceTest { firmwareInfo.setTenantId(tenantId); OtaPackageInfo savedFirmwareInfo = otaPackageService.saveOtaPackageInfo(firmwareInfo, true); - - thrown.expect(DataValidationException.class); - thrown.expectMessage("Updating otaPackage URL is prohibited!"); - savedFirmwareInfo.setUrl("https://newurl.com"); - otaPackageService.saveOtaPackageInfo(savedFirmwareInfo, true); + assertThatThrownBy(() -> otaPackageService.saveOtaPackageInfo(savedFirmwareInfo, true)) + .isInstanceOf(DataValidationException.class) + .hasMessageContaining("Updating otaPackage URL is prohibited!"); } @Test @@ -673,10 +672,9 @@ public abstract class BaseOtaPackageServiceTest extends AbstractServiceTest { firmwareInfo.setUrl(URL); firmwareInfo.setTenantId(tenantId); - thrown.expect(DataValidationException.class); - thrown.expectMessage("title length must be equal or less than 255"); - - otaPackageService.saveOtaPackageInfo(firmwareInfo, true); + assertThatThrownBy(() -> otaPackageService.saveOtaPackageInfo(firmwareInfo, true)) + .isInstanceOf(DataValidationException.class) + .hasMessageContaining("title length must be equal or less than 255"); } @Test @@ -687,11 +685,11 @@ public abstract class BaseOtaPackageServiceTest extends AbstractServiceTest { firmwareInfo.setUrl(URL); firmwareInfo.setTenantId(tenantId); firmwareInfo.setTitle(TITLE); - firmwareInfo.setVersion(StringUtils.random(257)); - thrown.expectMessage("version length must be equal or less than 255"); - otaPackageService.saveOtaPackageInfo(firmwareInfo, true); + assertThatThrownBy(() -> otaPackageService.saveOtaPackageInfo(firmwareInfo, true)) + .isInstanceOf(DataValidationException.class) + .hasMessageContaining("version length must be equal or less than 255"); } private OtaPackage createAndSaveFirmware(TenantId tenantId, String version) { From 3841deae247eebd3f6b491449508b73bb21f1943 Mon Sep 17 00:00:00 2001 From: Oleksandra Matviienko Date: Mon, 13 Mar 2023 23:08:19 +0100 Subject: [PATCH 13/28] BaseTbResourceServiceTest, BaseDeviceServiceTest: Rule ExpectedException refactored with AssertJ Exception Assertions --- .../resource/sql/BaseTbResourceServiceTest.java | 13 ++++--------- .../server/dao/service/BaseDeviceServiceTest.java | 13 ++++--------- 2 files changed, 8 insertions(+), 18 deletions(-) diff --git a/application/src/test/java/org/thingsboard/server/service/resource/sql/BaseTbResourceServiceTest.java b/application/src/test/java/org/thingsboard/server/service/resource/sql/BaseTbResourceServiceTest.java index b0282832bc..e2c5985553 100644 --- a/application/src/test/java/org/thingsboard/server/service/resource/sql/BaseTbResourceServiceTest.java +++ b/application/src/test/java/org/thingsboard/server/service/resource/sql/BaseTbResourceServiceTest.java @@ -19,10 +19,8 @@ import com.datastax.oss.driver.api.core.uuid.Uuids; import org.junit.After; import org.junit.Assert; import org.junit.Before; -import org.junit.Rule; import org.junit.Test; import org.junit.jupiter.api.Assertions; -import org.junit.rules.ExpectedException; import org.springframework.beans.factory.annotation.Autowired; import org.thingsboard.server.common.data.EntityInfo; import org.thingsboard.server.common.data.ResourceType; @@ -46,6 +44,7 @@ import java.util.Base64; import java.util.Collections; import java.util.List; +import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; @DaoSqlTest @@ -116,10 +115,6 @@ public class BaseTbResourceServiceTest extends AbstractControllerTest { .andExpect(status().isOk()); } - @SuppressWarnings("deprecation") - @Rule - public ExpectedException thrown = ExpectedException.none(); - @Test public void testSaveResourceWithMaxSumDataSizeOutOfLimit() throws Exception { loginSysAdmin(); @@ -138,9 +133,9 @@ public class BaseTbResourceServiceTest extends AbstractControllerTest { Assert.assertEquals(1, resourceService.sumDataSizeByTenantId(tenantId)); try { - thrown.expect(DataValidationException.class); - thrown.expectMessage(String.format("Failed to create the tb resource, files size limit is exhausted %d bytes!", limit)); - createResource("test1", 1 + DEFAULT_FILE_NAME); + assertThatThrownBy(() -> createResource("test1", 1 + DEFAULT_FILE_NAME)) + .isInstanceOf(DataValidationException.class) + .hasMessageContaining("Failed to create the tb resource, files size limit is exhausted %d bytes!", limit); } finally { defaultTenantProfile.getProfileData().setConfiguration(DefaultTenantProfileConfiguration.builder().maxResourcesInBytes(0).build()); loginSysAdmin(); diff --git a/dao/src/test/java/org/thingsboard/server/dao/service/BaseDeviceServiceTest.java b/dao/src/test/java/org/thingsboard/server/dao/service/BaseDeviceServiceTest.java index 010f56235f..900eea8a6d 100644 --- a/dao/src/test/java/org/thingsboard/server/dao/service/BaseDeviceServiceTest.java +++ b/dao/src/test/java/org/thingsboard/server/dao/service/BaseDeviceServiceTest.java @@ -19,10 +19,8 @@ import com.datastax.oss.driver.api.core.uuid.Uuids; import org.junit.After; import org.junit.Assert; import org.junit.Before; -import org.junit.Rule; import org.junit.Test; import org.junit.jupiter.api.Assertions; -import org.junit.rules.ExpectedException; import org.thingsboard.server.common.data.Customer; import org.thingsboard.server.common.data.Device; import org.thingsboard.server.common.data.DeviceInfo; @@ -47,6 +45,7 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; +import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.thingsboard.server.common.data.ota.OtaPackageType.FIRMWARE; import static org.thingsboard.server.dao.model.ModelConstants.NULL_UUID; @@ -72,10 +71,6 @@ public abstract class BaseDeviceServiceTest extends AbstractServiceTest { tenantProfileService.deleteTenantProfiles(anotherTenantId); } - @SuppressWarnings("deprecation") - @Rule - public ExpectedException thrown = ExpectedException.none(); - @Test public void testSaveDevicesWithoutMaxDeviceLimit() { Device device = this.saveDevice(tenantId, "My device"); @@ -244,9 +239,9 @@ public abstract class BaseDeviceServiceTest extends AbstractServiceTest { savedDevice.setFirmwareId(savedFirmware.getId()); - thrown.expect(DataValidationException.class); - thrown.expectMessage("Can't assign firmware with different deviceProfile!"); - deviceService.saveDevice(savedDevice); + assertThatThrownBy(() -> deviceService.saveDevice(savedDevice)) + .isInstanceOf(DataValidationException.class) + .hasMessageContaining("Can't assign firmware with different deviceProfile!"); } @Test From 16061ec4fcf27e355ae22444676de8318d4e0b65 Mon Sep 17 00:00:00 2001 From: Seraphym-Tuhai Date: Tue, 14 Mar 2023 11:48:10 +0200 Subject: [PATCH 14/28] rename openLocalhost() method --- .../server/msa/ui/base/AbstractDriverBaseTest.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/ui/base/AbstractDriverBaseTest.java b/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/ui/base/AbstractDriverBaseTest.java index 634bf47c14..3820563a8a 100644 --- a/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/ui/base/AbstractDriverBaseTest.java +++ b/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/ui/base/AbstractDriverBaseTest.java @@ -81,12 +81,12 @@ abstract public class AbstractDriverBaseTest extends AbstractContainerTest { driver = new ChromeDriver(options); } driver.manage().window().setSize(dimension); - openLocalhost(); + openBaseUiUrl(); } @BeforeMethod public void open() { - openLocalhost(); + openBaseUiUrl(); } @AfterMethod @@ -105,7 +105,7 @@ abstract public class AbstractDriverBaseTest extends AbstractContainerTest { return (String) js.executeScript("return window.localStorage.getItem('jwt_token');"); } - public void openLocalhost() { + public void openBaseUiUrl() { driver.get(getBaseUiUrl()); } From 12041ee6e22e8b04e2a8f509fee345c6a12cd13d Mon Sep 17 00:00:00 2001 From: Seraphym-Tuhai Date: Tue, 14 Mar 2023 12:20:18 +0200 Subject: [PATCH 15/28] return Assertions.fail() in catch block of custom waiters method --- .../server/msa/ui/base/AbstractBasePage.java | 27 ++++++++----------- 1 file changed, 11 insertions(+), 16 deletions(-) diff --git a/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/ui/base/AbstractBasePage.java b/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/ui/base/AbstractBasePage.java index cd4ca51698..286428218d 100644 --- a/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/ui/base/AbstractBasePage.java +++ b/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/ui/base/AbstractBasePage.java @@ -16,7 +16,6 @@ package org.thingsboard.server.msa.ui.base; import lombok.SneakyThrows; -import lombok.extern.slf4j.Slf4j; import org.openqa.selenium.By; import org.openqa.selenium.JavascriptExecutor; import org.openqa.selenium.WebDriver; @@ -34,7 +33,8 @@ import java.util.UUID; import java.util.concurrent.ThreadLocalRandom; import java.util.concurrent.TimeUnit; -@Slf4j +import static org.junit.jupiter.api.Assertions.fail; + abstract public class AbstractBasePage { public static final long WAIT_TIMEOUT = TimeUnit.SECONDS.toMillis(30); protected WebDriver driver; @@ -59,8 +59,7 @@ abstract public class AbstractBasePage { try { return wait.until(ExpectedConditions.visibilityOfElementLocated(By.xpath(locator))); } catch (WebDriverException e) { - log.error("No visibility element: " + locator); - return null; + return fail("No visibility element: " + locator); } } @@ -68,8 +67,7 @@ abstract public class AbstractBasePage { try { return wait.until(ExpectedConditions.presenceOfElementLocated(By.xpath(locator))); } catch (WebDriverException e) { - log.error("No presence element: " + locator); - return null; + return fail("No presence element: " + locator); } } @@ -77,8 +75,7 @@ abstract public class AbstractBasePage { try { return wait.until(ExpectedConditions.elementToBeClickable(By.xpath(locator))); } catch (WebDriverException e) { - log.error("No clickable element: " + locator); - return null; + return fail("No clickable element: " + locator); } } @@ -87,8 +84,7 @@ abstract public class AbstractBasePage { wait.until(ExpectedConditions.visibilityOfElementLocated(By.xpath(locator))); return driver.findElements(By.xpath(locator)); } catch (WebDriverException e) { - log.error("No visibility elements: " + locator); - return null; + return fail("No visibility elements: " + locator); } } @@ -97,8 +93,7 @@ abstract public class AbstractBasePage { wait.until(ExpectedConditions.elementToBeClickable(By.xpath(locator))); return driver.findElements(By.xpath(locator)); } catch (WebDriverException e) { - log.error("No clickable elements: " + locator); - return null; + return fail("No clickable elements: " + locator); } } @@ -106,7 +101,7 @@ abstract public class AbstractBasePage { try { wait.until(ExpectedConditions.urlContains(urlPath)); } catch (WebDriverException e) { - log.error("This URL path is missing"); + fail("This URL path is missing"); } } @@ -122,7 +117,7 @@ abstract public class AbstractBasePage { try { return wait.until(ExpectedConditions.not(ExpectedConditions.visibilityOfElementLocated(By.xpath(locator)))); } catch (WebDriverException e) { - throw new AssertionError("Element is present"); + return fail("Element is present"); } } @@ -130,7 +125,7 @@ abstract public class AbstractBasePage { try { return wait.until(ExpectedConditions.not(ExpectedConditions.visibilityOfAllElementsLocatedBy(By.xpath(locator)))); } catch (WebDriverException e) { - throw new AssertionError("Elements is present"); + return fail("Elements is present"); } } @@ -138,7 +133,7 @@ abstract public class AbstractBasePage { try { wait.until(ExpectedConditions.numberOfWindowsToBe(tabNumber)); } catch (WebDriverException e) { - log.error("No tabs with this number"); + fail("No tabs with this number: " + tabNumber); } } From 80c331705f1b21b2884961b119349766a653a60b Mon Sep 17 00:00:00 2001 From: Seraphym-Tuhai Date: Tue, 14 Mar 2023 12:27:17 +0200 Subject: [PATCH 16/28] small refactoring --- .../org/thingsboard/server/msa/ui/base/AbstractBasePage.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/ui/base/AbstractBasePage.java b/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/ui/base/AbstractBasePage.java index 286428218d..6384e17426 100644 --- a/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/ui/base/AbstractBasePage.java +++ b/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/ui/base/AbstractBasePage.java @@ -33,7 +33,7 @@ import java.util.UUID; import java.util.concurrent.ThreadLocalRandom; import java.util.concurrent.TimeUnit; -import static org.junit.jupiter.api.Assertions.fail; +import static org.assertj.core.api.Assertions.fail; abstract public class AbstractBasePage { public static final long WAIT_TIMEOUT = TimeUnit.SECONDS.toMillis(30); From d5177f5bbf49527eedc0d1d5e5bbe4883a21a138 Mon Sep 17 00:00:00 2001 From: Andrii Shvaika Date: Tue, 14 Mar 2023 13:52:21 +0200 Subject: [PATCH 17/28] Fix attribute/RPC subscription tests --- .../AbstractMqttV5ClientSparkplugAttributesTest.java | 7 +++++++ .../mqtt/sparkplug/rpc/AbstractMqttV5RpcSparkplugTest.java | 4 ++++ 2 files changed, 11 insertions(+) diff --git a/application/src/test/java/org/thingsboard/server/transport/mqtt/sparkplug/attributes/AbstractMqttV5ClientSparkplugAttributesTest.java b/application/src/test/java/org/thingsboard/server/transport/mqtt/sparkplug/attributes/AbstractMqttV5ClientSparkplugAttributesTest.java index 04349d0672..4e05e44668 100644 --- a/application/src/test/java/org/thingsboard/server/transport/mqtt/sparkplug/attributes/AbstractMqttV5ClientSparkplugAttributesTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/mqtt/sparkplug/attributes/AbstractMqttV5ClientSparkplugAttributesTest.java @@ -20,6 +20,7 @@ import io.netty.handler.codec.mqtt.MqttQoS; import lombok.extern.slf4j.Slf4j; import org.junit.Assert; import org.thingsboard.server.common.data.Device; +import org.thingsboard.server.common.msg.session.FeatureType; import org.thingsboard.server.transport.mqtt.sparkplug.AbstractMqttV5ClientSparkplugTest; import org.thingsboard.server.transport.mqtt.util.sparkplug.MetricDataType; import org.thingsboard.server.transport.mqtt.util.sparkplug.SparkplugMessageType; @@ -50,6 +51,7 @@ public abstract class AbstractMqttV5ClientSparkplugAttributesTest extends Abstra String SHARED_ATTRIBUTES_PAYLOAD = "{\"" + keyNodeRebirth + "\":" + value + "}"; Assert.assertTrue("Connection node is failed", client.isConnected()); client.subscribeAndWait(NAMESPACE + "/" + groupId + "/" + NCMD.name() + "/" + edgeNode + "/#", MqttQoS.AT_MOST_ONCE); + awaitForDeviceActorToReceiveSubscription(savedGateway.getId(), FeatureType.ATTRIBUTES, 1); doPostAsync("/api/plugins/telemetry/DEVICE/" + savedGateway.getId().getId() + "/attributes/SHARED_SCOPE", SHARED_ATTRIBUTES_PAYLOAD, String.class, status().isOk()); await(alias + SparkplugMessageType.NBIRTH.name()) .atMost(40, TimeUnit.SECONDS) @@ -75,6 +77,7 @@ public abstract class AbstractMqttV5ClientSparkplugAttributesTest extends Abstra connectionWithNBirth(metricDataType, metricKey, metricValue); Assert.assertTrue("Connection node is failed", client.isConnected()); client.subscribeAndWait(NAMESPACE + "/" + groupId + "/" + NCMD.name() + "/" + edgeNode + "/#", MqttQoS.AT_MOST_ONCE); + awaitForDeviceActorToReceiveSubscription(savedGateway.getId(), FeatureType.ATTRIBUTES, 1); // Boolean <-> String boolean expectedValue = true; @@ -138,6 +141,7 @@ public abstract class AbstractMqttV5ClientSparkplugAttributesTest extends Abstra connectionWithNBirth(metricDataType, metricKey, metricValue); Assert.assertTrue("Connection node is failed", client.isConnected()); client.subscribeAndWait(NAMESPACE + "/" + groupId + "/" + NCMD.name() + "/" + edgeNode + "/#", MqttQoS.AT_MOST_ONCE); + awaitForDeviceActorToReceiveSubscription(savedGateway.getId(), FeatureType.ATTRIBUTES, 1); // Long <-> String String valueStr = "123"; @@ -189,6 +193,7 @@ public abstract class AbstractMqttV5ClientSparkplugAttributesTest extends Abstra connectionWithNBirth(metricDataType, metricKey, metricValue); Assert.assertTrue("Connection node is failed", client.isConnected()); client.subscribeAndWait(NAMESPACE + "/" + groupId + "/" + NCMD.name() + "/" + edgeNode + "/#", MqttQoS.AT_MOST_ONCE); + awaitForDeviceActorToReceiveSubscription(savedGateway.getId(), FeatureType.ATTRIBUTES, 1); // Float <-> String String valueStr = "123.345"; @@ -240,6 +245,7 @@ public abstract class AbstractMqttV5ClientSparkplugAttributesTest extends Abstra connectionWithNBirth(metricDataType, metricKey, metricValue); Assert.assertTrue("Connection node is failed", client.isConnected()); client.subscribeAndWait(NAMESPACE + "/" + groupId + "/" + NCMD.name() + "/" + edgeNode + "/#", MqttQoS.AT_MOST_ONCE); + awaitForDeviceActorToReceiveSubscription(savedGateway.getId(), FeatureType.ATTRIBUTES, 1); // Double <-> String String valueStr = "123345456"; @@ -291,6 +297,7 @@ public abstract class AbstractMqttV5ClientSparkplugAttributesTest extends Abstra connectionWithNBirth(metricDataType, metricKey, metricValue); Assert.assertTrue("Connection node is failed", client.isConnected()); client.subscribeAndWait(NAMESPACE + "/" + groupId + "/" + NCMD.name() + "/" + edgeNode + "/#", MqttQoS.AT_MOST_ONCE); + awaitForDeviceActorToReceiveSubscription(savedGateway.getId(), FeatureType.ATTRIBUTES, 1); // String <-> Long long valueLong = 123345456L; diff --git a/application/src/test/java/org/thingsboard/server/transport/mqtt/sparkplug/rpc/AbstractMqttV5RpcSparkplugTest.java b/application/src/test/java/org/thingsboard/server/transport/mqtt/sparkplug/rpc/AbstractMqttV5RpcSparkplugTest.java index b08baac875..036b779de1 100644 --- a/application/src/test/java/org/thingsboard/server/transport/mqtt/sparkplug/rpc/AbstractMqttV5RpcSparkplugTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/mqtt/sparkplug/rpc/AbstractMqttV5RpcSparkplugTest.java @@ -20,6 +20,7 @@ import lombok.extern.slf4j.Slf4j; import org.junit.Assert; import org.junit.Test; import org.thingsboard.server.common.data.Device; +import org.thingsboard.server.common.msg.session.FeatureType; import org.thingsboard.server.transport.mqtt.sparkplug.AbstractMqttV5ClientSparkplugTest; import org.thingsboard.server.transport.mqtt.util.sparkplug.SparkplugMessageType; @@ -45,6 +46,7 @@ public abstract class AbstractMqttV5RpcSparkplugTest extends AbstractMqttV5Clie connectionWithNBirth(metricBirthDataType_Int32, metricBirthName_Int32, nextInt32()); Assert.assertTrue("Connection node is failed", client.isConnected()); client.subscribeAndWait(NAMESPACE + "/" + groupId + "/" + NCMD.name() + "/" + edgeNode + "/#", MqttQoS.AT_MOST_ONCE); + awaitForDeviceActorToReceiveSubscription(savedGateway.getId(), FeatureType.RPC, 1); String expected = "{\"result\":\"Success: " + SparkplugMessageType.NCMD.name() + "\"}"; String actual = sendRPCSparkplug(NCMD.name(), sparkplugRpcRequest, savedGateway); await(alias + SparkplugMessageType.NCMD.name()) @@ -79,6 +81,7 @@ public abstract class AbstractMqttV5RpcSparkplugTest extends AbstractMqttV5Clie connectionWithNBirth(metricBirthDataType_Int32, metricBirthName_Int32, nextInt32()); Assert.assertTrue("Connection node is failed", client.isConnected()); client.subscribeAndWait(NAMESPACE + "/" + groupId + "/" + NCMD.name() + "/" + edgeNode + "/#", MqttQoS.AT_MOST_ONCE); + awaitForDeviceActorToReceiveSubscription(savedGateway.getId(), FeatureType.RPC, 1); String invalidateTypeMessageName = "RCMD"; String expected = "{\"result\":\"" + INVALID_ARGUMENTS + "\",\"error\":\"Failed to convert device RPC command to MQTT msg: " + invalidateTypeMessageName + "{\\\"metricName\\\":\\\"" + metricBirthName_Int32 + "\\\",\\\"value\\\":" + metricBirthValue_Int32 + "}\"}"; @@ -92,6 +95,7 @@ public abstract class AbstractMqttV5RpcSparkplugTest extends AbstractMqttV5Clie connectionWithNBirth(metricBirthDataType_Int32, metricBirthName_Int32, nextInt32()); Assert.assertTrue("Connection node is failed", client.isConnected()); client.subscribeAndWait(NAMESPACE + "/" + groupId + "/" + NCMD.name() + "/" + edgeNode + "/#", MqttQoS.AT_MOST_ONCE); + awaitForDeviceActorToReceiveSubscription(savedGateway.getId(), FeatureType.RPC, 1); String metricNameBad = metricBirthName_Int32 + "_Bad"; String sparkplugRpcRequestBad = "{\"metricName\":\"" + metricNameBad + "\",\"value\":" + metricBirthValue_Int32 + "}"; String expected = "{\"result\":\"BAD_REQUEST_PARAMS\",\"error\":\"Failed send To Node Rpc Request: " + From b00f5d26ae242063da5d0a31c41f2369dd9afe24 Mon Sep 17 00:00:00 2001 From: Sergey Matvienko Date: Tue, 14 Mar 2023 13:48:34 +0100 Subject: [PATCH 18/28] log node refactored and tests improved --- .../rule/engine/action/TbLogNode.java | 11 +++- .../rule/engine/action/TbLogNodeTest.java | 62 +++++++++++++++++-- 2 files changed, 64 insertions(+), 9 deletions(-) diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbLogNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbLogNode.java index 48e134a7f7..6c3d80dade 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbLogNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbLogNode.java @@ -57,7 +57,11 @@ public class TbLogNode implements TbNode { public void init(TbContext ctx, TbNodeConfiguration configuration) throws TbNodeException { this.config = TbNodeUtils.convert(configuration, TbLogNodeConfiguration.class); this.standard = isStandard(config); - this.scriptEngine = this.standard ? null : ctx.createScriptEngine(config.getScriptLang(), + this.scriptEngine = this.standard ? null : createScriptEngine(ctx, config); + } + + ScriptEngine createScriptEngine(TbContext ctx, TbLogNodeConfiguration config) { + return ctx.createScriptEngine(config.getScriptLang(), ScriptLanguage.TBEL.equals(config.getScriptLang()) ? config.getTbelScript() : config.getJsScript()); } @@ -91,9 +95,10 @@ public class TbLogNode implements TbNode { switch (conf.getScriptLang()) { case JS: return defaultConfig.getJsScript().equals(conf.getJsScript()); case TBEL: return defaultConfig.getTbelScript().equals(conf.getTbelScript()); + default: + log.warn("No rule to define isStandard script for script language [{}], assuming that is non-standard", conf.getScriptLang()); + return false; } - log.warn("No rule to define isStandard script for script language [{}], assuming that is non-standard", conf.getScriptLang()); - return false; } void logStandard(TbContext ctx, TbMsg msg) { diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/action/TbLogNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/action/TbLogNodeTest.java index 4d960fc71e..21e99af819 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/action/TbLogNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/action/TbLogNodeTest.java @@ -17,6 +17,12 @@ package org.thingsboard.rule.engine.action; import lombok.extern.slf4j.Slf4j; import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.EnumSource; +import org.thingsboard.common.util.JacksonUtil; +import org.thingsboard.rule.engine.api.TbContext; +import org.thingsboard.rule.engine.api.TbNodeConfiguration; +import org.thingsboard.rule.engine.api.TbNodeException; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.script.ScriptLanguage; import org.thingsboard.server.common.msg.TbMsg; @@ -24,8 +30,16 @@ import org.thingsboard.server.common.msg.TbMsgMetaData; import java.util.Collections; import java.util.Map; +import java.util.UUID; import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoMoreInteractions; @Slf4j public class TbLogNodeTest { @@ -79,14 +93,50 @@ public class TbLogNodeTest { "{}"); } + @ParameterizedTest + @EnumSource(ScriptLanguage.class) + void givenDefaultConfig_whenIsStandardForEachScriptLanguage_thenTrue(ScriptLanguage scriptLanguage) throws TbNodeException { + + TbLogNodeConfiguration config = new TbLogNodeConfiguration().defaultConfiguration(); + config.setScriptLang(scriptLanguage); + TbLogNode node = spy(new TbLogNode()); + TbNodeConfiguration tbNodeConfiguration = new TbNodeConfiguration(JacksonUtil.valueToTree(config)); + TbContext ctx = mock(TbContext.class); + node.init(ctx, tbNodeConfiguration); + + assertThat(node.isStandard(config)).as("Script is standard for language " + scriptLanguage).isTrue(); + verify(node, never()).createScriptEngine(any(), any()); + verify(ctx, never()).createScriptEngine(any(), anyString()); + + } + + @Test + void givenScriptEngineEnum_whenNewAdded_thenFailed() { + assertThat(ScriptLanguage.values().length).as("only two ScriptLanguage supported").isEqualTo(2); + } + + @Test + void givenScriptEngineLangJs_whenCreateScriptEngine_thenSupplyJsScript(){ + TbLogNodeConfiguration configJs = new TbLogNodeConfiguration().defaultConfiguration(); + configJs.setScriptLang(ScriptLanguage.JS); + configJs.setJsScript(configJs.getJsScript() + " // This is JS script " + UUID.randomUUID()); + TbLogNode node = new TbLogNode(); + TbContext ctx = mock(TbContext.class); + node.createScriptEngine(ctx, configJs); + verify(ctx).createScriptEngine(ScriptLanguage.JS, configJs.getJsScript()); + verifyNoMoreInteractions(ctx); + } + @Test - void givenDefaultConfig_whenIsStandardForEachScriptLanguage_thenTrue() { + void givenScriptEngineLangTbel_whenCreateScriptEngine_thenSupplyTbelScript(){ + TbLogNodeConfiguration configTbel = new TbLogNodeConfiguration().defaultConfiguration(); + configTbel.setScriptLang(ScriptLanguage.TBEL); + configTbel.setTbelScript(configTbel.getTbelScript() + " // This is TBEL script " + UUID.randomUUID()); TbLogNode node = new TbLogNode(); - for (ScriptLanguage scriptLanguage : ScriptLanguage.values()) { - TbLogNodeConfiguration config = new TbLogNodeConfiguration().defaultConfiguration(); - config.setScriptLang(scriptLanguage); - assertThat(node.isStandard(config)).as("Script is standard for language " + scriptLanguage).isTrue(); - } + TbContext ctx = mock(TbContext.class); + node.createScriptEngine(ctx, configTbel); + verify(ctx).createScriptEngine(ScriptLanguage.TBEL, configTbel.getTbelScript()); + verifyNoMoreInteractions(ctx); } } From 2a6000d8ceda2e8e7f030243258bcaaf5720e1c9 Mon Sep 17 00:00:00 2001 From: nickAS21 Date: Tue, 14 Mar 2023 15:13:55 +0200 Subject: [PATCH 19/28] fix bug close session of device: sessionMetaData.setOverwriteActivityTime(true); --- .../server/transport/mqtt/MqttTransportHandler.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/MqttTransportHandler.java b/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/MqttTransportHandler.java index 0d43fc6c93..e58e2c5d89 100644 --- a/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/MqttTransportHandler.java +++ b/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/MqttTransportHandler.java @@ -1060,7 +1060,7 @@ public class MqttTransportHandler extends ChannelInboundHandlerAdapter implement } } - private void checkSparkplugNodeSession(MqttConnectMessage connectMessage, ChannelHandlerContext ctx) { + private void checkSparkplugNodeSession(MqttConnectMessage connectMessage, ChannelHandlerContext ctx, SessionMetaData sessionMetaData) { try { if (sparkplugSessionHandler == null) { SparkplugTopic sparkplugTopicNode = validatedSparkplugTopicConnectedNode(connectMessage); @@ -1069,6 +1069,7 @@ public class MqttTransportHandler extends ChannelInboundHandlerAdapter implement sparkplugSessionHandler = new SparkplugNodeSessionHandler(this, deviceSessionCtx, sessionId, sparkplugTopicNode); sparkplugSessionHandler.onAttributesTelemetryProto(0, sparkplugBProtoNode, deviceSessionCtx.getDeviceInfo().getDeviceName(), sparkplugTopicNode); + sessionMetaData.setOverwriteActivityTime(true); } else { log.trace("[{}][{}] Failed to fetch sparkplugDevice connect: sparkplugTopicName without SparkplugMessageType.NDEATH.", sessionId, deviceSessionCtx.getDeviceInfo().getDeviceName()); throw new ThingsboardException("Invalid request body", ThingsboardErrorCode.BAD_REQUEST_PARAMS); @@ -1145,7 +1146,7 @@ public class MqttTransportHandler extends ChannelInboundHandlerAdapter implement public void onSuccess(Void msg) { SessionMetaData sessionMetaData = transportService.registerAsyncSession(deviceSessionCtx.getSessionInfo(), MqttTransportHandler.this); if (deviceSessionCtx.isSparkplug()) { - checkSparkplugNodeSession(connectMessage, ctx); + checkSparkplugNodeSession(connectMessage, ctx, sessionMetaData); } else { checkGatewaySession(sessionMetaData); } From c6230a48b8256e534f89deee61bb8233fd28ac1d Mon Sep 17 00:00:00 2001 From: Vladyslav_Prykhodko Date: Tue, 14 Mar 2023 16:37:05 +0200 Subject: [PATCH 20/28] UI: Fix notification after change API --- .../pages/admin/general-settings.component.html | 2 +- .../admin/notification-settings.component.html | 14 ++++++++------ .../rule-notification-dialog.component.html | 8 ++++---- .../rule-notification-dialog.component.ts | 4 ++-- .../target-notification-dialog.componet.ts | 7 ++++++- .../notification/notification.component.ts | 2 +- .../src/app/shared/models/notification.models.ts | 14 +++++++------- .../src/assets/locale/locale.constant-en_US.json | 4 ++-- 8 files changed, 31 insertions(+), 24 deletions(-) diff --git a/ui-ngx/src/app/modules/home/pages/admin/general-settings.component.html b/ui-ngx/src/app/modules/home/pages/admin/general-settings.component.html index 0bef085781..da0e9fede3 100644 --- a/ui-ngx/src/app/modules/home/pages/admin/general-settings.component.html +++ b/ui-ngx/src/app/modules/home/pages/admin/general-settings.component.html @@ -27,7 +27,7 @@
- +
diff --git a/ui-ngx/src/app/modules/home/pages/admin/notification-settings.component.html b/ui-ngx/src/app/modules/home/pages/admin/notification-settings.component.html index edfff9e593..f5fa148993 100644 --- a/ui-ngx/src/app/modules/home/pages/admin/notification-settings.component.html +++ b/ui-ngx/src/app/modules/home/pages/admin/notification-settings.component.html @@ -16,12 +16,14 @@ -->
- - -
- admin.notification.notification-settings -
-
+ + + +
+ admin.notification.notification-settings +
+
+
diff --git a/ui-ngx/src/app/modules/home/pages/notification-center/rule-table/rule-notification-dialog.component.html b/ui-ngx/src/app/modules/home/pages/notification-center/rule-table/rule-notification-dialog.component.html index 8abc108e50..a3db4399f9 100644 --- a/ui-ngx/src/app/modules/home/pages/notification-center/rule-table/rule-notification-dialog.component.html +++ b/ui-ngx/src/app/modules/home/pages/notification-center/rule-table/rule-notification-dialog.component.html @@ -112,8 +112,8 @@ notification.clear-rule alarm.alarm-status-list - + {{ alarmSearchStatusTranslationMap.get(searchStatus) | translate }} @@ -232,8 +232,8 @@ alarm.alarm-status-list - + {{ alarmSearchStatusTranslationMap.get(searchStatus) | translate }} diff --git a/ui-ngx/src/app/modules/home/pages/notification-center/rule-table/rule-notification-dialog.component.ts b/ui-ngx/src/app/modules/home/pages/notification-center/rule-table/rule-notification-dialog.component.ts index efa2d88b05..b9c64b7235 100644 --- a/ui-ngx/src/app/modules/home/pages/notification-center/rule-table/rule-notification-dialog.component.ts +++ b/ui-ngx/src/app/modules/home/pages/notification-center/rule-table/rule-notification-dialog.component.ts @@ -151,7 +151,7 @@ export class RuleNotificationDialogComponent extends alarmTypes: [null], alarmSeverities: [[]], clearRule: this.fb.group({ - alarmStatus: [[]] + alarmStatuses: [[]] }) }) }); @@ -189,7 +189,7 @@ export class RuleNotificationDialogComponent extends triggerConfig: this.fb.group({ alarmTypes: [null], alarmSeverities: [[]], - alarmStatus: [[]] + alarmStatuses: [[]] }) }); diff --git a/ui-ngx/src/app/modules/home/pages/notification-center/targets-table/target-notification-dialog.componet.ts b/ui-ngx/src/app/modules/home/pages/notification-center/targets-table/target-notification-dialog.componet.ts index 324c8dba95..c54fcfa2a6 100644 --- a/ui-ngx/src/app/modules/home/pages/notification-center/targets-table/target-notification-dialog.componet.ts +++ b/ui-ngx/src/app/modules/home/pages/notification-center/targets-table/target-notification-dialog.componet.ts @@ -150,10 +150,15 @@ export class TargetNotificationDialogComponent extends } save() { - let formValue = deepTrim(this.targetNotificationForm.value); + let formValue: NotificationTarget = deepTrim(this.targetNotificationForm.value); if (isDefined(this.data.target)) { formValue = Object.assign({}, this.data.target, formValue); } + if (formValue.configuration.type === NotificationTargetType.PLATFORM_USERS && !formValue.configuration.usersFilter) { + formValue.configuration.usersFilter = { + type: NotificationTargetConfigType.ALL_USERS + } + } this.notificationService.saveNotificationTarget(formValue).subscribe( (target) => this.dialogRef.close(target) ); diff --git a/ui-ngx/src/app/shared/components/notification/notification.component.ts b/ui-ngx/src/app/shared/components/notification/notification.component.ts index 2173c30023..3e73753d14 100644 --- a/ui-ngx/src/app/shared/components/notification/notification.component.ts +++ b/ui-ngx/src/app/shared/components/notification/notification.component.ts @@ -101,7 +101,7 @@ export class NotificationComponent implements OnInit { const stateObject: StateObject = {}; if (this.notification.additionalConfig.actionButtonConfig.setEntityIdInState) { stateObject.params = { - entityId: this.notification.info.originatorId ?? null + entityId: this.notification.info.stateEntityId ?? null }; } else { stateObject.params = {}; diff --git a/ui-ngx/src/app/shared/models/notification.models.ts b/ui-ngx/src/app/shared/models/notification.models.ts index 3c4ffbb994..28bf639ab0 100644 --- a/ui-ngx/src/app/shared/models/notification.models.ts +++ b/ui-ngx/src/app/shared/models/notification.models.ts @@ -45,7 +45,7 @@ export interface NotificationInfo { alarmSeverity?: AlarmSeverity; alarmStatus?: AlarmStatus; alarmType?: string; - originatorId?: EntityId; + stateEntityId?: EntityId; } export interface NotificationRequest extends Omit, 'label'> { @@ -112,9 +112,9 @@ export interface NotificationRule extends Omit, 'la export interface NotificationRuleTriggerConfig { alarmTypes?: Array; alarmSeverities?: Array; - alarmStatus?: Array; + alarmStatuses?: Array; clearRule?: { - alarmStatus: Array; + alarmStatuses: Array; }; devices?: Array; deviceProfiles?: Array; @@ -209,11 +209,11 @@ interface PushDeliveryMethodAdditionalConfig { actionButtonConfig: { enabled: boolean; text: string; - linkType: ActionButtonLinkType, + linkType: ActionButtonLinkType; link?: string; dashboardId?: string; dashboardState?: string; - setEntityIdInState?: boolean + setEntityIdInState?: boolean; }; } @@ -242,7 +242,7 @@ export const NotificationDeliveryMethodTranslateMap = new Map Date: Wed, 15 Mar 2023 11:27:12 +0100 Subject: [PATCH 21/28] tests: awaitForDeviceActorToReceiveSubscription --- .../org/thingsboard/server/controller/AbstractWebTest.java | 5 ++++- .../org/thingsboard/server/edge/BaseDeviceEdgeTest.java | 1 + .../attributes/AbstractMqttAttributesIntegrationTest.java | 6 ++++++ .../rpc/AbstractMqttServerSideRpcIntegrationTest.java | 1 - .../mqttv5/attributes/AbstractAttributesMqttV5Test.java | 2 ++ .../connection/AbstractMqttV5ClientConnectionTest.java | 2 ++ .../subscribe/AbstractMqttV5ClientSubscriptionTest.java | 3 +++ .../unsubscribe/AbstractMqttV5ClientUnsubscribeTest.java | 2 ++ .../transport/mqtt/mqttv5/rpc/AbstractMqttV5RpcTest.java | 3 +++ 9 files changed, 23 insertions(+), 2 deletions(-) diff --git a/application/src/test/java/org/thingsboard/server/controller/AbstractWebTest.java b/application/src/test/java/org/thingsboard/server/controller/AbstractWebTest.java index c09f259aaa..c9b739bad1 100644 --- a/application/src/test/java/org/thingsboard/server/controller/AbstractWebTest.java +++ b/application/src/test/java/org/thingsboard/server/controller/AbstractWebTest.java @@ -862,7 +862,10 @@ public abstract class AbstractWebTest extends AbstractInMemoryStorageTest { protected void awaitForDeviceActorToReceiveSubscription(DeviceId deviceId, FeatureType featureType, int subscriptionCount) { DeviceActorMessageProcessor processor = getDeviceActorProcessor(deviceId); Map subscriptions = (Map) ReflectionTestUtils.getField(processor, getMapName(featureType)); - Awaitility.await("Device actor received subscription command from the transport").atMost(TIMEOUT, TimeUnit.SECONDS).until(() -> subscriptions.size() == subscriptionCount); + Awaitility.await("Device actor received subscription command from the transport").atMost(5, TimeUnit.SECONDS).until(() -> { + log.warn("device {}, subscriptions.size() == {}", deviceId, subscriptions.size()); + return subscriptions.size() == subscriptionCount; + }); } protected static String getMapName(FeatureType featureType) { diff --git a/application/src/test/java/org/thingsboard/server/edge/BaseDeviceEdgeTest.java b/application/src/test/java/org/thingsboard/server/edge/BaseDeviceEdgeTest.java index 303e91ee80..904a6246ab 100644 --- a/application/src/test/java/org/thingsboard/server/edge/BaseDeviceEdgeTest.java +++ b/application/src/test/java/org/thingsboard/server/edge/BaseDeviceEdgeTest.java @@ -671,6 +671,7 @@ abstract public class BaseDeviceEdgeTest extends AbstractEdgeTest { client.setCallback(onUpdateCallback); client.subscribeAndWait("v1/devices/me/attributes", MqttQoS.AT_MOST_ONCE); + awaitForDeviceActorToReceiveSubscription(device.getId(), FeatureType.ATTRIBUTES, 1); edgeImitator.expectResponsesAmount(1); diff --git a/application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv3/attributes/AbstractMqttAttributesIntegrationTest.java b/application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv3/attributes/AbstractMqttAttributesIntegrationTest.java index f8165b0237..fa6c4d16a3 100644 --- a/application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv3/attributes/AbstractMqttAttributesIntegrationTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv3/attributes/AbstractMqttAttributesIntegrationTest.java @@ -354,6 +354,8 @@ public abstract class AbstractMqttAttributesIntegrationTest extends AbstractMqtt SHARED_ATTRIBUTES_PAYLOAD, String.class, status().isOk()); client.publishAndWait(attrPubTopic, CLIENT_ATTRIBUTES_PAYLOAD.getBytes()); client.subscribeAndWait(attrSubTopic, MqttQoS.AT_MOST_ONCE); + //RequestAttributes does not make any subscriptions in device actor + String update = getWsClient().waitForUpdate(); assertThat(update).as("ws update received").isNotBlank(); MqttTestCallback callback = new MqttTestCallback(attrSubTopic.replace("+", "1")); @@ -383,6 +385,8 @@ public abstract class AbstractMqttAttributesIntegrationTest extends AbstractMqtt doPostAsync("/api/plugins/telemetry/DEVICE/" + savedDevice.getId().getId() + "/attributes/SHARED_SCOPE", SHARED_ATTRIBUTES_PAYLOAD, String.class, status().isOk()); client.publishAndWait(attrPubTopic, getAttributesProtoPayloadBytes()); client.subscribeAndWait(attrSubTopic, MqttQoS.AT_MOST_ONCE); + //RequestAttributes does not make any subscriptions in device actor + String update = getWsClient().waitForUpdate(); assertThat(update).as("ws update received").isNotBlank(); MqttTestCallback callback = new MqttTestCallback(attrSubTopic.replace("+", "1")); @@ -442,6 +446,7 @@ public abstract class AbstractMqttAttributesIntegrationTest extends AbstractMqtt assertThat(update).as("ws update received").isNotBlank(); client.subscribeAndWait(GATEWAY_ATTRIBUTES_RESPONSE_TOPIC, MqttQoS.AT_LEAST_ONCE); + //RequestAttributes does not make any subscriptions in device actor MqttTestCallback clientAttributesCallback = new MqttTestCallback(GATEWAY_ATTRIBUTES_RESPONSE_TOPIC); client.setCallback(clientAttributesCallback); @@ -495,6 +500,7 @@ public abstract class AbstractMqttAttributesIntegrationTest extends AbstractMqtt assertThat(update).as("ws update received").isNotBlank(); client.subscribeAndWait(GATEWAY_ATTRIBUTES_RESPONSE_TOPIC, MqttQoS.AT_LEAST_ONCE); + awaitForDeviceActorToReceiveSubscription(device.getId(), FeatureType.ATTRIBUTES, 1); MqttTestCallback clientAttributesCallback = new MqttTestCallback(GATEWAY_ATTRIBUTES_RESPONSE_TOPIC); client.setCallback(clientAttributesCallback); diff --git a/application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv3/rpc/AbstractMqttServerSideRpcIntegrationTest.java b/application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv3/rpc/AbstractMqttServerSideRpcIntegrationTest.java index 924b4d50a6..205386a32e 100644 --- a/application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv3/rpc/AbstractMqttServerSideRpcIntegrationTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv3/rpc/AbstractMqttServerSideRpcIntegrationTest.java @@ -223,7 +223,6 @@ public abstract class AbstractMqttServerSideRpcIntegrationTest extends AbstractM MqttTestCallback callback = new MqttTestCallback(GATEWAY_RPC_TOPIC); client.setCallback(callback); - client.subscribeAndWait(GATEWAY_RPC_TOPIC, MqttQoS.AT_MOST_ONCE); subscribeAndCheckSubscription(client, GATEWAY_RPC_TOPIC, savedDevice.getId(), FeatureType.RPC); String setGpioRequest = "{\"method\": \"toggle_gpio\", \"params\": {\"pin\":1}}"; diff --git a/application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv5/attributes/AbstractAttributesMqttV5Test.java b/application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv5/attributes/AbstractAttributesMqttV5Test.java index e3dfc6fb55..347b397ef5 100644 --- a/application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv5/attributes/AbstractAttributesMqttV5Test.java +++ b/application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv5/attributes/AbstractAttributesMqttV5Test.java @@ -21,6 +21,7 @@ import org.junit.Before; import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.server.common.data.device.profile.MqttTopics; import org.thingsboard.server.common.data.id.DeviceId; +import org.thingsboard.server.common.msg.session.FeatureType; import org.thingsboard.server.transport.mqtt.MqttTestConfigProperties; import org.thingsboard.server.transport.mqtt.mqttv5.AbstractMqttV5Test; import org.thingsboard.server.transport.mqtt.mqttv5.MqttV5TestCallback; @@ -104,6 +105,7 @@ public abstract class AbstractAttributesMqttV5Test extends AbstractMqttV5Test { MqttV5TestCallback onUpdateCallback = new MqttV5TestCallback(); client.setCallback(onUpdateCallback); client.subscribeAndWait(MqttTopics.DEVICE_ATTRIBUTES_TOPIC, MqttQoS.AT_MOST_ONCE); + awaitForDeviceActorToReceiveSubscription(savedDevice.getId(), FeatureType.ATTRIBUTES, 1); doPostAsync("/api/plugins/telemetry/DEVICE/" + savedDevice.getId().getId() + "/attributes/SHARED_SCOPE", SHARED_ATTRIBUTES_PAYLOAD, String.class, status().isOk()); onUpdateCallback.getSubscribeLatch().await(3, TimeUnit.SECONDS); diff --git a/application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv5/client/connection/AbstractMqttV5ClientConnectionTest.java b/application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv5/client/connection/AbstractMqttV5ClientConnectionTest.java index 81b015e245..93d349e0ec 100644 --- a/application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv5/client/connection/AbstractMqttV5ClientConnectionTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv5/client/connection/AbstractMqttV5ClientConnectionTest.java @@ -25,6 +25,7 @@ import org.eclipse.paho.mqttv5.common.packet.MqttReturnCode; import org.eclipse.paho.mqttv5.common.packet.MqttWireMessage; import org.junit.Assert; import org.thingsboard.server.common.data.device.profile.MqttTopics; +import org.thingsboard.server.common.msg.session.FeatureType; import org.thingsboard.server.transport.mqtt.AbstractMqttIntegrationTest; import org.thingsboard.server.transport.mqtt.mqttv5.MqttV5TestCallback; import org.thingsboard.server.transport.mqtt.mqttv5.MqttV5TestClient; @@ -101,6 +102,7 @@ public abstract class AbstractMqttV5ClientConnectionTest extends AbstractMqttInt MqttV5TestCallback onUpdateCallback = new MqttV5TestCallback(); client.setCallback(onUpdateCallback); client.subscribeAndWait(MqttTopics.DEVICE_ATTRIBUTES_TOPIC, MqttQoS.AT_MOST_ONCE); + awaitForDeviceActorToReceiveSubscription(savedDevice.getId(), FeatureType.ATTRIBUTES, 1); String payload = "{\"sharedStr\":\"" + StringUtils.repeat("*", valueLen) + "\"}"; diff --git a/application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv5/client/subscribe/AbstractMqttV5ClientSubscriptionTest.java b/application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv5/client/subscribe/AbstractMqttV5ClientSubscriptionTest.java index f681ad5b55..aebb5a7ed2 100644 --- a/application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv5/client/subscribe/AbstractMqttV5ClientSubscriptionTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv5/client/subscribe/AbstractMqttV5ClientSubscriptionTest.java @@ -22,6 +22,7 @@ import org.eclipse.paho.mqttv5.common.packet.MqttSubAck; import org.eclipse.paho.mqttv5.common.packet.MqttWireMessage; import org.junit.Assert; import org.thingsboard.server.common.data.device.profile.MqttTopics; +import org.thingsboard.server.common.msg.session.FeatureType; import org.thingsboard.server.transport.mqtt.AbstractMqttIntegrationTest; import org.thingsboard.server.transport.mqtt.mqttv5.MqttV5TestClient; @@ -34,6 +35,7 @@ public abstract class AbstractMqttV5ClientSubscriptionTest extends AbstractMqttI client.connectAndWait(accessToken); IMqttToken subscriptionResult = client.subscribeAndWait(MqttTopics.DEVICE_ATTRIBUTES_TOPIC, MqttQoS.AT_MOST_ONCE); + awaitForDeviceActorToReceiveSubscription(savedDevice.getId(), FeatureType.ATTRIBUTES, 1); MqttWireMessage response = subscriptionResult.getResponse(); @@ -52,6 +54,7 @@ public abstract class AbstractMqttV5ClientSubscriptionTest extends AbstractMqttI client.connectAndWait(accessToken); IMqttToken iMqttToken = client.subscribeAndWait("wrong/topic/+", MqttQoS.AT_MOST_ONCE); + awaitForDeviceActorToReceiveSubscription(savedDevice.getId(), FeatureType.ATTRIBUTES, 0); Assert.assertEquals(MESSAGE_TYPE_SUBACK,iMqttToken.getResponse().getType()); MqttSubAck subAck = (MqttSubAck) iMqttToken.getResponse(); Assert.assertEquals(1, subAck.getReturnCodes().length); diff --git a/application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv5/client/unsubscribe/AbstractMqttV5ClientUnsubscribeTest.java b/application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv5/client/unsubscribe/AbstractMqttV5ClientUnsubscribeTest.java index 835e225da4..ca534b9999 100644 --- a/application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv5/client/unsubscribe/AbstractMqttV5ClientUnsubscribeTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv5/client/unsubscribe/AbstractMqttV5ClientUnsubscribeTest.java @@ -22,6 +22,7 @@ import org.eclipse.paho.mqttv5.common.packet.MqttUnsubAck; import org.eclipse.paho.mqttv5.common.packet.MqttWireMessage; import org.junit.Assert; import org.thingsboard.server.common.data.device.profile.MqttTopics; +import org.thingsboard.server.common.msg.session.FeatureType; import org.thingsboard.server.transport.mqtt.AbstractMqttIntegrationTest; import org.thingsboard.server.transport.mqtt.mqttv5.MqttV5TestClient; @@ -34,6 +35,7 @@ public abstract class AbstractMqttV5ClientUnsubscribeTest extends AbstractMqttIn client.connectAndWait(accessToken); client.subscribeAndWait(MqttTopics.DEVICE_ATTRIBUTES_TOPIC, MqttQoS.AT_MOST_ONCE); + awaitForDeviceActorToReceiveSubscription(savedDevice.getId(), FeatureType.ATTRIBUTES, 1); IMqttToken unsubscribeResult = client.unsubscribeAndWait(MqttTopics.DEVICE_ATTRIBUTES_TOPIC); MqttWireMessage response = unsubscribeResult.getResponse(); Assert.assertEquals(MESSAGE_TYPE_UNSUBACK, response.getType()); diff --git a/application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv5/rpc/AbstractMqttV5RpcTest.java b/application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv5/rpc/AbstractMqttV5RpcTest.java index b6604439da..aecd1124e3 100644 --- a/application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv5/rpc/AbstractMqttV5RpcTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv5/rpc/AbstractMqttV5RpcTest.java @@ -22,6 +22,7 @@ import org.eclipse.paho.mqttv5.common.MqttException; import org.eclipse.paho.mqttv5.common.MqttMessage; import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.server.common.data.StringUtils; +import org.thingsboard.server.common.msg.session.FeatureType; import org.thingsboard.server.transport.mqtt.mqttv5.AbstractMqttV5Test; import org.thingsboard.server.transport.mqtt.mqttv5.MqttV5TestCallback; import org.thingsboard.server.transport.mqtt.mqttv5.MqttV5TestClient; @@ -45,6 +46,7 @@ public abstract class AbstractMqttV5RpcTest extends AbstractMqttV5Test { MqttV5TestCallback callback = new MqttV5TestCallback(DEVICE_RPC_REQUESTS_SUB_TOPIC.replace("+", "0")); client.setCallback(callback); client.subscribeAndWait(DEVICE_RPC_REQUESTS_SUB_TOPIC, MqttQoS.AT_MOST_ONCE); + awaitForDeviceActorToReceiveSubscription(savedDevice.getId(), FeatureType.RPC, 1); String setGpioRequest = "{\"method\":\"setGpio\",\"params\":{\"pin\": \"23\",\"value\": 1}}"; String result = doPostAsync("/api/rpc/oneway/" + savedDevice.getId(), setGpioRequest, String.class, status().isOk()); @@ -59,6 +61,7 @@ public abstract class AbstractMqttV5RpcTest extends AbstractMqttV5Test { MqttV5TestClient client = new MqttV5TestClient(); client.connectAndWait(accessToken); client.subscribeAndWait(DEVICE_RPC_REQUESTS_SUB_TOPIC, MqttQoS.AT_LEAST_ONCE); + awaitForDeviceActorToReceiveSubscription(savedDevice.getId(), FeatureType.RPC, 1); MqttV5TestRpcCallback callback = new MqttV5TestRpcCallback(client, DEVICE_RPC_REQUESTS_SUB_TOPIC.replace("+", "0")); client.setCallback(callback); String setGpioRequest = "{\"method\":\"setGpio\",\"params\":{\"pin\": \"26\",\"value\": 1}}"; From ba8f27fa76279aee680ec1d94841cf431951da95 Mon Sep 17 00:00:00 2001 From: ViacheslavKlimov Date: Wed, 15 Mar 2023 12:32:23 +0200 Subject: [PATCH 22/28] Notification system refactoring and improvements --- .../main/data/upgrade/3.4.4/schema_update.sql | 24 ++-- .../server/actors/tenant/TenantActor.java | 1 + .../NotificationRuleController.java | 8 +- .../NotificationTargetController.java | 10 +- .../NotificationExecutorService.java | 6 +- .../DefaultNotificationCenter.java | 50 +++----- ...aultNotificationRuleProcessingService.java | 120 ++++++++---------- .../trigger/AlarmCommentTriggerProcessor.java | 10 +- .../DeviceInactivityTriggerProcessor.java | 10 +- .../trigger/EntityActionTriggerProcessor.java | 8 +- ...neMsgNotificationRuleTriggerProcessor.java | 27 ++++ .../queue/DefaultTbCoreConsumerService.java | 3 +- .../DefaultTbRuleEngineConsumerService.java | 4 +- .../processing/AbstractConsumerService.java | 4 - .../service/ws/DefaultWebSocketService.java | 3 +- .../DefaultNotificationCommandsHandler.java | 108 +++++++--------- .../sub/NotificationRequestUpdate.java | 2 - .../notification/sub/NotificationUpdate.java | 10 +- .../src/main/resources/thingsboard.yml | 3 - .../AbstractNotificationApiTest.java | 8 +- .../notification/NotificationApiTest.java | 63 +++------ .../notification/NotificationRuleApiTest.java | 24 ++-- .../NotificationTemplateApiTest.java | 6 +- .../NotificationRequestService.java | 2 +- .../dao/notification/NotificationService.java | 2 - .../server/dao/user/UserService.java | 2 +- .../server/common/data/CacheConstants.java | 1 - .../data/notification/Notification.java | 11 -- .../NotificationDeliveryMethod.java | 2 +- .../NotificationProcessingContext.java | 10 +- .../trigger/NotificationRuleTriggerType.java | 17 +-- .../targets/NotificationTargetType.java | 2 +- .../targets/platform/UsersFilterType.java | 4 - .../DeliveryMethodNotificationTemplate.java | 2 +- ...ebDeliveryMethodNotificationTemplate.java} | 10 +- .../DefaultNotificationRequestService.java | 39 +----- .../DefaultNotificationService.java | 6 - .../DefaultNotificationTargetService.java | 2 +- .../dao/notification/NotificationDao.java | 2 - .../cache/NotificationRequestCacheKey.java | 43 ------- .../cache/NotificationRequestCacheValue.java | 38 ------ .../NotificationRequestCaffeineCache.java | 32 ----- .../cache/NotificationRequestRedisCache.java | 35 ----- .../sql/notification/JpaNotificationDao.java | 5 - .../JpaNotificationRequestDao.java | 2 +- .../notification/NotificationRepository.java | 7 - .../NotificationRequestRepository.java | 2 +- .../server/dao/user/UserServiceImpl.java | 2 +- .../resources/sql/schema-entities-idx.sql | 3 + .../main/resources/sql/schema-entities.sql | 1 - .../rule/engine/api/NotificationCenter.java | 2 - 51 files changed, 275 insertions(+), 523 deletions(-) create mode 100644 application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/RuleEngineMsgNotificationRuleTriggerProcessor.java rename common/data/src/main/java/org/thingsboard/server/common/data/notification/template/{PushDeliveryMethodNotificationTemplate.java => WebDeliveryMethodNotificationTemplate.java} (77%) delete mode 100644 dao/src/main/java/org/thingsboard/server/dao/notification/cache/NotificationRequestCacheKey.java delete mode 100644 dao/src/main/java/org/thingsboard/server/dao/notification/cache/NotificationRequestCacheValue.java delete mode 100644 dao/src/main/java/org/thingsboard/server/dao/notification/cache/NotificationRequestCaffeineCache.java delete mode 100644 dao/src/main/java/org/thingsboard/server/dao/notification/cache/NotificationRequestRedisCache.java diff --git a/application/src/main/data/upgrade/3.4.4/schema_update.sql b/application/src/main/data/upgrade/3.4.4/schema_update.sql index 75cb42e1cf..7030ff7af1 100644 --- a/application/src/main/data/upgrade/3.4.4/schema_update.sql +++ b/application/src/main/data/upgrade/3.4.4/schema_update.sql @@ -89,6 +89,10 @@ CREATE TABLE IF NOT EXISTS alarm_comment ( ) PARTITION BY RANGE (created_time); CREATE INDEX IF NOT EXISTS idx_alarm_comment_alarm_id ON alarm_comment(alarm_id); +-- ALARM COMMENTS END + +-- NOTIFICATIONS START + CREATE TABLE IF NOT EXISTS notification_target ( id UUID NOT NULL CONSTRAINT notification_target_pkey PRIMARY KEY, created_time BIGINT NOT NULL, @@ -122,7 +126,7 @@ CREATE TABLE IF NOT EXISTS notification_rule ( additional_config VARCHAR(255), CONSTRAINT uq_notification_rule_name UNIQUE (tenant_id, name) ); -CREATE INDEX IF NOT EXISTS idx_notification_rule_tenant_id_created_time ON notification_rule(tenant_id, created_time DESC); +CREATE INDEX IF NOT EXISTS idx_notification_rule_tenant_id_trigger_type_created_time ON notification_rule(tenant_id, trigger_type, created_time DESC); CREATE TABLE IF NOT EXISTS notification_request ( id UUID NOT NULL CONSTRAINT notification_request_pkey PRIMARY KEY, @@ -139,9 +143,12 @@ CREATE TABLE IF NOT EXISTS notification_request ( status VARCHAR(32), stats VARCHAR(10000) ); -CREATE INDEX IF NOT EXISTS idx_notification_request_tenant_id_originator_type_created_time ON notification_request(tenant_id, originator_entity_type, created_time DESC); -CREATE INDEX IF NOT EXISTS idx_notification_request_rule_id_originator_entity_id ON notification_request(rule_id, originator_entity_id); -CREATE INDEX IF NOT EXISTS idx_notification_request_status ON notification_request(status); +CREATE INDEX IF NOT EXISTS idx_notification_request_tenant_id_user_created_time ON notification_request(tenant_id, created_time DESC) + WHERE originator_entity_type = 'USER'; +CREATE INDEX IF NOT EXISTS idx_notification_request_rule_id_originator_entity_id ON notification_request(rule_id, originator_entity_id) + WHERE originator_entity_type = 'ALARM'; +CREATE INDEX IF NOT EXISTS idx_notification_request_status ON notification_request(status) + WHERE status = 'SCHEDULED'; CREATE TABLE IF NOT EXISTS notification ( id UUID NOT NULL, @@ -152,11 +159,12 @@ CREATE TABLE IF NOT EXISTS notification ( subject VARCHAR(255), text VARCHAR(1000) NOT NULL, additional_config VARCHAR(1000), - info VARCHAR(1000), status VARCHAR(32) ) PARTITION BY RANGE (created_time); -CREATE INDEX IF NOT EXISTS idx_notification_id_recipient_id ON notification(id, recipient_id); -CREATE INDEX IF NOT EXISTS idx_notification_recipient_id_status_created_time ON notification(recipient_id, status, created_time DESC); +CREATE INDEX IF NOT EXISTS idx_notification_id ON notification(id); +CREATE INDEX IF NOT EXISTS idx_notification_recipient_id_created_time ON notification(recipient_id, created_time DESC); + +-- NOTIFICATIONS END ALTER TABLE tb_user ADD COLUMN IF NOT EXISTS phone VARCHAR(255); @@ -166,8 +174,6 @@ CREATE TABLE IF NOT EXISTS user_settings ( CONSTRAINT fk_user_id FOREIGN KEY (user_id) REFERENCES tb_user(id) ON DELETE CASCADE ); --- ALARM COMMENTS END - -- ALARM INFO VIEW DROP VIEW IF EXISTS alarm_info CASCADE; diff --git a/application/src/main/java/org/thingsboard/server/actors/tenant/TenantActor.java b/application/src/main/java/org/thingsboard/server/actors/tenant/TenantActor.java index e176895ac8..dc9413bf2d 100644 --- a/application/src/main/java/org/thingsboard/server/actors/tenant/TenantActor.java +++ b/application/src/main/java/org/thingsboard/server/actors/tenant/TenantActor.java @@ -208,6 +208,7 @@ public class TenantActor extends RuleChainManagerActor { log.trace("[{}] Ack message because Rule Engine is disabled", tenantId); tbMsg.getCallback().onSuccess(); } + systemContext.getNotificationRuleProcessingService().process(tenantId, tbMsg); } private void onRuleChainMsg(RuleChainAwareMsg msg) { 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 8c08e1eab2..fe326ef6b8 100644 --- a/application/src/main/java/org/thingsboard/server/controller/NotificationRuleController.java +++ b/application/src/main/java/org/thingsboard/server/controller/NotificationRuleController.java @@ -55,7 +55,7 @@ public class NotificationRuleController extends BaseController { private final NotificationRuleService notificationRuleService; @PostMapping("/rule") - @PreAuthorize("hasAnyAuthority('TENANT_ADMIN')") + @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')") public NotificationRule saveNotificationRule(@RequestBody @Valid NotificationRule notificationRule) throws Exception { notificationRule.setTenantId(getTenantId()); checkEntity(notificationRule.getId(), notificationRule, NOTIFICATION); @@ -63,14 +63,14 @@ public class NotificationRuleController extends BaseController { } @GetMapping("/rule/{id}") - @PreAuthorize("hasAnyAuthority('TENANT_ADMIN')") + @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')") public NotificationRuleInfo getNotificationRuleById(@PathVariable UUID id) throws ThingsboardException { NotificationRuleId notificationRuleId = new NotificationRuleId(id); return checkEntityId(notificationRuleId, notificationRuleService::findNotificationRuleInfoById, Operation.READ); } @GetMapping("/rules") - @PreAuthorize("hasAnyAuthority('TENANT_ADMIN')") + @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')") public PageData getNotificationRules(@RequestParam int pageSize, @RequestParam int page, @RequestParam(required = false) String textSearch, @@ -83,7 +83,7 @@ public class NotificationRuleController extends BaseController { } @DeleteMapping("/rule/{id}") - @PreAuthorize("hasAnyAuthority('TENANT_ADMIN')") + @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')") public void deleteNotificationRule(@PathVariable UUID id, @AuthenticationPrincipal SecurityUser user) throws Exception { NotificationRuleId notificationRuleId = new NotificationRuleId(id); 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 b07cff0849..4f4380c2df 100644 --- a/application/src/main/java/org/thingsboard/server/controller/NotificationTargetController.java +++ b/application/src/main/java/org/thingsboard/server/controller/NotificationTargetController.java @@ -33,15 +33,16 @@ import org.thingsboard.server.common.data.User; import org.thingsboard.server.common.data.exception.ThingsboardException; import org.thingsboard.server.common.data.id.CustomerId; import org.thingsboard.server.common.data.id.NotificationTargetId; +import org.thingsboard.server.common.data.id.UserId; import org.thingsboard.server.common.data.notification.targets.NotificationTarget; import org.thingsboard.server.common.data.notification.targets.NotificationTargetConfig; import org.thingsboard.server.common.data.notification.targets.NotificationTargetType; import org.thingsboard.server.common.data.notification.targets.platform.CustomerUsersFilter; import org.thingsboard.server.common.data.notification.targets.platform.PlatformUsersNotificationTargetConfig; +import org.thingsboard.server.common.data.notification.targets.platform.UserListFilter; import org.thingsboard.server.common.data.notification.targets.platform.UsersFilter; import org.thingsboard.server.common.data.notification.targets.platform.UsersFilterType; import org.thingsboard.server.common.data.page.PageData; -import org.thingsboard.server.common.data.page.PageDataIterable; import org.thingsboard.server.common.data.page.PageLink; import org.thingsboard.server.dao.notification.NotificationTargetService; import org.thingsboard.server.queue.util.TbCoreComponent; @@ -159,11 +160,8 @@ public class NotificationTargetController extends BaseController { // generic permission for users UsersFilter usersFilter = ((PlatformUsersNotificationTargetConfig) targetConfig).getUsersFilter(); if (usersFilter.getType() == UsersFilterType.USER_LIST) { - PageDataIterable recipients = new PageDataIterable<>(pageLink -> { - return notificationTargetService.findRecipientsForNotificationTargetConfig(user.getTenantId(), null, targetConfig, pageLink); - }, 200); - for (User recipient : recipients) { - checkEntity(user, recipient, Operation.READ); + for (UUID recipientId : ((UserListFilter) usersFilter).getUsersIds()) { + checkUserId(new UserId(recipientId), Operation.READ); } } else if (usersFilter.getType() == UsersFilterType.CUSTOMER_USERS) { CustomerId customerId = new CustomerId(((CustomerUsersFilter) usersFilter).getCustomerId()); diff --git a/application/src/main/java/org/thingsboard/server/service/executors/NotificationExecutorService.java b/application/src/main/java/org/thingsboard/server/service/executors/NotificationExecutorService.java index 39b472c988..53d55fdad6 100644 --- a/application/src/main/java/org/thingsboard/server/service/executors/NotificationExecutorService.java +++ b/application/src/main/java/org/thingsboard/server/service/executors/NotificationExecutorService.java @@ -22,12 +22,12 @@ import org.thingsboard.common.util.AbstractListeningExecutor; @Component public class NotificationExecutorService extends AbstractListeningExecutor { - @Value("${notification_system.thread_pool_size}") - private int notificationSystemExecutorThreadPoolSize; + @Value("${notification_system.thread_pool_size:30}") + private int threadPoolSize; @Override protected int getThreadPollSize() { - return notificationSystemExecutorThreadPoolSize; + return threadPoolSize; } } diff --git a/application/src/main/java/org/thingsboard/server/service/notification/DefaultNotificationCenter.java b/application/src/main/java/org/thingsboard/server/service/notification/DefaultNotificationCenter.java index 0f165fb0d8..81c0fbf6a5 100644 --- a/application/src/main/java/org/thingsboard/server/service/notification/DefaultNotificationCenter.java +++ b/application/src/main/java/org/thingsboard/server/service/notification/DefaultNotificationCenter.java @@ -45,7 +45,7 @@ import org.thingsboard.server.common.data.notification.targets.NotificationTarge import org.thingsboard.server.common.data.notification.targets.slack.SlackNotificationTargetConfig; import org.thingsboard.server.common.data.notification.template.DeliveryMethodNotificationTemplate; import org.thingsboard.server.common.data.notification.template.NotificationTemplate; -import org.thingsboard.server.common.data.notification.template.PushDeliveryMethodNotificationTemplate; +import org.thingsboard.server.common.data.notification.template.WebDeliveryMethodNotificationTemplate; import org.thingsboard.server.common.data.page.PageDataIterable; import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent; import org.thingsboard.server.common.msg.queue.ServiceType; @@ -82,7 +82,7 @@ import java.util.stream.Collectors; @Slf4j @RequiredArgsConstructor @SuppressWarnings({"UnstableApiUsage", "rawtypes"}) -public class DefaultNotificationCenter extends AbstractSubscriptionService implements NotificationCenter, NotificationChannel { +public class DefaultNotificationCenter extends AbstractSubscriptionService implements NotificationCenter, NotificationChannel { private final NotificationTargetService notificationTargetService; private final NotificationRequestService notificationRequestService; @@ -93,6 +93,7 @@ public class DefaultNotificationCenter extends AbstractSubscriptionService imple private final DbCallbackExecutorService dbCallbackExecutorService; private final NotificationsTopicService notificationsTopicService; private final TbQueueProducerProvider producerProvider; + private Map channels; @@ -244,7 +245,7 @@ public class DefaultNotificationCenter extends AbstractSubscriptionService imple } @Override - public ListenableFuture sendNotification(User recipient, PushDeliveryMethodNotificationTemplate processedTemplate, NotificationProcessingContext ctx) { + public ListenableFuture sendNotification(User recipient, WebDeliveryMethodNotificationTemplate processedTemplate, NotificationProcessingContext ctx) { NotificationRequest request = ctx.getRequest(); Notification notification = Notification.builder() .requestId(request.getId()) @@ -264,8 +265,8 @@ public class DefaultNotificationCenter extends AbstractSubscriptionService imple } NotificationUpdate update = NotificationUpdate.builder() + .created(true) .notification(notification) - .updateType(ComponentLifecycleEvent.CREATED) .build(); return onNotificationUpdate(recipient.getTenantId(), recipient.getId(), update); } @@ -282,8 +283,8 @@ public class DefaultNotificationCenter extends AbstractSubscriptionService imple notification = notificationService.saveNotification(TenantId.SYS_TENANT_ID, notification); NotificationUpdate update = NotificationUpdate.builder() + .created(true) .notification(notification) - .updateType(ComponentLifecycleEvent.CREATED) .build(); onNotificationUpdate(tenantId, recipientId, update); } @@ -294,9 +295,9 @@ public class DefaultNotificationCenter extends AbstractSubscriptionService imple if (updated) { log.trace("Marked notification {} as read (recipient id: {}, tenant id: {})", notificationId, recipientId, tenantId); NotificationUpdate update = NotificationUpdate.builder() + .updated(true) .notificationId(notificationId) - .updatedStatus(NotificationStatus.READ) - .updateType(ComponentLifecycleEvent.UPDATED) + .newStatus(NotificationStatus.READ) .build(); onNotificationUpdate(tenantId, recipientId, update); } @@ -308,9 +309,9 @@ public class DefaultNotificationCenter extends AbstractSubscriptionService imple if (updatedCount > 0) { log.trace("Marked all notifications as read (recipient id: {}, tenant id: {})", recipientId, tenantId); NotificationUpdate update = NotificationUpdate.builder() + .updated(true) .allNotifications(true) - .updatedStatus(NotificationStatus.READ) - .updateType(ComponentLifecycleEvent.UPDATED) + .newStatus(NotificationStatus.READ) .build(); onNotificationUpdate(tenantId, recipientId, update); } @@ -322,43 +323,28 @@ public class DefaultNotificationCenter extends AbstractSubscriptionService imple boolean deleted = notificationService.deleteNotification(tenantId, recipientId, notificationId); if (deleted) { NotificationUpdate update = NotificationUpdate.builder() + .deleted(true) .notification(notification) - .updateType(ComponentLifecycleEvent.DELETED) .build(); onNotificationUpdate(tenantId, recipientId, update); } } - @Override - public NotificationRequest updateNotificationRequest(TenantId tenantId, NotificationRequest notificationRequest) { - log.debug("Updating notification request {}", notificationRequest.getId()); - notificationRequest = notificationRequestService.saveNotificationRequest(tenantId, notificationRequest); - // marking related notifications as unread: TODO: causes each subscription to fetch notifications on each request update - notificationService.updateNotificationsStatusByRequestId(tenantId, notificationRequest.getId(), NotificationStatus.SENT); - - // TODO: no need to send request update for other than PLATFORM_USERS target type - onNotificationRequestUpdate(tenantId, NotificationRequestUpdate.builder() - .notificationRequestId(notificationRequest.getId()) - .notificationInfo(notificationRequest.getInfo()) - .deleted(false) - .build()); - return notificationRequest; - } - @Override public void deleteNotificationRequest(TenantId tenantId, NotificationRequestId notificationRequestId) { log.debug("Deleting notification request {}", notificationRequestId); NotificationRequest notificationRequest = notificationRequestService.findNotificationRequestById(tenantId, notificationRequestId); - notificationRequestService.deleteNotificationRequest(tenantId, notificationRequest); + notificationRequestService.deleteNotificationRequest(tenantId, notificationRequestId); - // TODO: no need to send request update for other than PLATFORM_USERS target type if (notificationRequest.isSent()) { + // TODO: no need to send request update for other than PLATFORM_USERS target type onNotificationRequestUpdate(tenantId, NotificationRequestUpdate.builder() .notificationRequestId(notificationRequestId) .deleted(true) .build()); + } else if (notificationRequest.isScheduled()) { + clusterService.broadcastEntityStateChangeEvent(tenantId, notificationRequestId, ComponentLifecycleEvent.DELETED); } - clusterService.broadcastEntityStateChangeEvent(tenantId, notificationRequestId, ComponentLifecycleEvent.DELETED); } private void forwardToNotificationSchedulerService(TenantId tenantId, NotificationRequestId notificationRequestId) { @@ -397,7 +383,7 @@ public class DefaultNotificationCenter extends AbstractSubscriptionService imple @Override public NotificationDeliveryMethod getDeliveryMethod() { - return NotificationDeliveryMethod.PUSH; + return NotificationDeliveryMethod.WEB; } @Override @@ -406,9 +392,9 @@ public class DefaultNotificationCenter extends AbstractSubscriptionService imple } @Autowired - public void setChannels(List channels, NotificationCenter websocketNotificationChannel) { + public void setChannels(List channels, NotificationCenter webNotificationChannel) { this.channels = channels.stream().collect(Collectors.toMap(NotificationChannel::getDeliveryMethod, c -> c)); - this.channels.put(NotificationDeliveryMethod.PUSH, (NotificationChannel) websocketNotificationChannel); + this.channels.put(NotificationDeliveryMethod.WEB, (NotificationChannel) webNotificationChannel); } } diff --git a/application/src/main/java/org/thingsboard/server/service/notification/rule/DefaultNotificationRuleProcessingService.java b/application/src/main/java/org/thingsboard/server/service/notification/rule/DefaultNotificationRuleProcessingService.java index c17b8f3bcd..c62c03f1f5 100644 --- a/application/src/main/java/org/thingsboard/server/service/notification/rule/DefaultNotificationRuleProcessingService.java +++ b/application/src/main/java/org/thingsboard/server/service/notification/rule/DefaultNotificationRuleProcessingService.java @@ -15,16 +15,13 @@ */ package org.thingsboard.server.service.notification.rule; -import com.google.common.util.concurrent.ListenableFuture; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Lazy; import org.springframework.context.event.EventListener; import org.springframework.stereotype.Service; -import org.thingsboard.common.util.DonAsynchron; import org.thingsboard.rule.engine.api.NotificationCenter; -import org.thingsboard.server.common.data.DataConstants; import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.alarm.Alarm; import org.thingsboard.server.common.data.id.EntityId; @@ -44,49 +41,45 @@ import org.thingsboard.server.common.msg.TbMsg; import org.thingsboard.server.common.msg.plugin.ComponentLifecycleMsg; import org.thingsboard.server.dao.notification.NotificationRequestService; import org.thingsboard.server.dao.notification.NotificationRuleService; -import org.thingsboard.server.service.executors.DbCallbackExecutorService; +import org.thingsboard.server.queue.discovery.PartitionService; import org.thingsboard.server.service.executors.NotificationExecutorService; import org.thingsboard.server.service.notification.rule.trigger.AlarmTriggerProcessor.AlarmTriggerObject; import org.thingsboard.server.service.notification.rule.trigger.NotificationRuleTriggerProcessor; import org.thingsboard.server.service.notification.rule.trigger.RuleEngineComponentLifecycleEventTriggerProcessor.RuleEngineComponentLifecycleEventTriggerObject; +import org.thingsboard.server.service.notification.rule.trigger.RuleEngineMsgNotificationRuleTriggerProcessor; import java.util.Collection; +import java.util.EnumMap; +import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Set; import java.util.UUID; import java.util.stream.Collectors; @Service @RequiredArgsConstructor @Slf4j +@SuppressWarnings("rawtypes") public class DefaultNotificationRuleProcessingService implements NotificationRuleProcessingService { private final NotificationRuleService notificationRuleService; private final NotificationRequestService notificationRequestService; @Autowired @Lazy private NotificationCenter notificationCenter; - private Map triggerProcessors; - private final NotificationExecutorService notificationExecutor; - private final DbCallbackExecutorService dbCallbackExecutor; - private final Map msgTypeToTriggerType = Map.of( - DataConstants.INACTIVITY_EVENT, NotificationRuleTriggerType.DEVICE_INACTIVITY, - DataConstants.ENTITY_CREATED, NotificationRuleTriggerType.ENTITY_ACTION, - DataConstants.ENTITY_UPDATED, NotificationRuleTriggerType.ENTITY_ACTION, - DataConstants.ENTITY_DELETED, NotificationRuleTriggerType.ENTITY_ACTION, - DataConstants.COMMENT_CREATED, NotificationRuleTriggerType.ALARM_COMMENT, - DataConstants.COMMENT_UPDATED, NotificationRuleTriggerType.ALARM_COMMENT - ); + private final Map triggerProcessors = new EnumMap<>(NotificationRuleTriggerType.class); + + private final Map ruleEngineMsgTypeToTriggerType = new HashMap<>(); @Override public void process(TenantId tenantId, TbMsg ruleEngineMsg) { String msgType = ruleEngineMsg.getType(); - NotificationRuleTriggerType triggerType = msgTypeToTriggerType.get(msgType); + NotificationRuleTriggerType triggerType = ruleEngineMsgTypeToTriggerType.get(msgType); if (triggerType == null) { return; } - processTrigger(tenantId, triggerType, ruleEngineMsg.getOriginator(), ruleEngineMsg); } @@ -113,55 +106,37 @@ public class DefaultNotificationRuleProcessingService implements NotificationRul } private void processTrigger(TenantId tenantId, NotificationRuleTriggerType triggerType, EntityId originatorEntityId, Object triggerObject) { - ListenableFuture> rulesFuture = dbCallbackExecutor.submit(() -> { - return notificationRuleService.findNotificationRulesByTenantIdAndTriggerType(tenantId, triggerType); - }); - DonAsynchron.withCallback(rulesFuture, rules -> { - for (NotificationRule rule : rules) { - notificationExecutor.submit(() -> { - processNotificationRule(rule, originatorEntityId, triggerObject); - }); - } - }, e -> { - log.error("Failed to find notification rules by trigger type {}", triggerType, e); - }); + List rules = notificationRuleService.findNotificationRulesByTenantIdAndTriggerType(tenantId, triggerType); + for (NotificationRule rule : rules) { + notificationExecutor.submit(() -> { + processNotificationRule(rule, originatorEntityId, triggerObject); + }); + } } private void processNotificationRule(NotificationRule rule, EntityId originatorEntityId, Object triggerObject) { NotificationRuleTriggerConfig triggerConfig = rule.getTriggerConfig(); log.debug("Processing notification rule '{}' for trigger type {}", rule.getName(), rule.getTriggerType()); - if (triggerConfig.getTriggerType().isUpdatable()) { + if (matchesClearRule(triggerObject, triggerConfig)) { List notificationRequests = notificationRequestService.findNotificationRequestsByRuleIdAndOriginatorEntityId(rule.getTenantId(), rule.getId(), originatorEntityId); - if (!notificationRequests.isEmpty()) { - if (matchesClearRule(triggerObject, triggerConfig)) { - notificationRequests = notificationRequests.stream() - .filter(notificationRequest -> { - if (!notificationRequest.isSent()) { - dbCallbackExecutor.submit(() -> { - notificationCenter.deleteNotificationRequest(rule.getTenantId(), notificationRequest.getId()); - }); - return false; - } else { - return true; - } - }) - .collect(Collectors.toList()); - // not returning because we need to update notifications if any - } - - NotificationInfo notificationInfo = constructNotificationInfo(triggerObject, triggerConfig); - for (NotificationRequest notificationRequest : notificationRequests) { - NotificationInfo previousNotificationInfo = notificationRequest.getInfo(); - if (!notificationInfo.equals(previousNotificationInfo)) { - notificationRequest.setInfo(notificationInfo); - dbCallbackExecutor.submit(() -> { - notificationCenter.updateNotificationRequest(rule.getTenantId(), notificationRequest); - }); - } - } + if (notificationRequests.isEmpty()) { return; } + + List targets = notificationRequests.stream() + .filter(NotificationRequest::isSent) + .flatMap(notificationRequest -> notificationRequest.getTargets().stream()) + .distinct().collect(Collectors.toList()); + NotificationInfo notificationInfo = constructNotificationInfo(triggerObject, triggerConfig); + submitNotificationRequest(targets, rule, originatorEntityId, notificationInfo, 0); + + notificationRequests.forEach(notificationRequest -> { + if (notificationRequest.isScheduled()) { + notificationCenter.deleteNotificationRequest(rule.getTenantId(), notificationRequest.getId()); + } + }); + return; } if (!matchesFilter(triggerObject, triggerConfig)) { @@ -170,14 +145,7 @@ public class DefaultNotificationRuleProcessingService implements NotificationRul NotificationInfo notificationInfo = constructNotificationInfo(triggerObject, triggerConfig); rule.getRecipientsConfig().getTargetsTable().forEach((delay, targets) -> { - notificationExecutor.submit(() -> { - try { - log.debug("Submitting notification request for rule '{}' with delay of {} sec to targets {}", rule.getName(), delay, targets); - submitNotificationRequest(targets, rule, originatorEntityId, notificationInfo, delay); - } catch (Exception e) { - log.error("Failed to submit notification request for rule {}", rule.getId(), e); - } - }); + submitNotificationRequest(targets, rule, originatorEntityId, notificationInfo, delay); }); } @@ -208,7 +176,14 @@ public class DefaultNotificationRuleProcessingService implements NotificationRul .ruleId(rule.getId()) .originatorEntityId(originatorEntityId) .build(); - notificationCenter.processNotificationRequest(rule.getTenantId(), notificationRequest); + notificationExecutor.submit(() -> { + try { + log.debug("Submitting notification request for rule '{}' with delay of {} sec to targets {}", rule.getName(), delayInSec, targets); + notificationCenter.processNotificationRequest(rule.getTenantId(), notificationRequest); + } catch (Exception e) { + log.error("Failed to process notification request for rule {}", rule.getId(), e); + } + }); } @EventListener(ComponentLifecycleMsg.class) @@ -220,7 +195,7 @@ public class DefaultNotificationRuleProcessingService implements NotificationRul TenantId tenantId = componentLifecycleMsg.getTenantId(); NotificationRuleId notificationRuleId = (NotificationRuleId) componentLifecycleMsg.getEntityId(); - dbCallbackExecutor.submit(() -> { + notificationExecutor.submit(() -> { List scheduledForRule = notificationRequestService.findNotificationRequestsIdsByStatusAndRuleId(tenantId, NotificationRequestStatus.SCHEDULED, notificationRuleId); for (NotificationRequestId notificationRequestId : scheduledForRule) { notificationCenter.deleteNotificationRequest(tenantId, notificationRequestId); @@ -230,8 +205,15 @@ public class DefaultNotificationRuleProcessingService implements NotificationRul @Autowired public void setTriggerProcessors(Collection processors) { - this.triggerProcessors = processors.stream() - .collect(Collectors.toMap(NotificationRuleTriggerProcessor::getTriggerType, p -> p)); + processors.forEach(processor -> { + triggerProcessors.put(processor.getTriggerType(), processor); + if (processor instanceof RuleEngineMsgNotificationRuleTriggerProcessor) { + Set supportedMsgTypes = ((RuleEngineMsgNotificationRuleTriggerProcessor) processor).getSupportedMsgTypes(); + supportedMsgTypes.forEach(supportedMsgType -> { + ruleEngineMsgTypeToTriggerType.put(supportedMsgType, processor.getTriggerType()); + }); + } + }); } } diff --git a/application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/AlarmCommentTriggerProcessor.java b/application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/AlarmCommentTriggerProcessor.java index 28a03830bf..cd30d9b580 100644 --- a/application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/AlarmCommentTriggerProcessor.java +++ b/application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/AlarmCommentTriggerProcessor.java @@ -17,6 +17,7 @@ package org.thingsboard.server.service.notification.rule.trigger; import org.springframework.stereotype.Service; import org.thingsboard.common.util.JacksonUtil; +import org.thingsboard.server.common.data.DataConstants; import org.thingsboard.server.common.data.alarm.Alarm; import org.thingsboard.server.common.data.alarm.AlarmComment; import org.thingsboard.server.common.data.alarm.AlarmStatusFilter; @@ -26,10 +27,12 @@ import org.thingsboard.server.common.data.notification.rule.trigger.AlarmComment import org.thingsboard.server.common.data.notification.rule.trigger.NotificationRuleTriggerType; import org.thingsboard.server.common.msg.TbMsg; +import java.util.Set; + import static org.apache.commons.collections.CollectionUtils.isEmpty; @Service -public class AlarmCommentTriggerProcessor implements NotificationRuleTriggerProcessor { +public class AlarmCommentTriggerProcessor implements RuleEngineMsgNotificationRuleTriggerProcessor { @Override public boolean matchesFilter(TbMsg ruleEngineMsg, AlarmCommentNotificationRuleTriggerConfig triggerConfig) { @@ -61,4 +64,9 @@ public class AlarmCommentTriggerProcessor implements NotificationRuleTriggerProc return NotificationRuleTriggerType.ALARM_COMMENT; } + @Override + public Set getSupportedMsgTypes() { + return Set.of(DataConstants.COMMENT_CREATED, DataConstants.COMMENT_UPDATED); + } + } diff --git a/application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/DeviceInactivityTriggerProcessor.java b/application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/DeviceInactivityTriggerProcessor.java index a193368b12..9f7c2d9401 100644 --- a/application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/DeviceInactivityTriggerProcessor.java +++ b/application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/DeviceInactivityTriggerProcessor.java @@ -18,6 +18,7 @@ package org.thingsboard.server.service.notification.rule.trigger; import lombok.RequiredArgsConstructor; import org.apache.commons.collections.CollectionUtils; import org.springframework.stereotype.Service; +import org.thingsboard.server.common.data.DataConstants; import org.thingsboard.server.common.data.DeviceProfile; import org.thingsboard.server.common.data.id.DeviceId; import org.thingsboard.server.common.data.id.TenantId; @@ -28,9 +29,11 @@ import org.thingsboard.server.common.data.notification.rule.trigger.Notification import org.thingsboard.server.common.msg.TbMsg; import org.thingsboard.server.service.profile.TbDeviceProfileCache; +import java.util.Set; + @Service @RequiredArgsConstructor -public class DeviceInactivityTriggerProcessor implements NotificationRuleTriggerProcessor { +public class DeviceInactivityTriggerProcessor implements RuleEngineMsgNotificationRuleTriggerProcessor { private final TbDeviceProfileCache deviceProfileCache; @@ -62,4 +65,9 @@ public class DeviceInactivityTriggerProcessor implements NotificationRuleTrigger return NotificationRuleTriggerType.DEVICE_INACTIVITY; } + @Override + public Set getSupportedMsgTypes() { + return Set.of(DataConstants.INACTIVITY_EVENT); + } + } diff --git a/application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/EntityActionTriggerProcessor.java b/application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/EntityActionTriggerProcessor.java index 33ade0238a..60044dd96a 100644 --- a/application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/EntityActionTriggerProcessor.java +++ b/application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/EntityActionTriggerProcessor.java @@ -25,10 +25,11 @@ import org.thingsboard.server.common.data.notification.rule.trigger.EntityAction import org.thingsboard.server.common.data.notification.rule.trigger.NotificationRuleTriggerType; import org.thingsboard.server.common.msg.TbMsg; +import java.util.Set; import java.util.UUID; @Service -public class EntityActionTriggerProcessor implements NotificationRuleTriggerProcessor { +public class EntityActionTriggerProcessor implements RuleEngineMsgNotificationRuleTriggerProcessor { @Override public boolean matchesFilter(TbMsg ruleEngineMsg, EntityActionNotificationRuleTriggerConfig triggerConfig) { @@ -73,4 +74,9 @@ public class EntityActionTriggerProcessor implements NotificationRuleTriggerProc return NotificationRuleTriggerType.ENTITY_ACTION; } + @Override + public Set getSupportedMsgTypes() { + return Set.of(DataConstants.ENTITY_CREATED, DataConstants.ENTITY_UPDATED, DataConstants.ENTITY_DELETED); + } + } diff --git a/application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/RuleEngineMsgNotificationRuleTriggerProcessor.java b/application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/RuleEngineMsgNotificationRuleTriggerProcessor.java new file mode 100644 index 0000000000..8d200c4ae3 --- /dev/null +++ b/application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/RuleEngineMsgNotificationRuleTriggerProcessor.java @@ -0,0 +1,27 @@ +/** + * Copyright © 2016-2023 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.service.notification.rule.trigger; + +import org.thingsboard.server.common.data.notification.rule.trigger.NotificationRuleTriggerConfig; +import org.thingsboard.server.common.msg.TbMsg; + +import java.util.Set; + +public interface RuleEngineMsgNotificationRuleTriggerProcessor extends NotificationRuleTriggerProcessor { + + Set getSupportedMsgTypes(); + +} diff --git a/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbCoreConsumerService.java b/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbCoreConsumerService.java index baded64603..2e736fefe1 100644 --- a/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbCoreConsumerService.java +++ b/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbCoreConsumerService.java @@ -156,10 +156,9 @@ public class DefaultTbCoreConsumerService extends AbstractConsumerService jwtSettingsService, NotificationSchedulerService notificationSchedulerService) { - super(actorContext, encodingService, tenantProfileCache, deviceProfileCache, assetProfileCache, apiUsageStateService, partitionService, eventPublisher, notificationRuleProcessingService, tbCoreQueueFactory.createToCoreNotificationsMsgConsumer(), jwtSettingsService); + super(actorContext, encodingService, tenantProfileCache, deviceProfileCache, assetProfileCache, apiUsageStateService, partitionService, eventPublisher, tbCoreQueueFactory.createToCoreNotificationsMsgConsumer(), jwtSettingsService); this.mainConsumer = tbCoreQueueFactory.createToCoreMsgConsumer(); this.usageStatsConsumer = tbCoreQueueFactory.createToUsageStatsServiceMsgConsumer(); this.firmwareStatesConsumer = tbCoreQueueFactory.createToOtaPackageStateServiceMsgConsumer(); diff --git a/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbRuleEngineConsumerService.java b/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbRuleEngineConsumerService.java index 3bd2915465..4460654617 100644 --- a/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbRuleEngineConsumerService.java +++ b/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbRuleEngineConsumerService.java @@ -129,9 +129,8 @@ public class DefaultTbRuleEngineConsumerService extends AbstractConsumerService< TbTenantProfileCache tenantProfileCache, TbApiUsageStateService apiUsageStateService, PartitionService partitionService, ApplicationEventPublisher eventPublisher, - NotificationRuleProcessingService notificationRuleProcessingService, TbServiceInfoProvider serviceInfoProvider, QueueService queueService) { - super(actorContext, encodingService, tenantProfileCache, deviceProfileCache, assetProfileCache, apiUsageStateService, partitionService, eventPublisher, notificationRuleProcessingService, tbRuleEngineQueueFactory.createToRuleEngineNotificationsMsgConsumer(), Optional.empty()); + super(actorContext, encodingService, tenantProfileCache, deviceProfileCache, assetProfileCache, apiUsageStateService, partitionService, eventPublisher, tbRuleEngineQueueFactory.createToRuleEngineNotificationsMsgConsumer(), Optional.empty()); this.statisticsService = statisticsService; this.tbRuleEngineQueueFactory = tbRuleEngineQueueFactory; this.submitStrategyFactory = submitStrategyFactory; @@ -482,7 +481,6 @@ public class DefaultTbRuleEngineConsumerService extends AbstractConsumerService< } msg = new QueueToRuleEngineMsg(tenantId, tbMsg, relationTypes, toRuleEngineMsg.getFailureMessage()); actorContext.tell(msg); - notificationRuleProcessingService.process(tenantId, tbMsg); } @Scheduled(fixedDelayString = "${queue.rule-engine.stats.print-interval-ms}") diff --git a/application/src/main/java/org/thingsboard/server/service/queue/processing/AbstractConsumerService.java b/application/src/main/java/org/thingsboard/server/service/queue/processing/AbstractConsumerService.java index 460813af13..15471e25e1 100644 --- a/application/src/main/java/org/thingsboard/server/service/queue/processing/AbstractConsumerService.java +++ b/application/src/main/java/org/thingsboard/server/service/queue/processing/AbstractConsumerService.java @@ -34,7 +34,6 @@ import org.thingsboard.server.common.msg.TbActorMsg; import org.thingsboard.server.common.msg.plugin.ComponentLifecycleMsg; import org.thingsboard.server.common.msg.queue.ServiceType; import org.thingsboard.server.common.msg.queue.TbCallback; -import org.thingsboard.server.service.notification.rule.NotificationRuleProcessingService; import org.thingsboard.server.service.security.auth.jwt.settings.JwtSettingsService; import org.thingsboard.server.dao.tenant.TbTenantProfileCache; import org.thingsboard.server.queue.TbQueueConsumer; @@ -78,7 +77,6 @@ public abstract class AbstractConsumerService> nfConsumer; protected final Optional jwtSettingsService; @@ -88,7 +86,6 @@ public abstract class AbstractConsumerService> nfConsumer, Optional jwtSettingsService) { this.actorContext = actorContext; this.encodingService = encodingService; @@ -98,7 +95,6 @@ public abstract class AbstractConsumerService subscription.getLimit()) { - Set beyondLimit = subscription.getSortedNotifications().stream().skip(subscription.getLimit()) - .map(IdBased::getUuidId).collect(Collectors.toSet()); - beyondLimit.forEach(id -> subscription.getLatestUnreadNotifications().remove(id)); - } - sendUpdate(subscription.getSessionId(), subscription.createPartialUpdate(notification)); - break; - } - case UPDATED: { - if (update.getUpdatedStatus() == NotificationStatus.READ) { - if (update.isAllNotifications() || subscription.getLatestUnreadNotifications().containsKey(notificationId)) { - fetchUnreadNotifications(subscription); - sendUpdate(subscription.getSessionId(), subscription.createFullUpdate()); - } else { - subscription.getTotalUnreadCounter().decrementAndGet(); - sendUpdate(subscription.getSessionId(), subscription.createCountUpdate()); - } - } else if (notification.getStatus() != NotificationStatus.READ) { - if (subscription.getLatestUnreadNotifications().containsKey(notificationId)) { - subscription.getLatestUnreadNotifications().put(notificationId, notification); - sendUpdate(subscription.getSessionId(), subscription.createPartialUpdate(notification)); - } - } - break; + if (update.isCreated()) { + subscription.getLatestUnreadNotifications().put(notificationId, notification); + subscription.getTotalUnreadCounter().incrementAndGet(); + if (subscription.getLatestUnreadNotifications().size() > subscription.getLimit()) { + Set beyondLimit = subscription.getSortedNotifications().stream().skip(subscription.getLimit()) + .map(IdBased::getUuidId).collect(Collectors.toSet()); + beyondLimit.forEach(id -> subscription.getLatestUnreadNotifications().remove(id)); } - case DELETED: { - if (subscription.getLatestUnreadNotifications().containsKey(notificationId)) { + sendUpdate(subscription.getSessionId(), subscription.createPartialUpdate(notification)); + } else if (update.isUpdated()) { + if (update.getNewStatus() == NotificationStatus.READ) { + if (update.isAllNotifications() || subscription.getLatestUnreadNotifications().containsKey(notificationId)) { fetchUnreadNotifications(subscription); sendUpdate(subscription.getSessionId(), subscription.createFullUpdate()); - } else if (notification.getStatus() != NotificationStatus.READ) { + } else { subscription.getTotalUnreadCounter().decrementAndGet(); sendUpdate(subscription.getSessionId(), subscription.createCountUpdate()); } - break; + } else if (notification.getStatus() != NotificationStatus.READ) { + if (subscription.getLatestUnreadNotifications().containsKey(notificationId)) { + subscription.getLatestUnreadNotifications().put(notificationId, notification); + sendUpdate(subscription.getSessionId(), subscription.createPartialUpdate(notification)); + } + } + } else if (update.isDeleted()) { + if (subscription.getLatestUnreadNotifications().containsKey(notificationId)) { + fetchUnreadNotifications(subscription); + sendUpdate(subscription.getSessionId(), subscription.createFullUpdate()); + } else if (notification.getStatus() != NotificationStatus.READ) { + subscription.getTotalUnreadCounter().decrementAndGet(); + sendUpdate(subscription.getSessionId(), subscription.createCountUpdate()); } } } private void handleNotificationRequestUpdate(NotificationsSubscription subscription, NotificationRequestUpdate update) { log.trace("[{}, subId: {}] Handling notification request update: {}", subscription.getSessionId(), subscription.getSubscriptionId(), update); - fetchUnreadNotifications(subscription); // FIXME: figure out how not to fetch notifications on each request update... + fetchUnreadNotifications(subscription); sendUpdate(subscription.getSessionId(), subscription.createFullUpdate()); } @@ -191,47 +184,33 @@ public class DefaultNotificationCommandsHandler implements NotificationCommandsH private void handleNotificationUpdate(NotificationsCountSubscription subscription, NotificationUpdate update) { log.trace("[{}, subId: {}] Handling notification update for count sub: {}", subscription.getSessionId(), subscription.getSubscriptionId(), update); - Notification notification = update.getNotification(); - switch (update.getUpdateType()) { - case CREATED: { - subscription.getUnreadCounter().incrementAndGet(); - sendUpdate(subscription.getSessionId(), subscription.createUpdate()); - break; - } - case UPDATED: { - if (update.getUpdatedStatus() == NotificationStatus.READ) { - if (update.isAllNotifications()) { - fetchUnreadNotificationsCount(subscription); - } else { - subscription.getUnreadCounter().decrementAndGet(); - } - sendUpdate(subscription.getSessionId(), subscription.createUpdate()); - } - break; - } - case DELETED: { - if (notification.getStatus() != NotificationStatus.READ) { + if (update.isCreated()) { + subscription.getUnreadCounter().incrementAndGet(); + sendUpdate(subscription.getSessionId(), subscription.createUpdate()); + } else if (update.isUpdated()) { + if (update.getNewStatus() == NotificationStatus.READ) { + if (update.isAllNotifications()) { + fetchUnreadNotificationsCount(subscription); + } else { subscription.getUnreadCounter().decrementAndGet(); - sendUpdate(subscription.getSessionId(), subscription.createUpdate()); } - break; + sendUpdate(subscription.getSessionId(), subscription.createUpdate()); + } + } else if (update.isDeleted()) { + if (update.getNotification().getStatus() != NotificationStatus.READ) { + subscription.getUnreadCounter().decrementAndGet(); + sendUpdate(subscription.getSessionId(), subscription.createUpdate()); } } } private void handleNotificationRequestUpdate(NotificationsCountSubscription subscription, NotificationRequestUpdate update) { log.trace("[{}, subId: {}] Handling notification request update for count sub: {}", subscription.getSessionId(), subscription.getSubscriptionId(), update); - fetchUnreadNotificationsCount(subscription); // FIXME: figure out how not to fetch notifications on each request update... + fetchUnreadNotificationsCount(subscription); sendUpdate(subscription.getSessionId(), subscription.createUpdate()); } - private void sendUpdate(String sessionId, CmdUpdate update) { - log.trace("[{}, cmdId: {}] Sending WS update: {}", sessionId, update.getCmdId(), update); - wsService.sendWsMsg(sessionId, update); - } - - @Override public void handleMarkAsReadCmd(WebSocketSessionRef sessionRef, MarkNotificationsAsReadCmd cmd) { SecurityUser securityCtx = sessionRef.getSecurityCtx(); @@ -253,4 +232,9 @@ public class DefaultNotificationCommandsHandler implements NotificationCommandsH localSubscriptionService.cancelSubscription(sessionRef.getSessionId(), cmd.getCmdId()); } + private void sendUpdate(String sessionId, CmdUpdate update) { + log.trace("[{}, cmdId: {}] Sending WS update: {}", sessionId, update.getCmdId(), update); + wsService.sendWsMsg(sessionId, update); + } + } diff --git a/application/src/main/java/org/thingsboard/server/service/ws/notification/sub/NotificationRequestUpdate.java b/application/src/main/java/org/thingsboard/server/service/ws/notification/sub/NotificationRequestUpdate.java index e3563a32f2..ebbcc716ab 100644 --- a/application/src/main/java/org/thingsboard/server/service/ws/notification/sub/NotificationRequestUpdate.java +++ b/application/src/main/java/org/thingsboard/server/service/ws/notification/sub/NotificationRequestUpdate.java @@ -20,7 +20,6 @@ import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; import org.thingsboard.server.common.data.id.NotificationRequestId; -import org.thingsboard.server.common.data.notification.info.NotificationInfo; @Data @NoArgsConstructor @@ -28,6 +27,5 @@ import org.thingsboard.server.common.data.notification.info.NotificationInfo; @Builder public class NotificationRequestUpdate { private NotificationRequestId notificationRequestId; - private NotificationInfo notificationInfo; private boolean deleted; } diff --git a/application/src/main/java/org/thingsboard/server/service/ws/notification/sub/NotificationUpdate.java b/application/src/main/java/org/thingsboard/server/service/ws/notification/sub/NotificationUpdate.java index be9bd8d5ae..beeb46b1ac 100644 --- a/application/src/main/java/org/thingsboard/server/service/ws/notification/sub/NotificationUpdate.java +++ b/application/src/main/java/org/thingsboard/server/service/ws/notification/sub/NotificationUpdate.java @@ -22,7 +22,6 @@ import lombok.NoArgsConstructor; import org.thingsboard.server.common.data.id.NotificationId; import org.thingsboard.server.common.data.notification.Notification; import org.thingsboard.server.common.data.notification.NotificationStatus; -import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent; import java.util.UUID; @@ -33,12 +32,15 @@ import java.util.UUID; public class NotificationUpdate { private NotificationId notificationId; + + private boolean created; private Notification notification; - boolean allNotifications; + private boolean updated; + private NotificationStatus newStatus; + private boolean allNotifications; - private NotificationStatus updatedStatus; - private ComponentLifecycleEvent updateType; + private boolean deleted; public UUID getNotificationId() { return notificationId != null ? notificationId.getId() : diff --git a/application/src/main/resources/thingsboard.yml b/application/src/main/resources/thingsboard.yml index 08fd0eef1e..db194cb6e0 100644 --- a/application/src/main/resources/thingsboard.yml +++ b/application/src/main/resources/thingsboard.yml @@ -440,9 +440,6 @@ cache: notificationRules: timeToLiveInMinutes: "${CACHE_SPECS_NOTIFICATION_RULES_TTL:1440}" maxSize: "${CACHE_SPECS_NOTIFICATION_RULES_MAX_SIZE:10000}" - notificationRequests: - timeToLiveInMinutes: "${CACHE_SPECS_NOTIFICATION_RULES_TTL:1440}" - maxSize: "${CACHE_SPECS_NOTIFICATION_RULES_MAX_SIZE:10000}" attributes: timeToLiveInMinutes: "${CACHE_SPECS_ATTRIBUTES_TTL:1440}" maxSize: "${CACHE_SPECS_ATTRIBUTES_MAX_SIZE:100000}" diff --git a/application/src/test/java/org/thingsboard/server/service/notification/AbstractNotificationApiTest.java b/application/src/test/java/org/thingsboard/server/service/notification/AbstractNotificationApiTest.java index 52d115a7dc..7988b5ae2e 100644 --- a/application/src/test/java/org/thingsboard/server/service/notification/AbstractNotificationApiTest.java +++ b/application/src/test/java/org/thingsboard/server/service/notification/AbstractNotificationApiTest.java @@ -44,7 +44,7 @@ import org.thingsboard.server.common.data.notification.template.DeliveryMethodNo import org.thingsboard.server.common.data.notification.template.EmailDeliveryMethodNotificationTemplate; import org.thingsboard.server.common.data.notification.template.NotificationTemplate; import org.thingsboard.server.common.data.notification.template.NotificationTemplateConfig; -import org.thingsboard.server.common.data.notification.template.PushDeliveryMethodNotificationTemplate; +import org.thingsboard.server.common.data.notification.template.WebDeliveryMethodNotificationTemplate; import org.thingsboard.server.common.data.notification.template.SmsDeliveryMethodNotificationTemplate; import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageLink; @@ -101,7 +101,7 @@ public abstract class AbstractNotificationApiTest extends AbstractControllerTest protected NotificationRequest submitNotificationRequest(List targets, String text, int delayInSec, NotificationDeliveryMethod... deliveryMethods) { if (deliveryMethods.length == 0) { - deliveryMethods = new NotificationDeliveryMethod[]{NotificationDeliveryMethod.PUSH}; + deliveryMethods = new NotificationDeliveryMethod[]{NotificationDeliveryMethod.WEB}; } NotificationTemplate notificationTemplate = createNotificationTemplate(DEFAULT_NOTIFICATION_TYPE, DEFAULT_NOTIFICATION_SUBJECT, text, deliveryMethods); return submitNotificationRequest(targets, notificationTemplate.getId(), delayInSec); @@ -137,8 +137,8 @@ public abstract class AbstractNotificationApiTest extends AbstractControllerTest for (NotificationDeliveryMethod deliveryMethod : deliveryMethods) { DeliveryMethodNotificationTemplate deliveryMethodNotificationTemplate; switch (deliveryMethod) { - case PUSH: { - PushDeliveryMethodNotificationTemplate template = new PushDeliveryMethodNotificationTemplate(); + case WEB: { + WebDeliveryMethodNotificationTemplate template = new WebDeliveryMethodNotificationTemplate(); template.setSubject(subject); deliveryMethodNotificationTemplate = template; break; diff --git a/application/src/test/java/org/thingsboard/server/service/notification/NotificationApiTest.java b/application/src/test/java/org/thingsboard/server/service/notification/NotificationApiTest.java index bb2bbce14a..f9c9f2836b 100644 --- a/application/src/test/java/org/thingsboard/server/service/notification/NotificationApiTest.java +++ b/application/src/test/java/org/thingsboard/server/service/notification/NotificationApiTest.java @@ -48,7 +48,7 @@ import org.thingsboard.server.common.data.notification.template.DeliveryMethodNo import org.thingsboard.server.common.data.notification.template.EmailDeliveryMethodNotificationTemplate; import org.thingsboard.server.common.data.notification.template.NotificationTemplate; import org.thingsboard.server.common.data.notification.template.NotificationTemplateConfig; -import org.thingsboard.server.common.data.notification.template.PushDeliveryMethodNotificationTemplate; +import org.thingsboard.server.common.data.notification.template.WebDeliveryMethodNotificationTemplate; import org.thingsboard.server.common.data.notification.template.SlackDeliveryMethodNotificationTemplate; import org.thingsboard.server.common.data.notification.template.SmsDeliveryMethodNotificationTemplate; import org.thingsboard.server.common.data.page.PageData; @@ -209,7 +209,7 @@ public class NotificationApiTest extends AbstractNotificationApiTest { int notificationsCount = 20; wsClient.registerWaitForUpdate(notificationsCount); for (int i = 1; i <= notificationsCount; i++) { - submitNotificationRequest(target.getId(), "Test " + i, NotificationDeliveryMethod.PUSH); + submitNotificationRequest(target.getId(), "Test " + i, NotificationDeliveryMethod.WEB); } wsClient.waitForUpdate(true); assertThat(wsClient.getLastDataUpdate().getTotalUnreadCount()).isEqualTo(notificationsCount); @@ -266,32 +266,6 @@ public class NotificationApiTest extends AbstractNotificationApiTest { assertThat(getMyNotifications(false, 10)).size().isZero(); } - @Test - public void whenNotificationRequestIsUpdated_thenUpdateNotifications() throws Exception { - wsClient.subscribeForUnreadNotifications(10); - wsClient.waitForReply(true); - - NotificationTarget notificationTarget = createNotificationTarget(customerUserId); - String notificationText = "Text"; - wsClient.registerWaitForUpdate(); - NotificationRequest notificationRequest = submitNotificationRequest(notificationTarget.getId(), notificationText); - wsClient.waitForUpdate(true); - Notification initialNotification = wsClient.getLastDataUpdate().getUpdate(); - loginCustomerUser(); - assertThat(getMyNotifications(false, 10)).singleElement().isEqualTo(initialNotification); - assertThat(initialNotification.getInfo()).isNotNull().isEqualTo(notificationRequest.getInfo()); - - wsClient.registerWaitForUpdate(); - UserOriginatedNotificationInfo newNotificationInfo = new UserOriginatedNotificationInfo(); - newNotificationInfo.setDescription("New description"); - notificationRequest.setInfo(newNotificationInfo); - notificationCenter.updateNotificationRequest(tenantId, notificationRequest); - wsClient.waitForUpdate(true); - Notification updatedNotification = wsClient.getLastDataUpdate().getNotifications().iterator().next(); - assertThat(updatedNotification.getInfo()).isEqualTo(newNotificationInfo); - assertThat(getMyNotifications(false, 10)).singleElement().isEqualTo(updatedNotification); - } - @Test public void testNotificationUpdatesForSeveralUsers() throws Exception { int usersCount = 150; @@ -319,7 +293,7 @@ public class NotificationApiTest extends AbstractNotificationApiTest { sessions.forEach((user, wsClient) -> wsClient.registerWaitForUpdate()); NotificationRequest notificationRequest = submitNotificationRequest(targets, "Hello, ${recipientEmail}", 0, - NotificationDeliveryMethod.PUSH); + NotificationDeliveryMethod.WEB); await().atMost(10, TimeUnit.SECONDS) .pollDelay(1, TimeUnit.SECONDS).pollInterval(500, TimeUnit.MILLISECONDS) .until(() -> { @@ -342,7 +316,7 @@ public class NotificationApiTest extends AbstractNotificationApiTest { await().atMost(2, TimeUnit.SECONDS) .until(() -> findNotificationRequest(notificationRequest.getId()).isSent()); NotificationRequestStats stats = getStats(notificationRequest.getId()); - assertThat(stats.getSent().get(NotificationDeliveryMethod.PUSH)).hasValue(usersCount); + assertThat(stats.getSent().get(NotificationDeliveryMethod.WEB)).hasValue(usersCount); sessions.values().forEach(wsClient -> wsClient.registerWaitForUpdate()); deleteNotificationRequest(notificationRequest.getId()); @@ -393,17 +367,17 @@ public class NotificationApiTest extends AbstractNotificationApiTest { String requestorEmail = TENANT_ADMIN_EMAIL; NotificationTemplateConfig templateConfig = new NotificationTemplateConfig(); - templateConfig.setDefaultTextTemplate("Default message for SMS and PUSH: ${recipientEmail}"); + templateConfig.setDefaultTextTemplate("Default message for SMS and WEB: ${recipientEmail}"); templateConfig.setNotificationSubject("Default subject for EMAIL: ${recipientEmail}"); HashMap templates = new HashMap<>(); templateConfig.setDeliveryMethodsTemplates(templates); notificationTemplate.setConfiguration(templateConfig); - PushDeliveryMethodNotificationTemplate pushNotificationTemplate = new PushDeliveryMethodNotificationTemplate(); - pushNotificationTemplate.setEnabled(true); - // using default message for push - pushNotificationTemplate.setSubject("Subject for PUSH: ${recipientEmail}"); - templates.put(NotificationDeliveryMethod.PUSH, pushNotificationTemplate); + WebDeliveryMethodNotificationTemplate webNotificationTemplate = new WebDeliveryMethodNotificationTemplate(); + webNotificationTemplate.setEnabled(true); + // using default message for web + webNotificationTemplate.setSubject("Subject for WEB: ${recipientEmail}"); + templates.put(NotificationDeliveryMethod.WEB, webNotificationTemplate); SmsDeliveryMethodNotificationTemplate smsNotificationTemplate = new SmsDeliveryMethodNotificationTemplate(); smsNotificationTemplate.setEnabled(true); @@ -435,19 +409,19 @@ public class NotificationApiTest extends AbstractNotificationApiTest { assertThat(preview.getTotalRecipientsCount()).isEqualTo(1 + customerUsersCount); Map processedTemplates = preview.getProcessedTemplates(); - assertThat(processedTemplates.get(NotificationDeliveryMethod.PUSH)).asInstanceOf(type(PushDeliveryMethodNotificationTemplate.class)) + assertThat(processedTemplates.get(NotificationDeliveryMethod.WEB)).asInstanceOf(type(WebDeliveryMethodNotificationTemplate.class)) .satisfies(template -> { assertThat(template.getBody()) - .startsWith("Default message for SMS and PUSH") + .startsWith("Default message for SMS and WEB") .endsWith(requestorEmail); assertThat(template.getSubject()) - .startsWith("Subject for PUSH") + .startsWith("Subject for WEB") .endsWith(requestorEmail); }); assertThat(processedTemplates.get(NotificationDeliveryMethod.SMS)).asInstanceOf(type(SmsDeliveryMethodNotificationTemplate.class)) .satisfies(template -> { assertThat(template.getBody()) - .startsWith("Default message for SMS and PUSH") + .startsWith("Default message for SMS and WEB") .endsWith(requestorEmail); }); assertThat(processedTemplates.get(NotificationDeliveryMethod.EMAIL)).asInstanceOf(type(EmailDeliveryMethodNotificationTemplate.class)) @@ -469,7 +443,7 @@ public class NotificationApiTest extends AbstractNotificationApiTest { @Test public void testNotificationRequestInfo() throws Exception { NotificationDeliveryMethod[] deliveryMethods = new NotificationDeliveryMethod[]{ - NotificationDeliveryMethod.PUSH, NotificationDeliveryMethod.EMAIL + NotificationDeliveryMethod.WEB, NotificationDeliveryMethod.EMAIL }; NotificationTemplate template = createNotificationTemplate(NotificationType.GENERAL, "Test subject", "Test text", deliveryMethods); NotificationTarget target = createNotificationTarget(tenantAdminUserId); @@ -489,15 +463,14 @@ public class NotificationApiTest extends AbstractNotificationApiTest { wsClient.registerWaitForUpdate(); NotificationTarget notificationTarget = createNotificationTarget(customerUserId); NotificationRequest notificationRequest = submitNotificationRequest(notificationTarget.getId(), "Test :)", - NotificationDeliveryMethod.PUSH, NotificationDeliveryMethod.EMAIL, NotificationDeliveryMethod.SMS); + NotificationDeliveryMethod.WEB, NotificationDeliveryMethod.SMS); wsClient.waitForUpdate(); await().atMost(2, TimeUnit.SECONDS) .until(() -> findNotificationRequest(notificationRequest.getId()).isSent()); NotificationRequestStats stats = getStats(notificationRequest.getId()); - assertThat(stats.getSent().get(NotificationDeliveryMethod.PUSH)).hasValue(1); - assertThat(stats.getSent().get(NotificationDeliveryMethod.EMAIL)).hasValue(1); + assertThat(stats.getSent().get(NotificationDeliveryMethod.WEB)).hasValue(1); assertThat(stats.getErrors().get(NotificationDeliveryMethod.SMS)).size().isOne(); } @@ -526,7 +499,7 @@ public class NotificationApiTest extends AbstractNotificationApiTest { NotificationTargetId notificationTargetId = notificationTarget.getId(); ListenableFuture request = executor.submit(() -> { - return submitNotificationRequest(notificationTargetId, "Hello, ${recipientEmail}", 0, NotificationDeliveryMethod.PUSH); + return submitNotificationRequest(notificationTargetId, "Hello, ${recipientEmail}", 0, NotificationDeliveryMethod.WEB); }); await().atMost(10, TimeUnit.SECONDS).until(request::isDone); NotificationRequest notificationRequest = request.get(); 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 d8214a9745..293eb07af9 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 @@ -23,6 +23,7 @@ import org.junit.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.mock.mockito.SpyBean; import org.springframework.data.util.Pair; +import org.springframework.test.context.TestPropertySource; import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.rule.engine.debug.TbMsgGeneratorNode; import org.thingsboard.rule.engine.debug.TbMsgGeneratorNodeConfiguration; @@ -92,6 +93,9 @@ import static org.awaitility.Awaitility.await; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; @DaoSqlTest +@TestPropertySource(properties = { + "js.evaluator=local" +}) public class NotificationRuleApiTest extends AbstractNotificationApiTest { @SpyBean @@ -111,10 +115,10 @@ public class NotificationRuleApiTest extends AbstractNotificationApiTest { public void testNotificationRuleProcessing_entityActionTrigger() throws Exception { String notificationSubject = "${actionType}: ${entityType} [${entityId}]"; String notificationText = "User: ${originatorUserName}"; - NotificationTemplate notificationTemplate = createNotificationTemplate(NotificationType.GENERAL, notificationSubject, notificationText, NotificationDeliveryMethod.PUSH); + NotificationTemplate notificationTemplate = createNotificationTemplate(NotificationType.GENERAL, notificationSubject, notificationText, NotificationDeliveryMethod.WEB); NotificationRule notificationRule = new NotificationRule(); - notificationRule.setName("Push-notification when any device is created, updated or deleted"); + notificationRule.setName("Web notification when any device is created, updated or deleted"); notificationRule.setTemplateId(notificationTemplate.getId()); notificationRule.setTriggerType(NotificationRuleTriggerType.ENTITY_ACTION); @@ -166,10 +170,10 @@ public class NotificationRuleApiTest extends AbstractNotificationApiTest { String notificationSubject = "Alarm type: ${alarmType}, status: ${alarmStatus}, " + "severity: ${alarmSeverity}, deviceId: ${alarmOriginatorId}"; String notificationText = "Status: ${alarmStatus}, severity: ${alarmSeverity}"; - NotificationTemplate notificationTemplate = createNotificationTemplate(NotificationType.ALARM, notificationSubject, notificationText, NotificationDeliveryMethod.PUSH); + NotificationTemplate notificationTemplate = createNotificationTemplate(NotificationType.ALARM, notificationSubject, notificationText, NotificationDeliveryMethod.WEB); NotificationRule notificationRule = new NotificationRule(); - notificationRule.setName("Push-notification on any alarm"); + notificationRule.setName("Web notification on any alarm"); notificationRule.setTemplateId(notificationTemplate.getId()); notificationRule.setTriggerType(NotificationRuleTriggerType.ALARM); @@ -240,7 +244,7 @@ public class NotificationRuleApiTest extends AbstractNotificationApiTest { AlarmSeverity expectedSeverity = AlarmSeverity.CRITICAL; clients.values().forEach(wsClient -> { wsClient.waitForUpdate(true); - Notification updatedNotification = wsClient.getLastDataUpdate().getNotifications().stream().findFirst().get(); + Notification updatedNotification = wsClient.getLastDataUpdate().getUpdate(); assertThat(updatedNotification.getSubject()).isEqualTo("Alarm type: " + alarmType + ", status: " + expectedStatus + ", " + "severity: " + expectedSeverity + ", deviceId: " + device.getId()); assertThat(updatedNotification.getText()).isEqualTo("Status: " + expectedStatus + ", severity: " + expectedSeverity); @@ -255,10 +259,10 @@ public class NotificationRuleApiTest extends AbstractNotificationApiTest { public void testNotificationRuleProcessing_alarmTrigger_clearRule() throws Exception { String notificationSubject = "${alarmSeverity} alarm '${alarmType}' is ${alarmStatus}"; String notificationText = "${alarmId}"; - NotificationTemplate notificationTemplate = createNotificationTemplate(NotificationType.ALARM, notificationSubject, notificationText, NotificationDeliveryMethod.PUSH); + NotificationTemplate notificationTemplate = createNotificationTemplate(NotificationType.ALARM, notificationSubject, notificationText, NotificationDeliveryMethod.WEB); NotificationRule notificationRule = new NotificationRule(); - notificationRule.setName("Push-notification on any alarm"); + notificationRule.setName("Web notification on any alarm"); notificationRule.setTemplateId(notificationTemplate.getId()); notificationRule.setTriggerType(NotificationRuleTriggerType.ALARM); @@ -311,7 +315,7 @@ public class NotificationRuleApiTest extends AbstractNotificationApiTest { getWsClient().registerWaitForUpdate(); alarmSubscriptionService.clearAlarm(tenantId, alarm.getId(), System.currentTimeMillis(), null); getWsClient().waitForUpdate(true); - notification = getWsClient().getLastDataUpdate().getNotifications().iterator().next(); + notification = getWsClient().getLastDataUpdate().getUpdate(); assertThat(notification.getSubject()).isEqualTo("CRITICAL alarm '" + alarmType + "' is CLEARED_UNACK"); assertThat(findNotificationRequests(EntityType.ALARM).getData()).filteredOn(NotificationRequest::isScheduled).isEmpty(); @@ -321,7 +325,7 @@ public class NotificationRuleApiTest extends AbstractNotificationApiTest { public void testNotificationRuleProcessing_ruleEngineComponentLifecycleEvent_ruleNodeStartError() { String subject = "Rule Node '${componentName}' in Rule Chain '${ruleChainName}' failed to start"; String text = "The error: ${error}"; - NotificationTemplate template = createNotificationTemplate(NotificationType.RULE_ENGINE_COMPONENT_LIFECYCLE_EVENT, subject, text, NotificationDeliveryMethod.PUSH); + NotificationTemplate template = createNotificationTemplate(NotificationType.RULE_ENGINE_COMPONENT_LIFECYCLE_EVENT, subject, text, NotificationDeliveryMethod.WEB); NotificationRule rule = new NotificationRule(); rule.setName("Rule node start-up failures in my rule chain"); @@ -361,7 +365,7 @@ public class NotificationRuleApiTest extends AbstractNotificationApiTest { @Test public void testNotificationRuleInfo() throws Exception { - NotificationDeliveryMethod[] deliveryMethods = {NotificationDeliveryMethod.PUSH, NotificationDeliveryMethod.EMAIL}; + NotificationDeliveryMethod[] deliveryMethods = {NotificationDeliveryMethod.WEB, NotificationDeliveryMethod.EMAIL}; NotificationTemplate template = createNotificationTemplate(NotificationType.ENTITY_ACTION, "Subject", "Text", deliveryMethods); NotificationRule rule = new NotificationRule(); diff --git a/application/src/test/java/org/thingsboard/server/service/notification/NotificationTemplateApiTest.java b/application/src/test/java/org/thingsboard/server/service/notification/NotificationTemplateApiTest.java index 17e8ca1043..67a7fd8bd4 100644 --- a/application/src/test/java/org/thingsboard/server/service/notification/NotificationTemplateApiTest.java +++ b/application/src/test/java/org/thingsboard/server/service/notification/NotificationTemplateApiTest.java @@ -86,9 +86,9 @@ public class NotificationTemplateApiTest extends AbstractNotificationApiTest { @Test public void testTemplatesSearch() throws Exception { - NotificationTemplate alarmNotificationTemplate = createNotificationTemplate(NotificationType.ALARM, "Alarm", "Alarm", NotificationDeliveryMethod.PUSH); - NotificationTemplate generalNotificationTemplate = createNotificationTemplate(NotificationType.GENERAL, "General", "General", NotificationDeliveryMethod.PUSH); - NotificationTemplate entityActionNotificationTemplate = createNotificationTemplate(NotificationType.ENTITY_ACTION, "Entity action", "Entity action", NotificationDeliveryMethod.PUSH); + NotificationTemplate alarmNotificationTemplate = createNotificationTemplate(NotificationType.ALARM, "Alarm", "Alarm", NotificationDeliveryMethod.WEB); + NotificationTemplate generalNotificationTemplate = createNotificationTemplate(NotificationType.GENERAL, "General", "General", NotificationDeliveryMethod.WEB); + NotificationTemplate entityActionNotificationTemplate = createNotificationTemplate(NotificationType.ENTITY_ACTION, "Entity action", "Entity action", NotificationDeliveryMethod.WEB); assertThat(findTemplates(NotificationType.ALARM)).extracting(IdBased::getId) .containsOnly(alarmNotificationTemplate.getId()); diff --git a/common/dao-api/src/main/java/org/thingsboard/server/dao/notification/NotificationRequestService.java b/common/dao-api/src/main/java/org/thingsboard/server/dao/notification/NotificationRequestService.java index c781f450cb..af214dbf3d 100644 --- a/common/dao-api/src/main/java/org/thingsboard/server/dao/notification/NotificationRequestService.java +++ b/common/dao-api/src/main/java/org/thingsboard/server/dao/notification/NotificationRequestService.java @@ -45,7 +45,7 @@ public interface NotificationRequestService { List findNotificationRequestsByRuleIdAndOriginatorEntityId(TenantId tenantId, NotificationRuleId ruleId, EntityId originatorEntityId); - void deleteNotificationRequest(TenantId tenantId, NotificationRequest notificationRequest); + void deleteNotificationRequest(TenantId tenantId, NotificationRequestId requestId); PageData findScheduledNotificationRequests(PageLink pageLink); diff --git a/common/dao-api/src/main/java/org/thingsboard/server/dao/notification/NotificationService.java b/common/dao-api/src/main/java/org/thingsboard/server/dao/notification/NotificationService.java index 39886500c8..35e74b36e7 100644 --- a/common/dao-api/src/main/java/org/thingsboard/server/dao/notification/NotificationService.java +++ b/common/dao-api/src/main/java/org/thingsboard/server/dao/notification/NotificationService.java @@ -40,8 +40,6 @@ public interface NotificationService { int countUnreadNotificationsByRecipientId(TenantId tenantId, UserId recipientId); - void updateNotificationsStatusByRequestId(TenantId tenantId, NotificationRequestId requestId, NotificationStatus status); - boolean deleteNotification(TenantId tenantId, UserId recipientId, NotificationId notificationId); } diff --git a/common/dao-api/src/main/java/org/thingsboard/server/dao/user/UserService.java b/common/dao-api/src/main/java/org/thingsboard/server/dao/user/UserService.java index 4031672c4f..389f16c1ee 100644 --- a/common/dao-api/src/main/java/org/thingsboard/server/dao/user/UserService.java +++ b/common/dao-api/src/main/java/org/thingsboard/server/dao/user/UserService.java @@ -60,7 +60,7 @@ public interface UserService extends EntityDaoService { PageData findTenantAdmins(TenantId tenantId, PageLink pageLink); - PageData findUsers(TenantId tenantId, PageLink pageLink); + PageData findAllUsers(TenantId tenantId, PageLink pageLink); void deleteTenantAdmins(TenantId tenantId); diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/CacheConstants.java b/common/data/src/main/java/org/thingsboard/server/common/data/CacheConstants.java index 766a431816..f59ea8d5d0 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/CacheConstants.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/CacheConstants.java @@ -30,7 +30,6 @@ public class CacheConstants { public static final String TENANTS_EXIST_CACHE = "tenantsExist"; public static final String DEVICE_PROFILE_CACHE = "deviceProfiles"; public static final String NOTIFICATION_RULES_CACHE = "notificationRules"; - public static final String NOTIFICATION_REQUESTS_CACHE = "notificationRequests"; public static final String ASSET_PROFILE_CACHE = "assetProfiles"; public static final String ATTRIBUTES_CACHE = "attributes"; diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/notification/Notification.java b/common/data/src/main/java/org/thingsboard/server/common/data/notification/Notification.java index ac15bd5d88..c3097d3c49 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/notification/Notification.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/notification/Notification.java @@ -15,7 +15,6 @@ */ package org.thingsboard.server.common.data.notification; -import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.databind.JsonNode; import lombok.AllArgsConstructor; import lombok.Builder; @@ -46,14 +45,4 @@ public class Notification extends BaseData { private NotificationStatus status; - @JsonProperty("text") - public String getProcessedText() { - return NotificationProcessingContext.processTemplate(text, info); - } - - @JsonProperty("subject") - public String getProcessedSubject() { - return NotificationProcessingContext.processTemplate(subject, info); - } - } diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/notification/NotificationDeliveryMethod.java b/common/data/src/main/java/org/thingsboard/server/common/data/notification/NotificationDeliveryMethod.java index 41522065d0..4a2c4657d5 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/notification/NotificationDeliveryMethod.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/notification/NotificationDeliveryMethod.java @@ -21,7 +21,7 @@ import lombok.RequiredArgsConstructor; @RequiredArgsConstructor public enum NotificationDeliveryMethod { - PUSH("push-notification"), + WEB("web"), EMAIL("email"), SMS("SMS"), SLACK("Slack"); diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/notification/NotificationProcessingContext.java b/common/data/src/main/java/org/thingsboard/server/common/data/notification/NotificationProcessingContext.java index c15d10db93..afcfa278f2 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/notification/NotificationProcessingContext.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/notification/NotificationProcessingContext.java @@ -33,7 +33,7 @@ import org.thingsboard.server.common.data.notification.template.DeliveryMethodNo import org.thingsboard.server.common.data.notification.template.HasSubject; import org.thingsboard.server.common.data.notification.template.NotificationTemplate; import org.thingsboard.server.common.data.notification.template.NotificationTemplateConfig; -import org.thingsboard.server.common.data.notification.template.PushDeliveryMethodNotificationTemplate; +import org.thingsboard.server.common.data.notification.template.WebDeliveryMethodNotificationTemplate; import java.util.Collections; import java.util.EnumMap; @@ -96,7 +96,7 @@ public class NotificationProcessingContext { public T getProcessedTemplate(NotificationDeliveryMethod deliveryMethod, Map templateContext) { NotificationInfo info = request.getInfo(); - if (info != null && deliveryMethod != NotificationDeliveryMethod.PUSH) { // for push notifications we are processing template from info on each serialization + if (info != null) { templateContext = new HashMap<>(templateContext); templateContext.putAll(info.getTemplateData()); } @@ -108,9 +108,9 @@ public class NotificationProcessingContext { ((HasSubject) template).setSubject(processTemplate(subject, templateContext)); } - if (deliveryMethod == NotificationDeliveryMethod.PUSH) { - PushDeliveryMethodNotificationTemplate pushNotificationTemplate = (PushDeliveryMethodNotificationTemplate) template; - Optional buttonConfig = Optional.ofNullable(pushNotificationTemplate.getAdditionalConfig()) + if (deliveryMethod == NotificationDeliveryMethod.WEB) { + WebDeliveryMethodNotificationTemplate webNotificationTemplate = (WebDeliveryMethodNotificationTemplate) template; + Optional buttonConfig = Optional.ofNullable(webNotificationTemplate.getAdditionalConfig()) .map(config -> config.get("actionButtonConfig")).filter(JsonNode::isObject) .map(config -> (ObjectNode) config); if (buttonConfig.isPresent()) { diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/NotificationRuleTriggerType.java b/common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/NotificationRuleTriggerType.java index 82756d0870..64bba1b9df 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/NotificationRuleTriggerType.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/NotificationRuleTriggerType.java @@ -15,19 +15,12 @@ */ package org.thingsboard.server.common.data.notification.rule.trigger; -import lombok.Getter; -import lombok.RequiredArgsConstructor; - -@RequiredArgsConstructor public enum NotificationRuleTriggerType { - ALARM(true), - ALARM_COMMENT(true), - DEVICE_INACTIVITY(false), - ENTITY_ACTION(false), - RULE_ENGINE_COMPONENT_LIFECYCLE_EVENT(false); - - @Getter - private final boolean updatable; + ALARM, + ALARM_COMMENT, + DEVICE_INACTIVITY, + ENTITY_ACTION, + RULE_ENGINE_COMPONENT_LIFECYCLE_EVENT } diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/notification/targets/NotificationTargetType.java b/common/data/src/main/java/org/thingsboard/server/common/data/notification/targets/NotificationTargetType.java index 202e329601..0c2441e37d 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/notification/targets/NotificationTargetType.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/notification/targets/NotificationTargetType.java @@ -24,7 +24,7 @@ import java.util.Set; @RequiredArgsConstructor public enum NotificationTargetType { - PLATFORM_USERS(Set.of(NotificationDeliveryMethod.PUSH, NotificationDeliveryMethod.EMAIL, NotificationDeliveryMethod.SMS)), + PLATFORM_USERS(Set.of(NotificationDeliveryMethod.WEB, NotificationDeliveryMethod.EMAIL, NotificationDeliveryMethod.SMS)), SLACK(Set.of(NotificationDeliveryMethod.SLACK)); @Getter diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/notification/targets/platform/UsersFilterType.java b/common/data/src/main/java/org/thingsboard/server/common/data/notification/targets/platform/UsersFilterType.java index f8598c2a71..86e1ec7f87 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/notification/targets/platform/UsersFilterType.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/notification/targets/platform/UsersFilterType.java @@ -20,8 +20,4 @@ public enum UsersFilterType { CUSTOMER_USERS, ALL_USERS, ORIGINATOR_ENTITY_OWNER_USERS - -// USER_GROUP, -// USERS_WITH_ROLE, -// QUERY // ? } diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/notification/template/DeliveryMethodNotificationTemplate.java b/common/data/src/main/java/org/thingsboard/server/common/data/notification/template/DeliveryMethodNotificationTemplate.java index fd19afd6f7..ba098304d6 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/notification/template/DeliveryMethodNotificationTemplate.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/notification/template/DeliveryMethodNotificationTemplate.java @@ -27,7 +27,7 @@ import org.thingsboard.server.common.data.notification.NotificationDeliveryMetho @JsonIgnoreProperties(ignoreUnknown = true) @JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "method") @JsonSubTypes({ - @Type(name = "PUSH", value = PushDeliveryMethodNotificationTemplate.class), + @Type(name = "WEB", value = WebDeliveryMethodNotificationTemplate.class), @Type(name = "EMAIL", value = EmailDeliveryMethodNotificationTemplate.class), @Type(name = "SMS", value = SmsDeliveryMethodNotificationTemplate.class), @Type(name = "SLACK", value = SlackDeliveryMethodNotificationTemplate.class) diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/notification/template/PushDeliveryMethodNotificationTemplate.java b/common/data/src/main/java/org/thingsboard/server/common/data/notification/template/WebDeliveryMethodNotificationTemplate.java similarity index 77% rename from common/data/src/main/java/org/thingsboard/server/common/data/notification/template/PushDeliveryMethodNotificationTemplate.java rename to common/data/src/main/java/org/thingsboard/server/common/data/notification/template/WebDeliveryMethodNotificationTemplate.java index df4ea141cc..3b9b852eff 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/notification/template/PushDeliveryMethodNotificationTemplate.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/notification/template/WebDeliveryMethodNotificationTemplate.java @@ -26,12 +26,12 @@ import org.thingsboard.server.common.data.notification.NotificationDeliveryMetho @NoArgsConstructor @EqualsAndHashCode(callSuper = true) @ToString(callSuper = true) -public class PushDeliveryMethodNotificationTemplate extends DeliveryMethodNotificationTemplate implements HasSubject { +public class WebDeliveryMethodNotificationTemplate extends DeliveryMethodNotificationTemplate implements HasSubject { private String subject; private JsonNode additionalConfig; - public PushDeliveryMethodNotificationTemplate(PushDeliveryMethodNotificationTemplate other) { + public WebDeliveryMethodNotificationTemplate(WebDeliveryMethodNotificationTemplate other) { super(other); this.subject = other.subject; this.additionalConfig = other.additionalConfig; @@ -39,12 +39,12 @@ public class PushDeliveryMethodNotificationTemplate extends DeliveryMethodNotifi @Override public NotificationDeliveryMethod getMethod() { - return NotificationDeliveryMethod.PUSH; + return NotificationDeliveryMethod.WEB; } @Override - public PushDeliveryMethodNotificationTemplate copy() { - return new PushDeliveryMethodNotificationTemplate(this); + public WebDeliveryMethodNotificationTemplate copy() { + return new WebDeliveryMethodNotificationTemplate(this); } } diff --git a/dao/src/main/java/org/thingsboard/server/dao/notification/DefaultNotificationRequestService.java b/dao/src/main/java/org/thingsboard/server/dao/notification/DefaultNotificationRequestService.java index f891e1b118..e951a75c7c 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/notification/DefaultNotificationRequestService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/notification/DefaultNotificationRequestService.java @@ -30,10 +30,7 @@ import org.thingsboard.server.common.data.notification.NotificationRequestStats; import org.thingsboard.server.common.data.notification.NotificationRequestStatus; import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageLink; -import org.thingsboard.server.dao.entity.AbstractCachedEntityService; import org.thingsboard.server.dao.entity.EntityDaoService; -import org.thingsboard.server.dao.notification.cache.NotificationRequestCacheKey; -import org.thingsboard.server.dao.notification.cache.NotificationRequestCacheValue; import org.thingsboard.server.dao.service.DataValidator; import java.util.List; @@ -42,7 +39,7 @@ import java.util.Optional; @Service @Slf4j @RequiredArgsConstructor -public class DefaultNotificationRequestService extends AbstractCachedEntityService implements NotificationRequestService, EntityDaoService { +public class DefaultNotificationRequestService implements NotificationRequestService, EntityDaoService { private final NotificationRequestDao notificationRequestDao; @@ -51,14 +48,7 @@ public class DefaultNotificationRequestService extends AbstractCachedEntityServi @Override public NotificationRequest saveNotificationRequest(TenantId tenantId, NotificationRequest notificationRequest) { notificationRequestValidator.validate(notificationRequest, NotificationRequest::getTenantId); - try { - notificationRequest = notificationRequestDao.save(tenantId, notificationRequest); - publishEvictEvent(notificationRequest); - } catch (Exception e) { - handleEvictEvent(notificationRequest); - throw e; - } - return notificationRequest; + return notificationRequestDao.save(tenantId, notificationRequest); } @Override @@ -88,21 +78,13 @@ public class DefaultNotificationRequestService extends AbstractCachedEntityServi @Override public List findNotificationRequestsByRuleIdAndOriginatorEntityId(TenantId tenantId, NotificationRuleId ruleId, EntityId originatorEntityId) { - NotificationRequestCacheKey cacheKey = NotificationRequestCacheKey.builder() - .originatorEntityId(originatorEntityId) - .ruleId(ruleId) - .build(); - return cache.getAndPutInTransaction(cacheKey, () -> NotificationRequestCacheValue.builder() - .notificationRequests(notificationRequestDao.findByRuleIdAndOriginatorEntityId(tenantId, ruleId, originatorEntityId)) - .build(), false) - .getNotificationRequests(); + return notificationRequestDao.findByRuleIdAndOriginatorEntityId(tenantId, ruleId, originatorEntityId); } // ON DELETE CASCADE is used: notifications for request are deleted as well @Override - public void deleteNotificationRequest(TenantId tenantId, NotificationRequest notificationRequest) { - publishEvictEvent(notificationRequest); - notificationRequestDao.removeById(tenantId, notificationRequest.getUuidId()); + public void deleteNotificationRequest(TenantId tenantId, NotificationRequestId requestId) { + notificationRequestDao.removeById(tenantId, requestId.getId()); } @Override @@ -120,17 +102,6 @@ public class DefaultNotificationRequestService extends AbstractCachedEntityServi notificationRequestDao.removeByTenantId(tenantId); } - @Override - public void handleEvictEvent(NotificationRequest notificationRequest) { - if (notificationRequest.getRuleId() == null) return; - - NotificationRequestCacheKey cacheKey = NotificationRequestCacheKey.builder() - .originatorEntityId(notificationRequest.getOriginatorEntityId()) - .ruleId(notificationRequest.getRuleId()) - .build(); - cache.evict(cacheKey); - } - @Override public Optional> findEntity(TenantId tenantId, EntityId entityId) { return Optional.ofNullable(findNotificationRequestById(tenantId, new NotificationRequestId(entityId.getId()))); diff --git a/dao/src/main/java/org/thingsboard/server/dao/notification/DefaultNotificationService.java b/dao/src/main/java/org/thingsboard/server/dao/notification/DefaultNotificationService.java index 78c964c4b8..cf34f6fcfb 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/notification/DefaultNotificationService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/notification/DefaultNotificationService.java @@ -19,7 +19,6 @@ import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; import org.thingsboard.server.common.data.id.NotificationId; -import org.thingsboard.server.common.data.id.NotificationRequestId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.id.UserId; import org.thingsboard.server.common.data.notification.Notification; @@ -77,11 +76,6 @@ public class DefaultNotificationService implements NotificationService { return notificationDao.countUnreadByRecipientId(tenantId, recipientId); } - @Override - public void updateNotificationsStatusByRequestId(TenantId tenantId, NotificationRequestId requestId, NotificationStatus status) { - notificationDao.updateStatusesByRequestId(tenantId, requestId, status); - } - @Override public boolean deleteNotification(TenantId tenantId, UserId recipientId, NotificationId notificationId) { return notificationDao.deleteByIdAndRecipientId(tenantId, recipientId, notificationId); diff --git a/dao/src/main/java/org/thingsboard/server/dao/notification/DefaultNotificationTargetService.java b/dao/src/main/java/org/thingsboard/server/dao/notification/DefaultNotificationTargetService.java index bdf802dea0..e1089b703a 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/notification/DefaultNotificationTargetService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/notification/DefaultNotificationTargetService.java @@ -121,7 +121,7 @@ public class DefaultNotificationTargetService extends AbstractEntityService impl if (!tenantId.equals(TenantId.SYS_TENANT_ID)) { return userService.findUsersByTenantId(tenantId, pageLink); } else { - return userService.findUsers(TenantId.SYS_TENANT_ID, pageLink); + return userService.findAllUsers(TenantId.SYS_TENANT_ID, pageLink); } } case ORIGINATOR_ENTITY_OWNER_USERS: { diff --git a/dao/src/main/java/org/thingsboard/server/dao/notification/NotificationDao.java b/dao/src/main/java/org/thingsboard/server/dao/notification/NotificationDao.java index 57e5c410de..1ced714bce 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/notification/NotificationDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/notification/NotificationDao.java @@ -37,8 +37,6 @@ public interface NotificationDao extends Dao { PageData findByRequestId(TenantId tenantId, NotificationRequestId notificationRequestId, PageLink pageLink); - void updateStatusesByRequestId(TenantId tenantId, NotificationRequestId requestId, NotificationStatus status); - boolean deleteByIdAndRecipientId(TenantId tenantId, UserId recipientId, NotificationId notificationId); int updateStatusByRecipientId(TenantId tenantId, UserId recipientId, NotificationStatus status); diff --git a/dao/src/main/java/org/thingsboard/server/dao/notification/cache/NotificationRequestCacheKey.java b/dao/src/main/java/org/thingsboard/server/dao/notification/cache/NotificationRequestCacheKey.java deleted file mode 100644 index 403e192fbb..0000000000 --- a/dao/src/main/java/org/thingsboard/server/dao/notification/cache/NotificationRequestCacheKey.java +++ /dev/null @@ -1,43 +0,0 @@ -/** - * Copyright © 2016-2023 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.dao.notification.cache; - -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Data; -import lombok.NoArgsConstructor; -import org.thingsboard.server.common.data.id.EntityId; -import org.thingsboard.server.common.data.id.NotificationRuleId; - -import java.io.Serializable; - -@Data -@AllArgsConstructor -@NoArgsConstructor -@Builder -public class NotificationRequestCacheKey implements Serializable { - - private static final long serialVersionUID = 59871139005482170L; - - private EntityId originatorEntityId; - private NotificationRuleId ruleId; - - @Override - public String toString() { - return ruleId + "_" + originatorEntityId; - } - -} diff --git a/dao/src/main/java/org/thingsboard/server/dao/notification/cache/NotificationRequestCacheValue.java b/dao/src/main/java/org/thingsboard/server/dao/notification/cache/NotificationRequestCacheValue.java deleted file mode 100644 index cdd21720ca..0000000000 --- a/dao/src/main/java/org/thingsboard/server/dao/notification/cache/NotificationRequestCacheValue.java +++ /dev/null @@ -1,38 +0,0 @@ -/** - * Copyright © 2016-2023 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.dao.notification.cache; - -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Data; -import lombok.NoArgsConstructor; -import org.thingsboard.server.common.data.notification.NotificationRequest; -import org.thingsboard.server.common.data.notification.rule.NotificationRule; - -import java.io.Serializable; -import java.util.List; - -@Data -@AllArgsConstructor -@NoArgsConstructor -@Builder -public class NotificationRequestCacheValue implements Serializable { - - private static final long serialVersionUID = 950211234585105415L; - - private List notificationRequests; - -} diff --git a/dao/src/main/java/org/thingsboard/server/dao/notification/cache/NotificationRequestCaffeineCache.java b/dao/src/main/java/org/thingsboard/server/dao/notification/cache/NotificationRequestCaffeineCache.java deleted file mode 100644 index 2b2dc91fc9..0000000000 --- a/dao/src/main/java/org/thingsboard/server/dao/notification/cache/NotificationRequestCaffeineCache.java +++ /dev/null @@ -1,32 +0,0 @@ -/** - * Copyright © 2016-2023 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.dao.notification.cache; - -import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; -import org.springframework.cache.CacheManager; -import org.springframework.stereotype.Service; -import org.thingsboard.server.cache.CaffeineTbTransactionalCache; -import org.thingsboard.server.common.data.CacheConstants; - -@ConditionalOnProperty(prefix = "cache", value = "type", havingValue = "caffeine", matchIfMissing = true) -@Service -public class NotificationRequestCaffeineCache extends CaffeineTbTransactionalCache { - - public NotificationRequestCaffeineCache(CacheManager cacheManager) { - super(cacheManager, CacheConstants.NOTIFICATION_REQUESTS_CACHE); - } - -} diff --git a/dao/src/main/java/org/thingsboard/server/dao/notification/cache/NotificationRequestRedisCache.java b/dao/src/main/java/org/thingsboard/server/dao/notification/cache/NotificationRequestRedisCache.java deleted file mode 100644 index 0da04c15db..0000000000 --- a/dao/src/main/java/org/thingsboard/server/dao/notification/cache/NotificationRequestRedisCache.java +++ /dev/null @@ -1,35 +0,0 @@ -/** - * Copyright © 2016-2023 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.dao.notification.cache; - -import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; -import org.springframework.data.redis.connection.RedisConnectionFactory; -import org.springframework.stereotype.Service; -import org.thingsboard.server.cache.CacheSpecsMap; -import org.thingsboard.server.cache.RedisTbTransactionalCache; -import org.thingsboard.server.cache.TBRedisCacheConfiguration; -import org.thingsboard.server.cache.TbFSTRedisSerializer; -import org.thingsboard.server.common.data.CacheConstants; - -@ConditionalOnProperty(prefix = "cache", value = "type", havingValue = "redis") -@Service -public class NotificationRequestRedisCache extends RedisTbTransactionalCache { - - public NotificationRequestRedisCache(CacheSpecsMap cacheSpecsMap, RedisConnectionFactory connectionFactory, TBRedisCacheConfiguration configuration) { - super(CacheConstants.NOTIFICATION_REQUESTS_CACHE, cacheSpecsMap, connectionFactory, configuration, new TbFSTRedisSerializer<>()); - } - -} diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/notification/JpaNotificationDao.java b/dao/src/main/java/org/thingsboard/server/dao/sql/notification/JpaNotificationDao.java index 0f1f4d9722..d998c355c5 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/notification/JpaNotificationDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/notification/JpaNotificationDao.java @@ -88,11 +88,6 @@ public class JpaNotificationDao extends JpaAbstractDao findByRuleIdAndOriginatorEntityId(TenantId tenantId, NotificationRuleId ruleId, EntityId originatorEntityId) { - return DaoUtil.convertDataList(notificationRequestRepository.findAllByRuleIdAndOriginatorEntityTypeAndOriginatorEntityId(ruleId.getId(), originatorEntityId.getEntityType(), originatorEntityId.getId())); + return DaoUtil.convertDataList(notificationRequestRepository.findAllByRuleIdAndOriginatorEntityIdAndOriginatorEntityType(ruleId.getId(), originatorEntityId.getId(), originatorEntityId.getEntityType())); } @Override diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/notification/NotificationRepository.java b/dao/src/main/java/org/thingsboard/server/dao/sql/notification/NotificationRepository.java index 1da2ebfcde..ebeb2a7a1b 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/notification/NotificationRepository.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/notification/NotificationRepository.java @@ -48,13 +48,6 @@ public interface NotificationRepository extends JpaRepository findByRequestId(UUID requestId, Pageable pageable); - @Modifying - @Transactional - @Query("UPDATE NotificationEntity n SET n.status = :status " + - "WHERE n.requestId = :requestId AND n.status <> :status") - int updateStatusesByRequestId(@Param("requestId") UUID requestId, - @Param("status") NotificationStatus status); - @Transactional int deleteByIdAndRecipientId(UUID id, UUID recipientId); diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/notification/NotificationRequestRepository.java b/dao/src/main/java/org/thingsboard/server/dao/sql/notification/NotificationRequestRepository.java index 611b56ee77..d28b0dc95b 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/notification/NotificationRequestRepository.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/notification/NotificationRequestRepository.java @@ -54,7 +54,7 @@ public interface NotificationRequestRepository extends JpaRepository findAllIdsByStatusAndRuleId(@Param("status") NotificationRequestStatus status, @Param("ruleId") UUID ruleId); - List findAllByRuleIdAndOriginatorEntityTypeAndOriginatorEntityId(UUID ruleId, EntityType originatorEntityType, UUID originatorEntityId); + List findAllByRuleIdAndOriginatorEntityIdAndOriginatorEntityType(UUID ruleId, UUID originatorEntityId, EntityType originatorEntityType); Page findAllByStatus(NotificationRequestStatus status, Pageable pageable); diff --git a/dao/src/main/java/org/thingsboard/server/dao/user/UserServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/user/UserServiceImpl.java index c59efe69ff..4b55cb099b 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/user/UserServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/user/UserServiceImpl.java @@ -250,7 +250,7 @@ public class UserServiceImpl extends AbstractEntityService implements UserServic } @Override - public PageData findUsers(TenantId tenantId, PageLink pageLink) { + public PageData findAllUsers(TenantId tenantId, PageLink pageLink) { return userDao.findAll(tenantId, pageLink); } diff --git a/dao/src/main/resources/sql/schema-entities-idx.sql b/dao/src/main/resources/sql/schema-entities-idx.sql index fb6940e2cb..34359302ad 100644 --- a/dao/src/main/resources/sql/schema-entities-idx.sql +++ b/dao/src/main/resources/sql/schema-entities-idx.sql @@ -97,8 +97,11 @@ CREATE INDEX IF NOT EXISTS idx_notification_template_tenant_id_created_time ON n CREATE INDEX IF NOT EXISTS idx_notification_rule_tenant_id_created_time ON notification_rule(tenant_id, created_time DESC); CREATE INDEX IF NOT EXISTS idx_notification_request_tenant_id_originator_type_created_time ON notification_request(tenant_id, originator_entity_type, created_time DESC); + CREATE INDEX IF NOT EXISTS idx_notification_request_rule_id_originator_entity_id ON notification_request(rule_id, originator_entity_id); + CREATE INDEX IF NOT EXISTS idx_notification_request_status ON notification_request(status); CREATE INDEX IF NOT EXISTS idx_notification_id_recipient_id ON notification(id, recipient_id); + CREATE INDEX IF NOT EXISTS idx_notification_recipient_id_status_created_time ON notification(recipient_id, status, created_time DESC); diff --git a/dao/src/main/resources/sql/schema-entities.sql b/dao/src/main/resources/sql/schema-entities.sql index f2518ecdcf..17a989a53e 100644 --- a/dao/src/main/resources/sql/schema-entities.sql +++ b/dao/src/main/resources/sql/schema-entities.sql @@ -846,7 +846,6 @@ CREATE TABLE IF NOT EXISTS notification ( subject VARCHAR(255), text VARCHAR(1000) NOT NULL, additional_config VARCHAR(1000), - info VARCHAR(1000), status VARCHAR(32) ) PARTITION BY RANGE (created_time); diff --git a/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/NotificationCenter.java b/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/NotificationCenter.java index d39897a5d3..eccc4f1423 100644 --- a/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/NotificationCenter.java +++ b/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/NotificationCenter.java @@ -25,8 +25,6 @@ public interface NotificationCenter { NotificationRequest processNotificationRequest(TenantId tenantId, NotificationRequest notificationRequest); - NotificationRequest updateNotificationRequest(TenantId tenantId, NotificationRequest notificationRequest); - void deleteNotificationRequest(TenantId tenantId, NotificationRequestId notificationRequestId); void sendBasicNotification(TenantId tenantId, UserId recipientId, String subject, String text); From a39db0a1cf329dcc4dbfaa1f4aa83769bad467b6 Mon Sep 17 00:00:00 2001 From: Vladyslav_Prykhodko Date: Wed, 15 Mar 2023 13:28:31 +0200 Subject: [PATCH 23/28] UI: Fix notification after change API --- ...fication-request-error-dialog.component.ts | 2 +- ...request-notification-dialog.component.html | 26 +++++------ .../request-notification-dialog.componet.ts | 4 +- .../rule-table/escalation-form.component.html | 4 +- .../rule-notification-dialog.component.html | 4 +- .../rule-notification-dialog.component.ts | 14 ++++++ .../template-table/template-configuration.ts | 44 +++++++++---------- ...emplate-notification-dialog.component.html | 20 ++++----- .../components/time/timeinterval.component.ts | 12 ++--- .../app/shared/models/notification.models.ts | 14 +++--- .../assets/locale/locale.constant-en_US.json | 10 ++--- 11 files changed, 85 insertions(+), 69 deletions(-) diff --git a/ui-ngx/src/app/modules/home/pages/notification-center/request-table/notification-request-error-dialog.component.ts b/ui-ngx/src/app/modules/home/pages/notification-center/request-table/notification-request-error-dialog.component.ts index d30639e310..807fa5c4a9 100644 --- a/ui-ngx/src/app/modules/home/pages/notification-center/request-table/notification-request-error-dialog.component.ts +++ b/ui-ngx/src/app/modules/home/pages/notification-center/request-table/notification-request-error-dialog.component.ts @@ -36,7 +36,7 @@ export class NotificationRequestErrorDialogComponent extends DialogComponent([ - [NotificationDeliveryMethod.PUSH, 'notification.delivery-method-type.push-failed-sent'], + [NotificationDeliveryMethod.WEB, 'notification.delivery-method-type.web-failed-sent'], [NotificationDeliveryMethod.SMS, 'notification.delivery-method-type.sms-failed-sent'], [NotificationDeliveryMethod.EMAIL, 'notification.delivery-method-type.email-failed-sent'], [NotificationDeliveryMethod.SLACK, 'notification.delivery-method-type.slack-failed-sent'], diff --git a/ui-ngx/src/app/modules/home/pages/notification-center/request-table/request-notification-dialog.component.html b/ui-ngx/src/app/modules/home/pages/notification-center/request-table/request-notification-dialog.component.html index b5f5b8057a..3d7f0b8ef3 100644 --- a/ui-ngx/src/app/modules/home/pages/notification-center/request-table/request-notification-dialog.component.html +++ b/ui-ngx/src/app/modules/home/pages/notification-center/request-table/request-notification-dialog.component.html @@ -120,13 +120,13 @@ + notificationRequestForm.get('template.configuration.deliveryMethodsTemplates.WEB.enabled').value" + [stepControl]="webTemplateForm"> {{ 'notification.web-settings' | translate }}
{{ notificationTemplateTypeTranslateMap.get(notificationType.GENERAL).hint | translate }}
-
+ notification.subject @@ -146,7 +146,7 @@ {{ 'icon.icon' | translate }} -
@@ -158,12 +158,12 @@ {{ 'notification.action-button' | translate }} -
+
notification.button-text - + {{ 'notification.button-text-required' | translate }} @@ -178,10 +178,10 @@ + *ngIf="webTemplateForm.get('additionalConfig.actionButtonConfig.linkType').value === actionButtonLinkType.LINK; else dashboardSelector"> notification.link - + {{ 'notification.link-required' | translate }} @@ -192,13 +192,13 @@ formControlName="dashboardId">
+ *ngIf="webTemplateForm.get('additionalConfig.actionButtonConfig.linkType').value === actionButtonLinkType.DASHBOARD"> {{ 'notification.set-entity-from-notification' | translate }}
@@ -270,13 +270,13 @@ strokeWidth="5" *ngIf="(isLoading$ | async) && !preview">
-
+
-
notification.delivery-method-type.push-preview
+
notification.delivery-method-type.web-preview
- +
diff --git a/ui-ngx/src/app/modules/home/pages/notification-center/request-table/request-notification-dialog.componet.ts b/ui-ngx/src/app/modules/home/pages/notification-center/request-table/request-notification-dialog.componet.ts index ceeb6d2e73..909d4acd6b 100644 --- a/ui-ngx/src/app/modules/home/pages/notification-center/request-table/request-notification-dialog.componet.ts +++ b/ui-ngx/src/app/modules/home/pages/notification-center/request-table/request-notification-dialog.componet.ts @@ -188,8 +188,8 @@ export class RequestNotificationDialogComponent extends this.preview = null; this.notificationService.getNotificationRequestPreview(this.notificationFormValue).pipe( map(data => { - if (data.processedTemplates.PUSH?.enabled) { - (data.processedTemplates.PUSH as any).text = data.processedTemplates.PUSH.body; + if (data.processedTemplates.WEB?.enabled) { + (data.processedTemplates.WEB as any).text = data.processedTemplates.WEB.body; } return data; }) diff --git a/ui-ngx/src/app/modules/home/pages/notification-center/rule-table/escalation-form.component.html b/ui-ngx/src/app/modules/home/pages/notification-center/rule-table/escalation-form.component.html index 43409aa9cc..f37da71867 100644 --- a/ui-ngx/src/app/modules/home/pages/notification-center/rule-table/escalation-form.component.html +++ b/ui-ngx/src/app/modules/home/pages/notification-center/rule-table/escalation-form.component.html @@ -24,8 +24,8 @@ notification.notify
diff --git a/ui-ngx/src/app/modules/home/pages/notification-center/rule-table/rule-notification-dialog.component.html b/ui-ngx/src/app/modules/home/pages/notification-center/rule-table/rule-notification-dialog.component.html index a3db4399f9..ff45dba894 100644 --- a/ui-ngx/src/app/modules/home/pages/notification-center/rule-table/rule-notification-dialog.component.html +++ b/ui-ngx/src/app/modules/home/pages/notification-center/rule-table/rule-notification-dialog.component.html @@ -76,7 +76,7 @@
- notification.hierarchy-of-receiving + notification.notification-chain
@@ -108,7 +108,7 @@
-
+
notification.clear-rule alarm.alarm-status-list diff --git a/ui-ngx/src/app/modules/home/pages/notification-center/rule-table/rule-notification-dialog.component.ts b/ui-ngx/src/app/modules/home/pages/notification-center/rule-table/rule-notification-dialog.component.ts index b9c64b7235..396c296d07 100644 --- a/ui-ngx/src/app/modules/home/pages/notification-center/rule-table/rule-notification-dialog.component.ts +++ b/ui-ngx/src/app/modules/home/pages/notification-center/rule-table/rule-notification-dialog.component.ts @@ -146,6 +146,16 @@ export class RuleNotificationDialogComponent extends } }); + this.ruleNotificationForm.get('recipientsConfig.escalationTable').valueChanges.pipe( + takeUntil(this.destroy$) + ).subscribe(value => { + if (this.countRecipientsChainConfig() > 1) { + this.alarmTemplateForm.get('triggerConfig.clearRule').enable({emitEvent: false}); + } else { + this.alarmTemplateForm.get('triggerConfig.clearRule').disable({emitEvent: false}); + } + }) + this.alarmTemplateForm = this.fb.group({ triggerConfig: this.fb.group({ alarmTypes: [null], @@ -312,4 +322,8 @@ export class RuleNotificationDialogComponent extends } }); } + + countRecipientsChainConfig(): number { + return Object.keys(this.ruleNotificationForm.get('recipientsConfig.escalationTable').value ?? {}).length; + } } diff --git a/ui-ngx/src/app/modules/home/pages/notification-center/template-table/template-configuration.ts b/ui-ngx/src/app/modules/home/pages/notification-center/template-table/template-configuration.ts index 9621b88bd7..260690e30a 100644 --- a/ui-ngx/src/app/modules/home/pages/notification-center/template-table/template-configuration.ts +++ b/ui-ngx/src/app/modules/home/pages/notification-center/template-table/template-configuration.ts @@ -39,7 +39,7 @@ import { deepClone, deepTrim } from '@core/utils'; export abstract class TemplateConfiguration extends DialogComponent implements OnDestroy{ templateNotificationForm: FormGroup; - pushTemplateForm: FormGroup; + webTemplateForm: FormGroup; emailTemplateForm: FormGroup; smsTemplateForm: FormGroup; slackTemplateForm: FormGroup; @@ -87,10 +87,10 @@ export abstract class TemplateConfiguration extends DialogComponent< this.notificationDeliveryMethods.forEach(method => { (this.templateNotificationForm.get('configuration.deliveryMethodsTemplates') as FormGroup) - .addControl(method, this.fb.group({enabled: method === NotificationDeliveryMethod.PUSH}), {emitEvent: false}); + .addControl(method, this.fb.group({enabled: method === NotificationDeliveryMethod.WEB}), {emitEvent: false}); }); - this.pushTemplateForm = this.fb.group({ + this.webTemplateForm = this.fb.group({ subject: [''], body: [''], additionalConfig: this.fb.group({ @@ -111,43 +111,43 @@ export abstract class TemplateConfiguration extends DialogComponent< }) }); - this.pushTemplateForm.get('additionalConfig.icon.enabled').valueChanges.pipe( + this.webTemplateForm.get('additionalConfig.icon.enabled').valueChanges.pipe( takeUntil(this.destroy$) ).subscribe((value) => { if (value) { - this.pushTemplateForm.get('additionalConfig.icon.icon').enable({emitEvent: false}); + this.webTemplateForm.get('additionalConfig.icon.icon').enable({emitEvent: false}); } else { - this.pushTemplateForm.get('additionalConfig.icon.icon').disable({emitEvent: false}); + this.webTemplateForm.get('additionalConfig.icon.icon').disable({emitEvent: false}); } }); - this.pushTemplateForm.get('additionalConfig.actionButtonConfig.enabled').valueChanges.pipe( + this.webTemplateForm.get('additionalConfig.actionButtonConfig.enabled').valueChanges.pipe( takeUntil(this.destroy$) ).subscribe((value) => { if (value) { - this.pushTemplateForm.get('additionalConfig.actionButtonConfig').enable({emitEvent: false}); - this.pushTemplateForm.get('additionalConfig.actionButtonConfig.linkType').updateValueAndValidity({onlySelf: true}); + this.webTemplateForm.get('additionalConfig.actionButtonConfig').enable({emitEvent: false}); + this.webTemplateForm.get('additionalConfig.actionButtonConfig.linkType').updateValueAndValidity({onlySelf: true}); } else { - this.pushTemplateForm.get('additionalConfig.actionButtonConfig').disable({emitEvent: false}); - this.pushTemplateForm.get('additionalConfig.actionButtonConfig.enabled').enable({emitEvent: false}); + this.webTemplateForm.get('additionalConfig.actionButtonConfig').disable({emitEvent: false}); + this.webTemplateForm.get('additionalConfig.actionButtonConfig.enabled').enable({emitEvent: false}); } }); - this.pushTemplateForm.get('additionalConfig.actionButtonConfig.linkType').valueChanges.pipe( + this.webTemplateForm.get('additionalConfig.actionButtonConfig.linkType').valueChanges.pipe( takeUntil(this.destroy$) ).subscribe((value) => { - const isEnabled = this.pushTemplateForm.get('additionalConfig.actionButtonConfig.enabled').value; + const isEnabled = this.webTemplateForm.get('additionalConfig.actionButtonConfig.enabled').value; if (isEnabled) { if (value === ActionButtonLinkType.LINK) { - this.pushTemplateForm.get('additionalConfig.actionButtonConfig.link').enable({emitEvent: false}); - this.pushTemplateForm.get('additionalConfig.actionButtonConfig.dashboardId').disable({emitEvent: false}); - this.pushTemplateForm.get('additionalConfig.actionButtonConfig.dashboardState').disable({emitEvent: false}); - this.pushTemplateForm.get('additionalConfig.actionButtonConfig.setEntityIdInState').disable({emitEvent: false}); + this.webTemplateForm.get('additionalConfig.actionButtonConfig.link').enable({emitEvent: false}); + this.webTemplateForm.get('additionalConfig.actionButtonConfig.dashboardId').disable({emitEvent: false}); + this.webTemplateForm.get('additionalConfig.actionButtonConfig.dashboardState').disable({emitEvent: false}); + this.webTemplateForm.get('additionalConfig.actionButtonConfig.setEntityIdInState').disable({emitEvent: false}); } else { - this.pushTemplateForm.get('additionalConfig.actionButtonConfig.link').disable({emitEvent: false}); - this.pushTemplateForm.get('additionalConfig.actionButtonConfig.dashboardId').enable({emitEvent: false}); - this.pushTemplateForm.get('additionalConfig.actionButtonConfig.dashboardState').enable({emitEvent: false}); - this.pushTemplateForm.get('additionalConfig.actionButtonConfig.setEntityIdInState').enable({emitEvent: false}); + this.webTemplateForm.get('additionalConfig.actionButtonConfig.link').disable({emitEvent: false}); + this.webTemplateForm.get('additionalConfig.actionButtonConfig.dashboardId').enable({emitEvent: false}); + this.webTemplateForm.get('additionalConfig.actionButtonConfig.dashboardState').enable({emitEvent: false}); + this.webTemplateForm.get('additionalConfig.actionButtonConfig.setEntityIdInState').enable({emitEvent: false}); } } }); @@ -166,7 +166,7 @@ export abstract class TemplateConfiguration extends DialogComponent< }); this.deliveryMethodFormsMap = new Map([ - [NotificationDeliveryMethod.PUSH, this.pushTemplateForm], + [NotificationDeliveryMethod.WEB, this.webTemplateForm], [NotificationDeliveryMethod.EMAIL, this.emailTemplateForm], [NotificationDeliveryMethod.SMS, this.smsTemplateForm], [NotificationDeliveryMethod.SLACK, this.slackTemplateForm] diff --git a/ui-ngx/src/app/modules/home/pages/notification-center/template-table/template-notification-dialog.component.html b/ui-ngx/src/app/modules/home/pages/notification-center/template-table/template-notification-dialog.component.html index 573d5404b3..67ae8d0e49 100644 --- a/ui-ngx/src/app/modules/home/pages/notification-center/template-table/template-notification-dialog.component.html +++ b/ui-ngx/src/app/modules/home/pages/notification-center/template-table/template-notification-dialog.component.html @@ -84,13 +84,13 @@ - + {{ 'notification.web-settings' | translate }}
{{ notificationTemplateTypeTranslateMap.get(templateNotificationForm.get('notificationType').value).hint | translate }}
-
+ notification.subject @@ -110,7 +110,7 @@ {{ 'icon.icon' | translate }} -
@@ -122,12 +122,12 @@ {{ 'notification.action-button' | translate }} -
+
notification.button-text - + {{ 'notification.button-text-required' | translate }} @@ -142,10 +142,10 @@ + *ngIf="webTemplateForm.get('additionalConfig.actionButtonConfig.linkType').value === actionButtonLinkType.LINK; else dashboardSelector"> notification.link - + {{ 'notification.link-required' | translate }} @@ -156,13 +156,13 @@ formControlName="dashboardId">
+ *ngIf="webTemplateForm.get('additionalConfig.actionButtonConfig.linkType').value === actionButtonLinkType.DASHBOARD"> {{ 'notification.set-entity-from-notification' | translate }}
diff --git a/ui-ngx/src/app/shared/components/time/timeinterval.component.ts b/ui-ngx/src/app/shared/components/time/timeinterval.component.ts index be2c449eaa..49bfec6fe3 100644 --- a/ui-ngx/src/app/shared/components/time/timeinterval.component.ts +++ b/ui-ngx/src/app/shared/components/time/timeinterval.component.ts @@ -17,7 +17,7 @@ import { Component, EventEmitter, forwardRef, Input, OnInit, Output } from '@angular/core'; import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms'; import { TimeInterval, TimeService } from '@core/services/time.service'; -import { coerceBooleanProperty } from '@angular/cdk/coercion'; +import { coerceBooleanProperty, coerceNumberProperty } from '@angular/cdk/coercion'; import { SubscriptSizing } from '@angular/material/form-field'; @Component({ @@ -39,8 +39,9 @@ export class TimeintervalComponent implements OnInit, ControlValueAccessor { @Input() set min(min: number) { - if (typeof min !== 'undefined' && min !== this.minValue) { - this.minValue = min; + const minValueData = coerceNumberProperty(min); + if (typeof minValueData !== 'undefined' && minValueData !== this.minValue) { + this.minValue = minValueData; this.maxValue = Math.max(this.maxValue, this.minValue); this.updateView(); } @@ -48,8 +49,9 @@ export class TimeintervalComponent implements OnInit, ControlValueAccessor { @Input() set max(max: number) { - if (typeof max !== 'undefined' && max !== this.maxValue) { - this.maxValue = max; + const maxValueData = coerceNumberProperty(max); + if (typeof maxValueData !== 'undefined' && maxValueData !== this.maxValue) { + this.maxValue = maxValueData; this.minValue = Math.min(this.minValue, this.maxValue); this.updateView(); } diff --git a/ui-ngx/src/app/shared/models/notification.models.ts b/ui-ngx/src/app/shared/models/notification.models.ts index 28bf639ab0..aa644ada73 100644 --- a/ui-ngx/src/app/shared/models/notification.models.ts +++ b/ui-ngx/src/app/shared/models/notification.models.ts @@ -36,7 +36,7 @@ export interface Notification { readonly info: NotificationInfo; readonly status: NotificationStatus; readonly createdTime: number; - readonly additionalConfig?: PushDeliveryMethodAdditionalConfig; + readonly additionalConfig?: WebDeliveryMethodAdditionalConfig; } export interface NotificationInfo { @@ -189,18 +189,18 @@ interface NotificationTemplateConfig { } export interface DeliveryMethodNotificationTemplate extends - Partial{ + Partial{ body?: string; enabled: boolean; method: NotificationDeliveryMethod; } -interface PushDeliveryMethodNotificationTemplate { +interface WebDeliveryMethodNotificationTemplate { subject?: string; - additionalConfig: PushDeliveryMethodAdditionalConfig; + additionalConfig: WebDeliveryMethodAdditionalConfig; } -interface PushDeliveryMethodAdditionalConfig { +interface WebDeliveryMethodAdditionalConfig { icon: { enabled: boolean; icon: string; @@ -232,14 +232,14 @@ export enum NotificationStatus { } export enum NotificationDeliveryMethod { - PUSH = 'PUSH', + WEB = 'WEB', SMS = 'SMS', EMAIL = 'EMAIL', SLACK = 'SLACK' } export const NotificationDeliveryMethodTranslateMap = new Map([ - [NotificationDeliveryMethod.PUSH, 'notification.delivery-method-type.push'], + [NotificationDeliveryMethod.WEB, 'notification.delivery-method-type.web'], [NotificationDeliveryMethod.SMS, 'notification.delivery-method-type.sms'], [NotificationDeliveryMethod.EMAIL, 'notification.delivery-method-type.email'], [NotificationDeliveryMethod.SLACK, 'notification.delivery-method-type.slack'] 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 2595622701..c1fcd07d3d 100644 --- a/ui-ngx/src/assets/locale/locale.constant-en_US.json +++ b/ui-ngx/src/assets/locale/locale.constant-en_US.json @@ -2755,9 +2755,9 @@ "email": "Email", "email-failed-sent": "Email messages failed sent", "email-preview": "Email notification preview", - "push": "Web", - "push-failed-sent": "Web messages failed sent", - "push-preview": "Web notification preview", + "web": "Web", + "web-failed-sent": "Web messages failed sent", + "web-preview": "Web notification preview", "slack": "Slack", "slack-failed-sent": "Slack messages failed sent", "slack-preview": "Slack notification preview", @@ -2785,7 +2785,6 @@ "fails": "Fails", "filter": "Filter", "first-recipient": "First recipient", - "hierarchy-of-receiving": "Hierarchy of receiving notifications", "inbox": "Inbox", "link": "Link", "link-required": "Link is required", @@ -2812,6 +2811,7 @@ "not-found-slack-recipient": "Not found slack recipient", "notification": "Notification", "notification-center": "Notification center", + "notification-chain": "Notification chain", "notification-target": "Notification recipient", "notify": "notify", "notify-again": "Notify again", @@ -2867,7 +2867,7 @@ "template-hint": { "alarm": "Available params: ${alarmType}, ${alarmSeverity}, ${alarmStatus}, ${alarmOriginatorEntityType}, ${alarmOriginatorId}, ${alarmId}, ${alarmAction}", "alarm-comment": "Available params: ${comment}, ${alarmType}, ${alarmId}, ${alarmType}, ${alarmSeverity}, ${alarmStatus}, ${alarmOriginatorEntityType}, ${alarmOriginatorId}, ${alarmId}, ${alarmAction}", - "device-inactivity": "Available params: ${deviceName}, ${deviceType}, ${deviceId}", + "device-inactivity": "Available params: ${deviceName}, ${deviceLabel}, ${deviceType}, ${deviceId}", "entity-action": "Available params: ${actionType}, ${entityType}, ${entityName}, ${entityId}, ${originatorUserName}, ${originatorUserId}", "general": "Available params: ${recipientEmail}, ${recipientFirstName}, ${recipientLastName}" }, From e69970b09f49b088ed4c1404338a7689f7ee3f59 Mon Sep 17 00:00:00 2001 From: Vladyslav_Prykhodko Date: Wed, 15 Mar 2023 16:15:53 +0200 Subject: [PATCH 24/28] UI: Fix notification escalation table --- .../rule-table/escalations.component.ts | 34 +++++-------------- .../components/time/timeinterval.component.ts | 34 +++++-------------- 2 files changed, 17 insertions(+), 51 deletions(-) diff --git a/ui-ngx/src/app/modules/home/pages/notification-center/rule-table/escalations.component.ts b/ui-ngx/src/app/modules/home/pages/notification-center/rule-table/escalations.component.ts index 14f93566ee..4413ca2941 100644 --- a/ui-ngx/src/app/modules/home/pages/notification-center/rule-table/escalations.component.ts +++ b/ui-ngx/src/app/modules/home/pages/notification-center/rule-table/escalations.component.ts @@ -54,7 +54,6 @@ import { coerceBoolean } from '@shared/decorators/coerce-boolean'; export class EscalationsComponent implements ControlValueAccessor, Validator, OnDestroy { escalationsFormGroup: FormGroup; - newEscalation = false; @Input() @coerceBoolean() @@ -63,11 +62,6 @@ export class EscalationsComponent implements ControlValueAccessor, Validator, On @Input() disabled: boolean; - private mainEscalaion = { - delayInSec: 0, - targets: null - }; - private destroy$ = new Subject(); private propagateChange = (v: any) => { }; @@ -113,23 +107,18 @@ export class EscalationsComponent implements ControlValueAccessor, Validator, On writeValue(escalations: {[key: string]: Array} | null): void { const escalationParse: Array = []; - // tslint:disable-next-line:forin for (const escalation in escalations) { - escalationParse.push({delayInSec: Number(escalation), targets: escalations[escalation]}); + escalationParse.push({delayInSec: Number(escalation) * 1000, targets: escalations[escalation]}); } if (escalationParse.length === 0) { - this.addEscalation(); + this.addEscalation(0); } else if (escalationParse?.length === this.escalationsFormArray.length) { this.escalationsFormArray.patchValue(escalationParse, {emitEvent: false}); } else { const escalationsControls: Array = []; - if (escalationParse) { - escalationParse.forEach(escalation => { - escalationsControls.push(this.fb.control(escalation, [Validators.required])); - }); - } else { - escalationsControls.push(this.fb.control(this.mainEscalaion, [Validators.required])); - } + escalationParse.forEach(escalation => { + escalationsControls.push(this.fb.control(escalation, [Validators.required])); + }); this.escalationsFormGroup.setControl('escalations', this.fb.array(escalationsControls), {emitEvent: false}); if (this.disabled) { this.escalationsFormGroup.disable({emitEvent: false}); @@ -143,18 +132,13 @@ export class EscalationsComponent implements ControlValueAccessor, Validator, On (this.escalationsFormGroup.get('escalations') as FormArray).removeAt(index); } - public addEscalation() { + public addEscalation(delay = 60000) { const escalation = { - delayInSec: 0, + delayInSec: delay, targets: null }; - this.newEscalation = true; const escalationArray = this.escalationsFormGroup.get('escalations') as FormArray; - escalationArray.push(this.fb.control(escalation, [])); - this.escalationsFormGroup.updateValueAndValidity(); - if (!this.escalationsFormGroup.valid) { - this.updateModel(); - } + escalationArray.push(this.fb.control(escalation, []), {emitEvent: false}); } public validate(c: AbstractControl): ValidationErrors | null { @@ -168,7 +152,7 @@ export class EscalationsComponent implements ControlValueAccessor, Validator, On private updateModel() { const escalations = {}; this.escalationsFormGroup.get('escalations').value.forEach( - escalation => escalations[escalation.delayInSec] = escalation.targets + escalation => escalations[escalation.delayInSec / 1000] = escalation.targets ); this.propagateChange(escalations); } diff --git a/ui-ngx/src/app/shared/components/time/timeinterval.component.ts b/ui-ngx/src/app/shared/components/time/timeinterval.component.ts index 49bfec6fe3..b3375cc53d 100644 --- a/ui-ngx/src/app/shared/components/time/timeinterval.component.ts +++ b/ui-ngx/src/app/shared/components/time/timeinterval.component.ts @@ -17,8 +17,9 @@ import { Component, EventEmitter, forwardRef, Input, OnInit, Output } from '@angular/core'; import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms'; import { TimeInterval, TimeService } from '@core/services/time.service'; -import { coerceBooleanProperty, coerceNumberProperty } from '@angular/cdk/coercion'; +import { coerceNumberProperty } from '@angular/cdk/coercion'; import { SubscriptSizing } from '@angular/material/form-field'; +import { coerceBoolean } from '@shared/decorators/coerce-boolean'; @Component({ selector: 'tb-timeinterval', @@ -59,38 +60,19 @@ export class TimeintervalComponent implements OnInit, ControlValueAccessor { @Input() predefinedName: string; - isEditValue = false; - @Input() - set isEdit(val) { - this.isEditValue = coerceBooleanProperty(val); - } - - get isEdit() { - return this.isEditValue; - } + @coerceBoolean() + isEdit = false; hideFlagValue = false; @Input() - get hideFlag() { - return this.hideFlagValue; - } - - set hideFlag(val) { - this.hideFlagValue = coerceBooleanProperty(val); - } - - private disabledAdvancedValue = false; - - get disabledAdvanced() { - return this.disabledAdvancedValue; - } + @coerceBoolean() + hideFlag = false; @Input() - set disabledAdvanced(val) { - this.disabledAdvancedValue = coerceBooleanProperty(val); - } + @coerceBoolean() + disabledAdvanced = false @Output() hideFlagChange = new EventEmitter(); From ec11d4174be414d7c4e0d3f6a1c1b58eaa93fcde Mon Sep 17 00:00:00 2001 From: Vladyslav_Prykhodko Date: Wed, 15 Mar 2023 17:26:50 +0200 Subject: [PATCH 25/28] UI: Improvement rule notification alarm --- .../rule-table/escalations.component.html | 2 +- .../rule-notification-dialog.component.html | 35 +++++++++++-------- .../rule-notification-dialog.component.scss | 15 +++++--- 3 files changed, 32 insertions(+), 20 deletions(-) diff --git a/ui-ngx/src/app/modules/home/pages/notification-center/rule-table/escalations.component.html b/ui-ngx/src/app/modules/home/pages/notification-center/rule-table/escalations.component.html index aff3d5f730..77db15257c 100644 --- a/ui-ngx/src/app/modules/home/pages/notification-center/rule-table/escalations.component.html +++ b/ui-ngx/src/app/modules/home/pages/notification-center/rule-table/escalations.component.html @@ -38,7 +38,7 @@ notification.no-rule
-
+
- -
- notification.clear-rule - - alarm.alarm-status-list - - - {{ alarmSearchStatusTranslationMap.get(searchStatus) | translate }} - - - -
diff --git a/ui-ngx/src/app/modules/home/pages/notification-center/rule-table/rule-notification-dialog.component.scss b/ui-ngx/src/app/modules/home/pages/notification-center/rule-table/rule-notification-dialog.component.scss index 51c6fae51e..f9d0d4b63d 100644 --- a/ui-ngx/src/app/modules/home/pages/notification-center/rule-table/rule-notification-dialog.component.scss +++ b/ui-ngx/src/app/modules/home/pages/notification-center/rule-table/rule-notification-dialog.component.scss @@ -38,10 +38,6 @@ margin-bottom: 12px; } - &.tb-margin-2 { - margin-bottom: 24px; - } - &.tb-hierarchy { padding: 0 0 8px 16px; } @@ -51,6 +47,15 @@ color: rgba(0, 0, 0, .7); width: fit-content; } + + .mat-body-2 { + margin-bottom: 8px; + color: rgba(0,0,0,.76); + } + + .clear-button-space { + margin-right: 48px; + } } ::ng-deep { @@ -71,7 +76,7 @@ } .mat-horizontal-content-container { - height: 550px; + height: 700px; max-height: 100%; width: 100%;; overflow-y: auto; From c7dbf6be89ad9709026e8828a9941d7550c057a9 Mon Sep 17 00:00:00 2001 From: Vladyslav_Prykhodko Date: Wed, 15 Mar 2023 18:39:06 +0200 Subject: [PATCH 26/28] UI: Add new notification type alarm assignment --- .../rule-notification-dialog.component.html | 48 +++++++++++++++++++ .../rule-notification-dialog.component.ts | 10 ++++ .../app/shared/models/notification.models.ts | 18 +++++-- .../assets/locale/locale.constant-en_US.json | 5 ++ 4 files changed, 77 insertions(+), 4 deletions(-) diff --git a/ui-ngx/src/app/modules/home/pages/notification-center/rule-table/rule-notification-dialog.component.html b/ui-ngx/src/app/modules/home/pages/notification-center/rule-table/rule-notification-dialog.component.html index ddbc21e294..6afa5f3440 100644 --- a/ui-ngx/src/app/modules/home/pages/notification-center/rule-table/rule-notification-dialog.component.html +++ b/ui-ngx/src/app/modules/home/pages/notification-center/rule-table/rule-notification-dialog.component.html @@ -258,6 +258,54 @@ + + {{ 'notification.alarm-assignment-trigger-settings' | translate }} +
+
+
+ notification.filter + + + + + alarm.alarm-severity-list + + + {{ alarmSeverityTranslationMap.get(alarmSeverity) | translate }} + + + + + alarm.alarm-status-list + + + {{ alarmSearchStatusTranslationMap.get(searchStatus) | translate }} + + + +
+ + {{ 'notification.notify-on-unassign' | translate }} + +
+
+
+
+ + notification.description + + +
+
+
diff --git a/ui-ngx/src/app/modules/home/pages/notification-center/rule-table/rule-notification-dialog.component.ts b/ui-ngx/src/app/modules/home/pages/notification-center/rule-table/rule-notification-dialog.component.ts index 396c296d07..7af6d846be 100644 --- a/ui-ngx/src/app/modules/home/pages/notification-center/rule-table/rule-notification-dialog.component.ts +++ b/ui-ngx/src/app/modules/home/pages/notification-center/rule-table/rule-notification-dialog.component.ts @@ -72,6 +72,7 @@ export class RuleNotificationDialogComponent extends deviceInactivityTemplateForm: FormGroup; entityActionTemplateForm: FormGroup; alarmCommentTemplateForm: FormGroup; + alarmAssignmentTemplateForm: FormGroup; triggerType = TriggerType; triggerTypes: TriggerType[] = Object.values(TriggerType); @@ -203,6 +204,15 @@ export class RuleNotificationDialogComponent extends }) }); + this.alarmAssignmentTemplateForm = this.fb.group({ + triggerConfig: this.fb.group({ + alarmTypes: [null], + alarmSeverities: [[]], + alarmStatuses: [[]], + notifyOnUnassign: [true] + }) + }); + this.triggerTypeFormsMap = new Map([ [TriggerType.ALARM, this.alarmTemplateForm], [TriggerType.ALARM_COMMENT, this.alarmCommentTemplateForm], diff --git a/ui-ngx/src/app/shared/models/notification.models.ts b/ui-ngx/src/app/shared/models/notification.models.ts index aa644ada73..cfcabdbb5e 100644 --- a/ui-ngx/src/app/shared/models/notification.models.ts +++ b/ui-ngx/src/app/shared/models/notification.models.ts @@ -288,14 +288,16 @@ export enum NotificationType { ALARM = 'ALARM', DEVICE_INACTIVITY = 'DEVICE_INACTIVITY', ENTITY_ACTION = 'ENTITY_ACTION', - ALARM_COMMENT = 'ALARM_COMMENT' + ALARM_COMMENT = 'ALARM_COMMENT', + ALARM_ASSIGNMENT = 'ALARM_ASSIGNMENT' } export const NotificationTypeIcons = new Map([ [NotificationType.ALARM, 'warning'], [NotificationType.DEVICE_INACTIVITY, 'phonelink_off'], [NotificationType.ENTITY_ACTION, 'devices'], - [NotificationType.ALARM_COMMENT, 'warning'] + [NotificationType.ALARM_COMMENT, 'comment'], + [NotificationType.ALARM_ASSIGNMENT, 'assignment_turned_in'], ]); export const AlarmSeverityNotificationColors = new Map( @@ -353,6 +355,12 @@ export const NotificationTemplateTypeTranslateMap = new Map([ [TriggerType.ALARM, 'notification.trigger.alarm'], [TriggerType.DEVICE_INACTIVITY, 'notification.trigger.device-inactivity'], [TriggerType.ENTITY_ACTION, 'notification.trigger.entity-action'], - [TriggerType.ALARM_COMMENT, 'notification.trigger.alarm-comment'] + [TriggerType.ALARM_COMMENT, 'notification.trigger.alarm-comment'], + [TriggerType.ALARM_ASSIGNMENT, 'notification.trigger.alarm-assignment'], ]); 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 c1fcd07d3d..2770a5235a 100644 --- a/ui-ngx/src/assets/locale/locale.constant-en_US.json +++ b/ui-ngx/src/assets/locale/locale.constant-en_US.json @@ -2723,6 +2723,7 @@ "add-target": "Add recipient", "add-template": "Add template", "after": "After", + "alarm-assignment-trigger-settings": "Alarm assignment trigger settings", "alarm-comment-trigger-settings": "Alarm comment trigger settings", "alarm-trigger-settings": "Alarm trigger settings", "all": "All", @@ -2815,6 +2816,7 @@ "notification-target": "Notification recipient", "notify": "notify", "notify-again": "Notify again", + "notify-on-unassign": "Notify on unassign", "platform-users": "Platform users", "recipient": "Recipient", "recipient-type": "Recipient type", @@ -2866,6 +2868,7 @@ "template": "Template", "template-hint": { "alarm": "Available params: ${alarmType}, ${alarmSeverity}, ${alarmStatus}, ${alarmOriginatorEntityType}, ${alarmOriginatorId}, ${alarmId}, ${alarmAction}", + "alarm-assignment": "Available params: ${assigneeFirstName}, ${assigneeLastName}, ${assigneeEmail}, ${assigneeFirstName}, ${userName}, ${alarmId}, ${alarmType}, ${alarmSeverity}, ${alarmStatus}, ${alarmOriginatorEntityType}, ${alarmOriginatorId}, ${alarmId}, ${alarmAction}", "alarm-comment": "Available params: ${comment}, ${alarmType}, ${alarmId}, ${alarmType}, ${alarmSeverity}, ${alarmStatus}, ${alarmOriginatorEntityType}, ${alarmOriginatorId}, ${alarmId}, ${alarmAction}", "device-inactivity": "Available params: ${deviceName}, ${deviceLabel}, ${deviceType}, ${deviceId}", "entity-action": "Available params: ${actionType}, ${entityType}, ${entityName}, ${entityId}, ${originatorUserName}, ${originatorUserId}", @@ -2875,6 +2878,7 @@ "template-required": "Template is required", "template-type": { "alarm": "Alarm", + "alarm-assignment": "Alarm assignment", "alarm-comment": "Alarm comment", "device-inactivity": "Device inactivity", "entity-action": "Entity action", @@ -2884,6 +2888,7 @@ "time": "Time", "trigger": { "alarm": "Alarm", + "alarm-assignment": "Alarm assignment", "alarm-comment": "Alarm comment", "device-inactivity": "Device inactivity", "entity-action": "Entity action", From 4a20adc62e14fc3c73083af6851cf848d4b8493e Mon Sep 17 00:00:00 2001 From: ViacheslavKlimov Date: Thu, 16 Mar 2023 13:12:04 +0200 Subject: [PATCH 27/28] Alarm related notification rules --- .../main/data/upgrade/3.4.4/schema_update.sql | 4 +- .../apiusage/DefaultApiLimitService.java | 53 ++++++++++++ .../DefaultTbNotificationEntityService.java | 3 +- .../entitiy/TbNotificationEntityService.java | 3 +- ...aultNotificationRuleProcessingService.java | 61 ++++++++++---- .../NotificationRuleProcessingService.java | 14 +++- .../AlarmAssignmentTriggerProcessor.java | 79 ++++++++++++++++++ .../trigger/AlarmCommentTriggerProcessor.java | 24 ++++-- .../rule/trigger/AlarmTriggerProcessor.java | 81 +++++++++++++------ .../DeviceInactivityTriggerProcessor.java | 1 + .../EntitiesLimitTriggerProcessor.java | 62 ++++++++++++++ .../NewPlatformVersionTriggerProcessor.java | 45 +++++++++++ .../impl/BackupCodeTwoFaProvider.java | 2 +- .../state/DefaultDeviceStateService.java | 4 + .../DefaultSubscriptionManagerService.java | 6 -- .../DefaultGitVersionControlQueueService.java | 5 +- .../DefaultAlarmSubscriptionService.java | 4 + .../service/update/DefaultUpdateService.java | 11 ++- .../notification/NotificationRuleApiTest.java | 5 +- .../server/dao/alarm/AlarmApiCallResult.java | 13 ++- .../dao/usagerecord/ApiLimitService.java | 25 ++++++ .../NotificationProcessingContext.java | 3 +- .../data/notification/NotificationType.java | 5 +- .../info/AlarmAssignmentNotificationInfo.java | 78 ++++++++++++++++++ .../info/AlarmCommentNotificationInfo.java | 19 ++++- .../info/AlarmNotificationInfo.java | 17 ++-- .../DeviceInactivityNotificationInfo.java | 7 +- .../info/EntitiesLimitNotificationInfo.java | 45 +++++++++++ .../info/EntityActionNotificationInfo.java | 4 +- .../NewPlatformVersionNotificationInfo.java | 42 ++++++++++ ...mponentLifecycleEventNotificationInfo.java | 6 +- .../notification/rule/NotificationRule.java | 1 + ...signmentNotificationRuleTriggerConfig.java | 37 +++++++++ ...mCommentNotificationRuleTriggerConfig.java | 1 + .../AlarmNotificationRuleTriggerConfig.java | 8 ++ ...iesLimitNotificationRuleTriggerConfig.java | 36 +++++++++ ...mVersionNotificationRuleTriggerConfig.java | 28 +++++++ .../NotificationRuleTriggerConfig.java | 5 +- .../trigger/NotificationRuleTriggerType.java | 5 +- .../DefaultTenantProfileConfiguration.java | 20 +++++ .../common/data}/util/CollectionsUtil.java | 22 ++++- .../lwm2m/server/model/LwM2MModelConfig.java | 2 +- .../uplink/DefaultLwM2mUplinkMsgHandler.java | 2 +- .../DefaultClusterVersionControlService.java | 2 +- .../server/dao/alarm/BaseAlarmService.java | 2 +- .../server/dao/model/ModelConstants.java | 3 +- .../server/dao/service/DataValidator.java | 19 ++--- .../service/validator/AssetDataValidator.java | 11 +-- .../validator/CustomerDataValidator.java | 13 +-- .../validator/DashboardDataValidator.java | 12 +-- .../validator/DeviceDataValidator.java | 12 +-- .../validator/RuleChainDataValidator.java | 9 +-- .../service/validator/UserDataValidator.java | 12 +-- .../resources/sql/schema-entities-idx.sql | 15 ++-- .../main/resources/sql/schema-entities.sql | 4 +- .../TbCopyAttributesToEntityViewNode.java | 2 +- 56 files changed, 838 insertions(+), 176 deletions(-) create mode 100644 application/src/main/java/org/thingsboard/server/service/apiusage/DefaultApiLimitService.java create mode 100644 application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/AlarmAssignmentTriggerProcessor.java create mode 100644 application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/EntitiesLimitTriggerProcessor.java create mode 100644 application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/NewPlatformVersionTriggerProcessor.java create mode 100644 common/dao-api/src/main/java/org/thingsboard/server/dao/usagerecord/ApiLimitService.java create mode 100644 common/data/src/main/java/org/thingsboard/server/common/data/notification/info/AlarmAssignmentNotificationInfo.java create mode 100644 common/data/src/main/java/org/thingsboard/server/common/data/notification/info/EntitiesLimitNotificationInfo.java create mode 100644 common/data/src/main/java/org/thingsboard/server/common/data/notification/info/NewPlatformVersionNotificationInfo.java create mode 100644 common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/AlarmAssignmentNotificationRuleTriggerConfig.java create mode 100644 common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/EntitiesLimitNotificationRuleTriggerConfig.java create mode 100644 common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/NewPlatformVersionNotificationRuleTriggerConfig.java rename common/{util/src/main/java/org/thingsboard/common => data/src/main/java/org/thingsboard/server/common/data}/util/CollectionsUtil.java (71%) diff --git a/application/src/main/data/upgrade/3.4.4/schema_update.sql b/application/src/main/data/upgrade/3.4.4/schema_update.sql index 7030ff7af1..91c49bf905 100644 --- a/application/src/main/data/upgrade/3.4.4/schema_update.sql +++ b/application/src/main/data/upgrade/3.4.4/schema_update.sql @@ -157,7 +157,7 @@ CREATE TABLE IF NOT EXISTS notification ( recipient_id UUID NOT NULL CONSTRAINT fk_notification_recipient_id REFERENCES tb_user(id) ON DELETE CASCADE, type VARCHAR(50) NOT NULL, subject VARCHAR(255), - text VARCHAR(1000) NOT NULL, + body VARCHAR(1000) NOT NULL, additional_config VARCHAR(1000), status VARCHAR(32) ) PARTITION BY RANGE (created_time); @@ -347,7 +347,7 @@ BEGIN UPDATE alarm a SET acknowledged = true, ack_ts = a_ts WHERE a.id = a_id AND a.tenant_id = t_id; END IF; SELECT * INTO result FROM alarm_info a WHERE a.id = a_id AND a.tenant_id = t_id; - RETURN json_build_object('success', true, 'modified', modified, 'alarm', row_to_json(result))::text; + RETURN json_build_object('success', true, 'modified', modified, 'alarm', row_to_json(result), 'old', row_to_json(existing))::text; END $$; diff --git a/application/src/main/java/org/thingsboard/server/service/apiusage/DefaultApiLimitService.java b/application/src/main/java/org/thingsboard/server/service/apiusage/DefaultApiLimitService.java new file mode 100644 index 0000000000..b12cb4bef3 --- /dev/null +++ b/application/src/main/java/org/thingsboard/server/service/apiusage/DefaultApiLimitService.java @@ -0,0 +1,53 @@ +/** + * Copyright © 2016-2023 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.service.apiusage; + +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.thingsboard.server.common.data.EntityType; +import org.thingsboard.server.common.data.id.TenantId; +import org.thingsboard.server.common.data.query.EntityCountQuery; +import org.thingsboard.server.common.data.query.EntityTypeFilter; +import org.thingsboard.server.common.data.tenant.profile.DefaultTenantProfileConfiguration; +import org.thingsboard.server.dao.entity.EntityService; +import org.thingsboard.server.dao.tenant.TbTenantProfileCache; +import org.thingsboard.server.dao.usagerecord.ApiLimitService; +import org.thingsboard.server.service.notification.rule.NotificationRuleProcessingService; + +@Service +@RequiredArgsConstructor +public class DefaultApiLimitService implements ApiLimitService { + + private final EntityService entityService; + private final TbTenantProfileCache tenantProfileCache; + private final NotificationRuleProcessingService notificationRuleProcessingService; + + @Override + public boolean checkEntitiesLimit(TenantId tenantId, EntityType entityType) { + DefaultTenantProfileConfiguration profileConfiguration = tenantProfileCache.get(tenantId).getDefaultProfileConfiguration(); + long limit = profileConfiguration.getEntitiesLimit(entityType); + if (limit > 0) { + EntityTypeFilter filter = new EntityTypeFilter(); + filter.setEntityType(entityType); + long currentCount = entityService.countEntitiesByQuery(tenantId, null, new EntityCountQuery(filter)); + notificationRuleProcessingService.process(tenantId, entityType, limit, currentCount); + return currentCount < limit; + } else { + return true; + } + } + +} diff --git a/application/src/main/java/org/thingsboard/server/service/entitiy/DefaultTbNotificationEntityService.java b/application/src/main/java/org/thingsboard/server/service/entitiy/DefaultTbNotificationEntityService.java index 03a0671162..fe4f761f81 100644 --- a/application/src/main/java/org/thingsboard/server/service/entitiy/DefaultTbNotificationEntityService.java +++ b/application/src/main/java/org/thingsboard/server/service/entitiy/DefaultTbNotificationEntityService.java @@ -29,6 +29,7 @@ import org.thingsboard.server.common.data.Tenant; import org.thingsboard.server.common.data.User; 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.Edge; import org.thingsboard.server.common.data.edge.EdgeEventActionType; @@ -221,7 +222,7 @@ public class DefaultTbNotificationEntityService implements TbNotificationEntityS } @Override - public void notifyCreateOrUpdateAlarm(Alarm alarm, ActionType actionType, User user, Object... additionalInfo) { + public void notifyCreateOrUpdateAlarm(AlarmInfo alarm, ActionType actionType, User user, Object... additionalInfo) { logEntityAction(alarm.getTenantId(), alarm.getOriginator(), alarm, alarm.getCustomerId(), actionType, user, additionalInfo); sendEntityNotificationMsg(alarm.getTenantId(), alarm.getId(), edgeTypeByActionType(actionType)); } diff --git a/application/src/main/java/org/thingsboard/server/service/entitiy/TbNotificationEntityService.java b/application/src/main/java/org/thingsboard/server/service/entitiy/TbNotificationEntityService.java index 3765358c6d..c5f8f85831 100644 --- a/application/src/main/java/org/thingsboard/server/service/entitiy/TbNotificationEntityService.java +++ b/application/src/main/java/org/thingsboard/server/service/entitiy/TbNotificationEntityService.java @@ -21,6 +21,7 @@ import org.thingsboard.server.common.data.Tenant; import org.thingsboard.server.common.data.User; 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.Edge; import org.thingsboard.server.common.data.edge.EdgeEventActionType; @@ -100,7 +101,7 @@ public interface TbNotificationEntityService { void notifyCreateOrUpdateOrDeleteEdge(TenantId tenantId, EdgeId edgeId, CustomerId customerId, Edge edge, ActionType actionType, User user, Object... additionalInfo); - void notifyCreateOrUpdateAlarm(Alarm alarm, ActionType actionType, User user, Object... additionalInfo); + void notifyCreateOrUpdateAlarm(AlarmInfo alarm, ActionType actionType, User user, Object... additionalInfo); void notifyAlarmComment(Alarm alarm, AlarmComment alarmComment, ActionType actionType, User user); diff --git a/application/src/main/java/org/thingsboard/server/service/notification/rule/DefaultNotificationRuleProcessingService.java b/application/src/main/java/org/thingsboard/server/service/notification/rule/DefaultNotificationRuleProcessingService.java index c62c03f1f5..5d89983b04 100644 --- a/application/src/main/java/org/thingsboard/server/service/notification/rule/DefaultNotificationRuleProcessingService.java +++ b/application/src/main/java/org/thingsboard/server/service/notification/rule/DefaultNotificationRuleProcessingService.java @@ -23,7 +23,7 @@ import org.springframework.context.event.EventListener; import org.springframework.stereotype.Service; import org.thingsboard.rule.engine.api.NotificationCenter; import org.thingsboard.server.common.data.EntityType; -import org.thingsboard.server.common.data.alarm.Alarm; +import org.thingsboard.server.common.data.UpdateMessage; import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.NotificationRequestId; import org.thingsboard.server.common.data.id.NotificationRuleId; @@ -39,11 +39,12 @@ import org.thingsboard.server.common.data.notification.rule.trigger.Notification import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent; import org.thingsboard.server.common.msg.TbMsg; import org.thingsboard.server.common.msg.plugin.ComponentLifecycleMsg; +import org.thingsboard.server.common.msg.queue.ServiceType; +import org.thingsboard.server.dao.alarm.AlarmApiCallResult; import org.thingsboard.server.dao.notification.NotificationRequestService; import org.thingsboard.server.dao.notification.NotificationRuleService; -import org.thingsboard.server.queue.discovery.PartitionService; import org.thingsboard.server.service.executors.NotificationExecutorService; -import org.thingsboard.server.service.notification.rule.trigger.AlarmTriggerProcessor.AlarmTriggerObject; +import org.thingsboard.server.service.notification.rule.trigger.EntitiesLimitTriggerProcessor.EntitiesLimitTriggerObject; import org.thingsboard.server.service.notification.rule.trigger.NotificationRuleTriggerProcessor; import org.thingsboard.server.service.notification.rule.trigger.RuleEngineComponentLifecycleEventTriggerProcessor.RuleEngineComponentLifecycleEventTriggerObject; import org.thingsboard.server.service.notification.rule.trigger.RuleEngineMsgNotificationRuleTriggerProcessor; @@ -84,12 +85,8 @@ public class DefaultNotificationRuleProcessingService implements NotificationRul } @Override - public void process(TenantId tenantId, Alarm alarm, boolean deleted) { - AlarmTriggerObject triggerObject = AlarmTriggerObject.builder() - .alarm(alarm) - .deleted(deleted) - .build(); - processTrigger(tenantId, NotificationRuleTriggerType.ALARM, alarm.getId(), triggerObject); + public void process(TenantId tenantId, AlarmApiCallResult alarmUpdate) { + processTrigger(tenantId, NotificationRuleTriggerType.ALARM, alarmUpdate.getAlarm().getId(), alarmUpdate); } @Override @@ -105,11 +102,43 @@ public class DefaultNotificationRuleProcessingService implements NotificationRul processTrigger(tenantId, NotificationRuleTriggerType.RULE_ENGINE_COMPONENT_LIFECYCLE_EVENT, componentId, triggerObject); } + @Override + public void process(UpdateMessage platformUpdateMessage) { +// if (!partitionService.resolve(ServiceType.TB_CORE, TenantId.SYS_TENANT_ID, TenantId.SYS_TENANT_ID).isMyPartition()) { +// return; +// } +// // todo: don't send repetitive notification after platform restart? +// +// processTrigger(TenantId.SYS_TENANT_ID, NotificationRuleTriggerType.NEW_PLATFORM_VERSION, TenantId.SYS_TENANT_ID, platformUpdateMessage); + } + + @Override + public void process(TenantId tenantId, EntityType entityType, long limit, long currentCount) { +// EntitiesLimitTriggerObject triggerObject = EntitiesLimitTriggerObject.builder() +// .entityType(entityType) +// .limit(limit) +// .currentCount(currentCount) +// .build(); + } + + @Override + public void process(ComponentLifecycleMsg componentLifecycleMsg) { +// EntityId entityId = componentLifecycleMsg.getEntityId(); +// switch (entityId.getEntityType()) { +// case TENANT: +// +// } + } + private void processTrigger(TenantId tenantId, NotificationRuleTriggerType triggerType, EntityId originatorEntityId, Object triggerObject) { List rules = notificationRuleService.findNotificationRulesByTenantIdAndTriggerType(tenantId, triggerType); for (NotificationRule rule : rules) { notificationExecutor.submit(() -> { - processNotificationRule(rule, originatorEntityId, triggerObject); + try { + processNotificationRule(rule, originatorEntityId, triggerObject); + } catch (Throwable e) { + log.error("Failed to process notification rule {} for trigger type {} with trigger object {}", rule.getId(), rule.getTriggerType(), triggerObject, e); + } }); } } @@ -139,14 +168,12 @@ public class DefaultNotificationRuleProcessingService implements NotificationRul return; } - if (!matchesFilter(triggerObject, triggerConfig)) { - return; + if (matchesFilter(triggerObject, triggerConfig)) { + NotificationInfo notificationInfo = constructNotificationInfo(triggerObject, triggerConfig); + rule.getRecipientsConfig().getTargetsTable().forEach((delay, targets) -> { + submitNotificationRequest(targets, rule, originatorEntityId, notificationInfo, delay); + }); } - - NotificationInfo notificationInfo = constructNotificationInfo(triggerObject, triggerConfig); - rule.getRecipientsConfig().getTargetsTable().forEach((delay, targets) -> { - submitNotificationRequest(targets, rule, originatorEntityId, notificationInfo, delay); - }); } private boolean matchesFilter(Object triggerObject, NotificationRuleTriggerConfig triggerConfig) { diff --git a/application/src/main/java/org/thingsboard/server/service/notification/rule/NotificationRuleProcessingService.java b/application/src/main/java/org/thingsboard/server/service/notification/rule/NotificationRuleProcessingService.java index d769983b6a..7d9db425f1 100644 --- a/application/src/main/java/org/thingsboard/server/service/notification/rule/NotificationRuleProcessingService.java +++ b/application/src/main/java/org/thingsboard/server/service/notification/rule/NotificationRuleProcessingService.java @@ -15,20 +15,30 @@ */ package org.thingsboard.server.service.notification.rule; -import org.thingsboard.server.common.data.alarm.Alarm; +import org.thingsboard.server.common.data.EntityType; +import org.thingsboard.server.common.data.UpdateMessage; import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.RuleChainId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent; import org.thingsboard.server.common.msg.TbMsg; +import org.thingsboard.server.common.msg.plugin.ComponentLifecycleMsg; +import org.thingsboard.server.dao.alarm.AlarmApiCallResult; public interface NotificationRuleProcessingService { void process(TenantId tenantId, TbMsg ruleEngineMsg); - void process(TenantId tenantId, Alarm alarm, boolean deleted); + // for handling internal component lifecycle events that are not getting to rule chain + void process(ComponentLifecycleMsg componentLifecycleMsg); + + void process(TenantId tenantId, AlarmApiCallResult alarmUpdate); void process(TenantId tenantId, RuleChainId ruleChainId, String ruleChainName, EntityId componentId, String componentName, ComponentLifecycleEvent eventType, Exception error); + void process(UpdateMessage platformUpdateMessage); + + void process(TenantId tenantId, EntityType entityType, long limit, long currentCount); + } diff --git a/application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/AlarmAssignmentTriggerProcessor.java b/application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/AlarmAssignmentTriggerProcessor.java new file mode 100644 index 0000000000..6ccff5686f --- /dev/null +++ b/application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/AlarmAssignmentTriggerProcessor.java @@ -0,0 +1,79 @@ +/** + * Copyright © 2016-2023 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.service.notification.rule.trigger; + +import org.springframework.stereotype.Service; +import org.thingsboard.common.util.JacksonUtil; +import org.thingsboard.server.common.data.DataConstants; +import org.thingsboard.server.common.data.alarm.Alarm; +import org.thingsboard.server.common.data.alarm.AlarmAssignee; +import org.thingsboard.server.common.data.alarm.AlarmInfo; +import org.thingsboard.server.common.data.alarm.AlarmStatusFilter; +import org.thingsboard.server.common.data.notification.info.AlarmAssignmentNotificationInfo; +import org.thingsboard.server.common.data.notification.info.NotificationInfo; +import org.thingsboard.server.common.data.notification.rule.trigger.AlarmAssignmentNotificationRuleTriggerConfig; +import org.thingsboard.server.common.data.notification.rule.trigger.NotificationRuleTriggerType; +import org.thingsboard.server.common.msg.TbMsg; + +import java.util.Set; + +import static org.apache.commons.collections.CollectionUtils.isEmpty; + +@Service +public class AlarmAssignmentTriggerProcessor implements RuleEngineMsgNotificationRuleTriggerProcessor { + + @Override + public boolean matchesFilter(TbMsg ruleEngineMsg, AlarmAssignmentNotificationRuleTriggerConfig triggerConfig) { + if (ruleEngineMsg.getType().equals(DataConstants.ALARM_UNASSIGN) && !triggerConfig.isNotifyOnUnassign()) { + return false; + } + Alarm alarm = JacksonUtil.fromString(ruleEngineMsg.getData(), Alarm.class); + return (isEmpty(triggerConfig.getAlarmTypes()) || triggerConfig.getAlarmTypes().contains(alarm.getType())) && + (isEmpty(triggerConfig.getAlarmSeverities()) || triggerConfig.getAlarmSeverities().contains(alarm.getSeverity())) && + (isEmpty(triggerConfig.getAlarmStatuses()) || AlarmStatusFilter.from(triggerConfig.getAlarmStatuses()).matches(alarm)); + } + + @Override + public NotificationInfo constructNotificationInfo(TbMsg ruleEngineMsg, AlarmAssignmentNotificationRuleTriggerConfig triggerConfig) { + // TODO: readable action + AlarmInfo alarmInfo = JacksonUtil.fromString(ruleEngineMsg.getData(), AlarmInfo.class); + AlarmAssignee assignee = alarmInfo.getAssignee(); + return AlarmAssignmentNotificationInfo.builder() + .assigneeFirstName(assignee != null ? assignee.getFirstName() : null) + .assigneeLastName(assignee != null ? assignee.getLastName() : null) + .assigneeEmail(assignee != null ? assignee.getEmail() : null) + .userName(ruleEngineMsg.getMetaData().getValue("userName")) + .alarmId(alarmInfo.getUuidId()) + .alarmType(alarmInfo.getType()) + .alarmOriginator(alarmInfo.getOriginator()) + .alarmOriginatorName(alarmInfo.getOriginatorName()) + .alarmSeverity(alarmInfo.getSeverity()) + .alarmStatus(alarmInfo.getStatus()) + .alarmCustomerId(alarmInfo.getCustomerId()) + .build(); + } + + @Override + public NotificationRuleTriggerType getTriggerType() { + return NotificationRuleTriggerType.ALARM_ASSIGNMENT; + } + + @Override + public Set getSupportedMsgTypes() { + return Set.of(DataConstants.ALARM_ASSIGN, DataConstants.ALARM_UNASSIGN); + } + +} diff --git a/application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/AlarmCommentTriggerProcessor.java b/application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/AlarmCommentTriggerProcessor.java index cd30d9b580..8be6e1622b 100644 --- a/application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/AlarmCommentTriggerProcessor.java +++ b/application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/AlarmCommentTriggerProcessor.java @@ -20,6 +20,8 @@ import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.server.common.data.DataConstants; import org.thingsboard.server.common.data.alarm.Alarm; import org.thingsboard.server.common.data.alarm.AlarmComment; +import org.thingsboard.server.common.data.alarm.AlarmCommentType; +import org.thingsboard.server.common.data.alarm.AlarmInfo; import org.thingsboard.server.common.data.alarm.AlarmStatusFilter; import org.thingsboard.server.common.data.notification.info.AlarmCommentNotificationInfo; import org.thingsboard.server.common.data.notification.info.NotificationInfo; @@ -39,6 +41,12 @@ public class AlarmCommentTriggerProcessor implements RuleEngineMsgNotificationRu if (ruleEngineMsg.getMetaData().getValue("comment") == null) { return false; } + if (triggerConfig.isOnlyUserComments()) { + AlarmComment comment = JacksonUtil.fromString(ruleEngineMsg.getMetaData().getValue("comment"), AlarmComment.class); + if (comment.getType() == AlarmCommentType.SYSTEM) { + return false; + } + } Alarm alarm = JacksonUtil.fromString(ruleEngineMsg.getData(), Alarm.class); return (isEmpty(triggerConfig.getAlarmTypes()) || triggerConfig.getAlarmTypes().contains(alarm.getType())) && (isEmpty(triggerConfig.getAlarmSeverities()) || triggerConfig.getAlarmSeverities().contains(alarm.getSeverity())) && @@ -47,15 +55,19 @@ public class AlarmCommentTriggerProcessor implements RuleEngineMsgNotificationRu @Override public NotificationInfo constructNotificationInfo(TbMsg ruleEngineMsg, AlarmCommentNotificationRuleTriggerConfig triggerConfig) { + // TODO: readable action AlarmComment comment = JacksonUtil.fromString(ruleEngineMsg.getMetaData().getValue("comment"), AlarmComment.class); - Alarm alarm = JacksonUtil.fromString(ruleEngineMsg.getData(), Alarm.class); + AlarmInfo alarmInfo = JacksonUtil.fromString(ruleEngineMsg.getData(), AlarmInfo.class); return AlarmCommentNotificationInfo.builder() .comment(comment.getComment().get("text").asText()) - .alarmId(alarm.getUuidId()) - .alarmType(alarm.getType()) - .alarmOriginator(alarm.getOriginator()) - .alarmSeverity(alarm.getSeverity()) - .alarmStatus(alarm.getStatus()) + .userName(ruleEngineMsg.getMetaData().getValue("userName")) + .alarmId(alarmInfo.getUuidId()) + .alarmType(alarmInfo.getType()) + .alarmOriginator(alarmInfo.getOriginator()) + .alarmOriginatorName(alarmInfo.getOriginatorName()) + .alarmSeverity(alarmInfo.getSeverity()) + .alarmStatus(alarmInfo.getStatus()) + .alarmCustomerId(alarmInfo.getCustomerId()) .build(); } diff --git a/application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/AlarmTriggerProcessor.java b/application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/AlarmTriggerProcessor.java index 9f226ca352..babe177eea 100644 --- a/application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/AlarmTriggerProcessor.java +++ b/application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/AlarmTriggerProcessor.java @@ -15,37 +15,63 @@ */ package org.thingsboard.server.service.notification.rule.trigger; -import lombok.Builder; -import lombok.Data; import org.springframework.stereotype.Service; import org.thingsboard.server.common.data.alarm.Alarm; +import org.thingsboard.server.common.data.alarm.AlarmInfo; import org.thingsboard.server.common.data.alarm.AlarmStatusFilter; import org.thingsboard.server.common.data.notification.info.AlarmNotificationInfo; import org.thingsboard.server.common.data.notification.info.NotificationInfo; import org.thingsboard.server.common.data.notification.rule.trigger.AlarmNotificationRuleTriggerConfig; +import org.thingsboard.server.common.data.notification.rule.trigger.AlarmNotificationRuleTriggerConfig.AlarmAction; import org.thingsboard.server.common.data.notification.rule.trigger.AlarmNotificationRuleTriggerConfig.ClearRule; import org.thingsboard.server.common.data.notification.rule.trigger.NotificationRuleTriggerType; -import org.thingsboard.server.service.notification.rule.trigger.AlarmTriggerProcessor.AlarmTriggerObject; +import org.thingsboard.server.dao.alarm.AlarmApiCallResult; import static org.apache.commons.collections.CollectionUtils.isEmpty; import static org.apache.commons.collections.CollectionUtils.isNotEmpty; @Service -public class AlarmTriggerProcessor implements NotificationRuleTriggerProcessor { +public class AlarmTriggerProcessor implements NotificationRuleTriggerProcessor { @Override - public boolean matchesFilter(AlarmTriggerObject triggerObject, AlarmNotificationRuleTriggerConfig triggerConfig) { - Alarm alarm = triggerObject.getAlarm(); - return (isEmpty(triggerConfig.getAlarmTypes()) || triggerConfig.getAlarmTypes().contains(alarm.getType())) && - (isEmpty(triggerConfig.getAlarmSeverities()) || triggerConfig.getAlarmSeverities().contains(alarm.getSeverity())); + public boolean matchesFilter(AlarmApiCallResult alarmUpdate, AlarmNotificationRuleTriggerConfig triggerConfig) { + Alarm alarm = alarmUpdate.getAlarm(); + if (!typeMatches(alarm, triggerConfig)) { + return false; + } + + if (alarmUpdate.isCreated()) { + if (triggerConfig.getNotifyOn().contains(AlarmAction.CREATED)) { + return severityMatches(alarm, triggerConfig); + } + } else if (alarmUpdate.isSeverityChanged()) { + if (triggerConfig.getNotifyOn().contains(AlarmAction.SEVERITY_CHANGED)) { + return severityMatches(alarmUpdate.getOld(), triggerConfig) || severityMatches(alarm, triggerConfig); + } else { + // if we haven't yet sent notification about the alarm + return !severityMatches(alarmUpdate.getOld(), triggerConfig) && severityMatches(alarm, triggerConfig); + } + } else if (alarmUpdate.isAcknowledged()) { + if (triggerConfig.getNotifyOn().contains(AlarmAction.ACKNOWLEDGED)) { + return severityMatches(alarm, triggerConfig); + } + } else if (alarmUpdate.isCleared()) { + if (triggerConfig.getNotifyOn().contains(AlarmAction.CLEARED)) { + return severityMatches(alarm, triggerConfig); + } + } + return false; } @Override - public boolean matchesClearRule(AlarmTriggerObject triggerObject, AlarmNotificationRuleTriggerConfig triggerConfig) { - if (triggerObject.isDeleted()) { + public boolean matchesClearRule(AlarmApiCallResult alarmUpdate, AlarmNotificationRuleTriggerConfig triggerConfig) { + Alarm alarm = alarmUpdate.getAlarm(); + if (!typeMatches(alarm, triggerConfig)) { + return false; + } + if (alarmUpdate.isDeleted()) { return true; } - Alarm alarm = triggerObject.getAlarm(); ClearRule clearRule = triggerConfig.getClearRule(); if (clearRule != null) { if (isNotEmpty(clearRule.getAlarmStatuses())) { @@ -55,16 +81,26 @@ public class AlarmTriggerProcessor implements NotificationRuleTriggerProcessor
{ + + @Override + public boolean matchesFilter(EntitiesLimitTriggerObject triggerObject, EntitiesLimitNotificationRuleTriggerConfig triggerConfig) { + if (isNotEmpty(triggerConfig.getEntityTypes()) && !triggerConfig.getEntityTypes().contains(triggerObject.getEntityType())) { + return false; + } + return ((float) triggerObject.getCurrentCount() / triggerObject.getLimit()) >= triggerConfig.getThreshold(); + } + + @Override + public NotificationInfo constructNotificationInfo(EntitiesLimitTriggerObject triggerObject, EntitiesLimitNotificationRuleTriggerConfig triggerConfig) { + return EntitiesLimitNotificationInfo.builder() + .entityType(triggerObject.getEntityType()) + .threshold((int) (triggerConfig.getThreshold() * 100)) + .build(); + } + + @Override + public NotificationRuleTriggerType getTriggerType() { + return NotificationRuleTriggerType.ENTITIES_LIMIT; + } + + @Data + @Builder + public static class EntitiesLimitTriggerObject { + private final EntityType entityType; + private final long limit; + private final long currentCount; + } + +} 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 new file mode 100644 index 0000000000..e26328404b --- /dev/null +++ b/application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/NewPlatformVersionTriggerProcessor.java @@ -0,0 +1,45 @@ +/** + * Copyright © 2016-2023 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.service.notification.rule.trigger; + +import org.springframework.stereotype.Service; +import org.thingsboard.server.common.data.UpdateMessage; +import org.thingsboard.server.common.data.notification.info.NewPlatformVersionNotificationInfo; +import org.thingsboard.server.common.data.notification.info.NotificationInfo; +import org.thingsboard.server.common.data.notification.rule.trigger.NewPlatformVersionNotificationRuleTriggerConfig; +import org.thingsboard.server.common.data.notification.rule.trigger.NotificationRuleTriggerType; + +@Service +public class NewPlatformVersionTriggerProcessor implements NotificationRuleTriggerProcessor { + + @Override + public boolean matchesFilter(UpdateMessage triggerObject, NewPlatformVersionNotificationRuleTriggerConfig triggerConfig) { + return triggerObject.isUpdateAvailable(); + } + + @Override + public NotificationInfo constructNotificationInfo(UpdateMessage updateMessage, NewPlatformVersionNotificationRuleTriggerConfig triggerConfig) { + return NewPlatformVersionNotificationInfo.builder() + .message(updateMessage.getMessage()) + .build(); + } + + @Override + public NotificationRuleTriggerType getTriggerType() { + return NotificationRuleTriggerType.NEW_PLATFORM_VERSION; + } + +} diff --git a/application/src/main/java/org/thingsboard/server/service/security/auth/mfa/provider/impl/BackupCodeTwoFaProvider.java b/application/src/main/java/org/thingsboard/server/service/security/auth/mfa/provider/impl/BackupCodeTwoFaProvider.java index 1369ece85e..cb718462bf 100644 --- a/application/src/main/java/org/thingsboard/server/service/security/auth/mfa/provider/impl/BackupCodeTwoFaProvider.java +++ b/application/src/main/java/org/thingsboard/server/service/security/auth/mfa/provider/impl/BackupCodeTwoFaProvider.java @@ -18,7 +18,7 @@ package org.thingsboard.server.service.security.auth.mfa.provider.impl; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Service; -import org.thingsboard.common.util.CollectionsUtil; +import org.thingsboard.server.common.data.util.CollectionsUtil; import org.thingsboard.server.common.data.StringUtils; import org.thingsboard.server.common.data.User; import org.thingsboard.server.common.data.security.model.mfa.account.BackupCodeTwoFaAccountConfig; diff --git a/application/src/main/java/org/thingsboard/server/service/state/DefaultDeviceStateService.java b/application/src/main/java/org/thingsboard/server/service/state/DefaultDeviceStateService.java index 80fd643253..60c159360b 100644 --- a/application/src/main/java/org/thingsboard/server/service/state/DefaultDeviceStateService.java +++ b/application/src/main/java/org/thingsboard/server/service/state/DefaultDeviceStateService.java @@ -139,6 +139,7 @@ public class DefaultDeviceStateService extends AbstractPartitionBasedService PERSISTENT_ENTITY_FIELDS = Arrays.asList( new EntityKey(EntityKeyType.ENTITY_FIELD, "name"), new EntityKey(EntityKeyType.ENTITY_FIELD, "type"), + new EntityKey(EntityKeyType.ENTITY_FIELD, "label"), new EntityKey(EntityKeyType.ENTITY_FIELD, "createdTime")); private final TenantService tenantService; @@ -329,6 +330,7 @@ public class DefaultDeviceStateService extends AbstractPartitionBasedService> subscriptionsByEntityId = new ConcurrentHashMap<>(); private final Map> subscriptionsByWsSessionId = new ConcurrentHashMap<>(); @@ -296,7 +292,6 @@ public class DefaultSubscriptionManagerService extends TbApplicationEventListene s -> alarm.getCreatedTime() >= s.getTs() || alarm.getAssignTs() >= s.getTs(), alarm, false ); - notificationRuleProcessingService.process(tenantId, alarm, false); callback.onSuccess(); } @@ -313,7 +308,6 @@ public class DefaultSubscriptionManagerService extends TbApplicationEventListene s -> alarm.getCreatedTime() >= s.getTs(), alarm, true ); - notificationRuleProcessingService.process(tenantId, alarm, true); callback.onSuccess(); } diff --git a/application/src/main/java/org/thingsboard/server/service/sync/vc/DefaultGitVersionControlQueueService.java b/application/src/main/java/org/thingsboard/server/service/sync/vc/DefaultGitVersionControlQueueService.java index 905fa53e91..785dd50a92 100644 --- a/application/src/main/java/org/thingsboard/server/service/sync/vc/DefaultGitVersionControlQueueService.java +++ b/application/src/main/java/org/thingsboard/server/service/sync/vc/DefaultGitVersionControlQueueService.java @@ -26,7 +26,7 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Service; -import org.thingsboard.common.util.CollectionsUtil; +import org.thingsboard.server.common.data.util.CollectionsUtil; import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.server.cluster.TbClusterService; import org.thingsboard.server.common.data.EntityType; @@ -64,7 +64,6 @@ import org.thingsboard.server.queue.util.DataDecodingEncodingService; import org.thingsboard.server.queue.util.TbCoreComponent; import org.thingsboard.server.service.sync.vc.data.ClearRepositoryGitRequest; import org.thingsboard.server.service.sync.vc.data.CommitGitRequest; -import org.thingsboard.server.service.sync.vc.data.ContentsDiffGitRequest; import org.thingsboard.server.service.sync.vc.data.EntitiesContentGitRequest; import org.thingsboard.server.service.sync.vc.data.EntityContentGitRequest; import org.thingsboard.server.service.sync.vc.data.ListBranchesGitRequest; @@ -78,11 +77,9 @@ import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; -import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Optional; -import java.util.TreeMap; import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.TimeUnit; diff --git a/application/src/main/java/org/thingsboard/server/service/telemetry/DefaultAlarmSubscriptionService.java b/application/src/main/java/org/thingsboard/server/service/telemetry/DefaultAlarmSubscriptionService.java index f412e76ad9..6adefb709e 100644 --- a/application/src/main/java/org/thingsboard/server/service/telemetry/DefaultAlarmSubscriptionService.java +++ b/application/src/main/java/org/thingsboard/server/service/telemetry/DefaultAlarmSubscriptionService.java @@ -52,6 +52,7 @@ import org.thingsboard.server.dao.alarm.AlarmOperationResult; import org.thingsboard.server.dao.alarm.AlarmService; import org.thingsboard.server.service.apiusage.TbApiUsageStateService; import org.thingsboard.server.service.entitiy.alarm.TbAlarmCommentService; +import org.thingsboard.server.service.notification.rule.NotificationRuleProcessingService; import org.thingsboard.server.service.subscription.TbSubscriptionUtils; import java.util.Collection; @@ -68,6 +69,7 @@ public class DefaultAlarmSubscriptionService extends AbstractSubscriptionService private final TbAlarmCommentService alarmCommentService; private final TbApiUsageReportClient apiUsageClient; private final TbApiUsageStateService apiUsageStateService; + private final NotificationRuleProcessingService notificationRuleProcessingService; @Override protected String getExecutorPrefix() { @@ -232,6 +234,7 @@ public class DefaultAlarmSubscriptionService extends AbstractSubscriptionService return TbSubscriptionUtils.toAlarmUpdateProto(tenantId, entityId, alarm); }); } + notificationRuleProcessingService.process(tenantId, result); }); } @@ -246,6 +249,7 @@ public class DefaultAlarmSubscriptionService extends AbstractSubscriptionService return TbSubscriptionUtils.toAlarmDeletedProto(tenantId, entityId, alarm); }); } + notificationRuleProcessingService.process(tenantId, result); }); } 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 ac3bfc497a..24e6ec7d13 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 @@ -19,12 +19,14 @@ import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.node.ObjectNode; import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; import org.springframework.web.client.RestTemplate; import org.thingsboard.common.util.ThingsBoardThreadFactory; import org.thingsboard.server.common.data.UpdateMessage; import org.thingsboard.server.queue.util.TbCoreComponent; +import org.thingsboard.server.service.notification.rule.NotificationRuleProcessingService; import javax.annotation.PostConstruct; import javax.annotation.PreDestroy; @@ -53,6 +55,9 @@ public class DefaultUpdateService implements UpdateService { @Value("${updates.enabled}") private boolean updatesEnabled; + @Autowired + private NotificationRuleProcessingService notificationRuleProcessingService; + private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1, ThingsBoardThreadFactory.forName("tb-update-service")); private ScheduledFuture checkUpdatesFuture = null; @@ -121,11 +126,15 @@ public class DefaultUpdateService implements UpdateService { request.put(PLATFORM_PARAM, platform); request.put(VERSION_PARAM, version); request.put(INSTANCE_ID_PARAM, instanceId.toString()); - JsonNode response = restClient.postForObject(UPDATE_SERVER_BASE_URL+"/api/thingsboard/updates", request, JsonNode.class); + JsonNode response = restClient.postForObject(UPDATE_SERVER_BASE_URL + "/api/thingsboard/updates", request, JsonNode.class); + UpdateMessage prevUpdateMessage = updateMessage; updateMessage = new UpdateMessage( response.get("message").asText(), response.get("updateAvailable").asBoolean() ); + if (updateMessage.isUpdateAvailable() && !updateMessage.equals(prevUpdateMessage)) { + notificationRuleProcessingService.process(updateMessage); + } } catch (Exception e) { log.trace(e.getMessage()); } 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 293eb07af9..84b22b5d14 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 @@ -56,6 +56,7 @@ import org.thingsboard.server.common.data.notification.rule.EscalatedNotificatio import org.thingsboard.server.common.data.notification.rule.NotificationRule; import org.thingsboard.server.common.data.notification.rule.NotificationRuleInfo; import org.thingsboard.server.common.data.notification.rule.trigger.AlarmNotificationRuleTriggerConfig; +import org.thingsboard.server.common.data.notification.rule.trigger.AlarmNotificationRuleTriggerConfig.AlarmAction; import org.thingsboard.server.common.data.notification.rule.trigger.EntityActionNotificationRuleTriggerConfig; import org.thingsboard.server.common.data.notification.rule.trigger.NotificationRuleTriggerType; import org.thingsboard.server.common.data.notification.rule.trigger.RuleEngineComponentLifecycleEventNotificationRuleTriggerConfig; @@ -180,6 +181,7 @@ public class NotificationRuleApiTest extends AbstractNotificationApiTest { AlarmNotificationRuleTriggerConfig triggerConfig = new AlarmNotificationRuleTriggerConfig(); triggerConfig.setAlarmTypes(null); triggerConfig.setAlarmSeverities(null); + triggerConfig.setNotifyOn(Set.of(AlarmAction.CREATED, AlarmAction.SEVERITY_CHANGED, AlarmAction.ACKNOWLEDGED, AlarmAction.CLEARED)); notificationRule.setTriggerConfig(triggerConfig); EscalatedNotificationRuleRecipientsConfig recipientsConfig = new EscalatedNotificationRuleRecipientsConfig(); @@ -251,8 +253,6 @@ public class NotificationRuleApiTest extends AbstractNotificationApiTest { wsClient.close(); }); - - // TODO: test severity changes } @Test @@ -273,6 +273,7 @@ public class NotificationRuleApiTest extends AbstractNotificationApiTest { AlarmNotificationRuleTriggerConfig triggerConfig = new AlarmNotificationRuleTriggerConfig(); triggerConfig.setAlarmTypes(Set.of(alarmType)); triggerConfig.setAlarmSeverities(null); + triggerConfig.setNotifyOn(Set.of(AlarmAction.CREATED, AlarmAction.SEVERITY_CHANGED, AlarmAction.ACKNOWLEDGED)); AlarmNotificationRuleTriggerConfig.ClearRule clearRule = new AlarmNotificationRuleTriggerConfig.ClearRule(); clearRule.setAlarmStatuses(Set.of(AlarmSearchStatus.CLEARED, AlarmSearchStatus.UNACK)); diff --git a/common/dao-api/src/main/java/org/thingsboard/server/dao/alarm/AlarmApiCallResult.java b/common/dao-api/src/main/java/org/thingsboard/server/dao/alarm/AlarmApiCallResult.java index a8aebf16e7..07f9b926dd 100644 --- a/common/dao-api/src/main/java/org/thingsboard/server/dao/alarm/AlarmApiCallResult.java +++ b/common/dao-api/src/main/java/org/thingsboard/server/dao/alarm/AlarmApiCallResult.java @@ -32,16 +32,18 @@ public class AlarmApiCallResult { private final boolean created; private final boolean modified; private final boolean cleared; + private final boolean deleted; private final AlarmInfo alarm; private final Alarm old; private final List propagatedEntitiesList; @Builder - private AlarmApiCallResult(boolean successful, boolean created, boolean modified, boolean cleared, AlarmInfo alarm, Alarm old, List propagatedEntitiesList) { + private AlarmApiCallResult(boolean successful, boolean created, boolean modified, boolean cleared, boolean deleted, AlarmInfo alarm, Alarm old, List propagatedEntitiesList) { this.successful = successful; this.created = created; this.modified = modified; this.cleared = cleared; + this.deleted = deleted; this.alarm = alarm; this.old = old; this.propagatedEntitiesList = propagatedEntitiesList; @@ -52,6 +54,7 @@ public class AlarmApiCallResult { this.created = other.created; this.modified = other.modified; this.cleared = other.cleared; + this.deleted = other.deleted; this.alarm = other.alarm; this.old = other.old; this.propagatedEntitiesList = propagatedEntitiesList; @@ -65,6 +68,14 @@ public class AlarmApiCallResult { } } + public boolean isAcknowledged() { + if (alarm == null || old == null) { + return false; + } else { + return alarm.isAcknowledged() != old.isAcknowledged(); + } + } + public AlarmSeverity getOldSeverity() { return isSeverityChanged() ? old.getSeverity() : null; } diff --git a/common/dao-api/src/main/java/org/thingsboard/server/dao/usagerecord/ApiLimitService.java b/common/dao-api/src/main/java/org/thingsboard/server/dao/usagerecord/ApiLimitService.java new file mode 100644 index 0000000000..cd9524e1b1 --- /dev/null +++ b/common/dao-api/src/main/java/org/thingsboard/server/dao/usagerecord/ApiLimitService.java @@ -0,0 +1,25 @@ +/** + * Copyright © 2016-2023 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.dao.usagerecord; + +import org.thingsboard.server.common.data.EntityType; +import org.thingsboard.server.common.data.id.TenantId; + +public interface ApiLimitService { + + boolean checkEntitiesLimit(TenantId tenantId, EntityType entityType); + +} diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/notification/NotificationProcessingContext.java b/common/data/src/main/java/org/thingsboard/server/common/data/notification/NotificationProcessingContext.java index afcfa278f2..a22f6a69d2 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/notification/NotificationProcessingContext.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/notification/NotificationProcessingContext.java @@ -129,7 +129,8 @@ public class NotificationProcessingContext { String result = template; for (Map context : contexts) { for (Map.Entry kv : context.entrySet()) { - result = result.replace("${" + kv.getKey() + '}', kv.getValue()); + String value = Strings.nullToEmpty(kv.getValue()); + result = result.replace("${" + kv.getKey() + '}', value); } } return result; diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/notification/NotificationType.java b/common/data/src/main/java/org/thingsboard/server/common/data/notification/NotificationType.java index 79dec384e7..05df8702a3 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/notification/NotificationType.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/notification/NotificationType.java @@ -22,6 +22,9 @@ public enum NotificationType { DEVICE_INACTIVITY, ENTITY_ACTION, ALARM_COMMENT, - RULE_ENGINE_COMPONENT_LIFECYCLE_EVENT + RULE_ENGINE_COMPONENT_LIFECYCLE_EVENT, + ALARM_ASSIGNMENT, + NEW_PLATFORM_VERSION, + ENTITIES_LIMIT } diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/notification/info/AlarmAssignmentNotificationInfo.java b/common/data/src/main/java/org/thingsboard/server/common/data/notification/info/AlarmAssignmentNotificationInfo.java new file mode 100644 index 0000000000..815bf4e3db --- /dev/null +++ b/common/data/src/main/java/org/thingsboard/server/common/data/notification/info/AlarmAssignmentNotificationInfo.java @@ -0,0 +1,78 @@ +/** + * Copyright © 2016-2023 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.notification.info; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.thingsboard.server.common.data.alarm.AlarmSeverity; +import org.thingsboard.server.common.data.alarm.AlarmStatus; +import org.thingsboard.server.common.data.id.CustomerId; +import org.thingsboard.server.common.data.id.EntityId; + +import java.util.Map; +import java.util.UUID; + +import static org.thingsboard.server.common.data.util.CollectionsUtil.mapOf; + +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class AlarmAssignmentNotificationInfo implements RuleOriginatedNotificationInfo { + + private String assigneeFirstName; + private String assigneeLastName; + private String assigneeEmail; + private String userName; + + private String alarmType; + private UUID alarmId; + private EntityId alarmOriginator; + private String alarmOriginatorName; + private AlarmSeverity alarmSeverity; + private AlarmStatus alarmStatus; + private CustomerId alarmCustomerId; + + @Override + public Map getTemplateData() { + return mapOf( + "assigneeFirstName", assigneeFirstName, + "assigneeLastName", assigneeLastName, + "assigneeEmail", assigneeEmail, + "userName", userName, + "alarmType", alarmType, + "alarmId", alarmId.toString(), + "alarmSeverity", alarmSeverity.toString(), + "alarmStatus", alarmStatus.toString(), + "alarmOriginatorEntityType", alarmOriginator.getEntityType().toString(), + "alarmOriginatorId", alarmOriginator.getId().toString(), + "alarmOriginatorName", alarmOriginatorName + ); + } + + @Override + public CustomerId getOriginatorEntityCustomerId() { + return alarmCustomerId; + } + + @Override + public EntityId getStateEntityId() { + return alarmOriginator; + } + +} diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/notification/info/AlarmCommentNotificationInfo.java b/common/data/src/main/java/org/thingsboard/server/common/data/notification/info/AlarmCommentNotificationInfo.java index 20764f56f4..3fce737194 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/notification/info/AlarmCommentNotificationInfo.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/notification/info/AlarmCommentNotificationInfo.java @@ -21,37 +21,50 @@ import lombok.Data; import lombok.NoArgsConstructor; import org.thingsboard.server.common.data.alarm.AlarmSeverity; import org.thingsboard.server.common.data.alarm.AlarmStatus; +import org.thingsboard.server.common.data.id.CustomerId; import org.thingsboard.server.common.data.id.EntityId; import java.util.Map; import java.util.UUID; +import static org.thingsboard.server.common.data.util.CollectionsUtil.mapOf; + @Data @AllArgsConstructor @NoArgsConstructor @Builder -public class AlarmCommentNotificationInfo implements NotificationInfo { +public class AlarmCommentNotificationInfo implements RuleOriginatedNotificationInfo { private String comment; + private String userName; private String alarmType; private UUID alarmId; private EntityId alarmOriginator; + private String alarmOriginatorName; private AlarmSeverity alarmSeverity; private AlarmStatus alarmStatus; + private CustomerId alarmCustomerId; @Override public Map getTemplateData() { - return Map.of( + return mapOf( "comment", comment, + "userName", userName, "alarmType", alarmType, "alarmId", alarmId.toString(), "alarmSeverity", alarmSeverity.toString(), "alarmStatus", alarmStatus.toString(), "alarmOriginatorEntityType", alarmOriginator.getEntityType().toString(), - "alarmOriginatorId", alarmOriginator.getId().toString() + "alarmOriginatorId", alarmOriginator.getId().toString(), + "alarmOriginatorName", alarmOriginatorName ); } + @Override + public CustomerId getOriginatorEntityCustomerId() { + return alarmCustomerId; + } + @Override public EntityId getStateEntityId() { return alarmOriginator; diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/notification/info/AlarmNotificationInfo.java b/common/data/src/main/java/org/thingsboard/server/common/data/notification/info/AlarmNotificationInfo.java index 4f387e3d86..502d6069dd 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/notification/info/AlarmNotificationInfo.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/notification/info/AlarmNotificationInfo.java @@ -27,6 +27,8 @@ import org.thingsboard.server.common.data.id.EntityId; import java.util.Map; import java.util.UUID; +import static org.thingsboard.server.common.data.util.CollectionsUtil.mapOf; + @Data @NoArgsConstructor @AllArgsConstructor @@ -36,27 +38,30 @@ public class AlarmNotificationInfo implements RuleOriginatedNotificationInfo { private String alarmType; private UUID alarmId; private EntityId alarmOriginator; + private String alarmOriginatorName; private AlarmSeverity alarmSeverity; private AlarmStatus alarmStatus; private CustomerId alarmCustomerId; - @Override - public CustomerId getOriginatorEntityCustomerId() { - return alarmCustomerId; - } - @Override public Map getTemplateData() { - return Map.of( + // TODO: readable status change + return mapOf( "alarmType", alarmType, "alarmId", alarmId.toString(), "alarmSeverity", alarmSeverity.toString(), "alarmStatus", alarmStatus.toString(), "alarmOriginatorEntityType", alarmOriginator.getEntityType().toString(), + "alarmOriginatorName", alarmOriginatorName, "alarmOriginatorId", alarmOriginator.getId().toString() ); } + @Override + public CustomerId getOriginatorEntityCustomerId() { + return alarmCustomerId; + } + @Override public EntityId getStateEntityId() { return alarmOriginator; diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/notification/info/DeviceInactivityNotificationInfo.java b/common/data/src/main/java/org/thingsboard/server/common/data/notification/info/DeviceInactivityNotificationInfo.java index 8a2d6941a0..6a4647ac62 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/notification/info/DeviceInactivityNotificationInfo.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/notification/info/DeviceInactivityNotificationInfo.java @@ -15,6 +15,7 @@ */ package org.thingsboard.server.common.data.notification.info; +import com.google.common.base.Strings; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; @@ -26,6 +27,8 @@ import org.thingsboard.server.common.data.id.EntityId; import java.util.Map; import java.util.UUID; +import static org.thingsboard.server.common.data.util.CollectionsUtil.mapOf; + @Data @NoArgsConstructor @AllArgsConstructor @@ -34,6 +37,7 @@ public class DeviceInactivityNotificationInfo implements RuleOriginatedNotificat private UUID deviceId; private String deviceName; + private String deviceLabel; private String deviceType; private CustomerId deviceCustomerId; @@ -44,9 +48,10 @@ public class DeviceInactivityNotificationInfo implements RuleOriginatedNotificat @Override public Map getTemplateData() { - return Map.of( + return mapOf( "deviceId", deviceId.toString(), "deviceName", deviceName, + "deviceLabel", deviceLabel, "deviceType", deviceType ); } diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/notification/info/EntitiesLimitNotificationInfo.java b/common/data/src/main/java/org/thingsboard/server/common/data/notification/info/EntitiesLimitNotificationInfo.java new file mode 100644 index 0000000000..add9f9d5d7 --- /dev/null +++ b/common/data/src/main/java/org/thingsboard/server/common/data/notification/info/EntitiesLimitNotificationInfo.java @@ -0,0 +1,45 @@ +/** + * Copyright © 2016-2023 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.notification.info; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.thingsboard.server.common.data.EntityType; + +import java.util.Map; + +import static org.thingsboard.server.common.data.util.CollectionsUtil.mapOf; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class EntitiesLimitNotificationInfo implements NotificationInfo { + + private EntityType entityType; + private int threshold; + + @Override + public Map getTemplateData() { + // FIXME: readable entity type name, e.g. 'Devices' + return mapOf( + "entityType", entityType.name(), + "threshold", String.valueOf(threshold) + ); + } +} diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/notification/info/EntityActionNotificationInfo.java b/common/data/src/main/java/org/thingsboard/server/common/data/notification/info/EntityActionNotificationInfo.java index 60061d3a78..b7e49183ea 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/notification/info/EntityActionNotificationInfo.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/notification/info/EntityActionNotificationInfo.java @@ -26,6 +26,8 @@ import org.thingsboard.server.common.data.id.EntityId; import java.util.Map; import java.util.UUID; +import static org.thingsboard.server.common.data.util.CollectionsUtil.mapOf; + @Data @NoArgsConstructor @AllArgsConstructor @@ -46,7 +48,7 @@ public class EntityActionNotificationInfo implements RuleOriginatedNotificationI @Override public Map getTemplateData() { - return Map.of( + return mapOf( "entityType", entityId.getEntityType().name(), "entityId", entityId.toString(), "entityName", entityName, 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 new file mode 100644 index 0000000000..0e85d95fd0 --- /dev/null +++ b/common/data/src/main/java/org/thingsboard/server/common/data/notification/info/NewPlatformVersionNotificationInfo.java @@ -0,0 +1,42 @@ +/** + * Copyright © 2016-2023 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.notification.info; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.Map; + +import static org.thingsboard.server.common.data.util.CollectionsUtil.mapOf; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class NewPlatformVersionNotificationInfo implements NotificationInfo { + + private String message; + + @Override + public Map getTemplateData() { + return mapOf( + "message", message + ); + } + +} diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/notification/info/RuleEngineComponentLifecycleEventNotificationInfo.java b/common/data/src/main/java/org/thingsboard/server/common/data/notification/info/RuleEngineComponentLifecycleEventNotificationInfo.java index 0dc942c588..45c1c689ac 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/notification/info/RuleEngineComponentLifecycleEventNotificationInfo.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/notification/info/RuleEngineComponentLifecycleEventNotificationInfo.java @@ -15,18 +15,18 @@ */ package org.thingsboard.server.common.data.notification.info; -import com.google.common.base.Strings; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; -import org.apache.commons.lang3.StringUtils; import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.RuleChainId; import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent; import java.util.Map; +import static org.thingsboard.server.common.data.util.CollectionsUtil.mapOf; + @Data @AllArgsConstructor @NoArgsConstructor @@ -42,7 +42,7 @@ public class RuleEngineComponentLifecycleEventNotificationInfo implements Notifi @Override public Map getTemplateData() { - return Map.of( + return mapOf( "ruleChainId", ruleChainId.toString(), "ruleChainName", ruleChainName, "componentId", componentId.toString(), diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/NotificationRule.java b/common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/NotificationRule.java index 563f5c308b..949ab40ff7 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/NotificationRule.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/NotificationRule.java @@ -47,6 +47,7 @@ public class NotificationRule extends BaseData implements Ha @NotNull private NotificationRuleTriggerType triggerType; @NotNull + @Valid private NotificationRuleTriggerConfig triggerConfig; @NotNull @Valid diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/AlarmAssignmentNotificationRuleTriggerConfig.java b/common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/AlarmAssignmentNotificationRuleTriggerConfig.java new file mode 100644 index 0000000000..88e2c5fd76 --- /dev/null +++ b/common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/AlarmAssignmentNotificationRuleTriggerConfig.java @@ -0,0 +1,37 @@ +/** + * Copyright © 2016-2023 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.notification.rule.trigger; + +import lombok.Data; +import org.thingsboard.server.common.data.alarm.AlarmSearchStatus; +import org.thingsboard.server.common.data.alarm.AlarmSeverity; + +import java.util.Set; + +@Data +public class AlarmAssignmentNotificationRuleTriggerConfig implements NotificationRuleTriggerConfig { + + private Set alarmTypes; + private Set alarmSeverities; + private Set alarmStatuses; + private boolean notifyOnUnassign; + + @Override + public NotificationRuleTriggerType getTriggerType() { + return NotificationRuleTriggerType.ALARM_ASSIGNMENT; + } + +} diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/AlarmCommentNotificationRuleTriggerConfig.java b/common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/AlarmCommentNotificationRuleTriggerConfig.java index f8cae97c0e..3cfdd7ae3c 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/AlarmCommentNotificationRuleTriggerConfig.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/AlarmCommentNotificationRuleTriggerConfig.java @@ -27,6 +27,7 @@ public class AlarmCommentNotificationRuleTriggerConfig implements NotificationRu private Set alarmTypes; private Set alarmSeverities; private Set alarmStatuses; + private boolean onlyUserComments; @Override public NotificationRuleTriggerType getTriggerType() { diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/AlarmNotificationRuleTriggerConfig.java b/common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/AlarmNotificationRuleTriggerConfig.java index 70d986cdf7..aa692fd9fe 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/AlarmNotificationRuleTriggerConfig.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/AlarmNotificationRuleTriggerConfig.java @@ -19,6 +19,7 @@ import lombok.Data; import org.thingsboard.server.common.data.alarm.AlarmSearchStatus; import org.thingsboard.server.common.data.alarm.AlarmSeverity; +import javax.validation.constraints.NotEmpty; import java.util.Set; @Data @@ -26,6 +27,9 @@ public class AlarmNotificationRuleTriggerConfig implements NotificationRuleTrigg private Set alarmTypes; private Set alarmSeverities; + @NotEmpty + private Set notifyOn; + private ClearRule clearRule; @Override @@ -38,4 +42,8 @@ public class AlarmNotificationRuleTriggerConfig implements NotificationRuleTrigg private Set alarmStatuses; } + public enum AlarmAction { + CREATED, SEVERITY_CHANGED, ACKNOWLEDGED, CLEARED + } + } diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/EntitiesLimitNotificationRuleTriggerConfig.java b/common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/EntitiesLimitNotificationRuleTriggerConfig.java new file mode 100644 index 0000000000..b799d4b81c --- /dev/null +++ b/common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/EntitiesLimitNotificationRuleTriggerConfig.java @@ -0,0 +1,36 @@ +/** + * Copyright © 2016-2023 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.notification.rule.trigger; + +import lombok.Data; +import org.thingsboard.server.common.data.EntityType; + +import javax.validation.constraints.Max; +import java.util.Set; + +@Data +public class EntitiesLimitNotificationRuleTriggerConfig implements NotificationRuleTriggerConfig { + + private Set entityTypes; + @Max(1) + private float threshold; // in percents, + + @Override + public NotificationRuleTriggerType getTriggerType() { + return NotificationRuleTriggerType.ENTITIES_LIMIT; + } + +} 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 new file mode 100644 index 0000000000..230be3b9d5 --- /dev/null +++ b/common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/NewPlatformVersionNotificationRuleTriggerConfig.java @@ -0,0 +1,28 @@ +/** + * Copyright © 2016-2023 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.notification.rule.trigger; + +import lombok.Data; + +@Data +public class NewPlatformVersionNotificationRuleTriggerConfig implements NotificationRuleTriggerConfig { + + @Override + public NotificationRuleTriggerType getTriggerType() { + return NotificationRuleTriggerType.NEW_PLATFORM_VERSION; + } + +} diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/NotificationRuleTriggerConfig.java b/common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/NotificationRuleTriggerConfig.java index 99c63e525e..c60c72b8de 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/NotificationRuleTriggerConfig.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/NotificationRuleTriggerConfig.java @@ -27,7 +27,10 @@ import com.fasterxml.jackson.annotation.JsonTypeInfo; @Type(value = DeviceInactivityNotificationRuleTriggerConfig.class, name = "DEVICE_INACTIVITY"), @Type(value = EntityActionNotificationRuleTriggerConfig.class, name = "ENTITY_ACTION"), @Type(value = AlarmCommentNotificationRuleTriggerConfig.class, name = "ALARM_COMMENT"), - @Type(value = RuleEngineComponentLifecycleEventNotificationRuleTriggerConfig.class, name = "RULE_ENGINE_COMPONENT_LIFECYCLE_EVENT") + @Type(value = RuleEngineComponentLifecycleEventNotificationRuleTriggerConfig.class, name = "RULE_ENGINE_COMPONENT_LIFECYCLE_EVENT"), + @Type(value = AlarmAssignmentNotificationRuleTriggerConfig.class, name = "ALARM_ASSIGNMENT"), + @Type(value = NewPlatformVersionNotificationRuleTriggerConfig.class, name = "NEW_PLATFORM_VERSION"), + @Type(value = EntitiesLimitNotificationRuleTriggerConfig.class, name = "ENTITIES_LIMIT") }) public interface NotificationRuleTriggerConfig { diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/NotificationRuleTriggerType.java b/common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/NotificationRuleTriggerType.java index 64bba1b9df..d843347b5a 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/NotificationRuleTriggerType.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/NotificationRuleTriggerType.java @@ -21,6 +21,9 @@ public enum NotificationRuleTriggerType { ALARM_COMMENT, DEVICE_INACTIVITY, ENTITY_ACTION, - RULE_ENGINE_COMPONENT_LIFECYCLE_EVENT + RULE_ENGINE_COMPONENT_LIFECYCLE_EVENT, + ALARM_ASSIGNMENT, + NEW_PLATFORM_VERSION, + ENTITIES_LIMIT } diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/tenant/profile/DefaultTenantProfileConfiguration.java b/common/data/src/main/java/org/thingsboard/server/common/data/tenant/profile/DefaultTenantProfileConfiguration.java index 44bff695a7..8790017b7d 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/tenant/profile/DefaultTenantProfileConfiguration.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/tenant/profile/DefaultTenantProfileConfiguration.java @@ -20,6 +20,7 @@ import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; import org.thingsboard.server.common.data.ApiUsageRecordKey; +import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.TenantProfileType; @AllArgsConstructor @@ -107,6 +108,25 @@ public class DefaultTenantProfileConfiguration implements TenantProfileConfigura return (long) (getProfileThreshold(key) * (warnThreshold > 0.0 ? warnThreshold : 0.8)); } + public long getEntitiesLimit(EntityType entityType) { + switch (entityType) { + case DEVICE: + return maxDevices; + case ASSET: + return maxAssets; + case CUSTOMER: + return maxCustomers; + case USER: + return maxUsers; + case DASHBOARD: + return maxDashboards; + case RULE_CHAIN: + return maxRuleChains; + default: + return 0; + } + } + @Override public TenantProfileType getType() { return TenantProfileType.DEFAULT; diff --git a/common/util/src/main/java/org/thingsboard/common/util/CollectionsUtil.java b/common/data/src/main/java/org/thingsboard/server/common/data/util/CollectionsUtil.java similarity index 71% rename from common/util/src/main/java/org/thingsboard/common/util/CollectionsUtil.java rename to common/data/src/main/java/org/thingsboard/server/common/data/util/CollectionsUtil.java index f1f0464425..85d5621ec4 100644 --- a/common/util/src/main/java/org/thingsboard/common/util/CollectionsUtil.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/util/CollectionsUtil.java @@ -13,9 +13,14 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.thingsboard.common.util; +package org.thingsboard.server.common.data.util; + +import com.google.common.collect.ImmutableMap; import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; import java.util.Set; import java.util.stream.Collectors; @@ -47,4 +52,19 @@ public class CollectionsUtil { return count; } + @SuppressWarnings("unchecked") + public static Map mapOf(Object... kvs) { + Map map = new HashMap<>(); + for (int i = 0; i < kvs.length; i += 2) { + K key = (K) kvs[i]; + V value = (V) kvs[i + 1]; + map.put(key, value); + } + return map; + } + + public static Map unmodifiableMapOf(Object... kvs) { + return Collections.unmodifiableMap(mapOf(kvs)); + } + } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/model/LwM2MModelConfig.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/model/LwM2MModelConfig.java index 2014fece71..395cf5450b 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/model/LwM2MModelConfig.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/model/LwM2MModelConfig.java @@ -27,7 +27,7 @@ import java.util.Map; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; -import static org.thingsboard.common.util.CollectionsUtil.diffSets; +import static org.thingsboard.server.common.data.util.CollectionsUtil.diffSets; @Data @NoArgsConstructor diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/uplink/DefaultLwM2mUplinkMsgHandler.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/uplink/DefaultLwM2mUplinkMsgHandler.java index 25e3a6b591..02ccdce3c0 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/uplink/DefaultLwM2mUplinkMsgHandler.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/uplink/DefaultLwM2mUplinkMsgHandler.java @@ -103,7 +103,7 @@ import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; -import static org.thingsboard.common.util.CollectionsUtil.diffSets; +import static org.thingsboard.server.common.data.util.CollectionsUtil.diffSets; import static org.thingsboard.server.common.data.lwm2m.LwM2mConstants.LWM2M_SEPARATOR_PATH; import static org.thingsboard.server.transport.lwm2m.server.ota.DefaultLwM2MOtaUpdateService.FW_3_VER_ID; import static org.thingsboard.server.transport.lwm2m.server.ota.DefaultLwM2MOtaUpdateService.FW_DELIVERY_METHOD; diff --git a/common/version-control/src/main/java/org/thingsboard/server/service/sync/vc/DefaultClusterVersionControlService.java b/common/version-control/src/main/java/org/thingsboard/server/service/sync/vc/DefaultClusterVersionControlService.java index e30b150d6f..c072d41d5a 100644 --- a/common/version-control/src/main/java/org/thingsboard/server/service/sync/vc/DefaultClusterVersionControlService.java +++ b/common/version-control/src/main/java/org/thingsboard/server/service/sync/vc/DefaultClusterVersionControlService.java @@ -29,7 +29,7 @@ import org.springframework.boot.context.event.ApplicationReadyEvent; import org.springframework.context.event.EventListener; import org.springframework.core.annotation.Order; import org.springframework.stereotype.Service; -import org.thingsboard.common.util.CollectionsUtil; +import org.thingsboard.server.common.data.util.CollectionsUtil; import org.thingsboard.common.util.ThingsBoardThreadFactory; import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.StringUtils; diff --git a/dao/src/main/java/org/thingsboard/server/dao/alarm/BaseAlarmService.java b/dao/src/main/java/org/thingsboard/server/dao/alarm/BaseAlarmService.java index 0dd2eebf87..72b0eaf7f1 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/alarm/BaseAlarmService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/alarm/BaseAlarmService.java @@ -185,7 +185,7 @@ public class BaseAlarmService extends AbstractEntityService implements AlarmServ } else { deleteEntityRelations(tenantId, alarm.getId()); alarmDao.removeById(tenantId, alarm.getUuidId()); - return AlarmApiCallResult.builder().alarm(alarm).successful(true).build(); + return AlarmApiCallResult.builder().alarm(alarm).deleted(true).successful(true).build(); } } diff --git a/dao/src/main/java/org/thingsboard/server/dao/model/ModelConstants.java b/dao/src/main/java/org/thingsboard/server/dao/model/ModelConstants.java index 0d4a5aa1a7..a0804e0c71 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/model/ModelConstants.java +++ b/dao/src/main/java/org/thingsboard/server/dao/model/ModelConstants.java @@ -680,7 +680,6 @@ public class ModelConstants { * */ public static final String NOTIFICATION_TARGET_TABLE_NAME = "notification_target"; - public static final String NOTIFICATION_TARGET_TYPE_PROPERTY = "type"; public static final String NOTIFICATION_TARGET_CONFIGURATION_PROPERTY = "configuration"; public static final String NOTIFICATION_TABLE_NAME = "notification"; @@ -688,7 +687,7 @@ public class ModelConstants { public static final String NOTIFICATION_RECIPIENT_ID_PROPERTY = "recipient_id"; public static final String NOTIFICATION_TYPE_PROPERTY = "type"; public static final String NOTIFICATION_SUBJECT_PROPERTY = "subject"; - public static final String NOTIFICATION_TEXT_PROPERTY = "text"; + public static final String NOTIFICATION_TEXT_PROPERTY = "body"; public static final String NOTIFICATION_ADDITIONAL_CONFIG_PROPERTY = "additional_config"; public static final String NOTIFICATION_STATUS_PROPERTY = "status"; diff --git a/dao/src/main/java/org/thingsboard/server/dao/service/DataValidator.java b/dao/src/main/java/org/thingsboard/server/dao/service/DataValidator.java index c2b714d81c..e95fee79ae 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/service/DataValidator.java +++ b/dao/src/main/java/org/thingsboard/server/dao/service/DataValidator.java @@ -17,13 +17,15 @@ package org.thingsboard.server.dao.service; import com.fasterxml.jackson.databind.JsonNode; import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Lazy; import org.thingsboard.server.common.data.BaseData; import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.StringUtils; import org.thingsboard.server.common.data.id.TenantId; -import org.thingsboard.server.dao.TenantEntityDao; import org.thingsboard.server.dao.TenantEntityWithDataDao; import org.thingsboard.server.dao.exception.DataValidationException; +import org.thingsboard.server.dao.usagerecord.ApiLimitService; import java.util.HashSet; import java.util.Iterator; @@ -32,6 +34,8 @@ import java.util.function.Function; import java.util.regex.Matcher; import java.util.regex.Pattern; +import static org.apache.commons.lang3.StringUtils.capitalize; + @Slf4j public abstract class DataValidator> { private static final Pattern EMAIL_PATTERN = @@ -42,6 +46,9 @@ public abstract class DataValidator> { private static final String NAME = "name"; private static final String TOPIC = "topic"; + @Autowired @Lazy + private ApiLimitService apiLimitService; + // Returns old instance of the same object that is fetched during validation. public D validate(D data, Function tenantIdFunction) { try { @@ -97,15 +104,9 @@ public abstract class DataValidator> { } protected void validateNumberOfEntitiesPerTenant(TenantId tenantId, - TenantEntityDao tenantEntityDao, - long maxEntities, EntityType entityType) { - if (maxEntities > 0) { - long currentEntitiesCount = tenantEntityDao.countByTenantId(tenantId); - if (currentEntitiesCount >= maxEntities) { - throw new DataValidationException(String.format("Can't create more then %d %ss!", - maxEntities, entityType.name().toLowerCase().replaceAll("_", " "))); - } + if (!apiLimitService.checkEntitiesLimit(tenantId, entityType)) { + throw new DataValidationException(String.format("%ss limit reached", capitalize(entityType.name().toLowerCase().replaceAll("_", " ")))); } } diff --git a/dao/src/main/java/org/thingsboard/server/dao/service/validator/AssetDataValidator.java b/dao/src/main/java/org/thingsboard/server/dao/service/validator/AssetDataValidator.java index c524aec551..57ae7d3c5e 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/service/validator/AssetDataValidator.java +++ b/dao/src/main/java/org/thingsboard/server/dao/service/validator/AssetDataValidator.java @@ -24,13 +24,11 @@ import org.thingsboard.server.common.data.StringUtils; import org.thingsboard.server.common.data.asset.Asset; import org.thingsboard.server.common.data.id.CustomerId; import org.thingsboard.server.common.data.id.TenantId; -import org.thingsboard.server.common.data.tenant.profile.DefaultTenantProfileConfiguration; import org.thingsboard.server.dao.asset.AssetDao; import org.thingsboard.server.dao.asset.BaseAssetService; import org.thingsboard.server.dao.customer.CustomerDao; import org.thingsboard.server.dao.exception.DataValidationException; import org.thingsboard.server.dao.service.DataValidator; -import org.thingsboard.server.dao.tenant.TbTenantProfileCache; import org.thingsboard.server.dao.tenant.TenantService; import static org.thingsboard.server.dao.model.ModelConstants.NULL_UUID; @@ -48,17 +46,10 @@ public class AssetDataValidator extends DataValidator { @Autowired private CustomerDao customerDao; - @Autowired - @Lazy - private TbTenantProfileCache tenantProfileCache; - @Override protected void validateCreate(TenantId tenantId, Asset asset) { - DefaultTenantProfileConfiguration profileConfiguration = - (DefaultTenantProfileConfiguration) tenantProfileCache.get(tenantId).getProfileData().getConfiguration(); if (!BaseAssetService.TB_SERVICE_QUEUE.equals(asset.getType())) { - long maxAssets = profileConfiguration.getMaxAssets(); - validateNumberOfEntitiesPerTenant(tenantId, assetDao, maxAssets, EntityType.ASSET); + validateNumberOfEntitiesPerTenant(tenantId, EntityType.ASSET); } } diff --git a/dao/src/main/java/org/thingsboard/server/dao/service/validator/CustomerDataValidator.java b/dao/src/main/java/org/thingsboard/server/dao/service/validator/CustomerDataValidator.java index 0e0c66550c..0f901e7ea2 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/service/validator/CustomerDataValidator.java +++ b/dao/src/main/java/org/thingsboard/server/dao/service/validator/CustomerDataValidator.java @@ -16,18 +16,15 @@ package org.thingsboard.server.dao.service.validator; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Component; import org.thingsboard.server.common.data.Customer; import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.StringUtils; import org.thingsboard.server.common.data.id.TenantId; -import org.thingsboard.server.common.data.tenant.profile.DefaultTenantProfileConfiguration; import org.thingsboard.server.dao.customer.CustomerDao; import org.thingsboard.server.dao.customer.CustomerServiceImpl; import org.thingsboard.server.dao.exception.DataValidationException; import org.thingsboard.server.dao.service.DataValidator; -import org.thingsboard.server.dao.tenant.TbTenantProfileCache; import org.thingsboard.server.dao.tenant.TenantService; import java.util.Optional; @@ -41,17 +38,9 @@ public class CustomerDataValidator extends DataValidator { @Autowired private TenantService tenantService; - @Autowired - @Lazy - private TbTenantProfileCache tenantProfileCache; - @Override protected void validateCreate(TenantId tenantId, Customer customer) { - DefaultTenantProfileConfiguration profileConfiguration = - (DefaultTenantProfileConfiguration) tenantProfileCache.get(tenantId).getProfileData().getConfiguration(); - long maxCustomers = profileConfiguration.getMaxCustomers(); - - validateNumberOfEntitiesPerTenant(tenantId, customerDao, maxCustomers, EntityType.CUSTOMER); + validateNumberOfEntitiesPerTenant(tenantId, EntityType.CUSTOMER); customerDao.findCustomersByTenantIdAndTitle(customer.getTenantId().getId(), customer.getTitle()).ifPresent( c -> { throw new DataValidationException("Customer with such title already exists!"); diff --git a/dao/src/main/java/org/thingsboard/server/dao/service/validator/DashboardDataValidator.java b/dao/src/main/java/org/thingsboard/server/dao/service/validator/DashboardDataValidator.java index 8b649faf63..246944199a 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/service/validator/DashboardDataValidator.java +++ b/dao/src/main/java/org/thingsboard/server/dao/service/validator/DashboardDataValidator.java @@ -16,17 +16,14 @@ package org.thingsboard.server.dao.service.validator; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Component; import org.thingsboard.server.common.data.Dashboard; import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.StringUtils; import org.thingsboard.server.common.data.id.TenantId; -import org.thingsboard.server.common.data.tenant.profile.DefaultTenantProfileConfiguration; import org.thingsboard.server.dao.dashboard.DashboardDao; import org.thingsboard.server.dao.exception.DataValidationException; import org.thingsboard.server.dao.service.DataValidator; -import org.thingsboard.server.dao.tenant.TbTenantProfileCache; import org.thingsboard.server.dao.tenant.TenantService; @Component @@ -38,16 +35,9 @@ public class DashboardDataValidator extends DataValidator { @Autowired private TenantService tenantService; - @Autowired - @Lazy - private TbTenantProfileCache tenantProfileCache; - @Override protected void validateCreate(TenantId tenantId, Dashboard data) { - DefaultTenantProfileConfiguration profileConfiguration = - (DefaultTenantProfileConfiguration) tenantProfileCache.get(tenantId).getProfileData().getConfiguration(); - long maxDashboards = profileConfiguration.getMaxDashboards(); - validateNumberOfEntitiesPerTenant(tenantId, dashboardDao, maxDashboards, EntityType.DASHBOARD); + validateNumberOfEntitiesPerTenant(tenantId, EntityType.DASHBOARD); } @Override diff --git a/dao/src/main/java/org/thingsboard/server/dao/service/validator/DeviceDataValidator.java b/dao/src/main/java/org/thingsboard/server/dao/service/validator/DeviceDataValidator.java index aff6b83169..51517a4dc2 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/service/validator/DeviceDataValidator.java +++ b/dao/src/main/java/org/thingsboard/server/dao/service/validator/DeviceDataValidator.java @@ -16,7 +16,6 @@ package org.thingsboard.server.dao.service.validator; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Component; import org.thingsboard.server.common.data.Customer; import org.thingsboard.server.common.data.Device; @@ -25,11 +24,9 @@ import org.thingsboard.server.common.data.StringUtils; import org.thingsboard.server.common.data.device.data.DeviceTransportConfiguration; import org.thingsboard.server.common.data.id.CustomerId; import org.thingsboard.server.common.data.id.TenantId; -import org.thingsboard.server.common.data.tenant.profile.DefaultTenantProfileConfiguration; import org.thingsboard.server.dao.customer.CustomerDao; import org.thingsboard.server.dao.device.DeviceDao; import org.thingsboard.server.dao.exception.DataValidationException; -import org.thingsboard.server.dao.tenant.TbTenantProfileCache; import org.thingsboard.server.dao.tenant.TenantService; import java.util.Optional; @@ -48,16 +45,9 @@ public class DeviceDataValidator extends AbstractHasOtaPackageValidator @Autowired private CustomerDao customerDao; - @Autowired - @Lazy - private TbTenantProfileCache tenantProfileCache; - @Override protected void validateCreate(TenantId tenantId, Device device) { - DefaultTenantProfileConfiguration profileConfiguration = - (DefaultTenantProfileConfiguration) tenantProfileCache.get(tenantId).getProfileData().getConfiguration(); - long maxDevices = profileConfiguration.getMaxDevices(); - validateNumberOfEntitiesPerTenant(tenantId, deviceDao, maxDevices, EntityType.DEVICE); + validateNumberOfEntitiesPerTenant(tenantId, EntityType.DEVICE); } @Override diff --git a/dao/src/main/java/org/thingsboard/server/dao/service/validator/RuleChainDataValidator.java b/dao/src/main/java/org/thingsboard/server/dao/service/validator/RuleChainDataValidator.java index 8a1f6319d1..ac145034a5 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/service/validator/RuleChainDataValidator.java +++ b/dao/src/main/java/org/thingsboard/server/dao/service/validator/RuleChainDataValidator.java @@ -60,16 +60,9 @@ public class RuleChainDataValidator extends DataValidator { @Autowired private TenantService tenantService; - @Autowired - @Lazy - private TbTenantProfileCache tenantProfileCache; - @Override protected void validateCreate(TenantId tenantId, RuleChain data) { - DefaultTenantProfileConfiguration profileConfiguration = - (DefaultTenantProfileConfiguration) tenantProfileCache.get(tenantId).getProfileData().getConfiguration(); - long maxRuleChains = profileConfiguration.getMaxRuleChains(); - validateNumberOfEntitiesPerTenant(tenantId, ruleChainDao, maxRuleChains, EntityType.RULE_CHAIN); + validateNumberOfEntitiesPerTenant(tenantId, EntityType.RULE_CHAIN); } @Override diff --git a/dao/src/main/java/org/thingsboard/server/dao/service/validator/UserDataValidator.java b/dao/src/main/java/org/thingsboard/server/dao/service/validator/UserDataValidator.java index 1c09073036..dc77afcfc2 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/service/validator/UserDataValidator.java +++ b/dao/src/main/java/org/thingsboard/server/dao/service/validator/UserDataValidator.java @@ -19,19 +19,16 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Component; import org.thingsboard.server.common.data.Customer; -import org.thingsboard.server.common.data.Device; import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.StringUtils; import org.thingsboard.server.common.data.User; import org.thingsboard.server.common.data.id.CustomerId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.security.Authority; -import org.thingsboard.server.common.data.tenant.profile.DefaultTenantProfileConfiguration; import org.thingsboard.server.dao.customer.CustomerDao; import org.thingsboard.server.dao.exception.DataValidationException; import org.thingsboard.server.dao.model.ModelConstants; import org.thingsboard.server.dao.service.DataValidator; -import org.thingsboard.server.dao.tenant.TbTenantProfileCache; import org.thingsboard.server.dao.tenant.TenantService; import org.thingsboard.server.dao.user.UserDao; import org.thingsboard.server.dao.user.UserService; @@ -49,10 +46,6 @@ public class UserDataValidator extends DataValidator { @Autowired private CustomerDao customerDao; - @Autowired - @Lazy - private TbTenantProfileCache tenantProfileCache; - @Autowired @Lazy private TenantService tenantService; @@ -60,10 +53,7 @@ public class UserDataValidator extends DataValidator { @Override protected void validateCreate(TenantId tenantId, User user) { if (!user.getTenantId().getId().equals(ModelConstants.NULL_UUID)) { - DefaultTenantProfileConfiguration profileConfiguration = - (DefaultTenantProfileConfiguration) tenantProfileCache.get(tenantId).getProfileData().getConfiguration(); - long maxUsers = profileConfiguration.getMaxUsers(); - validateNumberOfEntitiesPerTenant(tenantId, userDao, maxUsers, EntityType.USER); + validateNumberOfEntitiesPerTenant(tenantId, EntityType.USER); } } diff --git a/dao/src/main/resources/sql/schema-entities-idx.sql b/dao/src/main/resources/sql/schema-entities-idx.sql index 34359302ad..96fb740088 100644 --- a/dao/src/main/resources/sql/schema-entities-idx.sql +++ b/dao/src/main/resources/sql/schema-entities-idx.sql @@ -94,14 +94,17 @@ CREATE INDEX IF NOT EXISTS idx_notification_target_tenant_id_created_time ON not CREATE INDEX IF NOT EXISTS idx_notification_template_tenant_id_created_time ON notification_template(tenant_id, created_time DESC); -CREATE INDEX IF NOT EXISTS idx_notification_rule_tenant_id_created_time ON notification_rule(tenant_id, created_time DESC); +CREATE INDEX IF NOT EXISTS idx_notification_rule_tenant_id_trigger_type_created_time ON notification_rule(tenant_id, trigger_type, created_time DESC); -CREATE INDEX IF NOT EXISTS idx_notification_request_tenant_id_originator_type_created_time ON notification_request(tenant_id, originator_entity_type, created_time DESC); +CREATE INDEX IF NOT EXISTS idx_notification_request_tenant_id_user_created_time ON notification_request(tenant_id, created_time DESC) + WHERE originator_entity_type = 'USER'; -CREATE INDEX IF NOT EXISTS idx_notification_request_rule_id_originator_entity_id ON notification_request(rule_id, originator_entity_id); +CREATE INDEX IF NOT EXISTS idx_notification_request_rule_id_originator_entity_id ON notification_request(rule_id, originator_entity_id) + WHERE originator_entity_type = 'ALARM'; -CREATE INDEX IF NOT EXISTS idx_notification_request_status ON notification_request(status); +CREATE INDEX IF NOT EXISTS idx_notification_request_status ON notification_request(status) + WHERE status = 'SCHEDULED'; -CREATE INDEX IF NOT EXISTS idx_notification_id_recipient_id ON notification(id, recipient_id); +CREATE INDEX IF NOT EXISTS idx_notification_id ON notification(id); -CREATE INDEX IF NOT EXISTS idx_notification_recipient_id_status_created_time ON notification(recipient_id, status, created_time DESC); +CREATE INDEX IF NOT EXISTS idx_notification_recipient_id_created_time ON notification(recipient_id, created_time DESC); diff --git a/dao/src/main/resources/sql/schema-entities.sql b/dao/src/main/resources/sql/schema-entities.sql index 17a989a53e..7d47138bab 100644 --- a/dao/src/main/resources/sql/schema-entities.sql +++ b/dao/src/main/resources/sql/schema-entities.sql @@ -844,7 +844,7 @@ CREATE TABLE IF NOT EXISTS notification ( recipient_id UUID NOT NULL CONSTRAINT fk_notification_recipient_id REFERENCES tb_user(id) ON DELETE CASCADE, type VARCHAR(50) NOT NULL, subject VARCHAR(255), - text VARCHAR(1000) NOT NULL, + body VARCHAR(1000) NOT NULL, additional_config VARCHAR(1000), status VARCHAR(32) ) PARTITION BY RANGE (created_time); @@ -1021,7 +1021,7 @@ BEGIN UPDATE alarm a SET acknowledged = true, ack_ts = a_ts WHERE a.id = a_id AND a.tenant_id = t_id; END IF; SELECT * INTO result FROM alarm_info a WHERE a.id = a_id AND a.tenant_id = t_id; - RETURN json_build_object('success', true, 'modified', modified, 'alarm', row_to_json(result))::text; + RETURN json_build_object('success', true, 'modified', modified, 'alarm', row_to_json(result), 'old', row_to_json(existing))::text; END $$; diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbCopyAttributesToEntityViewNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbCopyAttributesToEntityViewNode.java index 2fcc1f0e39..029531494e 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbCopyAttributesToEntityViewNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbCopyAttributesToEntityViewNode.java @@ -22,7 +22,7 @@ import com.google.gson.JsonParser; import com.google.gson.JsonPrimitive; import lombok.extern.slf4j.Slf4j; import org.jetbrains.annotations.NotNull; -import org.thingsboard.common.util.CollectionsUtil; +import org.thingsboard.server.common.data.util.CollectionsUtil; import org.thingsboard.common.util.DonAsynchron; import org.thingsboard.rule.engine.api.EmptyNodeConfiguration; import org.thingsboard.rule.engine.api.RuleNode; From ca2fac4b9d4cb8d480a116c3b72cd5e656105cfb Mon Sep 17 00:00:00 2001 From: Vladyslav_Prykhodko Date: Thu, 16 Mar 2023 15:45:34 +0200 Subject: [PATCH 28/28] UI: Add new notification rule settings --- .../rule-notification-dialog.component.html | 18 +++++- .../rule-notification-dialog.component.scss | 4 ++ .../rule-notification-dialog.component.ts | 14 ++++- .../app/shared/models/notification.models.ts | 57 ++++++++++++++++--- .../assets/locale/locale.constant-en_US.json | 9 +++ 5 files changed, 88 insertions(+), 14 deletions(-) diff --git a/ui-ngx/src/app/modules/home/pages/notification-center/rule-table/rule-notification-dialog.component.html b/ui-ngx/src/app/modules/home/pages/notification-center/rule-table/rule-notification-dialog.component.html index 6afa5f3440..4e72dcbfa4 100644 --- a/ui-ngx/src/app/modules/home/pages/notification-center/rule-table/rule-notification-dialog.component.html +++ b/ui-ngx/src/app/modules/home/pages/notification-center/rule-table/rule-notification-dialog.component.html @@ -107,7 +107,7 @@ {{ 'notification.alarm-trigger-settings' | translate }}
-
+
notification.filter - + alarm.alarm-severity-list @@ -127,6 +127,17 @@
+ + notification.notify-on + + + {{ alarmActionTranslationMap.get(alarmAction) | translate }} + + + + {{ 'notification.notify-on-required' | translate }} + +
@@ -247,6 +258,9 @@
+ + {{ 'notification.notify-only-user-comments' | translate }} +
diff --git a/ui-ngx/src/app/modules/home/pages/notification-center/rule-table/rule-notification-dialog.component.scss b/ui-ngx/src/app/modules/home/pages/notification-center/rule-table/rule-notification-dialog.component.scss index f9d0d4b63d..a3db5bf58b 100644 --- a/ui-ngx/src/app/modules/home/pages/notification-center/rule-table/rule-notification-dialog.component.scss +++ b/ui-ngx/src/app/modules/home/pages/notification-center/rule-table/rule-notification-dialog.component.scss @@ -38,6 +38,10 @@ margin-bottom: 12px; } + &.tb-margin-before-field { + margin-bottom: 12px; + } + &.tb-hierarchy { padding: 0 0 8px 16px; } diff --git a/ui-ngx/src/app/modules/home/pages/notification-center/rule-table/rule-notification-dialog.component.ts b/ui-ngx/src/app/modules/home/pages/notification-center/rule-table/rule-notification-dialog.component.ts index 7af6d846be..e4335cc130 100644 --- a/ui-ngx/src/app/modules/home/pages/notification-center/rule-table/rule-notification-dialog.component.ts +++ b/ui-ngx/src/app/modules/home/pages/notification-center/rule-table/rule-notification-dialog.component.ts @@ -15,6 +15,8 @@ /// import { + AlarmAction, + AlarmActionTranslationMap, NotificationRule, NotificationTarget, TriggerType, @@ -89,6 +91,9 @@ export class RuleNotificationDialogComponent extends alarmSeverityTranslationMap = alarmSeverityTranslations; alarmSeverities = Object.keys(AlarmSeverity) as Array; + alarmActions: AlarmAction[] = Object.values(AlarmAction); + alarmActionTranslationMap = AlarmActionTranslationMap; + entityType = EntityType; entityTypes: EntityType[] = Object.values(EntityType); isAdd = true; @@ -163,7 +168,8 @@ export class RuleNotificationDialogComponent extends alarmSeverities: [[]], clearRule: this.fb.group({ alarmStatuses: [[]] - }) + }), + notifyOn: [[AlarmAction.CREATED], Validators.required] }) }); @@ -200,7 +206,8 @@ export class RuleNotificationDialogComponent extends triggerConfig: this.fb.group({ alarmTypes: [null], alarmSeverities: [[]], - alarmStatuses: [[]] + alarmStatuses: [[]], + onlyUserComments: [false] }) }); @@ -217,7 +224,8 @@ export class RuleNotificationDialogComponent extends [TriggerType.ALARM, this.alarmTemplateForm], [TriggerType.ALARM_COMMENT, this.alarmCommentTemplateForm], [TriggerType.DEVICE_INACTIVITY, this.deviceInactivityTemplateForm], - [TriggerType.ENTITY_ACTION, this.entityActionTemplateForm] + [TriggerType.ENTITY_ACTION, this.entityActionTemplateForm], + [TriggerType.ALARM_ASSIGNMENT, this.alarmAssignmentTemplateForm], ]); if (data.isAdd || data.isCopy) { diff --git a/ui-ngx/src/app/shared/models/notification.models.ts b/ui-ngx/src/app/shared/models/notification.models.ts index cfcabdbb5e..a728496e82 100644 --- a/ui-ngx/src/app/shared/models/notification.models.ts +++ b/ui-ngx/src/app/shared/models/notification.models.ts @@ -109,21 +109,60 @@ export interface NotificationRule extends Omit, 'la additionalConfig: {description: string}; } -export interface NotificationRuleTriggerConfig { +export type NotificationRuleTriggerConfig = Partial + +export interface AlarmNotificationRuleTriggerConfig { alarmTypes?: Array; alarmSeverities?: Array; - alarmStatuses?: Array; - clearRule?: { - alarmStatuses: Array; - }; + notifyOn: Array; + clearRule?: ClearRule; +} + +interface ClearRule { + alarmStatuses: Array +} + +export interface DeviceInactivityNotificationRuleTriggerConfig { devices?: Array; deviceProfiles?: Array; - entityType?: EntityType; - created?: boolean; - updated?: boolean; - deleted?: boolean; } +export interface EntityActionNotificationRuleTriggerConfig { + entityType: EntityType; + created: boolean; + updated: boolean; + deleted: boolean; +} + +export interface AlarmCommentNotificationRuleTriggerConfig { + alarmTypes?: Array; + alarmSeverities?: Array; + alarmStatuses?: Array; + notifyOnUnassign?: boolean; + onlyUserComments?: boolean; +} + +export interface AlarmAssignmentNotificationRuleTriggerConfig { + alarmTypes?: Array; + alarmSeverities?: Array; + alarmStatuses?: Array; + notifyOnUnassign?: boolean; +} + +export enum AlarmAction { + CREATED = 'CREATED', + SEVERITY_CHANGED = 'SEVERITY_CHANGED', + ACKNOWLEDGED = 'ACKNOWLEDGED', + CLEARED = 'CLEARED' +} + +export const AlarmActionTranslationMap = new Map([ + [AlarmAction.CREATED, 'notification.notify-alarm-action.created'], + [AlarmAction.SEVERITY_CHANGED, 'notification.notify-alarm-action.severity-changed'], + [AlarmAction.ACKNOWLEDGED, 'notification.notify-alarm-action.acknowledged'], + [AlarmAction.CLEARED, 'notification.notify-alarm-action.cleared'] +]) + export interface NotificationRuleRecipientConfig { targets?: Array; escalationTable?: {[key: number]: Array}; 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 2770a5235a..9b378be529 100644 --- a/ui-ngx/src/assets/locale/locale.constant-en_US.json +++ b/ui-ngx/src/assets/locale/locale.constant-en_US.json @@ -2815,7 +2815,16 @@ "notification-chain": "Notification chain", "notification-target": "Notification recipient", "notify": "notify", + "notify-alarm-action": { + "created": "Alarm created", + "severity-changed": "Alarm severity changed", + "acknowledged": "Alarm acknowledged", + "cleared": "Alarm cleared" + }, "notify-again": "Notify again", + "notify-on": "Notify on", + "notify-on-required": "Notify on is required", + "notify-only-user-comments": "Notify only user comments", "notify-on-unassign": "Notify on unassign", "platform-users": "Platform users", "recipient": "Recipient",