Browse Source

Notification system improvements and refactoring

pull/7511/head
ViacheslavKlimov 4 years ago
parent
commit
f5247386fa
  1. 104
      application/src/main/java/org/thingsboard/server/controller/NotificationController.java
  2. 67
      application/src/main/java/org/thingsboard/server/controller/NotificationTargetController.java
  3. 72
      application/src/main/java/org/thingsboard/server/service/notification/DefaultNotificationProcessingService.java
  4. 3
      application/src/main/java/org/thingsboard/server/service/notification/NotificationProcessingService.java
  5. 2
      application/src/main/resources/thingsboard.yml
  6. 5
      common/dao-api/src/main/java/org/thingsboard/server/dao/notification/NotificationService.java
  7. 2
      common/dao-api/src/main/java/org/thingsboard/server/dao/notification/NotificationTargetService.java
  8. 7
      common/data/src/main/java/org/thingsboard/server/common/data/notification/Notification.java
  9. 37
      common/data/src/main/java/org/thingsboard/server/common/data/notification/NotificationInfo.java
  10. 46
      common/data/src/main/java/org/thingsboard/server/common/data/notification/NotificationRequest.java
  11. 23
      common/data/src/main/java/org/thingsboard/server/common/data/notification/NotificationRequestConfig.java
  12. 1
      common/data/src/main/java/org/thingsboard/server/common/data/notification/NotificationStatus.java
  13. 9
      common/data/src/main/java/org/thingsboard/server/common/data/notification/targets/NotificationTarget.java
  14. 3
      common/data/src/main/java/org/thingsboard/server/common/data/notification/targets/NotificationTargetConfig.java
  15. 8
      common/data/src/main/java/org/thingsboard/server/common/data/notification/targets/NotificationTargetConfigType.java
  16. 33
      common/data/src/main/java/org/thingsboard/server/common/data/notification/targets/UserListNotificationTargetConfig.java
  17. 15
      dao/src/main/java/org/thingsboard/server/dao/model/ModelConstants.java
  18. 54
      dao/src/main/java/org/thingsboard/server/dao/model/sql/NotificationEntity.java
  19. 81
      dao/src/main/java/org/thingsboard/server/dao/model/sql/NotificationRequestEntity.java
  20. 1
      dao/src/main/java/org/thingsboard/server/dao/model/sql/NotificationTargetEntity.java
  21. 46
      dao/src/main/java/org/thingsboard/server/dao/notification/DefaultNotificationService.java
  22. 15
      dao/src/main/java/org/thingsboard/server/dao/notification/DefaultNotificationTargetService.java
  23. 13
      dao/src/main/java/org/thingsboard/server/dao/notification/NotificationDao.java
  24. 6
      dao/src/main/java/org/thingsboard/server/dao/notification/NotificationRequestDao.java
  25. 6
      dao/src/main/java/org/thingsboard/server/dao/notification/NotificationTargetDao.java
  26. 44
      dao/src/main/java/org/thingsboard/server/dao/sql/notification/JpaNotificationDao.java
  27. 11
      dao/src/main/java/org/thingsboard/server/dao/sql/notification/JpaNotificationRequestDao.java
  28. 11
      dao/src/main/java/org/thingsboard/server/dao/sql/notification/JpaNotificationTargetDao.java
  29. 17
      dao/src/main/java/org/thingsboard/server/dao/sql/notification/NotificationRepository.java
  30. 11
      dao/src/main/java/org/thingsboard/server/dao/sql/notification/NotificationRequestRepository.java
  31. 7
      dao/src/main/java/org/thingsboard/server/dao/sql/notification/NotificationTargetRepository.java

104
application/src/main/java/org/thingsboard/server/controller/NotificationController.java

@ -0,0 +1,104 @@
/**
* Copyright © 2016-2022 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.controller;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.thingsboard.server.common.data.exception.ThingsboardException;
import org.thingsboard.server.common.data.id.NotificationId;
import org.thingsboard.server.common.data.notification.Notification;
import org.thingsboard.server.common.data.notification.NotificationRequest;
import org.thingsboard.server.common.data.notification.NotificationStatus;
import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.PageLink;
import org.thingsboard.server.dao.notification.NotificationService;
import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.notification.NotificationProcessingService;
import org.thingsboard.server.service.security.model.SecurityUser;
import org.thingsboard.server.service.security.permission.Operation;
import org.thingsboard.server.service.security.permission.Resource;
import java.util.UUID;
@RestController
@TbCoreComponent
@RequestMapping("/api")
@RequiredArgsConstructor
@Slf4j
public class NotificationController extends BaseController {
private final NotificationService notificationService;
private final NotificationProcessingService notificationProcessingService;
@GetMapping("/notifications")
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')")
public PageData<Notification> getNotifications(@RequestParam int pageSize,
@RequestParam int page,
@RequestParam(required = false) String textSearch,
@RequestParam(required = false) String sortProperty,
@RequestParam(required = false) String sortOrder,
@RequestParam(defaultValue = "false") boolean unreadOnly,
@AuthenticationPrincipal SecurityUser user) throws ThingsboardException {
PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder);
return notificationService.findNotificationsByUserIdAndReadStatusAndPageLink(user.getTenantId(), user.getId(), unreadOnly, pageLink);
}
@PutMapping("/notification/{id}/read") // or maybe to NotificationUpdateRequest for the future
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')")
public void markNotificationAsRead(@PathVariable UUID id,
@AuthenticationPrincipal SecurityUser user) {
NotificationId notificationId = new NotificationId(id);
notificationService.updateNotificationStatus(user.getTenantId(), notificationId, NotificationStatus.READ);
}
@PostMapping("/notification/request")
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')")
public NotificationRequest createNotificationRequest(@RequestBody NotificationRequest notificationRequest,
@AuthenticationPrincipal SecurityUser user) throws ThingsboardException {
accessControlService.checkPermission(user, Resource.NOTIFICATION, Operation.CREATE);
return notificationProcessingService.processNotificationRequest(user, notificationRequest);
}
@GetMapping("/notification/requests")
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')")
public PageData<NotificationRequest> getNotificationRequests(@RequestParam int pageSize,
@RequestParam int page,
@RequestParam(required = false) String textSearch,
@RequestParam(required = false) String sortProperty,
@RequestParam(required = false) String sortOrder,
@AuthenticationPrincipal SecurityUser user) throws ThingsboardException {
accessControlService.checkPermission(user, Resource.NOTIFICATION, Operation.CREATE);
PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder);
return notificationService.findNotificationRequestsByTenantIdAndPageLink(user.getTenantId(), pageLink);
}
// delete request and sent notifications
public void deleteNotificationRequest() {
}
}

67
application/src/main/java/org/thingsboard/server/controller/NotificationTargetController.java

@ -19,16 +19,32 @@ import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.thingsboard.server.common.data.User;
import org.thingsboard.server.common.data.exception.ThingsboardException;
import org.thingsboard.server.common.data.id.NotificationTargetId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.id.UserId;
import org.thingsboard.server.common.data.notification.targets.NotificationTarget;
import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.PageLink;
import org.thingsboard.server.dao.notification.NotificationTargetService;
import org.thingsboard.server.dao.user.UserService;
import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.security.model.SecurityUser;
import org.thingsboard.server.service.security.permission.Operation;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import java.util.stream.Collectors;
@RestController
@TbCoreComponent
@ -36,21 +52,58 @@ import org.thingsboard.server.service.security.model.SecurityUser;
@RequiredArgsConstructor
@Slf4j
public class NotificationTargetController extends BaseController {
// fixme: permission check, log action, events
private final NotificationTargetService notificationTargetService;
private final UserService userService;
@PostMapping("/target")
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')")
public NotificationTarget saveNotificationTarget(NotificationTarget notificationTarget) throws Exception {
SecurityUser user = getCurrentUser();
// fixme: permission check, log action
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')")
public NotificationTarget saveNotificationTarget(@RequestBody NotificationTarget notificationTarget,
@AuthenticationPrincipal SecurityUser user) {
return notificationTargetService.saveNotificationTarget(user.getTenantId(), notificationTarget);
}
@GetMapping("/target/{id}")
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')")
public NotificationTarget getNotificationTargetById(@PathVariable UUID id,
@AuthenticationPrincipal SecurityUser user) {
NotificationTargetId notificationTargetId = new NotificationTargetId(id);
return notificationTargetService.findNotificationTargetById(user.getTenantId(), notificationTargetId);
}
@GetMapping("/target/{id}/recipients")
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')")
public List<User> getRecipientsForNotificationTarget(@PathVariable UUID id,
@AuthenticationPrincipal SecurityUser user) throws ThingsboardException {
NotificationTargetId notificationTargetId = new NotificationTargetId(id);
// fixme: to page data
// todo: check read permission for recipients
List<User> recipients = new ArrayList<>();
for (UserId userId : notificationTargetService.findRecipientsForNotificationTarget(user.getTenantId(), notificationTargetId)) {
recipients.add(checkUserId(userId, Operation.READ));
}
return recipients;
}
@GetMapping("/targets")
public PageData<NotificationTarget> getNotificationTargets(@AuthenticationPrincipal SecurityUser user) throws ThingsboardException {
// notificationTargetService.findNotificationTargetsByTenantIdAndPageLink()
return null;
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')")
public PageData<NotificationTarget> getNotificationTargets(@RequestParam int pageSize,
@RequestParam int page,
@RequestParam(required = false) String textSearch,
@RequestParam(required = false) String sortProperty,
@RequestParam(required = false) String sortOrder,
@AuthenticationPrincipal SecurityUser user) throws ThingsboardException {
PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder);
return notificationTargetService.findNotificationTargetsByTenantIdAndPageLink(user.getTenantId(), pageLink);
}
@DeleteMapping("/target/{id}")
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')")
public void deleteNotificationTarget(@PathVariable UUID id,
@AuthenticationPrincipal SecurityUser user) {
NotificationTargetId notificationTargetId = new NotificationTargetId(id);
notificationTargetService.deleteNotificationTarget(user.getTenantId(), notificationTargetId);
}
}

72
application/src/main/java/org/thingsboard/server/service/notification/DefaultNotificationProcessingService.java

@ -17,11 +17,15 @@ package org.thingsboard.server.service.notification;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.thingsboard.rule.engine.api.util.TbNodeUtils;
import org.thingsboard.server.cluster.TbClusterService;
import org.thingsboard.server.common.data.User;
import org.thingsboard.server.common.data.exception.ThingsboardException;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.id.UserId;
import org.thingsboard.server.common.data.notification.Notification;
import org.thingsboard.server.common.data.notification.NotificationRequest;
import org.thingsboard.server.common.data.notification.NotificationStatus;
import org.thingsboard.server.dao.notification.NotificationService;
import org.thingsboard.server.dao.notification.NotificationTargetService;
import org.thingsboard.server.dao.user.UserService;
@ -29,9 +33,13 @@ import org.thingsboard.server.queue.discovery.PartitionService;
import org.thingsboard.server.service.executors.DbCallbackExecutorService;
import org.thingsboard.server.service.security.model.SecurityUser;
import org.thingsboard.server.service.security.permission.AccessControlService;
import org.thingsboard.server.service.security.permission.Operation;
import org.thingsboard.server.service.security.permission.Resource;
import org.thingsboard.server.service.telemetry.AbstractSubscriptionService;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
@Service
@Slf4j
@ -57,37 +65,57 @@ public class DefaultNotificationProcessingService extends AbstractSubscriptionSe
}
@Override
public void processNotificationRequest(SecurityUser user, NotificationRequest notificationRequest) {
public NotificationRequest processNotificationRequest(SecurityUser user, NotificationRequest notificationRequest) throws ThingsboardException {
TenantId tenantId = user.getTenantId();
notificationRequest = notificationService.createNotificationRequest(tenantId, notificationRequest);
List<UserId> recipients = notificationTargetService.findRecipientsForNotificationTarget(tenantId, notificationRequest.getTargetId());
for (UserId recipientId : recipients) {
try {
// todo: check read permission for recipientId
Notification notification = Notification.builder()
.tenantId(tenantId)
.requestId(notificationRequest.getId())
.status(null)
.recipientId(recipientId)
.text(formatNotificationText(notificationRequest.getTextTemplate(), null))
.severity(notificationRequest.getSeverity())
.senderId(notificationRequest.getSenderId())
.build();
notification = notificationService.createNotification(tenantId, notification);
List<UserId> recipientsIds = notificationTargetService.findRecipientsForNotificationTarget(tenantId, notificationRequest.getTargetId());
List<User> recipients = new ArrayList<>();
for (UserId recipientId : recipientsIds) {
User recipient = userService.findUserById(tenantId, recipientId); // todo: add caching
accessControlService.checkPermission(user, Resource.USER, Operation.READ, recipientId, recipient);
recipients.add(recipient);
}
notificationRequest.setTenantId(tenantId);
notificationRequest.setSenderId(user.getId());
NotificationRequest savedNotificationRequest = notificationService.createNotificationRequest(tenantId, notificationRequest);
// todo: delayed sending; check all delayed notification requests on start up, schedule send
for (User recipient : recipients) {
dbCallbackExecutorService.submit(() -> {
Notification notification = createNotification(recipient, notificationRequest);
onNewNotification(notification);
} catch (Exception e) {
// fixme: handle
}
});
}
return savedNotificationRequest;
}
private Notification createNotification(User recipient, NotificationRequest notificationRequest) {
Notification notification = Notification.builder()
.requestId(notificationRequest.getId())
.recipientId(recipient.getId())
.text(formatNotificationText(notificationRequest.getTextTemplate(), recipient))
.severity(notificationRequest.getNotificationSeverity())
.status(NotificationStatus.SENT)
.build();
notification = notificationService.createNotification(recipient.getTenantId(), notification);
return notification;
}
private void onNewNotification(Notification notification) {
wsCallBackExecutor.submit(() -> {
})
}
private String formatNotificationText(String template, Object context) {
return template;
private String formatNotificationText(String template, User recipient) {
Map<String, String> context = Map.of(
"recipientEmail", recipient.getEmail(),
"recipientFirstName", recipient.getFirstName(),
"recipientLastName", recipient.getLastName()
);
return TbNodeUtils.processTemplate(template, context);
}
@Override

3
application/src/main/java/org/thingsboard/server/service/notification/NotificationProcessingService.java

@ -15,11 +15,12 @@
*/
package org.thingsboard.server.service.notification;
import org.thingsboard.server.common.data.exception.ThingsboardException;
import org.thingsboard.server.common.data.notification.NotificationRequest;
import org.thingsboard.server.service.security.model.SecurityUser;
public interface NotificationProcessingService {
void processNotificationRequest(SecurityUser user, NotificationRequest notificationRequest);
NotificationRequest processNotificationRequest(SecurityUser user, NotificationRequest notificationRequest) throws ThingsboardException;
}

2
application/src/main/resources/thingsboard.yml

@ -267,6 +267,8 @@ sql:
stats_print_interval_ms: "${SQL_EDGE_EVENTS_BATCH_STATS_PRINT_MS:10000}"
audit_logs:
partition_size: "${SQL_AUDIT_LOGS_PARTITION_SIZE_HOURS:168}" # Default value - 1 week
notifications:
partition_size: "${SQL_NOTIFICATIONS_PARTITION_SIZE_HOURS:168}"
# Specify whether to sort entities before batch update. Should be enabled for cluster mode to avoid deadlocks
batch_sort: "${SQL_BATCH_SORT:false}"
# Specify whether to remove null characters from strValue of attributes and timeseries before insert

5
common/dao-api/src/main/java/org/thingsboard/server/dao/notification/NotificationService.java

@ -30,10 +30,13 @@ public interface NotificationService {
PageData<NotificationRequest> findNotificationRequestsByTenantIdAndPageLink(TenantId tenantId, PageLink pageLink);
Notification createNotification(TenantId tenantId, Notification notification);
void updateNotificationStatus(TenantId tenantId, NotificationId notificationId, NotificationStatus status);
PageData<Notification> findNotificationsByUserIdAndPageLink(TenantId tenantId, UserId userId, PageLink pageLink);
PageData<Notification> findNotificationsByUserIdAndReadStatusAndPageLink(TenantId tenantId, UserId userId, boolean unreadOnly, PageLink pageLink);
PageData<Notification> findLatestUnreadNotificationsByUserId(TenantId tenantId, UserId userId, int limit);
}

2
common/dao-api/src/main/java/org/thingsboard/server/dao/notification/NotificationTargetService.java

@ -34,4 +34,6 @@ public interface NotificationTargetService {
List<UserId> findRecipientsForNotificationTarget(TenantId tenantId, NotificationTargetId notificationTargetId);
void deleteNotificationTarget(TenantId tenantId, NotificationTargetId notificationTargetId);
}

7
common/data/src/main/java/org/thingsboard/server/common/data/notification/Notification.java

@ -23,12 +23,8 @@ import lombok.NoArgsConstructor;
import org.thingsboard.server.common.data.SearchTextBased;
import org.thingsboard.server.common.data.id.NotificationId;
import org.thingsboard.server.common.data.id.NotificationRequestId;
import org.thingsboard.server.common.data.id.NotificationTargetId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.id.UserId;
import java.util.UUID;
@Data
@AllArgsConstructor
@NoArgsConstructor
@ -37,12 +33,11 @@ import java.util.UUID;
public class Notification extends SearchTextBased<NotificationId> {
private NotificationRequestId requestId;
private TenantId tenantId;
private UserId recipientId;
private String text;
private NotificationSeverity severity;
private NotificationStatus status;
private UserId senderId;
// private UserId senderId;
@Override
public String getSearchText() {

37
common/data/src/main/java/org/thingsboard/server/common/data/notification/NotificationInfo.java

@ -0,0 +1,37 @@
/**
* Copyright © 2016-2022 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;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.databind.node.ObjectNode;
import lombok.Data;
import org.thingsboard.server.common.data.id.DashboardId;
import org.thingsboard.server.common.data.validation.NoXss;
@Data
//@JsonIgnoreProperties(ignoreUnknown = true)
//@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "notificationType", visible = true, defaultImpl = NotificationInfo.class)
//@JsonSubTypes({
// @Type(name = "ALARM", value = DeviceExportData.class),
//})
public class NotificationInfo {
@NoXss
private String description;
private ObjectNode alarmDetails; // move to child class
private DashboardId dashboardId;
}

46
common/data/src/main/java/org/thingsboard/server/common/data/notification/NotificationRequest.java

@ -15,39 +15,45 @@
*/
package org.thingsboard.server.common.data.notification;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.thingsboard.server.common.data.SearchTextBased;
import org.thingsboard.server.common.data.id.NotificationId;
import lombok.NoArgsConstructor;
import org.thingsboard.server.common.data.BaseData;
import org.thingsboard.server.common.data.HasTenantId;
import org.thingsboard.server.common.data.id.NotificationRequestId;
import org.thingsboard.server.common.data.id.NotificationTargetId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.id.UserId;
import org.thingsboard.server.common.data.validation.NoXss;
import java.util.UUID;
import javax.validation.Valid;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
@Data
@EqualsAndHashCode(callSuper = true)
public class NotificationRequest extends SearchTextBased<NotificationRequestId> {
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class NotificationRequest extends BaseData<NotificationRequestId> implements HasTenantId {
private NotificationTargetId targetId;
private String textTemplate; // html with params?
private Object notificationType; // ALARM, ADMIN,
private Object notificationInfo; // for alarms: alarm details, link to dashboard etc.
private NotificationSeverity severity;
private TenantId tenantId;
@NotNull(message = "Target is not specified")
private NotificationTargetId targetId;
@NoXss
private String notificationReason; // "Alarm", "Scheduled event". "General" by default
// @NoXss
@NotBlank(message = "Notification text template is missing")
private String textTemplate;
@Valid
private NotificationInfo notificationInfo;
private NotificationSeverity notificationSeverity;
private NotificationRequestConfig additionalConfig;
private UserId senderId;
@Override
public String getSearchText() {
return textTemplate;
}
// todo: scheduling
public static final String GENERAL_NOTIFICATION_REASON = "General";
public static final String ALARM_NOTIFICATION_REASON = "Alarm";
}
/*
* NotificationService - manages NotificationRequest and Notification entities
* NotificationTargetService - manages NotificationTarget
* */

23
common/data/src/main/java/org/thingsboard/server/common/data/notification/NotificationRequestConfig.java

@ -0,0 +1,23 @@
/**
* Copyright © 2016-2022 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;
import lombok.Data;
@Data
public class NotificationRequestConfig {
private Long sendingDelayMs;
}

1
common/data/src/main/java/org/thingsboard/server/common/data/notification/NotificationStatus.java

@ -16,6 +16,7 @@
package org.thingsboard.server.common.data.notification;
public enum NotificationStatus {
SENT,
DELIVERED,
READ
}

9
common/data/src/main/java/org/thingsboard/server/common/data/notification/targets/NotificationTarget.java

@ -17,23 +17,18 @@ package org.thingsboard.server.common.data.notification.targets;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.thingsboard.server.common.data.BaseData;
import org.thingsboard.server.common.data.HasName;
import org.thingsboard.server.common.data.HasTenantId;
import org.thingsboard.server.common.data.SearchTextBased;
import org.thingsboard.server.common.data.id.NotificationTargetId;
import org.thingsboard.server.common.data.id.TenantId;
@Data
@EqualsAndHashCode(callSuper = true)
public class NotificationTarget extends SearchTextBased<NotificationTargetId> implements HasTenantId, HasName {
public class NotificationTarget extends BaseData<NotificationTargetId> implements HasTenantId, HasName {
private TenantId tenantId;
private String name;
private NotificationTargetConfig configuration;
@Override
public String getSearchText() {
return name;
}
}

3
common/data/src/main/java/org/thingsboard/server/common/data/notification/targets/NotificationTargetConfig.java

@ -23,7 +23,8 @@ import com.fasterxml.jackson.annotation.JsonTypeInfo;
@JsonIgnoreProperties(ignoreUnknown = true)
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type")
@JsonSubTypes({
@Type(value = SingleUserNotificationTargetConfig.class, name = "SINGLE_USER")
@Type(value = SingleUserNotificationTargetConfig.class, name = "SINGLE_USER"),
@Type(value = UserListNotificationTargetConfig.class, name = "USER_LIST")
})
public interface NotificationTargetConfig {

8
common/data/src/main/java/org/thingsboard/server/common/data/notification/targets/NotificationTargetConfigType.java

@ -17,7 +17,9 @@ package org.thingsboard.server.common.data.notification.targets;
public enum NotificationTargetConfigType {
SINGLE_USER,
USER_GROUP,
USERS_WITH_ROLE,
QUERY // ?
USER_LIST,
// USER_GROUP,
// USERS_WITH_ROLE,
// QUERY // ?
}

33
common/data/src/main/java/org/thingsboard/server/common/data/notification/targets/UserListNotificationTargetConfig.java

@ -0,0 +1,33 @@
/**
* Copyright © 2016-2022 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.targets;
import lombok.Data;
import org.thingsboard.server.common.data.id.UserId;
import java.util.List;
@Data
public class UserListNotificationTargetConfig implements NotificationTargetConfig {
private List<UserId> usersIds;
@Override
public NotificationTargetConfigType getType() {
return NotificationTargetConfigType.USER_LIST;
}
}

15
dao/src/main/java/org/thingsboard/server/dao/model/ModelConstants.java

@ -652,6 +652,21 @@ public class ModelConstants {
public static final String NOTIFICATION_TARGET_TABLE_NAME = "notification_target";
public static final String NOTIFICATION_TARGET_CONFIGURATION_PROPERTY = "configuration";
public static final String NOTIFICATION_TABLE_NAME = "notification";
public static final String NOTIFICATION_REQUEST_ID_PROPERTY = "request_id";
public static final String NOTIFICATION_RECIPIENT_ID_PROPERTY = "recipient_id";
public static final String NOTIFICATION_TEXT_PROPERTY = "text";
public static final String NOTIFICATION_SEVERITY_PROPERTY = "severity";
public static final String NOTIFICATION_STATUS_PROPERTY = "status";
public static final String NOTIFICATION_REQUEST_TABLE_NAME = "notification_request";
public static final String NOTIFICATION_REQUEST_TARGET_ID_PROPERTY = "target_id";
public static final String NOTIFICATION_REQUEST_TEXT_TEMPLATE_PROPERTY = "text_template";
public static final String NOTIFICATION_REQUEST_NOTIFICATION_REASON_PROPERTY = "notification_reason";
public static final String NOTIFICATION_REQUEST_NOTIFICATION_INFO_PROPERTY = "notification_info";
public static final String NOTIFICATION_REQUEST_NOTIFICATION_SEVERITY_PROPERTY = "notification_severity";
public static final String NOTIFICATION_REQUEST_ADDITIONAL_CONFIG_PROPERTY = "additional_config";
public static final String NOTIFICATION_REQUEST_SENDER_ID_PROPERTY = "sender_id";
protected static final String[] NONE_AGGREGATION_COLUMNS = new String[]{LONG_VALUE_COLUMN, DOUBLE_VALUE_COLUMN, BOOLEAN_VALUE_COLUMN, STRING_VALUE_COLUMN, JSON_VALUE_COLUMN, KEY_COLUMN, TS_COLUMN};

54
dao/src/main/java/org/thingsboard/server/dao/model/sql/NotificationEntity.java

@ -15,15 +15,67 @@
*/
package org.thingsboard.server.dao.model.sql;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.thingsboard.server.common.data.id.NotificationId;
import org.thingsboard.server.common.data.id.NotificationRequestId;
import org.thingsboard.server.common.data.id.UserId;
import org.thingsboard.server.common.data.notification.Notification;
import org.thingsboard.server.common.data.notification.NotificationSeverity;
import org.thingsboard.server.common.data.notification.NotificationStatus;
import org.thingsboard.server.dao.model.BaseSqlEntity;
import org.thingsboard.server.dao.model.ModelConstants;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.Table;
import java.util.UUID;
@Data
@EqualsAndHashCode(callSuper = true)
@Entity
@Table(name = ModelConstants.NOTIFICATION_TABLE_NAME)
public class NotificationEntity extends BaseSqlEntity<Notification> {
@Column(name = ModelConstants.NOTIFICATION_REQUEST_ID_PROPERTY)
private UUID requestId;
@Column(name = ModelConstants.NOTIFICATION_RECIPIENT_ID_PROPERTY)
private UUID recipientId;
@Column(name = ModelConstants.NOTIFICATION_TEXT_PROPERTY)
private String text;
@Column(name = ModelConstants.NOTIFICATION_SEVERITY_PROPERTY)
private NotificationSeverity severity;
@Enumerated(EnumType.STRING)
@Column(name = ModelConstants.NOTIFICATION_STATUS_PROPERTY)
private NotificationStatus status;
public NotificationEntity() {}
public NotificationEntity(Notification notification) {
setId(notification.getUuidId());
setCreatedTime(notification.getCreatedTime());
setRequestId(getUuid(notification.getRequestId()));
setRecipientId(getUuid(notification.getRecipientId()));
setText(notification.getText());
setStatus(notification.getStatus());
}
@Override
public Notification toData() {
return null;
Notification notification = new Notification();
notification.setId(new NotificationId(id));
notification.setCreatedTime(createdTime);
notification.setRequestId(createId(requestId, NotificationRequestId::new));
notification.setRecipientId(createId(recipientId, UserId::new));
notification.setText(text);
notification.setStatus(status);
return notification;
}
}

81
dao/src/main/java/org/thingsboard/server/dao/model/sql/NotificationRequestEntity.java

@ -15,15 +15,94 @@
*/
package org.thingsboard.server.dao.model.sql;
import com.fasterxml.jackson.databind.JsonNode;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.hibernate.annotations.Type;
import org.hibernate.annotations.TypeDef;
import org.thingsboard.common.util.JacksonUtil;
import org.thingsboard.server.common.data.id.NotificationRequestId;
import org.thingsboard.server.common.data.id.NotificationTargetId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.id.UserId;
import org.thingsboard.server.common.data.notification.NotificationInfo;
import org.thingsboard.server.common.data.notification.NotificationRequest;
import org.thingsboard.server.common.data.notification.NotificationRequestConfig;
import org.thingsboard.server.common.data.notification.NotificationSeverity;
import org.thingsboard.server.dao.model.BaseSqlEntity;
import org.thingsboard.server.dao.model.ModelConstants;
import org.thingsboard.server.dao.util.mapping.JsonStringType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.Table;
import java.util.UUID;
@Data
@EqualsAndHashCode(callSuper = true)
@Entity
@TypeDef(name = "json", typeClass = JsonStringType.class)
@Table(name = ModelConstants.NOTIFICATION_REQUEST_TABLE_NAME)
public class NotificationRequestEntity extends BaseSqlEntity<NotificationRequest> {
@Column(name = ModelConstants.TENANT_ID_PROPERTY)
private UUID tenantId;
@Column(name = ModelConstants.NOTIFICATION_REQUEST_TARGET_ID_PROPERTY)
private UUID targetId;
@Column(name = ModelConstants.NOTIFICATION_REQUEST_NOTIFICATION_REASON_PROPERTY)
private String notificationReason;
@Column(name = ModelConstants.NOTIFICATION_REQUEST_TEXT_TEMPLATE_PROPERTY)
private String textTemplate;
@Type(type = "json")
@Column(name = ModelConstants.NOTIFICATION_REQUEST_NOTIFICATION_INFO_PROPERTY)
private JsonNode notificationInfo;
@Enumerated(EnumType.STRING)
@Column(name = ModelConstants.NOTIFICATION_REQUEST_NOTIFICATION_SEVERITY_PROPERTY)
private NotificationSeverity notificationSeverity;
@Type(type = "json")
@Column(name = ModelConstants.NOTIFICATION_REQUEST_ADDITIONAL_CONFIG_PROPERTY)
private JsonNode additionalConfig;
@Column(name = ModelConstants.NOTIFICATION_REQUEST_SENDER_ID_PROPERTY)
private UUID senderId;
public NotificationRequestEntity() {}
public NotificationRequestEntity(NotificationRequest notificationRequest) {
setId(notificationRequest.getUuidId());
setCreatedTime(notificationRequest.getCreatedTime());
setTenantId(getUuid(notificationRequest.getTenantId()));
setTargetId(getUuid(notificationRequest.getTargetId()));
setNotificationReason(notificationRequest.getNotificationReason());
setTextTemplate(notificationRequest.getTextTemplate());
setNotificationInfo(JacksonUtil.valueToTree(notificationRequest.getNotificationInfo()));
setNotificationSeverity(notificationRequest.getNotificationSeverity());
setAdditionalConfig(JacksonUtil.valueToTree(notificationRequest.getAdditionalConfig()));
setSenderId(getUuid(notificationRequest.getSenderId()));
}
@Override
public NotificationRequest toData() {
return null;
NotificationRequest notificationRequest = new NotificationRequest();
notificationRequest.setId(new NotificationRequestId(id));
notificationRequest.setCreatedTime(createdTime);
notificationRequest.setTenantId(createId(tenantId, TenantId::new));
notificationRequest.setTargetId(createId(targetId, NotificationTargetId::new));
notificationRequest.setNotificationReason(notificationReason);
notificationRequest.setTextTemplate(textTemplate);
notificationRequest.setNotificationInfo(JacksonUtil.treeToValue(notificationInfo, NotificationInfo.class));
notificationRequest.setNotificationSeverity(notificationSeverity);
notificationRequest.setAdditionalConfig(JacksonUtil.treeToValue(additionalConfig, NotificationRequestConfig.class));
notificationRequest.setSenderId(createId(senderId, UserId::new));
return notificationRequest;
}
}

1
dao/src/main/java/org/thingsboard/server/dao/model/sql/NotificationTargetEntity.java

@ -27,6 +27,7 @@ import org.thingsboard.server.common.data.notification.targets.NotificationTarge
import org.thingsboard.server.common.data.notification.targets.NotificationTargetConfig;
import org.thingsboard.server.dao.model.BaseSqlEntity;
import org.thingsboard.server.dao.model.ModelConstants;
import org.thingsboard.server.dao.model.SearchTextEntity;
import org.thingsboard.server.dao.util.mapping.JsonStringType;
import javax.persistence.Column;

46
dao/src/main/java/org/thingsboard/server/dao/notification/DefaultNotificationService.java

@ -17,16 +17,21 @@ package org.thingsboard.server.dao.notification;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.thingsboard.server.common.data.id.NotificationId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.id.UserId;
import org.thingsboard.server.common.data.notification.Notification;
import org.thingsboard.server.common.data.notification.NotificationRequest;
import org.thingsboard.server.common.data.notification.NotificationSeverity;
import org.thingsboard.server.common.data.notification.NotificationStatus;
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.exception.DataValidationException;
import org.thingsboard.server.dao.service.DataValidator;
import org.thingsboard.server.dao.sql.query.EntityKeyMapping;
@Service
@Slf4j
@ -35,13 +40,16 @@ public class DefaultNotificationService implements NotificationService {
private final NotificationRequestDao notificationRequestDao;
private final NotificationDao notificationDao;
private final NotificationTargetService notificationTargetService;
private final NotificationRequestValidator notificationRequestValidator = new NotificationRequestValidator();
@Override
public NotificationRequest createNotificationRequest(TenantId tenantId, NotificationRequest notificationRequest) {
if (notificationRequest.getId() != null) {
throw new IllegalArgumentException();
if (StringUtils.isBlank(notificationRequest.getNotificationReason())) {
notificationRequest.setNotificationReason(NotificationRequest.GENERAL_NOTIFICATION_REASON);
}
if (notificationRequest.getNotificationSeverity() == null) {
notificationRequest.setNotificationSeverity(NotificationSeverity.NORMAL);
}
notificationRequestValidator.validate(notificationRequest, NotificationRequest::getTenantId);
return notificationRequestDao.save(tenantId, notificationRequest);
@ -49,28 +57,52 @@ public class DefaultNotificationService implements NotificationService {
@Override
public PageData<NotificationRequest> findNotificationRequestsByTenantIdAndPageLink(TenantId tenantId, PageLink pageLink) {
return null;
return notificationRequestDao.findByTenantIdAndPageLink(tenantId, pageLink);
}
@Override
public Notification createNotification(TenantId tenantId, Notification notification) {
if (notification.getId() != null) {
throw new IllegalArgumentException();
throw new DataValidationException("Notification cannot be updated"); // tmp ?
}
return notificationDao.save(tenantId, notification);
}
@Override
public void updateNotificationStatus(TenantId tenantId, NotificationId notificationId, NotificationStatus status) {
notificationDao.updateStatus(tenantId, notificationId, status);
}
@Override
public PageData<Notification> findNotificationsByUserIdAndReadStatusAndPageLink(TenantId tenantId, UserId userId, boolean unreadOnly, PageLink pageLink) {
if (unreadOnly) {
return notificationDao.findUnreadByUserIdAndPageLink(tenantId, userId, pageLink);
} else {
return notificationDao.findByUserIdAndPageLink(tenantId, userId, pageLink);
}
}
@Override
public PageData<Notification> findNotificationsByUserIdAndPageLink(TenantId tenantId, UserId userId, PageLink pageLink) {
return null;
public PageData<Notification> findLatestUnreadNotificationsByUserId(TenantId tenantId, UserId userId, int limit) {
SortOrder sortOrder = new SortOrder(EntityKeyMapping.CREATED_TIME, SortOrder.Direction.DESC);
PageLink pageLink = new PageLink(limit, 0, null, sortOrder);
return findNotificationsByUserIdAndReadStatusAndPageLink(tenantId, userId, true, pageLink);
}
private static class NotificationRequestValidator extends DataValidator<NotificationRequest> {
@Override
protected void validateDataImpl(TenantId tenantId, NotificationRequest notificationRequest) {
if (notificationRequest.getId() != null) {
throw new DataValidationException("Notification request cannot be changed once created");
}
if (notificationRequest.getSenderId() != null) {
if (notificationRequest.getNotificationReason().equalsIgnoreCase(NotificationRequest.ALARM_NOTIFICATION_REASON)) {
throw new DataValidationException("'Alarm' notification reason is for internal usage");
}
}
}
}
}

15
dao/src/main/java/org/thingsboard/server/dao/notification/DefaultNotificationTargetService.java

@ -24,6 +24,7 @@ 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.SingleUserNotificationTargetConfig;
import org.thingsboard.server.common.data.notification.targets.UserListNotificationTargetConfig;
import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.PageLink;
import org.thingsboard.server.dao.service.DataValidator;
@ -47,12 +48,12 @@ public class DefaultNotificationTargetService implements NotificationTargetServi
@Override
public NotificationTarget findNotificationTargetById(TenantId tenantId, NotificationTargetId id) {
return null;
return notificationTargetDao.findById(tenantId, id.getId());
}
@Override
public PageData<NotificationTarget> findNotificationTargetsByTenantIdAndPageLink(TenantId tenantId, PageLink pageLink) {
return null;
return notificationTargetDao.findByTenantIdAndPageLink(tenantId, pageLink);
}
@Override
@ -65,10 +66,20 @@ public class DefaultNotificationTargetService implements NotificationTargetServi
SingleUserNotificationTargetConfig singleUserNotificationTargetConfig = (SingleUserNotificationTargetConfig) configuration;
recipients.add(singleUserNotificationTargetConfig.getUserId());
break;
case USER_LIST:
UserListNotificationTargetConfig userListNotificationTargetConfig = (UserListNotificationTargetConfig) configuration;
recipients.addAll(userListNotificationTargetConfig.getUsersIds());
break;
}
return recipients;
}
@Override
public void deleteNotificationTarget(TenantId tenantId, NotificationTargetId notificationTargetId) {
notificationTargetDao.removeById(tenantId, notificationTargetId.getId());
// todo: delete related notification requests (?)
}
private static class NotificationTargetValidator extends DataValidator<NotificationTarget> {
}

13
dao/src/main/java/org/thingsboard/server/dao/notification/NotificationDao.java

@ -15,8 +15,21 @@
*/
package org.thingsboard.server.dao.notification;
import org.thingsboard.server.common.data.id.NotificationId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.id.UserId;
import org.thingsboard.server.common.data.notification.Notification;
import org.thingsboard.server.common.data.notification.NotificationStatus;
import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.PageLink;
import org.thingsboard.server.dao.Dao;
public interface NotificationDao extends Dao<Notification> {
PageData<Notification> findUnreadByUserIdAndPageLink(TenantId tenantId, UserId userId, PageLink pageLink);
PageData<Notification> findByUserIdAndPageLink(TenantId tenantId, UserId userId, PageLink pageLink);
void updateStatus(TenantId tenantId, NotificationId notificationId, NotificationStatus status);
}

6
dao/src/main/java/org/thingsboard/server/dao/notification/NotificationRequestDao.java

@ -15,8 +15,14 @@
*/
package org.thingsboard.server.dao.notification;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.notification.NotificationRequest;
import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.PageLink;
import org.thingsboard.server.dao.Dao;
public interface NotificationRequestDao extends Dao<NotificationRequest> {
PageData<NotificationRequest> findByTenantIdAndPageLink(TenantId tenantId, PageLink pageLink);
}

6
dao/src/main/java/org/thingsboard/server/dao/notification/NotificationTargetDao.java

@ -15,8 +15,14 @@
*/
package org.thingsboard.server.dao.notification;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.notification.targets.NotificationTarget;
import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.PageLink;
import org.thingsboard.server.dao.Dao;
public interface NotificationTargetDao extends Dao<NotificationTarget> {
PageData<NotificationTarget> findByTenantIdAndPageLink(TenantId tenantId, PageLink pageLink);
}

44
dao/src/main/java/org/thingsboard/server/dao/sql/notification/JpaNotificationDao.java

@ -15,16 +15,28 @@
*/
package org.thingsboard.server.dao.sql.notification;
import com.datastax.oss.driver.api.core.uuid.Uuids;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Component;
import org.thingsboard.server.common.data.id.NotificationId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.id.UserId;
import org.thingsboard.server.common.data.notification.Notification;
import org.thingsboard.server.common.data.notification.NotificationStatus;
import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.PageLink;
import org.thingsboard.server.dao.DaoUtil;
import org.thingsboard.server.dao.model.ModelConstants;
import org.thingsboard.server.dao.model.sql.NotificationEntity;
import org.thingsboard.server.dao.notification.NotificationDao;
import org.thingsboard.server.dao.sql.JpaAbstractDao;
import org.thingsboard.server.dao.sqlts.insert.sql.SqlPartitioningRepository;
import org.thingsboard.server.dao.util.SqlDao;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
@Component
@SqlDao
@ -32,6 +44,38 @@ import java.util.UUID;
public class JpaNotificationDao extends JpaAbstractDao<NotificationEntity, Notification> implements NotificationDao {
private final NotificationRepository notificationRepository;
private final SqlPartitioningRepository partitioningRepository;
@Value("${sql.notifications.partition_size:168}")
private int partitionSizeInHours;
@Override
public Notification save(TenantId tenantId, Notification notification) {
if (notification.getId() == null) {
UUID uuid = Uuids.timeBased();
notification.setId(new NotificationId(uuid));
notification.setCreatedTime(Uuids.unixTimestamp(uuid));
// todo: regarding ttl, it might be better to remove notifications on NotificationRequest level
partitioningRepository.createPartitionIfNotExists(ModelConstants.NOTIFICATION_TABLE_NAME,
notification.getCreatedTime(), TimeUnit.HOURS.toMillis(partitionSizeInHours));
}
return super.save(tenantId, notification);
}
@Override
public PageData<Notification> findUnreadByUserIdAndPageLink(TenantId tenantId, UserId userId, PageLink pageLink) {
return DaoUtil.toPageData(notificationRepository.findByRecipientIdAndStatusNot(userId.getId(), NotificationStatus.READ, DaoUtil.toPageable(pageLink)));
}
@Override
public PageData<Notification> findByUserIdAndPageLink(TenantId tenantId, UserId userId, PageLink pageLink) {
return DaoUtil.toPageData(notificationRepository.findByRecipientId(userId.getId(), DaoUtil.toPageable(pageLink)));
}
@Override
public void updateStatus(TenantId tenantId, NotificationId notificationId, NotificationStatus status) {
notificationRepository.updateStatus(notificationId.getId(), status);
}
@Override
protected Class<NotificationEntity> getEntityClass() {

11
dao/src/main/java/org/thingsboard/server/dao/sql/notification/JpaNotificationRequestDao.java

@ -15,10 +15,15 @@
*/
package org.thingsboard.server.dao.sql.notification;
import com.google.common.base.Strings;
import lombok.RequiredArgsConstructor;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Component;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.notification.NotificationRequest;
import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.PageLink;
import org.thingsboard.server.dao.DaoUtil;
import org.thingsboard.server.dao.model.sql.NotificationRequestEntity;
import org.thingsboard.server.dao.notification.NotificationRequestDao;
import org.thingsboard.server.dao.sql.JpaAbstractDao;
@ -33,6 +38,12 @@ public class JpaNotificationRequestDao extends JpaAbstractDao<NotificationReques
private final NotificationRequestRepository notificationRequestRepository;
@Override
public PageData<NotificationRequest> findByTenantIdAndPageLink(TenantId tenantId, PageLink pageLink) {
return DaoUtil.toPageData(notificationRequestRepository.findByTenantIdAndSearchText(tenantId.getId(),
Strings.nullToEmpty(pageLink.getTextSearch()), DaoUtil.toPageable(pageLink)));
}
@Override
protected Class<NotificationRequestEntity> getEntityClass() {
return NotificationRequestEntity.class;

11
dao/src/main/java/org/thingsboard/server/dao/sql/notification/JpaNotificationTargetDao.java

@ -15,10 +15,15 @@
*/
package org.thingsboard.server.dao.sql.notification;
import com.google.common.base.Strings;
import lombok.RequiredArgsConstructor;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Component;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.notification.targets.NotificationTarget;
import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.PageLink;
import org.thingsboard.server.dao.DaoUtil;
import org.thingsboard.server.dao.model.sql.NotificationTargetEntity;
import org.thingsboard.server.dao.notification.NotificationTargetDao;
import org.thingsboard.server.dao.sql.JpaAbstractDao;
@ -33,6 +38,12 @@ public class JpaNotificationTargetDao extends JpaAbstractDao<NotificationTargetE
private final NotificationTargetRepository notificationTargetRepository;
@Override
public PageData<NotificationTarget> findByTenantIdAndPageLink(TenantId tenantId, PageLink pageLink) {
return DaoUtil.toPageData(notificationTargetRepository.findByTenantIdAndNameContainingIgnoreCase(tenantId.getId(),
Strings.nullToEmpty(pageLink.getTextSearch()), DaoUtil.toPageable(pageLink)));
}
@Override
protected Class<NotificationTargetEntity> getEntityClass() {
return NotificationTargetEntity.class;

17
dao/src/main/java/org/thingsboard/server/dao/sql/notification/NotificationRepository.java

@ -15,12 +15,29 @@
*/
package org.thingsboard.server.dao.sql.notification;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;
import org.thingsboard.server.common.data.notification.NotificationStatus;
import org.thingsboard.server.dao.model.sql.NotificationEntity;
import java.util.UUID;
@Repository
public interface NotificationRepository extends JpaRepository<NotificationEntity, UUID> {
Page<NotificationEntity> findByRecipientIdAndStatusNot(UUID recipientId, NotificationStatus status, Pageable pageable);
Page<NotificationEntity> findByRecipientId(UUID recipientId, Pageable pageable);
@Modifying
@Transactional
@Query("UPDATE NotificationEntity n SET n.status = :status WHERE n.id = :id")
void updateStatus(@Param("id") UUID id, @Param("status") NotificationStatus status);
}

11
dao/src/main/java/org/thingsboard/server/dao/sql/notification/NotificationRequestRepository.java

@ -15,7 +15,11 @@
*/
package org.thingsboard.server.dao.sql.notification;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;
import org.thingsboard.server.dao.model.sql.NotificationRequestEntity;
@ -23,4 +27,11 @@ import java.util.UUID;
@Repository
public interface NotificationRequestRepository extends JpaRepository<NotificationRequestEntity, UUID> {
@Query("SELECT r FROM NotificationRequestEntity r WHERE r.tenantId = :tenantId AND " +
"(lower(r.notificationReason) LIKE lower(concat('%', :searchText, '%')) OR " +
"lower(r.textTemplate) LIKE lower(concat('%', :searchText, '%')))")
Page<NotificationRequestEntity> findByTenantIdAndSearchText(@Param("tenantId") UUID tenantId,
@Param("searchText") String searchText, Pageable pageable);
}

7
dao/src/main/java/org/thingsboard/server/dao/sql/notification/NotificationTargetRepository.java

@ -15,7 +15,11 @@
*/
package org.thingsboard.server.dao.sql.notification;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;
import org.thingsboard.server.dao.model.sql.NotificationTargetEntity;
@ -23,4 +27,7 @@ import java.util.UUID;
@Repository
public interface NotificationTargetRepository extends JpaRepository<NotificationTargetEntity, UUID> {
Page<NotificationTargetEntity> findByTenantIdAndNameContainingIgnoreCase(UUID tenantId, String searchText, Pageable pageable);
}

Loading…
Cancel
Save