FINERACT-1724: Put user notification feature behind feature toggle
This commit is contained in:
committed by
Arnold Gálovics
parent
3a176f4cbf
commit
d21110f7b2
+15
@@ -58,6 +58,8 @@ public class FineractProperties {
|
||||
private FineractQueryProperties query;
|
||||
private FineractApiProperties api;
|
||||
|
||||
private FineractNotificationProperties notification;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
public static class FineractTenantProperties {
|
||||
@@ -280,4 +282,17 @@ public class FineractProperties {
|
||||
private int inlineLoanCob;
|
||||
}
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
public static class FineractNotificationProperties {
|
||||
|
||||
private UserNotificationSystemProperties userNotificationSystem;
|
||||
}
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
public static class UserNotificationSystemProperties {
|
||||
|
||||
private boolean enabled;
|
||||
}
|
||||
}
|
||||
|
||||
+3
-3
@@ -37,7 +37,7 @@ import org.apache.fineract.infrastructure.core.service.ThreadLocalContextUtil;
|
||||
import org.apache.fineract.infrastructure.security.data.PlatformRequestLog;
|
||||
import org.apache.fineract.infrastructure.security.exception.InvalidTenantIdentifierException;
|
||||
import org.apache.fineract.infrastructure.security.service.BasicAuthTenantDetailsService;
|
||||
import org.apache.fineract.notification.service.NotificationReadPlatformService;
|
||||
import org.apache.fineract.notification.service.UserNotificationService;
|
||||
import org.apache.fineract.useradministration.domain.AppUser;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
@@ -79,7 +79,7 @@ public class TenantAwareBasicAuthenticationFilter extends BasicAuthenticationFil
|
||||
private CacheWritePlatformService cacheWritePlatformService;
|
||||
|
||||
@Autowired
|
||||
private NotificationReadPlatformService notificationReadPlatformService;
|
||||
private UserNotificationService userNotificationService;
|
||||
|
||||
@Autowired
|
||||
private BasicAuthTenantDetailsService basicAuthTenantDetailsService;
|
||||
@@ -170,7 +170,7 @@ public class TenantAwareBasicAuthenticationFilter extends BasicAuthenticationFil
|
||||
super.onSuccessfulAuthentication(request, response, authResult);
|
||||
AppUser user = (AppUser) authResult.getPrincipal();
|
||||
|
||||
if (notificationReadPlatformService.hasUnreadNotifications(user.getId())) {
|
||||
if (userNotificationService.hasUnreadUserNotifications(user.getId())) {
|
||||
response.addHeader("X-Notification-Refresh", "true");
|
||||
} else {
|
||||
response.addHeader("X-Notification-Refresh", "false");
|
||||
|
||||
+3
-30
@@ -18,46 +18,19 @@
|
||||
*/
|
||||
package org.apache.fineract.notification.eventandlistener;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.apache.fineract.notification.data.NotificationData;
|
||||
import org.apache.fineract.notification.service.NotificationWritePlatformService;
|
||||
import org.apache.fineract.useradministration.domain.AppUser;
|
||||
import org.apache.fineract.useradministration.domain.AppUserRepository;
|
||||
import org.apache.fineract.notification.service.UserNotificationService;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class NotificationEventListener {
|
||||
|
||||
private final NotificationWritePlatformService notificationWritePlatformService;
|
||||
private final AppUserRepository appUserRepository;
|
||||
private final UserNotificationService userNotificationService;
|
||||
|
||||
public void receive(NotificationData notificationData) {
|
||||
Long appUserId = notificationData.getActorId();
|
||||
userNotificationService.notifyUsers(notificationData);
|
||||
|
||||
Set<Long> userIds = notificationData.getUserIds();
|
||||
|
||||
if (notificationData.getOfficeId() != null) {
|
||||
List<Long> tempUserIds = new ArrayList<>(userIds);
|
||||
for (Long userId : tempUserIds) {
|
||||
AppUser appUser = appUserRepository.findById(userId).orElseThrow();
|
||||
if (!Objects.equals(appUser.getOffice().getId(), notificationData.getOfficeId())) {
|
||||
userIds.remove(userId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Don't notify the same user who triggered the event
|
||||
if (userIds.contains(appUserId)) {
|
||||
userIds.remove(appUserId);
|
||||
}
|
||||
|
||||
notificationWritePlatformService.notify(userIds, notificationData.getObjectType(), notificationData.getObjectId(),
|
||||
notificationData.getAction(), notificationData.getActorId(), notificationData.getContent(),
|
||||
notificationData.isSystemGenerated());
|
||||
}
|
||||
}
|
||||
|
||||
+2
-27
@@ -18,15 +18,10 @@
|
||||
*/
|
||||
package org.apache.fineract.notification.service;
|
||||
|
||||
import static java.util.stream.Collectors.toSet;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Set;
|
||||
import javax.annotation.PostConstruct;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
|
||||
import org.apache.fineract.infrastructure.core.service.ThreadLocalContextUtil;
|
||||
import org.apache.fineract.infrastructure.event.business.BusinessEventListener;
|
||||
import org.apache.fineract.infrastructure.event.business.domain.client.ClientCreateBusinessEvent;
|
||||
import org.apache.fineract.infrastructure.event.business.domain.deposit.FixedDepositAccountCreateBusinessEvent;
|
||||
@@ -50,8 +45,6 @@ import org.apache.fineract.infrastructure.event.business.domain.share.ShareAccou
|
||||
import org.apache.fineract.infrastructure.event.business.domain.share.ShareProductDividentsCreateBusinessEvent;
|
||||
import org.apache.fineract.infrastructure.event.business.service.BusinessEventNotifierService;
|
||||
import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext;
|
||||
import org.apache.fineract.notification.data.NotificationData;
|
||||
import org.apache.fineract.notification.eventandlistener.NotificationEventPublisher;
|
||||
import org.apache.fineract.portfolio.client.domain.Client;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.Loan;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanTransaction;
|
||||
@@ -62,8 +55,6 @@ import org.apache.fineract.portfolio.savings.domain.RecurringDepositAccount;
|
||||
import org.apache.fineract.portfolio.savings.domain.SavingsAccount;
|
||||
import org.apache.fineract.portfolio.savings.domain.SavingsAccountTransaction;
|
||||
import org.apache.fineract.portfolio.shareaccounts.domain.ShareAccount;
|
||||
import org.apache.fineract.useradministration.domain.AppUser;
|
||||
import org.apache.fineract.useradministration.domain.AppUserRepository;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@Service
|
||||
@@ -73,8 +64,7 @@ public class NotificationDomainServiceImpl implements NotificationDomainService
|
||||
|
||||
private final BusinessEventNotifierService businessEventNotifierService;
|
||||
private final PlatformSecurityContext context;
|
||||
private final NotificationEventPublisher notificationEventPublisher;
|
||||
private final AppUserRepository appUserRepository;
|
||||
private final UserNotificationService userNotificationService;
|
||||
|
||||
@PostConstruct
|
||||
public void addListeners() {
|
||||
@@ -327,22 +317,7 @@ public class NotificationDomainServiceImpl implements NotificationDomainService
|
||||
private void buildNotification(String permission, String objectType, Long objectIdentifier, String notificationContent,
|
||||
String eventType, Long appUserId, Long officeId) {
|
||||
|
||||
String tenantIdentifier = ThreadLocalContextUtil.getTenant().getTenantIdentifier();
|
||||
Set<Long> userIds = getNotifiableUserIds(officeId, permission);
|
||||
NotificationData notificationData = new NotificationData().setObjectType(objectType).setObjectId(objectIdentifier)
|
||||
.setAction(eventType).setActorId(appUserId).setContent(notificationContent).setRead(false).setSystemGenerated(false)
|
||||
.setTenantIdentifier(tenantIdentifier).setOfficeId(officeId).setUserIds(userIds);
|
||||
try {
|
||||
notificationEventPublisher.broadcastNotification(notificationData);
|
||||
} catch (Exception e) {
|
||||
// We want to avoid rethrowing the exception to stop the business transaction from rolling back
|
||||
log.error("Error while broadcasting notification event", e);
|
||||
}
|
||||
userNotificationService.notifyUsers(permission, objectType, objectIdentifier, notificationContent, eventType, appUserId, officeId);
|
||||
}
|
||||
|
||||
private Set<Long> getNotifiableUserIds(Long officeId, String permission) {
|
||||
Collection<AppUser> users = appUserRepository.findByOfficeId(officeId);
|
||||
Collection<AppUser> usersWithPermission = users.stream().filter(aU -> aU.hasAnyPermission(permission, "ALL_FUNCTIONS")).toList();
|
||||
return usersWithPermission.stream().map(AppUser::getId).collect(toSet());
|
||||
}
|
||||
}
|
||||
|
||||
-3
@@ -22,9 +22,6 @@ import java.util.Collection;
|
||||
|
||||
public interface NotificationWritePlatformService {
|
||||
|
||||
Long notify(Long userId, String objectType, Long objectId, String action, Long actorId, String notificationContent,
|
||||
boolean isSystemGenerated);
|
||||
|
||||
Long notify(Collection<Long> userIds, String objectType, Long objectId, String action, Long actorId, String notificationContent,
|
||||
boolean isSystemGenerated);
|
||||
}
|
||||
|
||||
-20
@@ -40,26 +40,6 @@ public class NotificationWritePlatformServiceImpl implements NotificationWritePl
|
||||
private final AppUserRepository appUserRepository;
|
||||
private final NotificationMapperWritePlatformService notificationMapperWritePlatformService;
|
||||
|
||||
@Override
|
||||
public Long notify(Long userId, String objectType, Long objectIdentifier, String action, Long actorId, String notificationContent,
|
||||
boolean isSystemGenerated) {
|
||||
|
||||
Long generatedNotificationId = insertIntoNotificationGenerator(objectType, objectIdentifier, action, actorId, notificationContent,
|
||||
isSystemGenerated);
|
||||
insertIntoNotificationMapper(userId, generatedNotificationId);
|
||||
return generatedNotificationId;
|
||||
}
|
||||
|
||||
private Long insertIntoNotificationMapper(Long userId, Long generatedNotificationId) {
|
||||
AppUser appUser = this.appUserRepository.findById(userId).orElse(null);
|
||||
NotificationMapper notificationMapper = new NotificationMapper()
|
||||
.setNotification(this.notificationGeneratorReadRepositoryWrapper.findById(generatedNotificationId)).setUserId(appUser)
|
||||
.setRead(false).setCreatedAt(DateUtils.getLocalDateTimeOfSystem());
|
||||
|
||||
this.notificationMapperWritePlatformService.create(notificationMapper);
|
||||
return notificationMapper.getId();
|
||||
}
|
||||
|
||||
private Long insertIntoNotificationGenerator(String objectType, Long objectIdentifier, String action, Long actorId,
|
||||
String notificationContent, boolean isSystemGenerated) {
|
||||
|
||||
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you 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.apache.fineract.notification.service;
|
||||
|
||||
import org.apache.fineract.notification.data.NotificationData;
|
||||
|
||||
public interface UserNotificationService {
|
||||
|
||||
void notifyUsers(String permission, String objectType, Long objectIdentifier, String notificationContent, String eventType,
|
||||
Long appUserId, Long officeId);
|
||||
|
||||
boolean hasUnreadUserNotifications(Long appUserId);
|
||||
|
||||
void notifyUsers(NotificationData notificationData);
|
||||
}
|
||||
+114
@@ -0,0 +1,114 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you 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.apache.fineract.notification.service;
|
||||
|
||||
import static java.util.stream.Collectors.toSet;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.fineract.infrastructure.core.config.FineractProperties;
|
||||
import org.apache.fineract.infrastructure.core.service.ThreadLocalContextUtil;
|
||||
import org.apache.fineract.notification.data.NotificationData;
|
||||
import org.apache.fineract.notification.eventandlistener.NotificationEventPublisher;
|
||||
import org.apache.fineract.useradministration.domain.AppUser;
|
||||
import org.apache.fineract.useradministration.domain.AppUserRepository;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
@Slf4j
|
||||
public class UserNotificationServiceImpl implements UserNotificationService {
|
||||
|
||||
private final NotificationEventPublisher notificationEventPublisher;
|
||||
private final AppUserRepository appUserRepository;
|
||||
private final FineractProperties fineractProperties;
|
||||
private final NotificationReadPlatformService notificationReadPlatformService;
|
||||
private final NotificationWritePlatformService notificationWritePlatformService;
|
||||
|
||||
@Override
|
||||
public void notifyUsers(String permission, String objectType, Long objectIdentifier, String notificationContent, String eventType,
|
||||
Long appUserId, Long officeId) {
|
||||
|
||||
if (userNotificationSystemIsEnabled()) {
|
||||
String tenantIdentifier = ThreadLocalContextUtil.getTenant().getTenantIdentifier();
|
||||
Set<Long> userIds = getNotifiableUserIds(officeId, permission);
|
||||
NotificationData notificationData = new NotificationData().setObjectType(objectType).setObjectId(objectIdentifier)
|
||||
.setAction(eventType).setActorId(appUserId).setContent(notificationContent).setRead(false).setSystemGenerated(false)
|
||||
.setTenantIdentifier(tenantIdentifier).setOfficeId(officeId).setUserIds(userIds);
|
||||
try {
|
||||
notificationEventPublisher.broadcastNotification(notificationData);
|
||||
} catch (Exception e) {
|
||||
// We want to avoid rethrowing the exception to stop the business transaction from rolling back
|
||||
log.error("Error while broadcasting notification event", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasUnreadUserNotifications(Long appUserId) {
|
||||
if (userNotificationSystemIsEnabled()) {
|
||||
return notificationReadPlatformService.hasUnreadNotifications(appUserId);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void notifyUsers(NotificationData notificationData) {
|
||||
if (userNotificationSystemIsEnabled()) {
|
||||
Long appUserId = notificationData.getActorId();
|
||||
|
||||
Set<Long> userIds = notificationData.getUserIds();
|
||||
|
||||
if (notificationData.getOfficeId() != null) {
|
||||
List<Long> tempUserIds = new ArrayList<>(userIds);
|
||||
for (Long userId : tempUserIds) {
|
||||
AppUser appUser = appUserRepository.findById(userId).orElseThrow();
|
||||
if (!Objects.equals(appUser.getOffice().getId(), notificationData.getOfficeId())) {
|
||||
userIds.remove(userId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Don't notify the same user who triggered the event
|
||||
if (userIds.contains(appUserId)) {
|
||||
userIds.remove(appUserId);
|
||||
}
|
||||
|
||||
notificationWritePlatformService.notify(userIds, notificationData.getObjectType(), notificationData.getObjectId(),
|
||||
notificationData.getAction(), notificationData.getActorId(), notificationData.getContent(),
|
||||
notificationData.isSystemGenerated());
|
||||
}
|
||||
}
|
||||
|
||||
private boolean userNotificationSystemIsEnabled() {
|
||||
return fineractProperties.getNotification().getUserNotificationSystem().isEnabled();
|
||||
}
|
||||
|
||||
private Set<Long> getNotifiableUserIds(Long officeId, String permission) {
|
||||
Collection<AppUser> users = appUserRepository.findByOfficeId(officeId);
|
||||
Collection<AppUser> usersWithPermission = users.stream().filter(aU -> aU.hasAnyPermission(permission, "ALL_FUNCTIONS")).toList();
|
||||
return usersWithPermission.stream().map(AppUser::getId).collect(toSet());
|
||||
}
|
||||
}
|
||||
@@ -102,6 +102,8 @@ fineract.report.export.s3.enabled=${FINERACT_REPORT_EXPORT_S3_ENABLED:false}
|
||||
|
||||
fineract.jpa.statementLoggingEnabled=${FINERACT_STATEMENT_LOGGING_ENABLED:false}
|
||||
|
||||
fineract.notification.user-notification-system.enabled=${FINERACT_USER_NOTIFICATION_SYSTEM_ENABLED:true}
|
||||
|
||||
# Logging pattern for the console
|
||||
logging.pattern.console=${CONSOLE_LOG_PATTERN:%clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){faint} %clr(${LOG_LEVEL_PATTERN:-%5p}) %clr(${PID:- }){magenta} %clr(%replace([%X{correlationId}]){'\\[\\]', ''}) %clr(---){faint} %clr([%15.15t]){faint} %clr(%-40.40logger{39}){cyan} %clr(:){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:%wEx}}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user