From c542bb9b161e57c96b6ab5ad98e40626433f12df Mon Sep 17 00:00:00 2001 From: ViacheslavKlimov Date: Thu, 27 Apr 2023 13:55:16 +0300 Subject: [PATCH 1/2] Notification system API description for Swagger --- .../controller/NotificationController.java | 108 +++++++++++++++++- .../NotificationRuleController.java | 78 ++++++++++++- .../NotificationTargetController.java | 60 ++++++++-- .../NotificationTemplateController.java | 77 ++++++++++--- .../DefaultNotificationCenter.java | 19 --- .../notification/NotificationRequest.java | 1 - .../trigger/NotificationRuleTriggerType.java | 6 +- .../rule/engine/api/NotificationCenter.java | 2 - 8 files changed, 297 insertions(+), 54 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/controller/NotificationController.java b/application/src/main/java/org/thingsboard/server/controller/NotificationController.java index c3e9215d90..0f4a288e33 100644 --- a/application/src/main/java/org/thingsboard/server/controller/NotificationController.java +++ b/application/src/main/java/org/thingsboard/server/controller/NotificationController.java @@ -16,6 +16,7 @@ package org.thingsboard.server.controller; import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiParam; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.security.access.prepost.PreAuthorize; @@ -76,6 +77,16 @@ import java.util.Set; import java.util.UUID; import java.util.stream.Collectors; +import static org.thingsboard.server.controller.ControllerConstants.AVAILABLE_FOR_ANY_AUTHORIZED_USER; +import static org.thingsboard.server.controller.ControllerConstants.MARKDOWN_CODE_BLOCK_END; +import static org.thingsboard.server.controller.ControllerConstants.MARKDOWN_CODE_BLOCK_START; +import static org.thingsboard.server.controller.ControllerConstants.NEW_LINE; +import static org.thingsboard.server.controller.ControllerConstants.PAGE_DATA_PARAMETERS; +import static org.thingsboard.server.controller.ControllerConstants.PAGE_NUMBER_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.PAGE_SIZE_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.SORT_ORDER_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.SORT_PROPERTY_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.SYSTEM_OR_TENANT_AUTHORITY_PARAGRAPH; import static org.thingsboard.server.service.security.permission.Resource.NOTIFICATION; @RestController @@ -93,7 +104,10 @@ public class NotificationController extends BaseController { private final NotificationSettingsService notificationSettingsService; @ApiOperation(value = "Get notifications (getNotifications)", - notes = "**WebSocket API**:\n\n" + + notes = "Returns the page of notifications for current user." + NEW_LINE + + PAGE_DATA_PARAMETERS + + AVAILABLE_FOR_ANY_AUTHORIZED_USER + NEW_LINE + + "**WebSocket API**:\n\n" + "There are 2 types of subscriptions: one for unread notifications count, another for unread notifications themselves.\n\n" + "The URI for opening WS session for notifications: `/api/ws/plugins/notifications`.\n\n" + "Subscription command for unread notifications count:\n" + @@ -144,11 +158,17 @@ public class NotificationController extends BaseController { "}\n```") @GetMapping("/notifications") @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") - public PageData getNotifications(@RequestParam int pageSize, + public PageData getNotifications(@ApiParam(value = PAGE_SIZE_DESCRIPTION, required = true) + @RequestParam int pageSize, + @ApiParam(value = PAGE_NUMBER_DESCRIPTION, required = true) @RequestParam int page, + @ApiParam(value = "Case-insensitive 'substring' filter based on notification subject or text") @RequestParam(required = false) String textSearch, + @ApiParam(value = SORT_PROPERTY_DESCRIPTION) @RequestParam(required = false) String sortProperty, + @ApiParam(value = SORT_ORDER_DESCRIPTION) @RequestParam(required = false) String sortOrder, + @ApiParam(value = "To search for unread notifications only") @RequestParam(defaultValue = "false") boolean unreadOnly, @AuthenticationPrincipal SecurityUser user) throws ThingsboardException { // no permissions @@ -156,6 +176,9 @@ public class NotificationController extends BaseController { return notificationService.findNotificationsByRecipientIdAndReadStatus(user.getTenantId(), user.getId(), unreadOnly, pageLink); } + @ApiOperation(value = "Mark notification as read (markNotificationAsRead)", + notes = "Marks notification as read by its id." + + AVAILABLE_FOR_ANY_AUTHORIZED_USER) @PutMapping("/notification/{id}/read") @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") public void markNotificationAsRead(@PathVariable UUID id, @@ -165,6 +188,9 @@ public class NotificationController extends BaseController { notificationCenter.markNotificationAsRead(user.getTenantId(), user.getId(), notificationId); } + @ApiOperation(value = "Mark all notifications as read (markAllNotificationsAsRead)", + notes = "Marks all unread notifications as read." + + AVAILABLE_FOR_ANY_AUTHORIZED_USER) @PutMapping("/notifications/read") @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") public void markAllNotificationsAsRead(@AuthenticationPrincipal SecurityUser user) { @@ -172,6 +198,9 @@ public class NotificationController extends BaseController { notificationCenter.markAllNotificationsAsRead(user.getTenantId(), user.getId()); } + @ApiOperation(value = "Delete notification (deleteNotification)", + notes = "Deletes notification by its id." + + AVAILABLE_FOR_ANY_AUTHORIZED_USER) @DeleteMapping("/notification/{id}") @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") public void deleteNotification(@PathVariable UUID id, @@ -181,6 +210,35 @@ public class NotificationController extends BaseController { notificationCenter.deleteNotification(user.getTenantId(), user.getId(), notificationId); } + @ApiOperation(value = "Create notification request (createNotificationRequest)", + notes = "Processes notification request.\n" + + "Mandatory request properties are `targets` (list of targets ids to send notification to), " + + "and either `templateId` (existing notification template id) or `template` (to send notification without saving the template).\n" + + "Optionally, you can set `sendingDelayInSec` inside the `additionalConfig` field to schedule the notification." + NEW_LINE + + "For each enabled delivery method in the notification template, there must be a target in the `targets` list that supports this delivery method: " + + "if you chose `WEB`, `EMAIL` or `SMS` - there must be at least one target in `targets` of `PLATFORM_USERS` type.\n" + + "For `SLACK` delivery method - you need to chose at least one `SLACK` notification target." + NEW_LINE + + "Notification request object with `PROCESSING` status will be returned immediately, " + + "and the notification sending itself is done asynchronously. After all notifications are sent, " + + "the `status` of the request becomes `SENT`. Use `getNotificationRequestById` to see " + + "the notification request processing status and some sending stats. " + NEW_LINE + + "Here is an example of notification request to one target using saved template:\n" + + MARKDOWN_CODE_BLOCK_START + + "{\n" + + " \"templateId\": {\n" + + " \"entityType\": \"NOTIFICATION_TEMPLATE\",\n" + + " \"id\": \"6dbc3670-e4dd-11ed-9401-dbcc5dff78be\"\n" + + " },\n" + + " \"targets\": [\n" + + " \"320e3ed0-d785-11ed-a06c-21dd57dd88ca\"\n" + + " ],\n" + + " \"additionalConfig\": {\n" + + " \"sendingDelayInSec\": 0\n" + + " }\n" + + "}" + + MARKDOWN_CODE_BLOCK_END + + SYSTEM_OR_TENANT_AUTHORITY_PARAGRAPH + ) @PostMapping("/notification/request") @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')") public NotificationRequest createNotificationRequest(@RequestBody @Valid NotificationRequest notificationRequest, @@ -200,9 +258,15 @@ public class NotificationController extends BaseController { return doSaveAndLog(EntityType.NOTIFICATION_REQUEST, notificationRequest, (tenantId, request) -> notificationCenter.processNotificationRequest(tenantId, request, null)); } + @ApiOperation(value = "Get notification request preview (getNotificationRequestPreview)", + notes = "Returns preview for notification request." + NEW_LINE + + "`processedTemplates` shows how the notifications for each delivery method will look like " + + "for the first recipient of the corresponding notification target." + + SYSTEM_OR_TENANT_AUTHORITY_PARAGRAPH) @PostMapping("/notification/request/preview") @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')") public NotificationRequestPreview getNotificationRequestPreview(@RequestBody @Valid NotificationRequest request, + @ApiParam(value = "Amount of the recipients to show in preview") @RequestParam(defaultValue = "20") int recipientsPreviewSize, @AuthenticationPrincipal SecurityUser user) throws ThingsboardException { NotificationTemplate template; @@ -281,6 +345,9 @@ public class NotificationController extends BaseController { return preview; } + @ApiOperation(value = "Get notification request by id (getNotificationRequestById)", + notes = "Fetches notification request info by request id." + + SYSTEM_OR_TENANT_AUTHORITY_PARAGRAPH) @GetMapping("/notification/request/{id}") @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')") public NotificationRequestInfo getNotificationRequestById(@PathVariable UUID id) throws ThingsboardException { @@ -288,12 +355,21 @@ public class NotificationController extends BaseController { return checkEntityId(notificationRequestId, notificationRequestService::findNotificationRequestInfoById, Operation.READ); } + @ApiOperation(value = "Get notification requests (getNotificationRequests)", + notes = "Returns the page of notification requests submitted by users of this tenant or sysadmins." + NEW_LINE + + PAGE_DATA_PARAMETERS + + SYSTEM_OR_TENANT_AUTHORITY_PARAGRAPH) @GetMapping("/notification/requests") @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')") - public PageData getNotificationRequests(@RequestParam int pageSize, + public PageData getNotificationRequests(@ApiParam(value = PAGE_SIZE_DESCRIPTION, required = true) + @RequestParam int pageSize, + @ApiParam(value = PAGE_NUMBER_DESCRIPTION, required = true) @RequestParam int page, + @ApiParam(value = "Case-insensitive 'substring' filed based on the used template name") @RequestParam(required = false) String textSearch, + @ApiParam(value = SORT_PROPERTY_DESCRIPTION) @RequestParam(required = false) String sortProperty, + @ApiParam(value = SORT_ORDER_DESCRIPTION) @RequestParam(required = false) String sortOrder, @AuthenticationPrincipal SecurityUser user) throws ThingsboardException { // generic permission @@ -301,6 +377,11 @@ public class NotificationController extends BaseController { return notificationRequestService.findNotificationRequestsInfosByTenantIdAndOriginatorType(user.getTenantId(), EntityType.USER, pageLink); } + @ApiOperation(value = "Delete notification request (deleteNotificationRequest)", + notes = "Deletes notification request by its id." + NEW_LINE + + "If the request has status `SENT` - all sent notifications for this request will be deleted. " + + "If it is `SCHEDULED`, the request will be cancelled." + + SYSTEM_OR_TENANT_AUTHORITY_PARAGRAPH) @DeleteMapping("/notification/request/{id}") @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')") public void deleteNotificationRequest(@PathVariable UUID id) throws Exception { @@ -310,6 +391,21 @@ public class NotificationController extends BaseController { } + @ApiOperation(value = "Save notification settings (saveNotificationSettings)", + notes = "Saves notification settings for this tenant or sysadmin.\n" + + "`deliveryMethodsConfigs` of the settings must be specified." + NEW_LINE + + "Here is an example of the notification settings with Slack configuration:\n" + + MARKDOWN_CODE_BLOCK_START + + "{\n" + + " \"deliveryMethodsConfigs\": {\n" + + " \"SLACK\": {\n" + + " \"method\": \"SLACK\",\n" + + " \"botToken\": \"xoxb-....\"\n" + + " }\n" + + " }\n" + + "}" + + MARKDOWN_CODE_BLOCK_END + + SYSTEM_OR_TENANT_AUTHORITY_PARAGRAPH) @PostMapping("/notification/settings") @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')") public NotificationSettings saveNotificationSettings(@RequestBody @Valid NotificationSettings notificationSettings, @@ -320,6 +416,9 @@ public class NotificationController extends BaseController { return notificationSettings; } + @ApiOperation(value = "Get notification settings (getNotificationSettings)", + notes = "Retrieves notification settings for this tenant or sysadmin." + + SYSTEM_OR_TENANT_AUTHORITY_PARAGRAPH) @GetMapping("/notification/settings") @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')") public NotificationSettings getNotificationSettings(@AuthenticationPrincipal SecurityUser user) throws ThingsboardException { @@ -328,6 +427,9 @@ public class NotificationController extends BaseController { return notificationSettingsService.findNotificationSettings(tenantId); } + @ApiOperation(value = "Get available delivery methods (getAvailableDeliveryMethods)", + notes = "Returns the list of delivery methods that are properly configured and are allowed to be used for sending notifications." + + SYSTEM_OR_TENANT_AUTHORITY_PARAGRAPH) @GetMapping("/notification/deliveryMethods") @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')") public Set getAvailableDeliveryMethods(@AuthenticationPrincipal SecurityUser user) throws ThingsboardException { 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 75e2b538a6..ccf2124113 100644 --- a/application/src/main/java/org/thingsboard/server/controller/NotificationRuleController.java +++ b/application/src/main/java/org/thingsboard/server/controller/NotificationRuleController.java @@ -15,6 +15,8 @@ */ package org.thingsboard.server.controller; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiParam; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.security.access.prepost.PreAuthorize; @@ -44,6 +46,15 @@ import org.thingsboard.server.service.security.permission.Operation; import javax.validation.Valid; import java.util.UUID; +import static org.thingsboard.server.controller.ControllerConstants.MARKDOWN_CODE_BLOCK_END; +import static org.thingsboard.server.controller.ControllerConstants.MARKDOWN_CODE_BLOCK_START; +import static org.thingsboard.server.controller.ControllerConstants.NEW_LINE; +import static org.thingsboard.server.controller.ControllerConstants.PAGE_DATA_PARAMETERS; +import static org.thingsboard.server.controller.ControllerConstants.PAGE_NUMBER_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.PAGE_SIZE_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.SORT_ORDER_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.SORT_PROPERTY_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.SYSTEM_OR_TENANT_AUTHORITY_PARAGRAPH; import static org.thingsboard.server.service.security.permission.Resource.NOTIFICATION; @RestController @@ -55,6 +66,53 @@ public class NotificationRuleController extends BaseController { private final NotificationRuleService notificationRuleService; + @ApiOperation(value = "Save notification rule (saveNotificationRule)", + notes = "Creates or updates notification rule. " + NEW_LINE + + "Mandatory properties are `name`, `templateId` (of a template with `notificationType` matching to rule's `triggerType`), " + + "`triggerType`, `triggerConfig` and `recipientConfig`. Additionally, you may specify rule `description` " + + "inside of `additionalConfig`." + NEW_LINE + + "Trigger type of the rule cannot be changed. " + + "Available trigger types for tenant: `ENTITY_ACTION`, `ALARM`, `ALARM_COMMENT`, `ALARM_ASSIGNMENT`, " + + "`DEVICE_ACTIVITY`, `RULE_ENGINE_COMPONENT_LIFECYCLE_EVENT`.\n" + + "For sysadmin, there are following trigger types available: `ENTITIES_LIMIT`, `API_USAGE_LIMIT`, " + + "`NEW_PLATFORM_VERSION`." + NEW_LINE + + "Here is an example of notification rule to send notification when a " + + "device, asset or customer is created or deleted:\n" + + MARKDOWN_CODE_BLOCK_START + + "{\n" + + " \"name\": \"Entity action\",\n" + + " \"templateId\": {\n" + + " \"entityType\": \"NOTIFICATION_TEMPLATE\",\n" + + " \"id\": \"32117320-d785-11ed-a06c-21dd57dd88ca\"\n" + + " },\n" + + " \"triggerType\": \"ENTITY_ACTION\",\n" + + " \"triggerConfig\": {\n" + + " \"entityTypes\": [\n" + + " \"CUSTOMER\",\n" + + " \"DEVICE\",\n" + + " \"ASSET\"\n" + + " ],\n" + + " \"created\": true,\n" + + " \"updated\": false,\n" + + " \"deleted\": true,\n" + + " \"triggerType\": \"ENTITY_ACTION\"\n" + + " },\n" + + " \"recipientsConfig\": {\n" + + " \"targets\": [\n" + + " \"320f2930-d785-11ed-a06c-21dd57dd88ca\"\n" + + " ],\n" + + " \"triggerType\": \"ENTITY_ACTION\"\n" + + " },\n" + + " \"additionalConfig\": {\n" + + " \"description\": \"Send notification to tenant admins or customer users when a device, asset or customer is created\"\n" + + " },\n" + + " \"templateName\": \"Entity action notification\",\n" + + " \"deliveryMethods\": [\n" + + " \"WEB\"\n" + + " ]\n" + + "}" + + MARKDOWN_CODE_BLOCK_END + + SYSTEM_OR_TENANT_AUTHORITY_PARAGRAPH) @PostMapping("/rule") @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')") public NotificationRule saveNotificationRule(@RequestBody @Valid NotificationRule notificationRule, @@ -74,6 +132,11 @@ public class NotificationRuleController extends BaseController { return notificationRule; } + @ApiOperation(value = "Get notification rule by id (getNotificationRuleById)", + notes = "Fetches notification rule info by rule's id.\n" + + "In addition to regular notification rule fields, " + + "there are `templateName` and `deliveryMethods` in the response." + + SYSTEM_OR_TENANT_AUTHORITY_PARAGRAPH) @GetMapping("/rule/{id}") @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')") public NotificationRuleInfo getNotificationRuleById(@PathVariable UUID id) throws ThingsboardException { @@ -81,12 +144,21 @@ public class NotificationRuleController extends BaseController { return checkEntityId(notificationRuleId, notificationRuleService::findNotificationRuleInfoById, Operation.READ); } + @ApiOperation(value = "Get notification rules (getNotificationRules)", + notes = "Returns the page of notification rules." + NEW_LINE + + PAGE_DATA_PARAMETERS + + SYSTEM_OR_TENANT_AUTHORITY_PARAGRAPH) @GetMapping("/rules") @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')") - public PageData getNotificationRules(@RequestParam int pageSize, + public PageData getNotificationRules(@ApiParam(value = PAGE_SIZE_DESCRIPTION, required = true) + @RequestParam int pageSize, + @ApiParam(value = PAGE_NUMBER_DESCRIPTION, required = true) @RequestParam int page, + @ApiParam(value = "Case-insensitive 'substring' filter based on rule's name") @RequestParam(required = false) String textSearch, + @ApiParam(value = SORT_PROPERTY_DESCRIPTION) @RequestParam(required = false) String sortProperty, + @ApiParam(value = SORT_ORDER_DESCRIPTION) @RequestParam(required = false) String sortOrder, @AuthenticationPrincipal SecurityUser user) throws ThingsboardException { // generic permission @@ -94,6 +166,10 @@ public class NotificationRuleController extends BaseController { return notificationRuleService.findNotificationRulesInfosByTenantId(user.getTenantId(), pageLink); } + @ApiOperation(value = "Delete notification rule (deleteNotificationRule)", + notes = "Deletes notification rule by id.\n" + + "Cancels all related scheduled notification requests (e.g. due to escalation table)" + + SYSTEM_OR_TENANT_AUTHORITY_PARAGRAPH) @DeleteMapping("/rule/{id}") @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')") public void deleteNotificationRule(@PathVariable UUID 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 6374b65710..a4c829796b 100644 --- a/application/src/main/java/org/thingsboard/server/controller/NotificationTargetController.java +++ b/application/src/main/java/org/thingsboard/server/controller/NotificationTargetController.java @@ -16,6 +16,7 @@ package org.thingsboard.server.controller; import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiParam; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.apache.commons.collections.CollectionUtils; @@ -58,6 +59,14 @@ import java.util.List; import java.util.UUID; import java.util.stream.Collectors; +import static org.thingsboard.server.controller.ControllerConstants.MARKDOWN_CODE_BLOCK_END; +import static org.thingsboard.server.controller.ControllerConstants.MARKDOWN_CODE_BLOCK_START; +import static org.thingsboard.server.controller.ControllerConstants.NEW_LINE; +import static org.thingsboard.server.controller.ControllerConstants.PAGE_DATA_PARAMETERS; +import static org.thingsboard.server.controller.ControllerConstants.PAGE_NUMBER_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.PAGE_SIZE_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.SORT_ORDER_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.SORT_PROPERTY_DESCRIPTION; import static org.thingsboard.server.controller.ControllerConstants.SYSTEM_OR_TENANT_AUTHORITY_PARAGRAPH; import static org.thingsboard.server.service.security.permission.Resource.NOTIFICATION; @@ -71,7 +80,28 @@ public class NotificationTargetController extends BaseController { private final NotificationTargetService notificationTargetService; @ApiOperation(value = "Save notification target (saveNotificationTarget)", - notes = "Create or update notification target." + + notes = "Creates or updates notification target." + NEW_LINE + + "Available `configuration` types are `PLATFORM_USERS` and `SLACK`.\n" + + "For `PLATFORM_USERS` the `usersFilter` must be specified. " + + "For tenant, there are following users filter types available: " + + "`USER_LIST`, `CUSTOMER_USERS`, `TENANT_ADMINISTRATORS`, `ALL_USERS`, " + + "`ORIGINATOR_ENTITY_OWNER_USERS`, `AFFECTED_USER`.\n" + + "For sysadmin: `TENANT_ADMINISTRATORS`, `AFFECTED_TENANT_ADMINISTRATORS`, " + + "`SYSTEM_ADMINISTRATORS`, `ALL_USERS`." + NEW_LINE + + "Here is an example of tenant-level notification target to send notification to customer's users:\n" + + MARKDOWN_CODE_BLOCK_START + + "{\n" + + " \"name\": \"Users of Customer A\",\n" + + " \"configuration\": {\n" + + " \"type\": \"PLATFORM_USERS\",\n" + + " \"usersFilter\": {\n" + + " \"type\": \"CUSTOMER_USERS\",\n" + + " \"customerId\": \"32499a20-d785-11ed-a06c-21dd57dd88ca\"\n" + + " },\n" + + " \"description\": \"Users of Customer A\"\n" + + " }\n" + + "}" + + MARKDOWN_CODE_BLOCK_END + SYSTEM_OR_TENANT_AUTHORITY_PARAGRAPH) @PostMapping("/target") @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')") @@ -89,7 +119,7 @@ public class NotificationTargetController extends BaseController { } @ApiOperation(value = "Get notification target by id (getNotificationTargetById)", - notes = "Fetch saved notification target by id." + + notes = "Fetches notification target by id." + SYSTEM_OR_TENANT_AUTHORITY_PARAGRAPH) @GetMapping("/target/{id}") @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')") @@ -99,12 +129,14 @@ public class NotificationTargetController extends BaseController { } @ApiOperation(value = "Get recipients for notification target config (getRecipientsForNotificationTargetConfig)", - notes = "Get the list (page) of recipients (users) for such notification target configuration." + + notes = "Returns the page of recipients for such notification target configuration." + SYSTEM_OR_TENANT_AUTHORITY_PARAGRAPH) @PostMapping("/target/recipients") @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')") public PageData getRecipientsForNotificationTargetConfig(@RequestBody NotificationTarget notificationTarget, + @ApiParam(value = PAGE_SIZE_DESCRIPTION, required = true) @RequestParam int pageSize, + @ApiParam(value = PAGE_NUMBER_DESCRIPTION, required = true) @RequestParam int page, @AuthenticationPrincipal SecurityUser user) throws ThingsboardException { // generic permission @@ -119,9 +151,13 @@ public class NotificationTargetController extends BaseController { return notificationTargetService.findRecipientsForNotificationTargetConfig(user.getTenantId(), (PlatformUsersNotificationTargetConfig) notificationTarget.getConfiguration(), pageLink); } + @ApiOperation(value = "Get notification targets by ids (getNotificationTargetsByIds)", + notes = "Returns the list of notification targets found by provided ids." + + SYSTEM_OR_TENANT_AUTHORITY_PARAGRAPH) @GetMapping(value = "/targets", params = {"ids"}) @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')") - public List getNotificationTargetsByIds(@RequestParam("ids") UUID[] ids, + public List getNotificationTargetsByIds(@ApiParam(value = "Comma-separated list of uuids representing targets ids", required = true) + @RequestParam("ids") UUID[] ids, @AuthenticationPrincipal SecurityUser user) { // generic permission List targetsIds = Arrays.stream(ids).map(NotificationTargetId::new).collect(Collectors.toList()); @@ -129,14 +165,20 @@ public class NotificationTargetController extends BaseController { } @ApiOperation(value = "Get notification targets (getNotificationTargets)", - notes = "Fetch the page of notification targets owned by sysadmin or tenant." + + notes = "Returns the page of notification targets owned by sysadmin or tenant." + NEW_LINE + + PAGE_DATA_PARAMETERS + SYSTEM_OR_TENANT_AUTHORITY_PARAGRAPH) @GetMapping("/targets") @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')") - public PageData getNotificationTargets(@RequestParam int pageSize, + public PageData getNotificationTargets(@ApiParam(value = PAGE_SIZE_DESCRIPTION, required = true) + @RequestParam int pageSize, + @ApiParam(value = PAGE_NUMBER_DESCRIPTION, required = true) @RequestParam int page, + @ApiParam(value = "Case-insensitive 'substring' filed based on the target's name") @RequestParam(required = false) String textSearch, + @ApiParam(value = SORT_PROPERTY_DESCRIPTION) @RequestParam(required = false) String sortProperty, + @ApiParam(value = SORT_ORDER_DESCRIPTION) @RequestParam(required = false) String sortOrder, @AuthenticationPrincipal SecurityUser user) throws ThingsboardException { // generic permission @@ -144,6 +186,10 @@ public class NotificationTargetController extends BaseController { return notificationTargetService.findNotificationTargetsByTenantId(user.getTenantId(), pageLink); } + @ApiOperation(value = "Get notification targets by supported notification type (getNotificationTargetsBySupportedNotificationType)", + notes = "Returns the page of notification targets filtered by notification type that they can be used for." + NEW_LINE + + PAGE_DATA_PARAMETERS + + SYSTEM_OR_TENANT_AUTHORITY_PARAGRAPH) @GetMapping(value = "/targets", params = "notificationType") @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')") public PageData getNotificationTargetsBySupportedNotificationType(@RequestParam int pageSize, @@ -158,7 +204,7 @@ public class NotificationTargetController extends BaseController { } @ApiOperation(value = "Delete notification target by id (deleteNotificationTargetById)", - notes = "Delete notification target by its id.\n\n" + + notes = "Deletes notification target by its id." + NEW_LINE + "This target cannot be referenced by existing scheduled notification requests or any notification rules." + SYSTEM_OR_TENANT_AUTHORITY_PARAGRAPH) @DeleteMapping("/target/{id}") diff --git a/application/src/main/java/org/thingsboard/server/controller/NotificationTemplateController.java b/application/src/main/java/org/thingsboard/server/controller/NotificationTemplateController.java index 751b139bd3..ab171efacf 100644 --- a/application/src/main/java/org/thingsboard/server/controller/NotificationTemplateController.java +++ b/application/src/main/java/org/thingsboard/server/controller/NotificationTemplateController.java @@ -16,6 +16,7 @@ package org.thingsboard.server.controller; import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiParam; import lombok.RequiredArgsConstructor; import org.apache.commons.lang3.StringUtils; import org.springframework.security.access.prepost.PreAuthorize; @@ -36,9 +37,9 @@ import org.thingsboard.server.common.data.notification.NotificationDeliveryMetho import org.thingsboard.server.common.data.notification.NotificationType; import org.thingsboard.server.common.data.notification.settings.NotificationSettings; import org.thingsboard.server.common.data.notification.settings.SlackNotificationDeliveryMethodConfig; +import org.thingsboard.server.common.data.notification.targets.slack.SlackConversation; import org.thingsboard.server.common.data.notification.targets.slack.SlackConversationType; import org.thingsboard.server.common.data.notification.template.NotificationTemplate; -import org.thingsboard.server.common.data.notification.targets.slack.SlackConversation; import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageLink; import org.thingsboard.server.dao.notification.NotificationSettingsService; @@ -51,6 +52,14 @@ import javax.validation.Valid; import java.util.List; import java.util.UUID; +import static org.thingsboard.server.controller.ControllerConstants.MARKDOWN_CODE_BLOCK_END; +import static org.thingsboard.server.controller.ControllerConstants.MARKDOWN_CODE_BLOCK_START; +import static org.thingsboard.server.controller.ControllerConstants.NEW_LINE; +import static org.thingsboard.server.controller.ControllerConstants.PAGE_DATA_PARAMETERS; +import static org.thingsboard.server.controller.ControllerConstants.PAGE_NUMBER_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.PAGE_SIZE_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.SORT_ORDER_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.SORT_PROPERTY_DESCRIPTION; import static org.thingsboard.server.controller.ControllerConstants.SYSTEM_OR_TENANT_AUTHORITY_PARAGRAPH; import static org.thingsboard.server.service.security.permission.Resource.NOTIFICATION; @@ -65,19 +74,44 @@ public class NotificationTemplateController extends BaseController { private final SlackService slackService; @ApiOperation(value = "Save notification template (saveNotificationTemplate)", - notes = "Create or update notification template.\n\n" + - "Example:\n" + - "```\n{\n \"name\": \"Hello to all my users\",\n" + - " \"notificationType\": \"Message from administrator\",\n" + + notes = "Creates or updates notification template." + NEW_LINE + + "Here is an example of template to send notification via Web, SMS and Slack:\n" + + MARKDOWN_CODE_BLOCK_START + + "{\n" + + " \"name\": \"Greetings\",\n" + + " \"notificationType\": \"GENERAL\",\n" + " \"configuration\": {\n" + - " \"defaultTextTemplate\": \"Hello everyone\", # required if any of the templates' bodies is not set\n" + - " \"templates\": {\n" + - " \"PUSH\": {\n \"method\": \"PUSH\",\n \"body\": null # defaultTextTemplate will be used if body is not set\n },\n" + - " \"SMS\": {\n \"method\": \"SMS\",\n \"body\": null\n },\n" + - " \"EMAIL\": {\n \"method\": \"EMAIL\",\n \"body\": \"Non-default value for email notification: Hello everyone\",\n \"subject\": \"Message from administrator\"\n },\n" + - " \"SLACK\": {\n \"method\": \"SLACK\",\n \"body\": null,\n \"conversationType\": \"PUBLIC_CHANNEL\",\n \"conversationId\": \"U02LD7BJOU2\" # received from listSlackConversations API method\n }\n" + + " \"deliveryMethodsTemplates\": {\n" + + " \"WEB\": {\n" + + " \"enabled\": true,\n" + + " \"subject\": \"Greetings\",\n" + + " \"body\": \"Hi there, ${recipientTitle}\",\n" + + " \"additionalConfig\": {\n" + + " \"icon\": {\n" + + " \"enabled\": true,\n" + + " \"icon\": \"back_hand\",\n" + + " \"color\": \"#757575\"\n" + + " },\n" + + " \"actionButtonConfig\": {\n" + + " \"enabled\": false\n" + + " }\n" + + " },\n" + + " \"method\": \"WEB\"\n" + + " },\n" + + " \"SMS\": {\n" + + " \"enabled\": true,\n" + + " \"body\": \"Hi there, ${recipientTitle}\",\n" + + " \"method\": \"SMS\"\n" + + " },\n" + + " \"SLACK\": {\n" + + " \"enabled\": true,\n" + + " \"body\": \"Hi there, @${recipientTitle}\",\n" + + " \"method\": \"SLACK\"\n" + + " }\n" + " }\n" + - " }\n}\n```" + + " }\n" + + "}" + + MARKDOWN_CODE_BLOCK_END + SYSTEM_OR_TENANT_AUTHORITY_PARAGRAPH) @PostMapping("/template") @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')") @@ -88,7 +122,7 @@ public class NotificationTemplateController extends BaseController { } @ApiOperation(value = "Get notification template by id (getNotificationTemplateById)", - notes = "Fetch notification template by id." + + notes = "Fetches notification template by id." + SYSTEM_OR_TENANT_AUTHORITY_PARAGRAPH) @GetMapping("/template/{id}") @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')") @@ -98,15 +132,22 @@ public class NotificationTemplateController extends BaseController { } @ApiOperation(value = "Get notification templates (getNotificationTemplates)", - notes = "Fetch the page of notification templates owned by sysadmin or tenant." + + notes = "Returns the page of notification templates owned by sysadmin or tenant." + NEW_LINE + + PAGE_DATA_PARAMETERS + SYSTEM_OR_TENANT_AUTHORITY_PARAGRAPH) @GetMapping("/templates") @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')") - public PageData getNotificationTemplates(@RequestParam int pageSize, + public PageData getNotificationTemplates(@ApiParam(value = PAGE_SIZE_DESCRIPTION, required = true) + @RequestParam int pageSize, + @ApiParam(value = PAGE_NUMBER_DESCRIPTION, required = true) @RequestParam int page, + @ApiParam(value = "Case-insensitive 'substring' filter based on template's name and notification type") @RequestParam(required = false) String textSearch, + @ApiParam(value = SORT_PROPERTY_DESCRIPTION) @RequestParam(required = false) String sortProperty, + @ApiParam(value = SORT_ORDER_DESCRIPTION) @RequestParam(required = false) String sortOrder, + @ApiParam(value = "Comma-separated list of notification types to filter the templates") @RequestParam(required = false) NotificationType[] notificationTypes, @AuthenticationPrincipal SecurityUser user) throws ThingsboardException { // generic permission @@ -119,7 +160,7 @@ public class NotificationTemplateController extends BaseController { } @ApiOperation(value = "Delete notification template by id (deleteNotificationTemplateById", - notes = "Delete notification template by its id.\n\n" + + notes = "Deletes notification template by its id." + NEW_LINE + "This template cannot be referenced by existing scheduled notification requests or any notification rules." + SYSTEM_OR_TENANT_AUTHORITY_PARAGRAPH) @DeleteMapping("/template/{id}") @@ -131,12 +172,12 @@ public class NotificationTemplateController extends BaseController { } @ApiOperation(value = "List Slack conversations (listSlackConversations)", - notes = "List available Slack conversations by type to use in notification template.\n\n" + - "Slack must be configured in notification settings." + + notes = "List available Slack conversations by type." + SYSTEM_OR_TENANT_AUTHORITY_PARAGRAPH) @GetMapping("/slack/conversations") @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')") public List listSlackConversations(@RequestParam SlackConversationType type, + @ApiParam(value = "Slack bot token. If absent - system Slack settings will be used") @RequestParam(required = false) String token, @AuthenticationPrincipal SecurityUser user) { // generic permission 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 91bc0863db..a8e3caad1f 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 @@ -39,7 +39,6 @@ import org.thingsboard.server.common.data.notification.NotificationRequestConfig import org.thingsboard.server.common.data.notification.NotificationRequestStats; import org.thingsboard.server.common.data.notification.NotificationRequestStatus; import org.thingsboard.server.common.data.notification.NotificationStatus; -import org.thingsboard.server.common.data.notification.NotificationType; import org.thingsboard.server.common.data.notification.info.RuleOriginatedNotificationInfo; import org.thingsboard.server.common.data.notification.settings.NotificationSettings; import org.thingsboard.server.common.data.notification.targets.NotificationRecipient; @@ -294,24 +293,6 @@ public class DefaultNotificationCenter extends AbstractSubscriptionService imple return onNotificationUpdate(recipient.getTenantId(), recipient.getId(), update); } - @Override - public void sendBasicNotification(TenantId tenantId, UserId recipientId, String subject, String text) { - Notification notification = Notification.builder() - .recipientId(recipientId) - .type(NotificationType.GENERAL) - .subject(subject) - .text(text) - .status(NotificationStatus.SENT) - .build(); - notification = notificationService.saveNotification(TenantId.SYS_TENANT_ID, notification); - - NotificationUpdate update = NotificationUpdate.builder() - .created(true) - .notification(notification) - .build(); - onNotificationUpdate(tenantId, recipientId, update); - } - @Override public void markNotificationAsRead(TenantId tenantId, UserId recipientId, NotificationId notificationId) { boolean updated = notificationService.markNotificationAsRead(tenantId, recipientId, notificationId); diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/notification/NotificationRequest.java b/common/data/src/main/java/org/thingsboard/server/common/data/notification/NotificationRequest.java index bd37d1315c..9b52b9dce6 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/notification/NotificationRequest.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/notification/NotificationRequest.java @@ -55,7 +55,6 @@ public class NotificationRequest extends BaseData impleme private NotificationTemplate template; @Valid private NotificationInfo info; - @NotNull @Valid private NotificationRequestConfig additionalConfig; 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 0489ac344b..34e42e768c 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 @@ -20,12 +20,12 @@ import lombok.Getter; @Getter public enum NotificationRuleTriggerType { + ENTITY_ACTION, ALARM, ALARM_COMMENT, - DEVICE_ACTIVITY, - ENTITY_ACTION, - RULE_ENGINE_COMPONENT_LIFECYCLE_EVENT, ALARM_ASSIGNMENT, + DEVICE_ACTIVITY, + RULE_ENGINE_COMPONENT_LIFECYCLE_EVENT, NEW_PLATFORM_VERSION(false), ENTITIES_LIMIT(false), API_USAGE_LIMIT(false); 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 75fdfbbac7..a91b809270 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 @@ -32,8 +32,6 @@ public interface NotificationCenter { void deleteNotificationRequest(TenantId tenantId, NotificationRequestId notificationRequestId); - void sendBasicNotification(TenantId tenantId, UserId recipientId, String subject, String text); - void markNotificationAsRead(TenantId tenantId, UserId recipientId, NotificationId notificationId); void markAllNotificationsAsRead(TenantId tenantId, UserId recipientId); From e8179271d23576028f1281de885b671d7bf73d2a Mon Sep 17 00:00:00 2001 From: ViacheslavKlimov Date: Thu, 27 Apr 2023 14:08:59 +0300 Subject: [PATCH 2/2] Change default entity action notification; fix default rules names --- .../notification/DefaultNotificationSettingsService.java | 2 +- .../server/dao/notification/DefaultNotifications.java | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/dao/src/main/java/org/thingsboard/server/dao/notification/DefaultNotificationSettingsService.java b/dao/src/main/java/org/thingsboard/server/dao/notification/DefaultNotificationSettingsService.java index 534e3136ca..4ca140e274 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/notification/DefaultNotificationSettingsService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/notification/DefaultNotificationSettingsService.java @@ -109,7 +109,7 @@ public class DefaultNotificationSettingsService implements NotificationSettingsS defaultNotifications.create(tenantId, DefaultNotifications.newAlarm, tenantAdmins.getId()); defaultNotifications.create(tenantId, DefaultNotifications.alarmUpdate, tenantAdmins.getId()); - defaultNotifications.create(tenantId, DefaultNotifications.deviceAction, tenantAdmins.getId()); + defaultNotifications.create(tenantId, DefaultNotifications.entityAction, tenantAdmins.getId()); defaultNotifications.create(tenantId, DefaultNotifications.deviceActivity, tenantAdmins.getId()); defaultNotifications.create(tenantId, DefaultNotifications.alarmComment, tenantAdmins.getId()); defaultNotifications.create(tenantId, DefaultNotifications.alarmAssignment, affectedUser.getId()); diff --git a/dao/src/main/java/org/thingsboard/server/dao/notification/DefaultNotifications.java b/dao/src/main/java/org/thingsboard/server/dao/notification/DefaultNotifications.java index b9ab9a322e..e5ab043f2d 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/notification/DefaultNotifications.java +++ b/dao/src/main/java/org/thingsboard/server/dao/notification/DefaultNotifications.java @@ -179,13 +179,13 @@ public class DefaultNotifications { .description("Send notification to tenant admins when any alarm is updated or cleared") .build()) .build(); - public static final DefaultNotification deviceAction = DefaultNotification.builder() - .name("Device action notification") + public static final DefaultNotification entityAction = DefaultNotification.builder() + .name("Entity action notification") .type(NotificationType.ENTITY_ACTION) .subject("${entityType} was ${actionType}") .text("${entityType} '${entityName}' was ${actionType} by user ${userEmail}") .icon("info").color(null) - .button("Go to device").link("/devices/${entityId}") + .button("Go to ${entityType:lowerCase}").link("/${entityType:lowerCase}s/${entityId}") .rule(DefaultRule.builder() .name("Device created") .triggerConfig(EntityActionNotificationRuleTriggerConfig.builder() @@ -341,7 +341,7 @@ public class DefaultNotifications { public NotificationRule toRule(NotificationTemplateId templateId, NotificationTargetId... targets) { DefaultRule defaultRule = this.rule; NotificationRule rule = new NotificationRule(); - rule.setName(name); + rule.setName(defaultRule.getName()); rule.setTemplateId(templateId); rule.setTriggerType(defaultRule.getTriggerConfig().getTriggerType()); rule.setTriggerConfig(defaultRule.getTriggerConfig());