argos/notification-service/notification/src/main/java/gr/cite/notification/service/userNotificationPreference/UserNotificationPreferenceS...

212 lines
11 KiB
Java

package gr.cite.notification.service.userNotificationPreference;
import gr.cite.commons.web.authz.service.AuthorizationService;
import gr.cite.notification.authorization.OwnedResource;
import gr.cite.notification.authorization.Permission;
import gr.cite.notification.common.enums.IsActive;
import gr.cite.notification.common.enums.NotificationContactType;
import gr.cite.notification.common.types.tenantconfiguration.NotifierListConfigurationDataContainer;
import gr.cite.notification.config.notification.NotificationConfig;
import gr.cite.notification.data.TenantEntityManager;
import gr.cite.notification.data.UserNotificationPreferenceEntity;
import gr.cite.notification.errorcode.ErrorThesaurusProperties;
import gr.cite.notification.model.UserNotificationPreference;
import gr.cite.notification.model.builder.UserNotificationPreferenceBuilder;
import gr.cite.notification.model.persist.UserNotificationPreferencePersist;
import gr.cite.notification.query.UserNotificationPreferenceQuery;
import gr.cite.notification.service.tenantconfiguration.TenantConfigurationService;
import gr.cite.tools.data.builder.BuilderFactory;
import gr.cite.tools.data.query.QueryFactory;
import gr.cite.tools.exception.MyApplicationException;
import gr.cite.tools.exception.MyValidationException;
import gr.cite.tools.fieldset.BaseFieldSet;
import gr.cite.tools.fieldset.FieldSet;
import gr.cite.tools.logging.LoggerService;
import gr.cite.tools.logging.MapLogEntry;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
import org.springframework.web.context.annotation.RequestScope;
import javax.management.InvalidApplicationException;
import java.time.Instant;
import java.util.*;
import java.util.stream.Collectors;
@Service
@RequestScope
public class UserNotificationPreferenceServiceImpl implements UserNotificationPreferenceService{
private static final LoggerService logger = new LoggerService(LoggerFactory.getLogger(UserNotificationPreferenceServiceImpl.class));
private final QueryFactory queryFactory;
private final BuilderFactory builderFactory;
private final AuthorizationService authService;
private final TenantConfigurationService tenantConfigurationService;
private final Map<UUID, List<NotificationContactType>> globalPoliciesMap;
private final ErrorThesaurusProperties errors;
private final TenantEntityManager entityManager;
@Autowired
public UserNotificationPreferenceServiceImpl(QueryFactory queryFactory,
BuilderFactory builderFactory,
AuthorizationService authService,
TenantConfigurationService tenantConfigurationService,
@Qualifier(NotificationConfig.BeanQualifier.GLOBAL_POLICIES_MAP)
Map<UUID, List<NotificationContactType>> globalPoliciesMap,
ErrorThesaurusProperties errors, TenantEntityManager entityManager) {
this.queryFactory = queryFactory;
this.builderFactory = builderFactory;
this.authService = authService;
this.tenantConfigurationService = tenantConfigurationService;
this.globalPoliciesMap = globalPoliciesMap;
this.errors = errors;
this.entityManager = entityManager;
}
@Override
public List<UserNotificationPreference> persist(UserNotificationPreferencePersist model, FieldSet fieldSet) {
logger.debug(new MapLogEntry("persisting").And("model", model).And("fields", fieldSet));
this.authService.authorizeAtLeastOneForce(model.getUserId() != null ? List.of(new OwnedResource(model.getUserId())) : null, Permission.EditUserNotificationPreference);
Map<UUID, List<NotificationContactType>> currentNotificationListPolicies;
NotifierListConfigurationDataContainer tenantNotifierListPolicies = this.tenantConfigurationService.collectTenantNotifierList();
if (tenantNotifierListPolicies != null)
{
currentNotificationListPolicies = mergeNotifierPolicies(tenantNotifierListPolicies.getNotifiers(), this.globalPoliciesMap);
}
else
{
currentNotificationListPolicies = this.globalPoliciesMap;
}
if (model.getNotificationPreferences().entrySet().stream().anyMatch(entry -> model.getNotificationPreferences().get(entry.getKey()).stream().anyMatch(contactType -> !currentNotificationListPolicies.get(entry.getKey()).contains(contactType))))
{
throw new MyValidationException(this.errors.getOverlappingTenantConfigurationNotifierList().getCode(), this.errors.getOverlappingTenantConfigurationNotifierList().getMessage());
}
List<UserNotificationPreferenceEntity> datas = this.patchAndSave(List.of(model));
return this.builderFactory.builder(UserNotificationPreferenceBuilder.class).build(fieldSet, datas);
}
@Override
public NotifierListConfigurationDataContainer collectUserAvailableNotifierList(Set<UUID> notificationTypes) {
Map<UUID, List<NotificationContactType>> currentNotificationListPolicies;
NotifierListConfigurationDataContainer tenantNotifierListPolicies = this.tenantConfigurationService.collectTenantNotifierList();
if (tenantNotifierListPolicies != null)
{
currentNotificationListPolicies = mergeNotifierPolicies(tenantNotifierListPolicies.getNotifiers(), this.globalPoliciesMap);
}
else
{
currentNotificationListPolicies = this.globalPoliciesMap;
}
if (notificationTypes != null && !notificationTypes.isEmpty())
{
return new NotifierListConfigurationDataContainer(currentNotificationListPolicies
.entrySet().stream()
.filter(x -> notificationTypes.contains(x.getKey()))
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)));
}
else return new NotifierListConfigurationDataContainer(currentNotificationListPolicies);
}
@Override
public List<UserNotificationPreference> collectUserNotificationPreferences(UUID id) {
Map<UUID, List<UserNotificationPreference>> result = this.collectUserNotificationPreferences(List.of(id));
if (result != null) {
return result.values().stream().flatMap(Collection::stream).collect(Collectors.toList());
}
logger.error("failed to collect user notification preferences for user " + id);
return new ArrayList<>();
}
@Override
public Map<UUID, List<UserNotificationPreference>> collectUserNotificationPreferences(List<UUID> ids) {
return this.builderFactory.builder(UserNotificationPreferenceBuilder.class)
.build(new BaseFieldSet(UserNotificationPreference._userId, UserNotificationPreference._type,
UserNotificationPreference._channel, UserNotificationPreference._ordinal), this.queryFactory
.query(UserNotificationPreferenceQuery.class)
.userId(ids).collect()).stream().collect(Collectors.groupingBy(UserNotificationPreference::getUserId)); //GK: Yep that exist on JAVA Streams
}
private Map<UUID, List<NotificationContactType>> mergeNotifierPolicies(Map<UUID, List<NotificationContactType>> overrides, Map<UUID, List<NotificationContactType>> bases)
{
Map<UUID, List<NotificationContactType>> mergedPolicies = new HashMap<>();
for(Map.Entry<UUID, List<NotificationContactType>> policyEntry: bases.entrySet())
{
if (overrides.containsKey(policyEntry.getKey()))
{
List<NotificationContactType> notifierList = overrides.get(policyEntry.getKey());
if(notifierList == null) throw new MyApplicationException(this.errors.getSystemError().getCode(), this.errors.getSystemError().getMessage());
mergedPolicies.put(policyEntry.getKey(), notifierList);
}
else
{
mergedPolicies.put(policyEntry.getKey(), policyEntry.getValue());
}
}
return mergedPolicies;
}
private List<UserNotificationPreferenceEntity> patchAndSave(List<UserNotificationPreferencePersist> models)
{
List<UserNotificationPreferenceEntity> datas = new ArrayList<>();
for (UserNotificationPreferencePersist model: models)
{
for (Map.Entry<UUID, List<NotificationContactType>> notificationPreference: model.getNotificationPreferences().entrySet())
{
this.patchAndSave(model.getUserId(), notificationPreference.getKey(), notificationPreference.getValue());
}
}
return datas;
}
private List<UserNotificationPreferenceEntity> patchAndSave(UUID userId, UUID type, List<NotificationContactType> contactTypes)
{
List<UserNotificationPreferenceEntity> preferences = null;
try {
preferences = this.queryFactory
.query(UserNotificationPreferenceQuery.class)
.type(type)
.isActives(IsActive.Active)
.userId(userId).collect();
int ordinal = 0;
List<UserNotificationPreferenceEntity> updatedPreferences = new ArrayList<>();
for (NotificationContactType contactType : contactTypes) {
UserNotificationPreferenceEntity preference = preferences.stream().filter(x -> x.getChannel() == contactType).findFirst().orElse(null);
boolean isUpdate = preference != null;
if (preference != null) {
preference.setOrdinal(ordinal);
} else {
preference = new UserNotificationPreferenceEntity();
preference.setUserId(userId);
preference.setType(type);
preference.setOrdinal(ordinal);
preference.setChannel(contactType);
preference.setCreatedAt(Instant.now());
preference.setIsActive(IsActive.Active);
}
preference.setUpdatedAt(Instant.now());
if(isUpdate) this.entityManager.merge(preference);
else this.entityManager.persist(preference);
updatedPreferences.add(preference);
ordinal++;
}
List<UserNotificationPreferenceEntity> toDelete = preferences.stream().filter(x -> !updatedPreferences.stream().map(y-> y.getChannel()).collect(Collectors.toList()).contains(x.getChannel())).collect(Collectors.toList());
for (UserNotificationPreferenceEntity deletable: toDelete) {
this.entityManager.remove(deletable);
}
} catch (InvalidApplicationException e) {
logger.error(e.getMessage(), e);
}
return preferences;
}
}