Merge pull request #12062 from thingsboard/feature/system-notifications
System notification type; improvements for notification center
This commit is contained in:
commit
eb54dd50e8
@ -90,6 +90,7 @@ import org.thingsboard.server.common.data.id.EntityViewId;
|
||||
import org.thingsboard.server.common.data.id.HasId;
|
||||
import org.thingsboard.server.common.data.id.MobileAppBundleId;
|
||||
import org.thingsboard.server.common.data.id.MobileAppId;
|
||||
import org.thingsboard.server.common.data.id.NotificationTargetId;
|
||||
import org.thingsboard.server.common.data.id.OAuth2ClientId;
|
||||
import org.thingsboard.server.common.data.id.OtaPackageId;
|
||||
import org.thingsboard.server.common.data.id.QueueId;
|
||||
@ -105,6 +106,7 @@ import org.thingsboard.server.common.data.id.WidgetTypeId;
|
||||
import org.thingsboard.server.common.data.id.WidgetsBundleId;
|
||||
import org.thingsboard.server.common.data.mobile.app.MobileApp;
|
||||
import org.thingsboard.server.common.data.mobile.bundle.MobileAppBundle;
|
||||
import org.thingsboard.server.common.data.notification.targets.NotificationTarget;
|
||||
import org.thingsboard.server.common.data.oauth2.OAuth2Client;
|
||||
import org.thingsboard.server.common.data.page.PageLink;
|
||||
import org.thingsboard.server.common.data.page.SortOrder;
|
||||
@ -141,6 +143,7 @@ import org.thingsboard.server.dao.exception.IncorrectParameterException;
|
||||
import org.thingsboard.server.dao.mobile.MobileAppBundleService;
|
||||
import org.thingsboard.server.dao.mobile.MobileAppService;
|
||||
import org.thingsboard.server.dao.model.ModelConstants;
|
||||
import org.thingsboard.server.dao.notification.NotificationTargetService;
|
||||
import org.thingsboard.server.dao.oauth2.OAuth2ClientService;
|
||||
import org.thingsboard.server.dao.oauth2.OAuth2ConfigTemplateService;
|
||||
import org.thingsboard.server.dao.ota.OtaPackageService;
|
||||
@ -355,6 +358,9 @@ public abstract class BaseController {
|
||||
@Autowired
|
||||
protected TbServiceInfoProvider serviceInfoProvider;
|
||||
|
||||
@Autowired
|
||||
protected NotificationTargetService notificationTargetService;
|
||||
|
||||
@Value("${server.log_controller_error_stack_trace}")
|
||||
@Getter
|
||||
private boolean logControllerErrorStackTrace;
|
||||
@ -852,6 +858,10 @@ public abstract class BaseController {
|
||||
return checkEntityId(mobileAppBundleId, mobileAppBundleService::findMobileAppBundleById, operation);
|
||||
}
|
||||
|
||||
NotificationTarget checkNotificationTargetId(NotificationTargetId notificationTargetId, Operation operation) throws ThingsboardException {
|
||||
return checkEntityId(notificationTargetId, notificationTargetService::findNotificationTargetById, operation);
|
||||
}
|
||||
|
||||
protected <I extends EntityId> I emptyId(EntityType entityType) {
|
||||
return (I) EntityIdFactory.getByTypeAndUuid(entityType, ModelConstants.NULL_UUID);
|
||||
}
|
||||
|
||||
@ -266,6 +266,12 @@ public class NotificationController extends BaseController {
|
||||
}
|
||||
notificationRequest.setTenantId(user.getTenantId());
|
||||
checkEntity(notificationRequest.getId(), notificationRequest, NOTIFICATION);
|
||||
List<NotificationTargetId> targets = notificationRequest.getTargets().stream()
|
||||
.map(NotificationTargetId::new)
|
||||
.toList();
|
||||
for (NotificationTargetId targetId : targets) {
|
||||
checkNotificationTargetId(targetId, Operation.READ);
|
||||
}
|
||||
|
||||
notificationRequest.setOriginatorEntityId(user.getId());
|
||||
notificationRequest.setInfo(null);
|
||||
@ -316,6 +322,8 @@ public class NotificationController extends BaseController {
|
||||
Map<String, Integer> recipientsCountByTarget = new LinkedHashMap<>();
|
||||
Map<NotificationTargetType, NotificationRecipient> firstRecipient = new HashMap<>();
|
||||
for (NotificationTarget target : targets) {
|
||||
checkEntity(getCurrentUser(), target, Operation.READ);
|
||||
|
||||
int recipientsCount;
|
||||
List<NotificationRecipient> recipientsPart;
|
||||
NotificationTargetType targetType = target.getConfiguration().getType();
|
||||
|
||||
@ -127,7 +127,7 @@ public class NotificationTargetController extends BaseController {
|
||||
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')")
|
||||
public NotificationTarget getNotificationTargetById(@PathVariable UUID id) throws ThingsboardException {
|
||||
NotificationTargetId notificationTargetId = new NotificationTargetId(id);
|
||||
return checkEntityId(notificationTargetId, notificationTargetService::findNotificationTargetById, Operation.READ);
|
||||
return checkNotificationTargetId(notificationTargetId, Operation.READ);
|
||||
}
|
||||
|
||||
@ApiOperation(value = "Get recipients for notification target config (getRecipientsForNotificationTargetConfig)",
|
||||
@ -214,7 +214,7 @@ public class NotificationTargetController extends BaseController {
|
||||
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')")
|
||||
public void deleteNotificationTargetById(@PathVariable UUID id) throws Exception {
|
||||
NotificationTargetId notificationTargetId = new NotificationTargetId(id);
|
||||
NotificationTarget notificationTarget = checkEntityId(notificationTargetId, notificationTargetService::findNotificationTargetById, Operation.DELETE);
|
||||
NotificationTarget notificationTarget = checkNotificationTargetId(notificationTargetId, Operation.DELETE);
|
||||
doDeleteAndLog(EntityType.NOTIFICATION_TARGET, notificationTarget, notificationTargetService::deleteNotificationTargetById);
|
||||
}
|
||||
|
||||
|
||||
@ -40,7 +40,9 @@ 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.GeneralNotificationInfo;
|
||||
import org.thingsboard.server.common.data.notification.info.NotificationInfo;
|
||||
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.settings.UserNotificationSettings;
|
||||
@ -217,6 +219,21 @@ public class DefaultNotificationCenter extends AbstractSubscriptionService imple
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendSystemNotification(TenantId tenantId, NotificationTargetId targetId, NotificationType type, NotificationInfo info) {
|
||||
log.debug("[{}] Sending {} system notification to {}: {}", tenantId, type, targetId, info);
|
||||
NotificationTemplate notificationTemplate = notificationTemplateService.findTenantOrSystemNotificationTemplate(tenantId, type)
|
||||
.orElseThrow(() -> new IllegalArgumentException("No notification template found for type " + type));
|
||||
NotificationRequest notificationRequest = NotificationRequest.builder()
|
||||
.tenantId(TenantId.SYS_TENANT_ID)
|
||||
.targets(List.of(targetId.getId()))
|
||||
.templateId(notificationTemplate.getId())
|
||||
.info(info)
|
||||
.originatorEntityId(TenantId.SYS_TENANT_ID)
|
||||
.build();
|
||||
processNotificationRequest(TenantId.SYS_TENANT_ID, notificationRequest, null);
|
||||
}
|
||||
|
||||
private void processNotificationRequestAsync(NotificationProcessingContext ctx, List<NotificationTarget> targets, FutureCallback<NotificationRequestStats> callback) {
|
||||
notificationExecutor.submit(() -> {
|
||||
long startTs = System.currentTimeMillis();
|
||||
@ -271,7 +288,7 @@ public class DefaultNotificationCenter extends AbstractSubscriptionService imple
|
||||
}, 256);
|
||||
} else {
|
||||
recipients = new PageDataIterable<>(pageLink -> {
|
||||
return notificationTargetService.findRecipientsForNotificationTargetConfig(ctx.getTenantId(), targetConfig, pageLink);
|
||||
return notificationTargetService.findRecipientsForNotificationTargetConfig(target.getTenantId(), targetConfig, pageLink);
|
||||
}, 256);
|
||||
}
|
||||
}
|
||||
|
||||
@ -23,6 +23,7 @@ import com.google.common.util.concurrent.ListeningExecutorService;
|
||||
import io.jsonwebtoken.Claims;
|
||||
import io.jsonwebtoken.Jws;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.RandomStringUtils;
|
||||
import org.awaitility.Awaitility;
|
||||
import org.hamcrest.Matcher;
|
||||
import org.hibernate.exception.ConstraintViolationException;
|
||||
@ -99,6 +100,21 @@ import org.thingsboard.server.common.data.id.TenantId;
|
||||
import org.thingsboard.server.common.data.id.TenantProfileId;
|
||||
import org.thingsboard.server.common.data.id.UUIDBased;
|
||||
import org.thingsboard.server.common.data.id.UserId;
|
||||
import org.thingsboard.server.common.data.notification.Notification;
|
||||
import org.thingsboard.server.common.data.notification.NotificationDeliveryMethod;
|
||||
import org.thingsboard.server.common.data.notification.NotificationType;
|
||||
import org.thingsboard.server.common.data.notification.targets.NotificationTarget;
|
||||
import org.thingsboard.server.common.data.notification.targets.platform.PlatformUsersNotificationTargetConfig;
|
||||
import org.thingsboard.server.common.data.notification.targets.platform.UserListFilter;
|
||||
import org.thingsboard.server.common.data.notification.targets.platform.UsersFilter;
|
||||
import org.thingsboard.server.common.data.notification.template.DeliveryMethodNotificationTemplate;
|
||||
import org.thingsboard.server.common.data.notification.template.EmailDeliveryMethodNotificationTemplate;
|
||||
import org.thingsboard.server.common.data.notification.template.HasSubject;
|
||||
import org.thingsboard.server.common.data.notification.template.MobileAppDeliveryMethodNotificationTemplate;
|
||||
import org.thingsboard.server.common.data.notification.template.NotificationTemplate;
|
||||
import org.thingsboard.server.common.data.notification.template.NotificationTemplateConfig;
|
||||
import org.thingsboard.server.common.data.notification.template.SmsDeliveryMethodNotificationTemplate;
|
||||
import org.thingsboard.server.common.data.notification.template.WebDeliveryMethodNotificationTemplate;
|
||||
import org.thingsboard.server.common.data.oauth2.MapperType;
|
||||
import org.thingsboard.server.common.data.oauth2.OAuth2Client;
|
||||
import org.thingsboard.server.common.data.oauth2.OAuth2CustomMapperConfig;
|
||||
@ -116,6 +132,7 @@ import org.thingsboard.server.common.data.tenant.profile.TenantProfileData;
|
||||
import org.thingsboard.server.common.msg.session.FeatureType;
|
||||
import org.thingsboard.server.config.ThingsboardSecurityConfiguration;
|
||||
import org.thingsboard.server.dao.Dao;
|
||||
import org.thingsboard.server.dao.DaoUtil;
|
||||
import org.thingsboard.server.dao.attributes.AttributesService;
|
||||
import org.thingsboard.server.dao.device.ClaimDevicesService;
|
||||
import org.thingsboard.server.dao.tenant.TenantProfileService;
|
||||
@ -136,6 +153,7 @@ import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
@ -1162,4 +1180,76 @@ public abstract class AbstractWebTest extends AbstractInMemoryStorageTest {
|
||||
return oAuth2Client;
|
||||
}
|
||||
|
||||
protected NotificationTarget createNotificationTarget(UserId... usersIds) {
|
||||
UserListFilter filter = new UserListFilter();
|
||||
filter.setUsersIds(DaoUtil.toUUIDs(List.of(usersIds)));
|
||||
return createNotificationTarget(filter);
|
||||
}
|
||||
|
||||
protected NotificationTarget createNotificationTarget(UsersFilter usersFilter) {
|
||||
NotificationTarget notificationTarget = new NotificationTarget();
|
||||
notificationTarget.setName(usersFilter.toString() + RandomStringUtils.randomNumeric(5));
|
||||
PlatformUsersNotificationTargetConfig targetConfig = new PlatformUsersNotificationTargetConfig();
|
||||
targetConfig.setUsersFilter(usersFilter);
|
||||
notificationTarget.setConfiguration(targetConfig);
|
||||
return saveNotificationTarget(notificationTarget);
|
||||
}
|
||||
|
||||
protected NotificationTarget saveNotificationTarget(NotificationTarget notificationTarget) {
|
||||
return doPost("/api/notification/target", notificationTarget, NotificationTarget.class);
|
||||
}
|
||||
|
||||
protected NotificationTemplate createNotificationTemplate(NotificationType notificationType, String subject,
|
||||
String text, NotificationDeliveryMethod... deliveryMethods) {
|
||||
NotificationTemplate notificationTemplate = new NotificationTemplate();
|
||||
notificationTemplate.setTenantId(tenantId);
|
||||
notificationTemplate.setName("Notification template: " + text);
|
||||
notificationTemplate.setNotificationType(notificationType);
|
||||
NotificationTemplateConfig config = new NotificationTemplateConfig();
|
||||
config.setDeliveryMethodsTemplates(new HashMap<>());
|
||||
for (NotificationDeliveryMethod deliveryMethod : deliveryMethods) {
|
||||
DeliveryMethodNotificationTemplate deliveryMethodNotificationTemplate;
|
||||
switch (deliveryMethod) {
|
||||
case WEB: {
|
||||
deliveryMethodNotificationTemplate = new WebDeliveryMethodNotificationTemplate();
|
||||
break;
|
||||
}
|
||||
case EMAIL: {
|
||||
deliveryMethodNotificationTemplate = new EmailDeliveryMethodNotificationTemplate();
|
||||
break;
|
||||
}
|
||||
case SMS: {
|
||||
deliveryMethodNotificationTemplate = new SmsDeliveryMethodNotificationTemplate();
|
||||
break;
|
||||
}
|
||||
case MOBILE_APP:
|
||||
deliveryMethodNotificationTemplate = new MobileAppDeliveryMethodNotificationTemplate();
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException("Unsupported delivery method " + deliveryMethod);
|
||||
}
|
||||
deliveryMethodNotificationTemplate.setEnabled(true);
|
||||
deliveryMethodNotificationTemplate.setBody(text);
|
||||
if (deliveryMethodNotificationTemplate instanceof HasSubject) {
|
||||
((HasSubject) deliveryMethodNotificationTemplate).setSubject(subject);
|
||||
}
|
||||
config.getDeliveryMethodsTemplates().put(deliveryMethod, deliveryMethodNotificationTemplate);
|
||||
}
|
||||
notificationTemplate.setConfiguration(config);
|
||||
return saveNotificationTemplate(notificationTemplate);
|
||||
}
|
||||
|
||||
protected NotificationTemplate saveNotificationTemplate(NotificationTemplate notificationTemplate) {
|
||||
return doPost("/api/notification/template", notificationTemplate, NotificationTemplate.class);
|
||||
}
|
||||
|
||||
protected List<Notification> getMyNotifications(boolean unreadOnly, int limit) throws Exception {
|
||||
return getMyNotifications(NotificationDeliveryMethod.WEB, unreadOnly, limit);
|
||||
}
|
||||
|
||||
protected List<Notification> getMyNotifications(NotificationDeliveryMethod deliveryMethod, boolean unreadOnly, int limit) throws Exception {
|
||||
return doGetTypedWithPageLink("/api/notifications?unreadOnly={unreadOnly}&deliveryMethod={deliveryMethod}&", new TypeReference<PageData<Notification>>() {},
|
||||
new PageLink(limit, 0), unreadOnly, deliveryMethod).getData();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -274,14 +274,6 @@ public class NotificationEdgeTest extends AbstractEdgeTest {
|
||||
return saveNotificationRule(notificationRule);
|
||||
}
|
||||
|
||||
private NotificationTemplate saveNotificationTemplate(NotificationTemplate notificationTemplate) {
|
||||
return doPost("/api/notification/template", notificationTemplate, NotificationTemplate.class);
|
||||
}
|
||||
|
||||
private NotificationTarget saveNotificationTarget(NotificationTarget notificationTarget) {
|
||||
return doPost("/api/notification/target", notificationTarget, NotificationTarget.class);
|
||||
}
|
||||
|
||||
private NotificationRule saveNotificationRule(NotificationRule notificationRule) {
|
||||
return doPost("/api/notification/rule", notificationRule, NotificationRule.class);
|
||||
}
|
||||
|
||||
@ -30,8 +30,6 @@ import org.thingsboard.server.common.data.id.NotificationTargetId;
|
||||
import org.thingsboard.server.common.data.id.NotificationTemplateId;
|
||||
import org.thingsboard.server.common.data.id.TenantId;
|
||||
import org.thingsboard.server.common.data.id.UUIDBased;
|
||||
import org.thingsboard.server.common.data.id.UserId;
|
||||
import org.thingsboard.server.common.data.notification.Notification;
|
||||
import org.thingsboard.server.common.data.notification.NotificationDeliveryMethod;
|
||||
import org.thingsboard.server.common.data.notification.NotificationRequest;
|
||||
import org.thingsboard.server.common.data.notification.NotificationRequestConfig;
|
||||
@ -44,18 +42,7 @@ import org.thingsboard.server.common.data.notification.rule.NotificationRuleInfo
|
||||
import org.thingsboard.server.common.data.notification.rule.trigger.config.NotificationRuleTriggerConfig;
|
||||
import org.thingsboard.server.common.data.notification.settings.NotificationDeliveryMethodConfig;
|
||||
import org.thingsboard.server.common.data.notification.settings.NotificationSettings;
|
||||
import org.thingsboard.server.common.data.notification.targets.NotificationTarget;
|
||||
import org.thingsboard.server.common.data.notification.targets.platform.PlatformUsersNotificationTargetConfig;
|
||||
import org.thingsboard.server.common.data.notification.targets.platform.UserListFilter;
|
||||
import org.thingsboard.server.common.data.notification.targets.platform.UsersFilter;
|
||||
import org.thingsboard.server.common.data.notification.template.DeliveryMethodNotificationTemplate;
|
||||
import org.thingsboard.server.common.data.notification.template.EmailDeliveryMethodNotificationTemplate;
|
||||
import org.thingsboard.server.common.data.notification.template.HasSubject;
|
||||
import org.thingsboard.server.common.data.notification.template.MobileAppDeliveryMethodNotificationTemplate;
|
||||
import org.thingsboard.server.common.data.notification.template.NotificationTemplate;
|
||||
import org.thingsboard.server.common.data.notification.template.NotificationTemplateConfig;
|
||||
import org.thingsboard.server.common.data.notification.template.SmsDeliveryMethodNotificationTemplate;
|
||||
import org.thingsboard.server.common.data.notification.template.WebDeliveryMethodNotificationTemplate;
|
||||
import org.thingsboard.server.common.data.page.PageData;
|
||||
import org.thingsboard.server.common.data.page.PageLink;
|
||||
import org.thingsboard.server.common.data.security.Authority;
|
||||
@ -71,7 +58,6 @@ import org.thingsboard.server.dao.sqlts.insert.sql.SqlPartitioningRepository;
|
||||
|
||||
import java.net.URISyntaxException;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.stream.Collectors;
|
||||
@ -120,25 +106,6 @@ public abstract class AbstractNotificationApiTest extends AbstractControllerTest
|
||||
notificationSettingsService.deleteNotificationSettings(TenantId.SYS_TENANT_ID);
|
||||
}
|
||||
|
||||
protected NotificationTarget createNotificationTarget(UserId... usersIds) {
|
||||
UserListFilter filter = new UserListFilter();
|
||||
filter.setUsersIds(DaoUtil.toUUIDs(List.of(usersIds)));
|
||||
return createNotificationTarget(filter);
|
||||
}
|
||||
|
||||
protected NotificationTarget createNotificationTarget(UsersFilter usersFilter) {
|
||||
NotificationTarget notificationTarget = new NotificationTarget();
|
||||
notificationTarget.setName(usersFilter.toString());
|
||||
PlatformUsersNotificationTargetConfig targetConfig = new PlatformUsersNotificationTargetConfig();
|
||||
targetConfig.setUsersFilter(usersFilter);
|
||||
notificationTarget.setConfiguration(targetConfig);
|
||||
return saveNotificationTarget(notificationTarget);
|
||||
}
|
||||
|
||||
protected NotificationTarget saveNotificationTarget(NotificationTarget notificationTarget) {
|
||||
return doPost("/api/notification/target", notificationTarget, NotificationTarget.class);
|
||||
}
|
||||
|
||||
protected NotificationRequest submitNotificationRequest(NotificationTargetId targetId, String text, NotificationDeliveryMethod... deliveryMethods) {
|
||||
return submitNotificationRequest(targetId, text, 0, deliveryMethods);
|
||||
}
|
||||
@ -178,50 +145,6 @@ public abstract class AbstractNotificationApiTest extends AbstractControllerTest
|
||||
return findNotificationRequest(notificationRequestId).getStats();
|
||||
}
|
||||
|
||||
protected NotificationTemplate createNotificationTemplate(NotificationType notificationType, String subject,
|
||||
String text, NotificationDeliveryMethod... deliveryMethods) {
|
||||
NotificationTemplate notificationTemplate = new NotificationTemplate();
|
||||
notificationTemplate.setTenantId(tenantId);
|
||||
notificationTemplate.setName("Notification template: " + text);
|
||||
notificationTemplate.setNotificationType(notificationType);
|
||||
NotificationTemplateConfig config = new NotificationTemplateConfig();
|
||||
config.setDeliveryMethodsTemplates(new HashMap<>());
|
||||
for (NotificationDeliveryMethod deliveryMethod : deliveryMethods) {
|
||||
DeliveryMethodNotificationTemplate deliveryMethodNotificationTemplate;
|
||||
switch (deliveryMethod) {
|
||||
case WEB: {
|
||||
deliveryMethodNotificationTemplate = new WebDeliveryMethodNotificationTemplate();
|
||||
break;
|
||||
}
|
||||
case EMAIL: {
|
||||
deliveryMethodNotificationTemplate = new EmailDeliveryMethodNotificationTemplate();
|
||||
break;
|
||||
}
|
||||
case SMS: {
|
||||
deliveryMethodNotificationTemplate = new SmsDeliveryMethodNotificationTemplate();
|
||||
break;
|
||||
}
|
||||
case MOBILE_APP:
|
||||
deliveryMethodNotificationTemplate = new MobileAppDeliveryMethodNotificationTemplate();
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException("Unsupported delivery method " + deliveryMethod);
|
||||
}
|
||||
deliveryMethodNotificationTemplate.setEnabled(true);
|
||||
deliveryMethodNotificationTemplate.setBody(text);
|
||||
if (deliveryMethodNotificationTemplate instanceof HasSubject) {
|
||||
((HasSubject) deliveryMethodNotificationTemplate).setSubject(subject);
|
||||
}
|
||||
config.getDeliveryMethodsTemplates().put(deliveryMethod, deliveryMethodNotificationTemplate);
|
||||
}
|
||||
notificationTemplate.setConfiguration(config);
|
||||
return saveNotificationTemplate(notificationTemplate);
|
||||
}
|
||||
|
||||
protected NotificationTemplate saveNotificationTemplate(NotificationTemplate notificationTemplate) {
|
||||
return doPost("/api/notification/template", notificationTemplate, NotificationTemplate.class);
|
||||
}
|
||||
|
||||
protected void saveNotificationSettings(NotificationSettings notificationSettings) throws Exception {
|
||||
doPost("/api/notification/settings", notificationSettings).andExpect(status().isOk());
|
||||
}
|
||||
@ -258,15 +181,6 @@ public abstract class AbstractNotificationApiTest extends AbstractControllerTest
|
||||
doDelete("/api/notification/request/" + id);
|
||||
}
|
||||
|
||||
protected List<Notification> getMyNotifications(boolean unreadOnly, int limit) throws Exception {
|
||||
return getMyNotifications(NotificationDeliveryMethod.WEB, unreadOnly, limit);
|
||||
}
|
||||
|
||||
protected List<Notification> getMyNotifications(NotificationDeliveryMethod deliveryMethod, boolean unreadOnly, int limit) throws Exception {
|
||||
return doGetTypedWithPageLink("/api/notifications?unreadOnly={unreadOnly}&deliveryMethod={deliveryMethod}&", new TypeReference<PageData<Notification>>() {},
|
||||
new PageLink(limit, 0), unreadOnly, deliveryMethod).getData();
|
||||
}
|
||||
|
||||
protected NotificationRule createNotificationRule(NotificationRuleTriggerConfig triggerConfig, String subject, String text, NotificationTargetId... targets) {
|
||||
return createNotificationRule(triggerConfig, subject, text, List.of(targets), NotificationDeliveryMethod.WEB);
|
||||
}
|
||||
|
||||
@ -15,11 +15,15 @@
|
||||
*/
|
||||
package org.thingsboard.server.dao.notification;
|
||||
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import org.thingsboard.server.common.data.id.TenantId;
|
||||
import org.thingsboard.server.common.data.id.UserId;
|
||||
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.UserNotificationSettings;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public interface NotificationSettingsService {
|
||||
|
||||
void saveNotificationSettings(TenantId tenantId, NotificationSettings settings);
|
||||
@ -36,4 +40,6 @@ public interface NotificationSettingsService {
|
||||
|
||||
void updateDefaultNotificationConfigs(TenantId tenantId);
|
||||
|
||||
void moveMailTemplatesToNotificationCenter(TenantId tenantId, JsonNode mailTemplates, Map<String, NotificationType> mailTemplatesNames);
|
||||
|
||||
}
|
||||
|
||||
@ -22,7 +22,9 @@ import org.thingsboard.server.common.data.notification.template.NotificationTemp
|
||||
import org.thingsboard.server.common.data.page.PageData;
|
||||
import org.thingsboard.server.common.data.page.PageLink;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
public interface NotificationTemplateService {
|
||||
|
||||
@ -32,7 +34,11 @@ public interface NotificationTemplateService {
|
||||
|
||||
PageData<NotificationTemplate> findNotificationTemplatesByTenantIdAndNotificationTypes(TenantId tenantId, List<NotificationType> notificationTypes, PageLink pageLink);
|
||||
|
||||
int countNotificationTemplatesByTenantIdAndNotificationTypes(TenantId tenantId, List<NotificationType> notificationTypes);
|
||||
Optional<NotificationTemplate> findTenantOrSystemNotificationTemplate(TenantId tenantId, NotificationType notificationType);
|
||||
|
||||
Optional<NotificationTemplate> findNotificationTemplateByTenantIdAndType(TenantId tenantId, NotificationType notificationType);
|
||||
|
||||
int countNotificationTemplatesByTenantIdAndNotificationTypes(TenantId tenantId, Collection<NotificationType> notificationTypes);
|
||||
|
||||
void deleteNotificationTemplateById(TenantId tenantId, NotificationTemplateId id);
|
||||
|
||||
|
||||
@ -15,6 +15,12 @@
|
||||
*/
|
||||
package org.thingsboard.server.common.data.notification;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
public enum NotificationType {
|
||||
|
||||
GENERAL,
|
||||
@ -31,6 +37,9 @@ public enum NotificationType {
|
||||
RATE_LIMITS,
|
||||
EDGE_CONNECTION,
|
||||
EDGE_COMMUNICATION_FAILURE,
|
||||
TASK_PROCESSING_FAILURE
|
||||
TASK_PROCESSING_FAILURE;
|
||||
|
||||
@Getter
|
||||
private boolean system; // for future use and compatibility with PE
|
||||
|
||||
}
|
||||
|
||||
@ -15,8 +15,11 @@
|
||||
*/
|
||||
package org.thingsboard.server.dao.notification;
|
||||
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.node.ObjectNode;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.cache.annotation.CacheEvict;
|
||||
import org.springframework.cache.annotation.Cacheable;
|
||||
import org.springframework.stereotype.Service;
|
||||
@ -41,7 +44,9 @@ import org.thingsboard.server.common.data.notification.targets.platform.SystemAd
|
||||
import org.thingsboard.server.common.data.notification.targets.platform.TenantAdministratorsFilter;
|
||||
import org.thingsboard.server.common.data.notification.targets.platform.UsersFilter;
|
||||
import org.thingsboard.server.common.data.notification.targets.platform.UsersFilterType;
|
||||
import org.thingsboard.server.common.data.notification.template.EmailDeliveryMethodNotificationTemplate;
|
||||
import org.thingsboard.server.common.data.notification.template.NotificationTemplate;
|
||||
import org.thingsboard.server.common.data.notification.template.NotificationTemplateConfig;
|
||||
import org.thingsboard.server.common.data.page.PageLink;
|
||||
import org.thingsboard.server.common.data.settings.UserSettings;
|
||||
import org.thingsboard.server.common.data.settings.UserSettingsType;
|
||||
@ -249,6 +254,52 @@ public class DefaultNotificationSettingsService implements NotificationSettingsS
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void moveMailTemplatesToNotificationCenter(TenantId tenantId, JsonNode mailTemplates, Map<String, NotificationType> mailTemplatesNames) {
|
||||
mailTemplatesNames.forEach((mailTemplateName, notificationType) -> {
|
||||
moveMailTemplateToNotificationCenter(tenantId, mailTemplates, mailTemplateName, notificationType);
|
||||
});
|
||||
}
|
||||
|
||||
private void moveMailTemplateToNotificationCenter(TenantId tenantId, JsonNode mailTemplates, String mailTemplateName, NotificationType notificationType) {
|
||||
JsonNode mailTemplate = mailTemplates.get(mailTemplateName);
|
||||
if (mailTemplate == null || mailTemplate.isNull() || !mailTemplate.has("subject") || !mailTemplate.has("body")) {
|
||||
return;
|
||||
}
|
||||
|
||||
String subject = mailTemplate.get("subject").asText();
|
||||
String body = mailTemplate.get("body").asText();
|
||||
body = body.replace("targetEmail", "recipientEmail");
|
||||
|
||||
NotificationTemplate notificationTemplate = null;
|
||||
if (tenantId.isSysTenantId()) {
|
||||
// updating system notification template, not touching tenants' templates
|
||||
notificationTemplate = notificationTemplateService.findNotificationTemplateByTenantIdAndType(tenantId, notificationType).orElse(null);
|
||||
}
|
||||
if (notificationTemplate == null) {
|
||||
log.debug("[{}] Creating {} template", tenantId, notificationType);
|
||||
notificationTemplate = new NotificationTemplate();
|
||||
} else {
|
||||
log.debug("[{}] Updating {} template", tenantId, notificationType);
|
||||
}
|
||||
String name = StringUtils.capitalize(notificationType.name().toLowerCase().replaceAll("_", " ")) + " notification";
|
||||
notificationTemplate.setName(name);
|
||||
notificationTemplate.setTenantId(tenantId);
|
||||
notificationTemplate.setNotificationType(notificationType);
|
||||
NotificationTemplateConfig notificationTemplateConfig = new NotificationTemplateConfig();
|
||||
|
||||
EmailDeliveryMethodNotificationTemplate emailNotificationTemplate = new EmailDeliveryMethodNotificationTemplate();
|
||||
emailNotificationTemplate.setEnabled(true);
|
||||
emailNotificationTemplate.setSubject(subject);
|
||||
emailNotificationTemplate.setBody(body);
|
||||
|
||||
notificationTemplateConfig.setDeliveryMethodsTemplates(Map.of(NotificationDeliveryMethod.EMAIL, emailNotificationTemplate));
|
||||
notificationTemplate.setConfiguration(notificationTemplateConfig);
|
||||
notificationTemplateService.saveNotificationTemplate(tenantId, notificationTemplate);
|
||||
|
||||
((ObjectNode) mailTemplates).remove(mailTemplateName);
|
||||
}
|
||||
|
||||
private boolean isNotificationConfigured(TenantId tenantId, NotificationType... notificationTypes) {
|
||||
return notificationTemplateService.countNotificationTemplatesByTenantIdAndNotificationTypes(tenantId, List.of(notificationTypes)) > 0;
|
||||
}
|
||||
|
||||
@ -109,7 +109,7 @@ public class DefaultNotificationTargetService extends AbstractEntityService impl
|
||||
NotificationTarget notificationTarget = findNotificationTargetById(tenantId, targetId);
|
||||
Objects.requireNonNull(notificationTarget, "Notification target [" + targetId + "] not found");
|
||||
NotificationTargetConfig configuration = notificationTarget.getConfiguration();
|
||||
return findRecipientsForNotificationTargetConfig(tenantId, (PlatformUsersNotificationTargetConfig) configuration, pageLink);
|
||||
return findRecipientsForNotificationTargetConfig(notificationTarget.getTenantId(), (PlatformUsersNotificationTargetConfig) configuration, pageLink);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@ -32,6 +32,7 @@ import org.thingsboard.server.dao.entity.EntityDaoService;
|
||||
import org.thingsboard.server.dao.eventsourcing.DeleteEntityEvent;
|
||||
import org.thingsboard.server.dao.eventsourcing.SaveEntityEvent;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
@ -50,11 +51,19 @@ public class DefaultNotificationTemplateService extends AbstractEntityService im
|
||||
|
||||
@Override
|
||||
public NotificationTemplate saveNotificationTemplate(TenantId tenantId, NotificationTemplate notificationTemplate) {
|
||||
NotificationType notificationType = notificationTemplate.getNotificationType();
|
||||
if (notificationTemplate.getId() != null) {
|
||||
NotificationTemplate oldNotificationTemplate = findNotificationTemplateById(tenantId, notificationTemplate.getId());
|
||||
if (notificationTemplate.getNotificationType() != oldNotificationTemplate.getNotificationType()) {
|
||||
if (notificationType != oldNotificationTemplate.getNotificationType()) {
|
||||
throw new IllegalArgumentException("Notification type cannot be updated");
|
||||
}
|
||||
} else {
|
||||
if (notificationType.isSystem()) {
|
||||
int systemTemplatesCount = countNotificationTemplatesByTenantIdAndNotificationTypes(tenantId, List.of(notificationType));
|
||||
if (systemTemplatesCount > 0) {
|
||||
throw new IllegalArgumentException("There can only be one notification template of this type");
|
||||
}
|
||||
}
|
||||
}
|
||||
try {
|
||||
NotificationTemplate savedTemplate = notificationTemplateDao.saveAndFlush(tenantId, notificationTemplate);
|
||||
@ -75,7 +84,19 @@ public class DefaultNotificationTemplateService extends AbstractEntityService im
|
||||
}
|
||||
|
||||
@Override
|
||||
public int countNotificationTemplatesByTenantIdAndNotificationTypes(TenantId tenantId, List<NotificationType> notificationTypes) {
|
||||
public Optional<NotificationTemplate> findTenantOrSystemNotificationTemplate(TenantId tenantId, NotificationType notificationType) {
|
||||
return findNotificationTemplateByTenantIdAndType(tenantId, notificationType)
|
||||
.or(() -> findNotificationTemplateByTenantIdAndType(TenantId.SYS_TENANT_ID, notificationType));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<NotificationTemplate> findNotificationTemplateByTenantIdAndType(TenantId tenantId, NotificationType notificationType) {
|
||||
return findNotificationTemplatesByTenantIdAndNotificationTypes(tenantId, List.of(notificationType), new PageLink(1)).getData()
|
||||
.stream().findFirst();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int countNotificationTemplatesByTenantIdAndNotificationTypes(TenantId tenantId, Collection<NotificationType> notificationTypes) {
|
||||
return notificationTemplateDao.countByTenantIdAndNotificationTypes(tenantId, notificationTypes);
|
||||
}
|
||||
|
||||
@ -86,8 +107,16 @@ public class DefaultNotificationTemplateService extends AbstractEntityService im
|
||||
|
||||
@Override
|
||||
public void deleteEntity(TenantId tenantId, EntityId id, boolean force) {
|
||||
if (!force && notificationRequestDao.existsByTenantIdAndStatusAndTemplateId(tenantId, NotificationRequestStatus.SCHEDULED, (NotificationTemplateId) id)) {
|
||||
throw new IllegalArgumentException("Notification template is referenced by scheduled notification request");
|
||||
if (!force) {
|
||||
if (notificationRequestDao.existsByTenantIdAndStatusAndTemplateId(tenantId, NotificationRequestStatus.SCHEDULED, (NotificationTemplateId) id)) {
|
||||
throw new IllegalArgumentException("Notification template is referenced by scheduled notification request");
|
||||
}
|
||||
if (tenantId.isSysTenantId()) {
|
||||
NotificationTemplate notificationTemplate = findNotificationTemplateById(tenantId, (NotificationTemplateId) id);
|
||||
if (notificationTemplate.getNotificationType().isSystem()) {
|
||||
throw new IllegalArgumentException("System notification template cannot be deleted");
|
||||
}
|
||||
}
|
||||
}
|
||||
try {
|
||||
notificationTemplateDao.removeById(tenantId, id.getId());
|
||||
|
||||
@ -24,13 +24,14 @@ import org.thingsboard.server.common.data.page.PageLink;
|
||||
import org.thingsboard.server.dao.Dao;
|
||||
import org.thingsboard.server.dao.ExportableEntityDao;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
public interface NotificationTemplateDao extends Dao<NotificationTemplate>, ExportableEntityDao<NotificationTemplateId, NotificationTemplate> {
|
||||
|
||||
PageData<NotificationTemplate> findByTenantIdAndNotificationTypesAndPageLink(TenantId tenantId, List<NotificationType> notificationTypes, PageLink pageLink);
|
||||
|
||||
int countByTenantIdAndNotificationTypes(TenantId tenantId, List<NotificationType> notificationTypes);
|
||||
int countByTenantIdAndNotificationTypes(TenantId tenantId, Collection<NotificationType> notificationTypes);
|
||||
|
||||
void removeByTenantId(TenantId tenantId);
|
||||
|
||||
|
||||
@ -31,6 +31,7 @@ import org.thingsboard.server.dao.notification.NotificationTemplateDao;
|
||||
import org.thingsboard.server.dao.sql.JpaAbstractDao;
|
||||
import org.thingsboard.server.dao.util.SqlDao;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
@ -53,7 +54,7 @@ public class JpaNotificationTemplateDao extends JpaAbstractDao<NotificationTempl
|
||||
}
|
||||
|
||||
@Override
|
||||
public int countByTenantIdAndNotificationTypes(TenantId tenantId, List<NotificationType> notificationTypes) {
|
||||
public int countByTenantIdAndNotificationTypes(TenantId tenantId, Collection<NotificationType> notificationTypes) {
|
||||
return notificationTemplateRepository.countByTenantIdAndNotificationTypes(tenantId.getId(), notificationTypes);
|
||||
}
|
||||
|
||||
|
||||
@ -27,6 +27,7 @@ import org.thingsboard.server.common.data.notification.NotificationType;
|
||||
import org.thingsboard.server.dao.ExportableEntityRepository;
|
||||
import org.thingsboard.server.dao.model.sql.NotificationTemplateEntity;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
@ -45,7 +46,7 @@ public interface NotificationTemplateRepository extends JpaRepository<Notificati
|
||||
@Query("SELECT count(t) FROM NotificationTemplateEntity t WHERE t.tenantId = :tenantId AND " +
|
||||
"t.notificationType IN :notificationTypes")
|
||||
int countByTenantIdAndNotificationTypes(@Param("tenantId") UUID tenantId,
|
||||
@Param("notificationTypes") List<NotificationType> notificationTypes);
|
||||
@Param("notificationTypes") Collection<NotificationType> notificationTypes);
|
||||
|
||||
@Transactional
|
||||
@Modifying
|
||||
|
||||
@ -18,12 +18,15 @@ package org.thingsboard.rule.engine.api;
|
||||
import com.google.common.util.concurrent.FutureCallback;
|
||||
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 org.thingsboard.server.common.data.notification.NotificationDeliveryMethod;
|
||||
import org.thingsboard.server.common.data.notification.NotificationRequest;
|
||||
import org.thingsboard.server.common.data.notification.NotificationRequestStats;
|
||||
import org.thingsboard.server.common.data.notification.NotificationType;
|
||||
import org.thingsboard.server.common.data.notification.info.GeneralNotificationInfo;
|
||||
import org.thingsboard.server.common.data.notification.info.NotificationInfo;
|
||||
import org.thingsboard.server.common.data.notification.targets.platform.UsersFilter;
|
||||
import org.thingsboard.server.common.data.notification.template.NotificationTemplate;
|
||||
|
||||
@ -35,6 +38,8 @@ public interface NotificationCenter {
|
||||
|
||||
void sendGeneralWebNotification(TenantId tenantId, UsersFilter recipients, NotificationTemplate template, GeneralNotificationInfo info);
|
||||
|
||||
void sendSystemNotification(TenantId tenantId, NotificationTargetId targetId, NotificationType type, NotificationInfo info); // for future use and compatibility with PE
|
||||
|
||||
void deleteNotificationRequest(TenantId tenantId, NotificationRequestId notificationRequestId);
|
||||
|
||||
void markNotificationAsRead(TenantId tenantId, UserId recipientId, NotificationId notificationId);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user