@ -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 < Notification > getNotifications ( @RequestParam int pageSize ,
public PageData < Notification > 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 < NotificationRequestInfo > getNotificationRequests ( @RequestParam int pageSize ,
public PageData < NotificationRequestInfo > 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 < NotificationDeliveryMethod > getAvailableDeliveryMethods ( @AuthenticationPrincipal SecurityUser user ) throws ThingsboardException {