Merge branch 'dmp-refactoring' of https://code-repo.d4science.org/MaDgiK-CITE/argos into dmp-refactoring
This commit is contained in:
commit
d94759ff5d
|
@ -4,6 +4,7 @@ import gr.cite.annotation.common.JsonHandlingService;
|
||||||
import gr.cite.annotation.common.enums.IsActive;
|
import gr.cite.annotation.common.enums.IsActive;
|
||||||
import gr.cite.annotation.common.scope.fake.FakeRequestScope;
|
import gr.cite.annotation.common.scope.fake.FakeRequestScope;
|
||||||
import gr.cite.annotation.data.QueueInboxEntity;
|
import gr.cite.annotation.data.QueueInboxEntity;
|
||||||
|
import gr.cite.annotation.data.TenantEntityManager;
|
||||||
import gr.cite.annotation.integrationevent.TrackedEvent;
|
import gr.cite.annotation.integrationevent.TrackedEvent;
|
||||||
import gr.cite.annotation.integrationevent.inbox.annotationentitiesremoval.AnnotationEntitiesRemovalIntegrationEventHandler;
|
import gr.cite.annotation.integrationevent.inbox.annotationentitiesremoval.AnnotationEntitiesRemovalIntegrationEventHandler;
|
||||||
import gr.cite.annotation.integrationevent.inbox.annotationentitiestouch.AnnotationEntitiesTouchedIntegrationEventHandler;
|
import gr.cite.annotation.integrationevent.inbox.annotationentitiestouch.AnnotationEntitiesTouchedIntegrationEventHandler;
|
||||||
|
@ -278,6 +279,10 @@ public class InboxRepositoryImpl implements InboxRepository {
|
||||||
|
|
||||||
entityManager = entityManagerFactory.createEntityManager();
|
entityManager = entityManagerFactory.createEntityManager();
|
||||||
transaction = entityManager.getTransaction();
|
transaction = entityManager.getTransaction();
|
||||||
|
|
||||||
|
TenantEntityManager tenantEntityManager = this.applicationContext.getBean(TenantEntityManager.class);
|
||||||
|
tenantEntityManager.setEntityManager(entityManager);
|
||||||
|
|
||||||
transaction.begin();
|
transaction.begin();
|
||||||
|
|
||||||
QueryFactory queryFactory = this.applicationContext.getBean(QueryFactory.class);
|
QueryFactory queryFactory = this.applicationContext.getBean(QueryFactory.class);
|
||||||
|
|
|
@ -32,6 +32,7 @@ import org.springframework.context.ApplicationContext;
|
||||||
import org.springframework.context.annotation.Scope;
|
import org.springframework.context.annotation.Scope;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import javax.management.InvalidApplicationException;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
@Component
|
@Component
|
||||||
|
@ -44,15 +45,26 @@ public class AnnotationEntitiesRemovalIntegrationEventHandlerImpl implements Ann
|
||||||
|
|
||||||
private final ValidatorFactory validatorFactory;
|
private final ValidatorFactory validatorFactory;
|
||||||
|
|
||||||
private final ApplicationContext applicationContext;
|
|
||||||
|
|
||||||
private final QueryFactory queryFactory;
|
private final QueryFactory queryFactory;
|
||||||
|
private final CurrentPrincipalResolver currentPrincipalResolver;
|
||||||
|
private final ClaimExtractorProperties claimExtractorProperties;
|
||||||
|
private final AuditService auditService;
|
||||||
|
private final TenantEntityManager tenantEntityManager;
|
||||||
|
private final DeleterFactory deleterFactory;
|
||||||
|
private final TenantScope tenantScope;
|
||||||
|
|
||||||
public AnnotationEntitiesRemovalIntegrationEventHandlerImpl(JsonHandlingService jsonHandlingService, ValidatorFactory validatorFactory, ApplicationContext applicationContext, QueryFactory queryFactory) {
|
|
||||||
|
public AnnotationEntitiesRemovalIntegrationEventHandlerImpl(JsonHandlingService jsonHandlingService, ValidatorFactory validatorFactory, QueryFactory queryFactory, CurrentPrincipalResolver currentPrincipalResolver, ClaimExtractorProperties claimExtractorProperties, AuditService auditService, TenantEntityManager tenantEntityManager, DeleterFactory deleterFactory, TenantScope tenantScope) {
|
||||||
this.jsonHandlingService = jsonHandlingService;
|
this.jsonHandlingService = jsonHandlingService;
|
||||||
this.validatorFactory = validatorFactory;
|
this.validatorFactory = validatorFactory;
|
||||||
this.applicationContext = applicationContext;
|
|
||||||
this.queryFactory = queryFactory;
|
this.queryFactory = queryFactory;
|
||||||
|
this.currentPrincipalResolver = currentPrincipalResolver;
|
||||||
|
this.claimExtractorProperties = claimExtractorProperties;
|
||||||
|
this.auditService = auditService;
|
||||||
|
this.tenantEntityManager = tenantEntityManager;
|
||||||
|
this.deleterFactory = deleterFactory;
|
||||||
|
this.tenantScope = tenantScope;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -65,41 +77,25 @@ public class AnnotationEntitiesRemovalIntegrationEventHandlerImpl implements Ann
|
||||||
|
|
||||||
this.validatorFactory.validator(AnnotationEntitiesRemovalIntegrationEvent.AnnotationEntitiesRemovalIntegrationEventValidator.class).validateForce(event);
|
this.validatorFactory.validator(AnnotationEntitiesRemovalIntegrationEvent.AnnotationEntitiesRemovalIntegrationEventValidator.class).validateForce(event);
|
||||||
|
|
||||||
EntityManager entityManager = null;
|
EventProcessingStatus status = EventProcessingStatus.Success;
|
||||||
EntityTransaction transaction = null;
|
|
||||||
try (FakeRequestScope ignored = new FakeRequestScope()) {
|
|
||||||
try {
|
try {
|
||||||
TenantScope scope = this.applicationContext.getBean(TenantScope.class);
|
if (this.tenantScope.isMultitenant() && properties.getTenantId() != null) {
|
||||||
if (scope.isMultitenant() && properties.getTenantId() != null) {
|
|
||||||
TenantEntity tenant = queryFactory.query(TenantQuery.class).ids(properties.getTenantId()).firstAs(new BaseFieldSet().ensure(Tenant._id).ensure(Tenant._code));
|
TenantEntity tenant = queryFactory.query(TenantQuery.class).ids(properties.getTenantId()).firstAs(new BaseFieldSet().ensure(Tenant._id).ensure(Tenant._code));
|
||||||
if (tenant == null) {
|
if (tenant == null) {
|
||||||
logger.error("missing tenant from event message");
|
logger.error("missing tenant from event message");
|
||||||
return EventProcessingStatus.Error;
|
return EventProcessingStatus.Error;
|
||||||
}
|
}
|
||||||
scope.setTenant(properties.getTenantId(), tenant.getCode());
|
this.tenantScope.setTempTenant(tenantEntityManager.getEntityManager(), properties.getTenantId(), tenant.getCode());
|
||||||
} else if (scope.isMultitenant()) {
|
} else if (this.tenantScope.isMultitenant()) {
|
||||||
// logger.error("missing tenant from event message");
|
// logger.error("missing tenant from event message");
|
||||||
// return EventProcessingStatus.Error;
|
// return EventProcessingStatus.Error;
|
||||||
scope.setTenant(null, scope.getDefaultTenantCode());
|
this.tenantScope.setTempTenant(tenantEntityManager.getEntityManager(), null, this.tenantScope.getDefaultTenantCode());
|
||||||
}
|
}
|
||||||
|
|
||||||
CurrentPrincipalResolver currentPrincipalResolver = this.applicationContext.getBean(CurrentPrincipalResolver.class);
|
|
||||||
|
|
||||||
ClaimExtractorProperties claimExtractorProperties = this.applicationContext.getBean(ClaimExtractorProperties.class);
|
|
||||||
currentPrincipalResolver.push(InboxPrincipal.build(properties, claimExtractorProperties));
|
currentPrincipalResolver.push(InboxPrincipal.build(properties, claimExtractorProperties));
|
||||||
|
|
||||||
EntityManagerFactory entityManagerFactory = this.applicationContext.getBean(EntityManagerFactory.class);
|
|
||||||
entityManager = entityManagerFactory.createEntityManager();
|
|
||||||
|
|
||||||
DeleterFactory deleterFactory = this.applicationContext.getBean(DeleterFactory.class);
|
|
||||||
|
|
||||||
transaction = entityManager.getTransaction();
|
|
||||||
transaction.begin();
|
|
||||||
|
|
||||||
try {
|
|
||||||
|
|
||||||
TenantEntityManager tenantEntityManager = this.applicationContext.getBean(TenantEntityManager.class);
|
|
||||||
tenantEntityManager.setEntityManager(entityManager);
|
|
||||||
tenantEntityManager.disableTenantFilters();
|
tenantEntityManager.disableTenantFilters();
|
||||||
EntityUserQuery entityUserQuery = this.queryFactory.query(EntityUserQuery.class);
|
EntityUserQuery entityUserQuery = this.queryFactory.query(EntityUserQuery.class);
|
||||||
List<EntityUserEntity> items = entityUserQuery
|
List<EntityUserEntity> items = entityUserQuery
|
||||||
|
@ -110,38 +106,24 @@ public class AnnotationEntitiesRemovalIntegrationEventHandlerImpl implements Ann
|
||||||
|
|
||||||
deleterFactory.deleter(gr.cite.EntityUser.model.deleter.EntityUserDeleter.class).delete(items);
|
deleterFactory.deleter(gr.cite.EntityUser.model.deleter.EntityUserDeleter.class).delete(items);
|
||||||
|
|
||||||
entityManager.flush();
|
|
||||||
|
|
||||||
AuditService auditService = this.applicationContext.getBean(AuditService.class);
|
|
||||||
|
|
||||||
auditService.track(AuditableAction.User_Persist, Map.ofEntries(
|
auditService.track(AuditableAction.User_Persist, Map.ofEntries(
|
||||||
new AbstractMap.SimpleEntry<String, Object>("model", event)
|
new AbstractMap.SimpleEntry<String, Object>("model", event)
|
||||||
));
|
));
|
||||||
|
|
||||||
transaction.commit();
|
|
||||||
} catch (Exception e) {
|
} catch (Exception ex) {
|
||||||
transaction.rollback();
|
status = EventProcessingStatus.Error;
|
||||||
throw e;
|
logger.error("Problem getting list of queue outbox. Skipping: {}", ex.getMessage(), ex);
|
||||||
} finally {
|
} finally {
|
||||||
currentPrincipalResolver.pop();
|
currentPrincipalResolver.pop();
|
||||||
|
tenantScope.removeTempTenant(this.tenantEntityManager.getEntityManager());
|
||||||
|
try {
|
||||||
|
this.tenantEntityManager.enableTenantFilters();
|
||||||
|
} catch (InvalidApplicationException e) {
|
||||||
}
|
}
|
||||||
} catch (OptimisticLockException ex) {
|
|
||||||
// we get this if/when someone else already modified the notifications. We want to essentially ignore this, and keep working
|
|
||||||
logger.debug("Concurrency exception getting queue outbox. Skipping: {} ", ex.getMessage());
|
|
||||||
if (transaction != null)
|
|
||||||
transaction.rollback();
|
|
||||||
} catch (Exception ex) {
|
|
||||||
logger.error("Problem getting list of queue outbox. Skipping: {}", ex.getMessage(), ex);
|
|
||||||
if (transaction != null)
|
|
||||||
transaction.rollback();
|
|
||||||
} finally {
|
|
||||||
if (entityManager != null)
|
|
||||||
entityManager.close();
|
|
||||||
}
|
}
|
||||||
} catch (Exception ex) {
|
return status;
|
||||||
logger.error("Problem getting list of queue outbox. Skipping: {}", ex.getMessage(), ex);
|
|
||||||
}
|
|
||||||
return EventProcessingStatus.Success;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,6 +14,7 @@ import gr.cite.annotation.integrationevent.inbox.IntegrationEventProperties;
|
||||||
import gr.cite.annotation.model.Tenant;
|
import gr.cite.annotation.model.Tenant;
|
||||||
import gr.cite.annotation.query.EntityUserQuery;
|
import gr.cite.annotation.query.EntityUserQuery;
|
||||||
import gr.cite.annotation.query.TenantQuery;
|
import gr.cite.annotation.query.TenantQuery;
|
||||||
|
import gr.cite.annotation.service.tenant.TenantService;
|
||||||
import gr.cite.commons.web.oidc.principal.CurrentPrincipalResolver;
|
import gr.cite.commons.web.oidc.principal.CurrentPrincipalResolver;
|
||||||
import gr.cite.commons.web.oidc.principal.extractor.ClaimExtractorProperties;
|
import gr.cite.commons.web.oidc.principal.extractor.ClaimExtractorProperties;
|
||||||
import gr.cite.tools.auditing.AuditService;
|
import gr.cite.tools.auditing.AuditService;
|
||||||
|
@ -32,6 +33,7 @@ import org.springframework.context.ApplicationContext;
|
||||||
import org.springframework.context.annotation.Scope;
|
import org.springframework.context.annotation.Scope;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import javax.management.InvalidApplicationException;
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
@ -46,15 +48,24 @@ public class AnnotationEntitiesTouchedIntegrationEventHandlerImpl implements Ann
|
||||||
|
|
||||||
private final ValidatorFactory validatorFactory;
|
private final ValidatorFactory validatorFactory;
|
||||||
|
|
||||||
private final ApplicationContext applicationContext;
|
|
||||||
|
|
||||||
private final QueryFactory queryFactory;
|
private final QueryFactory queryFactory;
|
||||||
|
private final CurrentPrincipalResolver currentPrincipalResolver;
|
||||||
|
private final ClaimExtractorProperties claimExtractorProperties;
|
||||||
|
private final AuditService auditService;
|
||||||
|
private final TenantEntityManager tenantEntityManager;
|
||||||
|
private final DeleterFactory deleterFactory;
|
||||||
|
private final TenantScope tenantScope;
|
||||||
|
|
||||||
public AnnotationEntitiesTouchedIntegrationEventHandlerImpl(JsonHandlingService jsonHandlingService, ValidatorFactory validatorFactory, ApplicationContext applicationContext, QueryFactory queryFactory) {
|
public AnnotationEntitiesTouchedIntegrationEventHandlerImpl(JsonHandlingService jsonHandlingService, ValidatorFactory validatorFactory, QueryFactory queryFactory, CurrentPrincipalResolver currentPrincipalResolver, ClaimExtractorProperties claimExtractorProperties, AuditService auditService, TenantEntityManager tenantEntityManager, DeleterFactory deleterFactory, TenantScope tenantScope) {
|
||||||
this.jsonHandlingService = jsonHandlingService;
|
this.jsonHandlingService = jsonHandlingService;
|
||||||
this.validatorFactory = validatorFactory;
|
this.validatorFactory = validatorFactory;
|
||||||
this.applicationContext = applicationContext;
|
this.currentPrincipalResolver = currentPrincipalResolver;
|
||||||
|
this.claimExtractorProperties = claimExtractorProperties;
|
||||||
|
this.auditService = auditService;
|
||||||
|
this.tenantEntityManager = tenantEntityManager;
|
||||||
this.queryFactory = queryFactory;
|
this.queryFactory = queryFactory;
|
||||||
|
this.deleterFactory = deleterFactory;
|
||||||
|
this.tenantScope = tenantScope;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -67,40 +78,23 @@ public class AnnotationEntitiesTouchedIntegrationEventHandlerImpl implements Ann
|
||||||
|
|
||||||
this.validatorFactory.validator(AnnotationEntitiesTouchedIntegrationEvent.AnnotationEntitiesTouchedIntegrationEventValidator.class).validateForce(event);
|
this.validatorFactory.validator(AnnotationEntitiesTouchedIntegrationEvent.AnnotationEntitiesTouchedIntegrationEventValidator.class).validateForce(event);
|
||||||
|
|
||||||
EntityManager entityManager = null;
|
EventProcessingStatus status = EventProcessingStatus.Success;
|
||||||
EntityTransaction transaction = null;
|
|
||||||
try (FakeRequestScope ignored = new FakeRequestScope()) {
|
|
||||||
try {
|
try {
|
||||||
TenantScope scope = this.applicationContext.getBean(TenantScope.class);
|
if (this.tenantScope.isMultitenant() && properties.getTenantId() != null) {
|
||||||
if (scope.isMultitenant() && properties.getTenantId() != null) {
|
|
||||||
TenantEntity tenant = queryFactory.query(TenantQuery.class).ids(properties.getTenantId()).firstAs(new BaseFieldSet().ensure(Tenant._id).ensure(Tenant._code));
|
TenantEntity tenant = queryFactory.query(TenantQuery.class).ids(properties.getTenantId()).firstAs(new BaseFieldSet().ensure(Tenant._id).ensure(Tenant._code));
|
||||||
if (tenant == null) {
|
if (tenant == null) {
|
||||||
logger.error("missing tenant from event message");
|
logger.error("missing tenant from event message");
|
||||||
return EventProcessingStatus.Error;
|
return EventProcessingStatus.Error;
|
||||||
}
|
}
|
||||||
scope.setTenant(properties.getTenantId(), tenant.getCode());
|
this.tenantScope.setTempTenant(tenantEntityManager.getEntityManager(), properties.getTenantId(), tenant.getCode());
|
||||||
} else if (scope.isMultitenant()) {
|
} else if (this.tenantScope.isMultitenant()) {
|
||||||
// logger.error("missing tenant from event message");
|
// logger.error("missing tenant from event message");
|
||||||
// return EventProcessingStatus.Error;
|
// return EventProcessingStatus.Error;
|
||||||
scope.setTenant(null, scope.getDefaultTenantCode());
|
this.tenantScope.setTempTenant(tenantEntityManager.getEntityManager(), null, this.tenantScope.getDefaultTenantCode());
|
||||||
}
|
}
|
||||||
|
|
||||||
CurrentPrincipalResolver currentPrincipalResolver = this.applicationContext.getBean(CurrentPrincipalResolver.class);
|
|
||||||
|
|
||||||
ClaimExtractorProperties claimExtractorProperties = this.applicationContext.getBean(ClaimExtractorProperties.class);
|
|
||||||
currentPrincipalResolver.push(InboxPrincipal.build(properties, claimExtractorProperties));
|
currentPrincipalResolver.push(InboxPrincipal.build(properties, claimExtractorProperties));
|
||||||
|
|
||||||
EntityManagerFactory entityManagerFactory = this.applicationContext.getBean(EntityManagerFactory.class);
|
|
||||||
entityManager = entityManagerFactory.createEntityManager();
|
|
||||||
|
|
||||||
DeleterFactory deleterFactory = this.applicationContext.getBean(DeleterFactory.class);
|
|
||||||
|
|
||||||
transaction = entityManager.getTransaction();
|
|
||||||
transaction.begin();
|
|
||||||
|
|
||||||
try {
|
|
||||||
TenantEntityManager tenantEntityManager = this.applicationContext.getBean(TenantEntityManager.class);
|
|
||||||
tenantEntityManager.setEntityManager(entityManager);
|
|
||||||
tenantEntityManager.disableTenantFilters();
|
tenantEntityManager.disableTenantFilters();
|
||||||
for (AnnotationEntitiesTouchedIntegrationEvent.AnnotationEntityTouchedIntegrationEvent entityEvent : event.getEvents()) {
|
for (AnnotationEntitiesTouchedIntegrationEvent.AnnotationEntityTouchedIntegrationEvent entityEvent : event.getEvents()) {
|
||||||
|
|
||||||
|
@ -122,7 +116,6 @@ public class AnnotationEntitiesTouchedIntegrationEventHandlerImpl implements Ann
|
||||||
data.setUpdatedAt(Instant.now());
|
data.setUpdatedAt(Instant.now());
|
||||||
data.setIsActive(IsActive.Active);
|
data.setIsActive(IsActive.Active);
|
||||||
|
|
||||||
entityManager.persist(data);
|
|
||||||
}
|
}
|
||||||
updatedCreatedIds.add(data.getId());
|
updatedCreatedIds.add(data.getId());
|
||||||
}
|
}
|
||||||
|
@ -130,39 +123,27 @@ public class AnnotationEntitiesTouchedIntegrationEventHandlerImpl implements Ann
|
||||||
List<EntityUserEntity> toDelete = items.stream().filter(x -> updatedCreatedIds.stream().noneMatch(y -> y.equals(x.getId()))).collect(Collectors.toList());
|
List<EntityUserEntity> toDelete = items.stream().filter(x -> updatedCreatedIds.stream().noneMatch(y -> y.equals(x.getId()))).collect(Collectors.toList());
|
||||||
deleterFactory.deleter(gr.cite.EntityUser.model.deleter.EntityUserDeleter.class).delete(toDelete);
|
deleterFactory.deleter(gr.cite.EntityUser.model.deleter.EntityUserDeleter.class).delete(toDelete);
|
||||||
|
|
||||||
entityManager.flush();
|
tenantEntityManager.flush();
|
||||||
}
|
|
||||||
|
|
||||||
AuditService auditService = this.applicationContext.getBean(AuditService.class);
|
|
||||||
|
|
||||||
auditService.track(AuditableAction.User_Persist, Map.ofEntries(
|
auditService.track(AuditableAction.User_Persist, Map.ofEntries(
|
||||||
new AbstractMap.SimpleEntry<String, Object>("model", event)
|
new AbstractMap.SimpleEntry<String, Object>("model", event)
|
||||||
));
|
));
|
||||||
|
}
|
||||||
|
|
||||||
transaction.commit();
|
} catch (Exception ex) {
|
||||||
} catch (Exception e) {
|
status = EventProcessingStatus.Error;
|
||||||
transaction.rollback();
|
logger.error("Problem getting list of queue outbox. Skipping: {}", ex.getMessage(), ex);
|
||||||
throw e;
|
|
||||||
} finally {
|
} finally {
|
||||||
currentPrincipalResolver.pop();
|
currentPrincipalResolver.pop();
|
||||||
|
tenantScope.removeTempTenant(this.tenantEntityManager.getEntityManager());
|
||||||
|
try {
|
||||||
|
this.tenantEntityManager.enableTenantFilters();
|
||||||
|
} catch (InvalidApplicationException e) {
|
||||||
}
|
}
|
||||||
} catch (OptimisticLockException ex) {
|
|
||||||
// we get this if/when someone else already modified the notifications. We want to essentially ignore this, and keep working
|
|
||||||
logger.debug("Concurrency exception getting queue outbox. Skipping: {} ", ex.getMessage());
|
|
||||||
if (transaction != null)
|
|
||||||
transaction.rollback();
|
|
||||||
} catch (Exception ex) {
|
|
||||||
logger.error("Problem getting list of queue outbox. Skipping: {}", ex.getMessage(), ex);
|
|
||||||
if (transaction != null)
|
|
||||||
transaction.rollback();
|
|
||||||
} finally {
|
|
||||||
if (entityManager != null)
|
|
||||||
entityManager.close();
|
|
||||||
}
|
}
|
||||||
} catch (Exception ex) {
|
|
||||||
logger.error("Problem getting list of queue outbox. Skipping: {}", ex.getMessage(), ex);
|
return status;
|
||||||
}
|
|
||||||
return EventProcessingStatus.Success;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,26 +1,18 @@
|
||||||
package gr.cite.annotation.integrationevent.inbox.tenantremoval;
|
package gr.cite.annotation.integrationevent.inbox.tenantremoval;
|
||||||
|
|
||||||
import gr.cite.annotation.data.TenantEntityManager;
|
|
||||||
import gr.cite.commons.web.oidc.principal.CurrentPrincipalResolver;
|
|
||||||
import gr.cite.annotation.audit.AuditableAction;
|
import gr.cite.annotation.audit.AuditableAction;
|
||||||
import gr.cite.annotation.common.JsonHandlingService;
|
import gr.cite.annotation.common.JsonHandlingService;
|
||||||
import gr.cite.annotation.common.scope.fake.FakeRequestScope;
|
import gr.cite.annotation.data.TenantEntityManager;
|
||||||
import gr.cite.annotation.errorcode.ErrorThesaurusProperties;
|
|
||||||
import gr.cite.annotation.integrationevent.inbox.EventProcessingStatus;
|
import gr.cite.annotation.integrationevent.inbox.EventProcessingStatus;
|
||||||
import gr.cite.annotation.integrationevent.inbox.InboxPrincipal;
|
import gr.cite.annotation.integrationevent.inbox.InboxPrincipal;
|
||||||
import gr.cite.annotation.integrationevent.inbox.IntegrationEventProperties;
|
import gr.cite.annotation.integrationevent.inbox.IntegrationEventProperties;
|
||||||
import gr.cite.annotation.service.tenant.TenantService;
|
import gr.cite.annotation.service.tenant.TenantService;
|
||||||
|
import gr.cite.commons.web.oidc.principal.CurrentPrincipalResolver;
|
||||||
import gr.cite.commons.web.oidc.principal.extractor.ClaimExtractorProperties;
|
import gr.cite.commons.web.oidc.principal.extractor.ClaimExtractorProperties;
|
||||||
import gr.cite.tools.auditing.AuditService;
|
import gr.cite.tools.auditing.AuditService;
|
||||||
import gr.cite.tools.logging.LoggerService;
|
import gr.cite.tools.logging.LoggerService;
|
||||||
import jakarta.persistence.EntityManager;
|
|
||||||
import jakarta.persistence.EntityManagerFactory;
|
|
||||||
import jakarta.persistence.EntityTransaction;
|
|
||||||
import jakarta.persistence.OptimisticLockException;
|
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
|
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
|
||||||
import org.springframework.context.ApplicationContext;
|
|
||||||
import org.springframework.context.MessageSource;
|
|
||||||
import org.springframework.context.annotation.Scope;
|
import org.springframework.context.annotation.Scope;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
@ -34,13 +26,20 @@ public class TenantRemovalIntegrationEventHandlerImpl implements TenantRemovalIn
|
||||||
private static final LoggerService logger = new LoggerService(LoggerFactory.getLogger(TenantRemovalIntegrationEventHandlerImpl.class));
|
private static final LoggerService logger = new LoggerService(LoggerFactory.getLogger(TenantRemovalIntegrationEventHandlerImpl.class));
|
||||||
|
|
||||||
private final JsonHandlingService jsonHandlingService;
|
private final JsonHandlingService jsonHandlingService;
|
||||||
|
private final CurrentPrincipalResolver currentPrincipalResolver;
|
||||||
private final ApplicationContext applicationContext;
|
private final ClaimExtractorProperties claimExtractorProperties;
|
||||||
|
private final TenantService tenantService;
|
||||||
|
private final AuditService auditService;
|
||||||
public TenantRemovalIntegrationEventHandlerImpl(JsonHandlingService jsonHandlingService, ApplicationContext applicationContext) {
|
private final TenantEntityManager tenantEntityManager;
|
||||||
|
private final TenantRemovalConsistencyHandler tenantRemovalConsistencyHandler;
|
||||||
|
public TenantRemovalIntegrationEventHandlerImpl(JsonHandlingService jsonHandlingService, CurrentPrincipalResolver currentPrincipalResolver, ClaimExtractorProperties claimExtractorProperties, TenantService tenantService, AuditService auditService, TenantEntityManager tenantEntityManager, TenantRemovalConsistencyHandler tenantRemovalConsistencyHandler) {
|
||||||
this.jsonHandlingService = jsonHandlingService;
|
this.jsonHandlingService = jsonHandlingService;
|
||||||
this.applicationContext = applicationContext;
|
this.currentPrincipalResolver = currentPrincipalResolver;
|
||||||
|
this.claimExtractorProperties = claimExtractorProperties;
|
||||||
|
this.tenantService = tenantService;
|
||||||
|
this.auditService = auditService;
|
||||||
|
this.tenantEntityManager = tenantEntityManager;
|
||||||
|
this.tenantRemovalConsistencyHandler = tenantRemovalConsistencyHandler;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -49,65 +48,34 @@ public class TenantRemovalIntegrationEventHandlerImpl implements TenantRemovalIn
|
||||||
if (event == null)
|
if (event == null)
|
||||||
return EventProcessingStatus.Error;
|
return EventProcessingStatus.Error;
|
||||||
|
|
||||||
EntityManager entityManager = null;
|
EventProcessingStatus status = EventProcessingStatus.Success;
|
||||||
EntityTransaction transaction = null;
|
|
||||||
try (FakeRequestScope ignored = new FakeRequestScope()) {
|
|
||||||
try {
|
try {
|
||||||
CurrentPrincipalResolver currentPrincipalResolver = this.applicationContext.getBean(CurrentPrincipalResolver.class);
|
|
||||||
|
|
||||||
ClaimExtractorProperties claimExtractorProperties = this.applicationContext.getBean(ClaimExtractorProperties.class);
|
|
||||||
currentPrincipalResolver.push(InboxPrincipal.build(properties, claimExtractorProperties));
|
currentPrincipalResolver.push(InboxPrincipal.build(properties, claimExtractorProperties));
|
||||||
|
|
||||||
TenantRemovalConsistencyHandler tenantRemovalConsistencyHandler = this.applicationContext.getBean(TenantRemovalConsistencyHandler.class);
|
if (!(tenantRemovalConsistencyHandler.isConsistent(new TenantRemovalConsistencyPredicates(event.getId())))) {
|
||||||
if (!(tenantRemovalConsistencyHandler.isConsistent(new TenantRemovalConsistencyPredicates(event.getId()))))
|
status = EventProcessingStatus.Postponed;
|
||||||
return EventProcessingStatus.Postponed;
|
currentPrincipalResolver.pop();
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
EntityManagerFactory entityManagerFactory = this.applicationContext.getBean(EntityManagerFactory.class);
|
|
||||||
entityManager = entityManagerFactory.createEntityManager();
|
|
||||||
|
|
||||||
transaction = entityManager.getTransaction();
|
|
||||||
transaction.begin();
|
|
||||||
|
|
||||||
try {
|
|
||||||
TenantEntityManager tenantEntityManager = this.applicationContext.getBean(TenantEntityManager.class);
|
|
||||||
tenantEntityManager.setEntityManager(entityManager);
|
|
||||||
tenantEntityManager.disableTenantFilters();
|
tenantEntityManager.disableTenantFilters();
|
||||||
TenantService tenantService = this.applicationContext.getBean(TenantService.class);
|
|
||||||
tenantService.deleteAndSave(event.getId());
|
tenantService.deleteAndSave(event.getId());
|
||||||
|
|
||||||
AuditService auditService = this.applicationContext.getBean(AuditService.class);
|
|
||||||
|
|
||||||
auditService.track(AuditableAction.Tenant_Delete, Map.ofEntries(
|
auditService.track(AuditableAction.Tenant_Delete, Map.ofEntries(
|
||||||
new AbstractMap.SimpleEntry<String, Object>("id", event.getId())
|
new AbstractMap.SimpleEntry<String, Object>("id", event.getId())
|
||||||
));
|
));
|
||||||
//auditService.trackIdentity(AuditableAction.IdentityTracking_Action);
|
//auditService.trackIdentity(AuditableAction.IdentityTracking_Action);
|
||||||
|
|
||||||
transaction.commit();
|
|
||||||
} catch (Exception e) {
|
} catch (Exception ex) {
|
||||||
transaction.rollback();
|
status = EventProcessingStatus.Error;
|
||||||
throw e;
|
logger.error("Problem getting list of queue outbox. Skipping: {}", ex.getMessage(), ex);
|
||||||
} finally {
|
} finally {
|
||||||
currentPrincipalResolver.pop();
|
currentPrincipalResolver.pop();
|
||||||
}
|
}
|
||||||
|
return status;
|
||||||
transaction.commit();
|
|
||||||
} catch (OptimisticLockException ex) {
|
|
||||||
// we get this if/when someone else already modified the notifications. We want to essentially ignore this, and keep working
|
|
||||||
logger.debug("Concurrency exception getting queue outbox. Skipping: {} ", ex.getMessage());
|
|
||||||
if (transaction != null)
|
|
||||||
transaction.rollback();
|
|
||||||
} catch (Exception ex) {
|
|
||||||
logger.error("Problem getting list of queue outbox. Skipping: {}", ex.getMessage(), ex);
|
|
||||||
if (transaction != null)
|
|
||||||
transaction.rollback();
|
|
||||||
} finally {
|
|
||||||
if (entityManager != null)
|
|
||||||
entityManager.close();
|
|
||||||
}
|
|
||||||
} catch (Exception ex) {
|
|
||||||
logger.error("Problem getting list of queue outbox. Skipping: {}", ex.getMessage(), ex);
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,27 +1,20 @@
|
||||||
package gr.cite.annotation.integrationevent.inbox.tenanttouch;
|
package gr.cite.annotation.integrationevent.inbox.tenanttouch;
|
||||||
|
|
||||||
import gr.cite.annotation.data.TenantEntityManager;
|
|
||||||
import gr.cite.commons.web.oidc.principal.CurrentPrincipalResolver;
|
|
||||||
import gr.cite.annotation.audit.AuditableAction;
|
import gr.cite.annotation.audit.AuditableAction;
|
||||||
import gr.cite.annotation.common.JsonHandlingService;
|
import gr.cite.annotation.common.JsonHandlingService;
|
||||||
import gr.cite.annotation.common.scope.fake.FakeRequestScope;
|
import gr.cite.annotation.data.TenantEntityManager;
|
||||||
import gr.cite.annotation.integrationevent.inbox.EventProcessingStatus;
|
import gr.cite.annotation.integrationevent.inbox.EventProcessingStatus;
|
||||||
import gr.cite.annotation.integrationevent.inbox.InboxPrincipal;
|
import gr.cite.annotation.integrationevent.inbox.InboxPrincipal;
|
||||||
import gr.cite.annotation.integrationevent.inbox.IntegrationEventProperties;
|
import gr.cite.annotation.integrationevent.inbox.IntegrationEventProperties;
|
||||||
import gr.cite.annotation.model.persist.TenantTouchedIntegrationEventPersist;
|
import gr.cite.annotation.model.persist.TenantTouchedIntegrationEventPersist;
|
||||||
import gr.cite.annotation.service.tenant.TenantService;
|
import gr.cite.annotation.service.tenant.TenantService;
|
||||||
import gr.cite.commons.web.oidc.principal.extractor.ClaimExtractor;
|
import gr.cite.commons.web.oidc.principal.CurrentPrincipalResolver;
|
||||||
import gr.cite.commons.web.oidc.principal.extractor.ClaimExtractorProperties;
|
import gr.cite.commons.web.oidc.principal.extractor.ClaimExtractorProperties;
|
||||||
import gr.cite.tools.auditing.AuditService;
|
import gr.cite.tools.auditing.AuditService;
|
||||||
import gr.cite.tools.logging.LoggerService;
|
import gr.cite.tools.logging.LoggerService;
|
||||||
import gr.cite.tools.validation.ValidatorFactory;
|
import gr.cite.tools.validation.ValidatorFactory;
|
||||||
import jakarta.persistence.EntityManager;
|
|
||||||
import jakarta.persistence.EntityManagerFactory;
|
|
||||||
import jakarta.persistence.EntityTransaction;
|
|
||||||
import jakarta.persistence.OptimisticLockException;
|
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
|
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
|
||||||
import org.springframework.context.ApplicationContext;
|
|
||||||
import org.springframework.context.annotation.Scope;
|
import org.springframework.context.annotation.Scope;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
@ -34,15 +27,23 @@ public class TenantTouchedIntegrationEventHandlerImpl implements TenantTouchedIn
|
||||||
|
|
||||||
private static final LoggerService logger = new LoggerService(LoggerFactory.getLogger(TenantTouchedIntegrationEventHandlerImpl.class));
|
private static final LoggerService logger = new LoggerService(LoggerFactory.getLogger(TenantTouchedIntegrationEventHandlerImpl.class));
|
||||||
|
|
||||||
protected final ApplicationContext applicationContext;
|
|
||||||
|
|
||||||
private final JsonHandlingService jsonHandlingService;
|
private final JsonHandlingService jsonHandlingService;
|
||||||
private final ValidatorFactory validatorFactory;
|
private final ValidatorFactory validatorFactory;
|
||||||
|
private final CurrentPrincipalResolver currentPrincipalResolver;
|
||||||
|
private final ClaimExtractorProperties claimExtractorProperties;
|
||||||
|
private final TenantService tenantService;
|
||||||
|
private final AuditService auditService;
|
||||||
|
private final TenantEntityManager tenantEntityManager;
|
||||||
|
|
||||||
public TenantTouchedIntegrationEventHandlerImpl(ApplicationContext applicationContext, JsonHandlingService jsonHandlingService, ValidatorFactory validatorFactory) {
|
public TenantTouchedIntegrationEventHandlerImpl(JsonHandlingService jsonHandlingService, ValidatorFactory validatorFactory, CurrentPrincipalResolver currentPrincipalResolver, ClaimExtractorProperties claimExtractorProperties, TenantService tenantService, AuditService auditService, TenantEntityManager tenantEntityManager) {
|
||||||
this.applicationContext = applicationContext;
|
|
||||||
this.jsonHandlingService = jsonHandlingService;
|
this.jsonHandlingService = jsonHandlingService;
|
||||||
this.validatorFactory = validatorFactory;
|
this.validatorFactory = validatorFactory;
|
||||||
|
this.currentPrincipalResolver = currentPrincipalResolver;
|
||||||
|
this.claimExtractorProperties = claimExtractorProperties;
|
||||||
|
this.tenantService = tenantService;
|
||||||
|
this.auditService = auditService;
|
||||||
|
this.tenantEntityManager = tenantEntityManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -56,59 +57,25 @@ public class TenantTouchedIntegrationEventHandlerImpl implements TenantTouchedIn
|
||||||
model.setCode(event.getCode());
|
model.setCode(event.getCode());
|
||||||
this.validatorFactory.validator(TenantTouchedIntegrationEventPersist.TenantTouchedIntegrationEventPersistValidator.class).validateForce(model);
|
this.validatorFactory.validator(TenantTouchedIntegrationEventPersist.TenantTouchedIntegrationEventPersistValidator.class).validateForce(model);
|
||||||
|
|
||||||
EntityManager entityManager = null;
|
EventProcessingStatus status = EventProcessingStatus.Success;
|
||||||
EntityTransaction transaction = null;
|
tenantEntityManager.disableTenantFilters();
|
||||||
try (FakeRequestScope ignored = new FakeRequestScope()) {
|
|
||||||
try {
|
try {
|
||||||
CurrentPrincipalResolver currentPrincipalResolver = this.applicationContext.getBean(CurrentPrincipalResolver.class);
|
|
||||||
ClaimExtractorProperties claimExtractorProperties = this.applicationContext.getBean(ClaimExtractorProperties.class);
|
|
||||||
currentPrincipalResolver.push(InboxPrincipal.build(properties, claimExtractorProperties));
|
currentPrincipalResolver.push(InboxPrincipal.build(properties, claimExtractorProperties));
|
||||||
|
|
||||||
EntityManagerFactory entityManagerFactory = this.applicationContext.getBean(EntityManagerFactory.class);
|
|
||||||
entityManager = entityManagerFactory.createEntityManager();
|
|
||||||
|
|
||||||
transaction = entityManager.getTransaction();
|
|
||||||
transaction.begin();
|
|
||||||
|
|
||||||
try {
|
|
||||||
TenantEntityManager tenantEntityManager = this.applicationContext.getBean(TenantEntityManager.class);
|
|
||||||
tenantEntityManager.setEntityManager(entityManager);
|
|
||||||
tenantEntityManager.disableTenantFilters();
|
|
||||||
TenantService tenantService = this.applicationContext.getBean(TenantService.class);
|
|
||||||
tenantService.persist(model, null);
|
tenantService.persist(model, null);
|
||||||
|
|
||||||
AuditService auditService = this.applicationContext.getBean(AuditService.class);
|
|
||||||
|
|
||||||
auditService.track(AuditableAction.Tenant_Persist, Map.ofEntries(
|
auditService.track(AuditableAction.Tenant_Persist, Map.ofEntries(
|
||||||
new AbstractMap.SimpleEntry<String, Object>("model", model)
|
new AbstractMap.SimpleEntry<String, Object>("model", model)
|
||||||
));
|
));
|
||||||
|
|
||||||
transaction.commit();
|
|
||||||
} catch (Exception e) {
|
} catch (Exception ex) {
|
||||||
transaction.rollback();
|
status = EventProcessingStatus.Error;
|
||||||
throw e;
|
logger.error("Problem getting list of queue outbox. Skipping: {}", ex.getMessage(), ex);
|
||||||
} finally {
|
} finally {
|
||||||
currentPrincipalResolver.pop();
|
currentPrincipalResolver.pop();
|
||||||
}
|
}
|
||||||
|
return status;
|
||||||
transaction.commit();
|
|
||||||
} catch (OptimisticLockException ex) {
|
|
||||||
// we get this if/when someone else already modified the notifications. We want to essentially ignore this, and keep working
|
|
||||||
logger.debug("Concurrency exception getting queue outbox. Skipping: {} ", ex.getMessage());
|
|
||||||
if (transaction != null)
|
|
||||||
transaction.rollback();
|
|
||||||
} catch (Exception ex) {
|
|
||||||
logger.error("Problem getting list of queue outbox. Skipping: {}", ex.getMessage(), ex);
|
|
||||||
if (transaction != null)
|
|
||||||
transaction.rollback();
|
|
||||||
} finally {
|
|
||||||
if (entityManager != null)
|
|
||||||
entityManager.close();
|
|
||||||
}
|
|
||||||
} catch (Exception ex) {
|
|
||||||
logger.error("Problem getting list of queue outbox. Skipping: {}", ex.getMessage(), ex);
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,12 +1,10 @@
|
||||||
package gr.cite.annotation.integrationevent.inbox.userremoval;
|
package gr.cite.annotation.integrationevent.inbox.userremoval;
|
||||||
|
|
||||||
import gr.cite.annotation.data.TenantEntityManager;
|
|
||||||
import gr.cite.commons.web.oidc.principal.CurrentPrincipalResolver;
|
|
||||||
import gr.cite.annotation.audit.AuditableAction;
|
import gr.cite.annotation.audit.AuditableAction;
|
||||||
import gr.cite.annotation.common.JsonHandlingService;
|
import gr.cite.annotation.common.JsonHandlingService;
|
||||||
import gr.cite.annotation.common.scope.fake.FakeRequestScope;
|
|
||||||
import gr.cite.annotation.common.scope.tenant.TenantScope;
|
import gr.cite.annotation.common.scope.tenant.TenantScope;
|
||||||
import gr.cite.annotation.data.TenantEntity;
|
import gr.cite.annotation.data.TenantEntity;
|
||||||
|
import gr.cite.annotation.data.TenantEntityManager;
|
||||||
import gr.cite.annotation.errorcode.ErrorThesaurusProperties;
|
import gr.cite.annotation.errorcode.ErrorThesaurusProperties;
|
||||||
import gr.cite.annotation.integrationevent.inbox.EventProcessingStatus;
|
import gr.cite.annotation.integrationevent.inbox.EventProcessingStatus;
|
||||||
import gr.cite.annotation.integrationevent.inbox.InboxPrincipal;
|
import gr.cite.annotation.integrationevent.inbox.InboxPrincipal;
|
||||||
|
@ -14,19 +12,15 @@ import gr.cite.annotation.integrationevent.inbox.IntegrationEventProperties;
|
||||||
import gr.cite.annotation.model.Tenant;
|
import gr.cite.annotation.model.Tenant;
|
||||||
import gr.cite.annotation.query.TenantQuery;
|
import gr.cite.annotation.query.TenantQuery;
|
||||||
import gr.cite.annotation.service.user.UserService;
|
import gr.cite.annotation.service.user.UserService;
|
||||||
|
import gr.cite.commons.web.oidc.principal.CurrentPrincipalResolver;
|
||||||
import gr.cite.commons.web.oidc.principal.extractor.ClaimExtractorProperties;
|
import gr.cite.commons.web.oidc.principal.extractor.ClaimExtractorProperties;
|
||||||
import gr.cite.tools.auditing.AuditService;
|
import gr.cite.tools.auditing.AuditService;
|
||||||
import gr.cite.tools.data.query.QueryFactory;
|
import gr.cite.tools.data.query.QueryFactory;
|
||||||
import gr.cite.tools.exception.MyValidationException;
|
import gr.cite.tools.exception.MyValidationException;
|
||||||
import gr.cite.tools.fieldset.BaseFieldSet;
|
import gr.cite.tools.fieldset.BaseFieldSet;
|
||||||
import gr.cite.tools.logging.LoggerService;
|
import gr.cite.tools.logging.LoggerService;
|
||||||
import jakarta.persistence.EntityManager;
|
|
||||||
import jakarta.persistence.EntityManagerFactory;
|
|
||||||
import jakarta.persistence.EntityTransaction;
|
|
||||||
import jakarta.persistence.OptimisticLockException;
|
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
|
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
|
||||||
import org.springframework.context.ApplicationContext;
|
|
||||||
import org.springframework.context.MessageSource;
|
import org.springframework.context.MessageSource;
|
||||||
import org.springframework.context.annotation.Scope;
|
import org.springframework.context.annotation.Scope;
|
||||||
import org.springframework.context.i18n.LocaleContextHolder;
|
import org.springframework.context.i18n.LocaleContextHolder;
|
||||||
|
@ -43,22 +37,35 @@ public class UserRemovalIntegrationEventHandlerImpl implements UserRemovalIntegr
|
||||||
|
|
||||||
private final JsonHandlingService jsonHandlingService;
|
private final JsonHandlingService jsonHandlingService;
|
||||||
|
|
||||||
private final ApplicationContext applicationContext;
|
|
||||||
|
|
||||||
private final ErrorThesaurusProperties errors;
|
private final ErrorThesaurusProperties errors;
|
||||||
|
|
||||||
private final MessageSource messageSource;
|
private final MessageSource messageSource;
|
||||||
|
private final QueryFactory queryFactory;
|
||||||
|
private final TenantScope tenantScope;
|
||||||
|
private final CurrentPrincipalResolver currentPrincipalResolver;
|
||||||
|
private final ClaimExtractorProperties claimExtractorProperties;
|
||||||
|
private final UserRemovalConsistencyHandler userRemovalConsistencyHandler;
|
||||||
|
private final UserService userService;
|
||||||
|
private final AuditService auditService;
|
||||||
|
private final TenantEntityManager tenantEntityManager;
|
||||||
|
|
||||||
public UserRemovalIntegrationEventHandlerImpl(
|
public UserRemovalIntegrationEventHandlerImpl(
|
||||||
JsonHandlingService jsonHandlingService,
|
JsonHandlingService jsonHandlingService,
|
||||||
ApplicationContext applicationContext,
|
|
||||||
ErrorThesaurusProperties errors,
|
ErrorThesaurusProperties errors,
|
||||||
MessageSource messageSource
|
MessageSource messageSource, QueryFactory queryFactory, TenantScope tenantScope, CurrentPrincipalResolver currentPrincipalResolver, ClaimExtractorProperties claimExtractorProperties, UserRemovalConsistencyHandler userRemovalConsistencyHandler, UserService userService, AuditService auditService, TenantEntityManager tenantEntityManager
|
||||||
) {
|
) {
|
||||||
this.jsonHandlingService = jsonHandlingService;
|
this.jsonHandlingService = jsonHandlingService;
|
||||||
this.applicationContext = applicationContext;
|
|
||||||
this.errors = errors;
|
this.errors = errors;
|
||||||
this.messageSource = messageSource;
|
this.messageSource = messageSource;
|
||||||
|
this.queryFactory = queryFactory;
|
||||||
|
this.tenantScope = tenantScope;
|
||||||
|
this.currentPrincipalResolver = currentPrincipalResolver;
|
||||||
|
this.claimExtractorProperties = claimExtractorProperties;
|
||||||
|
this.userRemovalConsistencyHandler = userRemovalConsistencyHandler;
|
||||||
|
this.userService = userService;
|
||||||
|
this.auditService = auditService;
|
||||||
|
this.tenantEntityManager = tenantEntityManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -71,77 +78,44 @@ public class UserRemovalIntegrationEventHandlerImpl implements UserRemovalIntegr
|
||||||
|
|
||||||
logger.debug("Handling {}", UserRemovalIntegrationEvent.class.getSimpleName());
|
logger.debug("Handling {}", UserRemovalIntegrationEvent.class.getSimpleName());
|
||||||
|
|
||||||
EntityManager entityManager = null;
|
EventProcessingStatus status = EventProcessingStatus.Success;
|
||||||
EntityTransaction transaction = null;
|
|
||||||
try (FakeRequestScope ignored = new FakeRequestScope()) {
|
|
||||||
try {
|
try {
|
||||||
QueryFactory queryFactory = this.applicationContext.getBean(QueryFactory.class);
|
if (this.tenantScope.isMultitenant() && properties.getTenantId() != null) {
|
||||||
TenantScope scope = this.applicationContext.getBean(TenantScope.class);
|
|
||||||
if (scope.isMultitenant() && properties.getTenantId() != null) {
|
|
||||||
TenantEntity tenant = queryFactory.query(TenantQuery.class).ids(properties.getTenantId()).firstAs(new BaseFieldSet().ensure(Tenant._id).ensure(Tenant._code));
|
TenantEntity tenant = queryFactory.query(TenantQuery.class).ids(properties.getTenantId()).firstAs(new BaseFieldSet().ensure(Tenant._id).ensure(Tenant._code));
|
||||||
if (tenant == null) {
|
if (tenant == null) {
|
||||||
logger.error("missing tenant from event message");
|
logger.error("missing tenant from event message");
|
||||||
return EventProcessingStatus.Error;
|
return EventProcessingStatus.Error;
|
||||||
}
|
}
|
||||||
scope.setTenant(properties.getTenantId(), tenant.getCode());
|
this.tenantScope.setTempTenant(tenantEntityManager.getEntityManager(), properties.getTenantId(), tenant.getCode());
|
||||||
} else if (scope.isMultitenant()) {
|
} else if (this.tenantScope.isMultitenant()) {
|
||||||
// logger.error("missing tenant from event message");
|
// logger.error("missing tenant from event message");
|
||||||
scope.setTenant(null, scope.getDefaultTenantCode());
|
// return EventProcessingStatus.Error;
|
||||||
|
this.tenantScope.setTempTenant(tenantEntityManager.getEntityManager(), null, this.tenantScope.getDefaultTenantCode());
|
||||||
}
|
}
|
||||||
|
|
||||||
CurrentPrincipalResolver currentPrincipalResolver = this.applicationContext.getBean(CurrentPrincipalResolver.class);
|
|
||||||
|
|
||||||
ClaimExtractorProperties claimExtractorProperties = this.applicationContext.getBean(ClaimExtractorProperties.class);
|
|
||||||
currentPrincipalResolver.push(InboxPrincipal.build(properties, claimExtractorProperties));
|
currentPrincipalResolver.push(InboxPrincipal.build(properties, claimExtractorProperties));
|
||||||
|
|
||||||
UserRemovalConsistencyHandler userRemovalConsistencyHandler = this.applicationContext.getBean(UserRemovalConsistencyHandler.class);
|
if (!(userRemovalConsistencyHandler.isConsistent(new UserRemovalConsistencyPredicates(event.getUserId())))) {
|
||||||
if (!(userRemovalConsistencyHandler.isConsistent(new UserRemovalConsistencyPredicates(event.getUserId()))))
|
status = EventProcessingStatus.Postponed;
|
||||||
return EventProcessingStatus.Postponed;
|
currentPrincipalResolver.pop();
|
||||||
|
tenantScope.removeTempTenant(this.tenantEntityManager.getEntityManager());
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
EntityManagerFactory entityManagerFactory = this.applicationContext.getBean(EntityManagerFactory.class);
|
|
||||||
entityManager = entityManagerFactory.createEntityManager();
|
|
||||||
|
|
||||||
transaction = entityManager.getTransaction();
|
|
||||||
transaction.begin();
|
|
||||||
|
|
||||||
try {
|
|
||||||
TenantEntityManager tenantEntityManager = this.applicationContext.getBean(TenantEntityManager.class);
|
|
||||||
tenantEntityManager.setEntityManager(entityManager);
|
|
||||||
UserService userService = this.applicationContext.getBean(UserService.class);
|
|
||||||
userService.deleteAndSave(event.getUserId());
|
userService.deleteAndSave(event.getUserId());
|
||||||
|
|
||||||
AuditService auditService = this.applicationContext.getBean(AuditService.class);
|
|
||||||
|
|
||||||
auditService.track(AuditableAction.User_Delete, Map.ofEntries(
|
auditService.track(AuditableAction.User_Delete, Map.ofEntries(
|
||||||
new AbstractMap.SimpleEntry<String, Object>("id", event.getUserId())
|
new AbstractMap.SimpleEntry<String, Object>("id", event.getUserId())
|
||||||
));
|
));
|
||||||
//auditService.trackIdentity(AuditableAction.IdentityTracking_Action);
|
//auditService.trackIdentity(AuditableAction.IdentityTracking_Action);
|
||||||
|
} catch (Exception ex) {
|
||||||
transaction.commit();
|
status = EventProcessingStatus.Error;
|
||||||
} catch (Exception e) {
|
logger.error("Problem getting list of queue outbox. Skipping: {}", ex.getMessage(), ex);
|
||||||
transaction.rollback();
|
|
||||||
throw e;
|
|
||||||
} finally {
|
} finally {
|
||||||
currentPrincipalResolver.pop();
|
currentPrincipalResolver.pop();
|
||||||
|
tenantScope.removeTempTenant(this.tenantEntityManager.getEntityManager());
|
||||||
}
|
}
|
||||||
|
|
||||||
transaction.commit();
|
return status;
|
||||||
} catch (OptimisticLockException ex) {
|
|
||||||
// we get this if/when someone else already modified the notifications. We want to essentially ignore this, and keep working
|
|
||||||
logger.debug("Concurrency exception getting queue outbox. Skipping: {} ", ex.getMessage());
|
|
||||||
if (transaction != null)
|
|
||||||
transaction.rollback();
|
|
||||||
} catch (Exception ex) {
|
|
||||||
logger.error("Problem getting list of queue outbox. Skipping: {}", ex.getMessage(), ex);
|
|
||||||
if (transaction != null)
|
|
||||||
transaction.rollback();
|
|
||||||
} finally {
|
|
||||||
if (entityManager != null)
|
|
||||||
entityManager.close();
|
|
||||||
}
|
|
||||||
} catch (Exception ex) {
|
|
||||||
logger.error("Problem getting list of queue outbox. Skipping: {}", ex.getMessage(), ex);
|
|
||||||
}
|
|
||||||
return EventProcessingStatus.Success;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,6 @@ import gr.cite.annotation.data.TenantEntityManager;
|
||||||
import gr.cite.commons.web.oidc.principal.CurrentPrincipalResolver;
|
import gr.cite.commons.web.oidc.principal.CurrentPrincipalResolver;
|
||||||
import gr.cite.annotation.audit.AuditableAction;
|
import gr.cite.annotation.audit.AuditableAction;
|
||||||
import gr.cite.annotation.common.JsonHandlingService;
|
import gr.cite.annotation.common.JsonHandlingService;
|
||||||
import gr.cite.annotation.common.scope.fake.FakeRequestScope;
|
|
||||||
import gr.cite.annotation.common.scope.tenant.TenantScope;
|
import gr.cite.annotation.common.scope.tenant.TenantScope;
|
||||||
import gr.cite.annotation.data.TenantEntity;
|
import gr.cite.annotation.data.TenantEntity;
|
||||||
import gr.cite.annotation.integrationevent.inbox.EventProcessingStatus;
|
import gr.cite.annotation.integrationevent.inbox.EventProcessingStatus;
|
||||||
|
@ -19,13 +18,8 @@ import gr.cite.tools.data.query.QueryFactory;
|
||||||
import gr.cite.tools.fieldset.BaseFieldSet;
|
import gr.cite.tools.fieldset.BaseFieldSet;
|
||||||
import gr.cite.tools.logging.LoggerService;
|
import gr.cite.tools.logging.LoggerService;
|
||||||
import gr.cite.tools.validation.ValidatorFactory;
|
import gr.cite.tools.validation.ValidatorFactory;
|
||||||
import jakarta.persistence.EntityManager;
|
|
||||||
import jakarta.persistence.EntityManagerFactory;
|
|
||||||
import jakarta.persistence.EntityTransaction;
|
|
||||||
import jakarta.persistence.OptimisticLockException;
|
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
|
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
|
||||||
import org.springframework.context.ApplicationContext;
|
|
||||||
import org.springframework.context.annotation.Scope;
|
import org.springframework.context.annotation.Scope;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
@ -38,19 +32,30 @@ public class UserTouchedIntegrationEventHandlerImpl implements UserTouchedIntegr
|
||||||
|
|
||||||
private static final LoggerService logger = new LoggerService(LoggerFactory.getLogger(UserTouchedIntegrationEventHandlerImpl.class));
|
private static final LoggerService logger = new LoggerService(LoggerFactory.getLogger(UserTouchedIntegrationEventHandlerImpl.class));
|
||||||
|
|
||||||
protected final ApplicationContext applicationContext;
|
|
||||||
|
|
||||||
private final JsonHandlingService jsonHandlingService;
|
private final JsonHandlingService jsonHandlingService;
|
||||||
|
|
||||||
private final ValidatorFactory validatorFactory;
|
private final ValidatorFactory validatorFactory;
|
||||||
|
private final QueryFactory queryFactory;
|
||||||
|
private final TenantScope tenantScope;
|
||||||
|
private final CurrentPrincipalResolver currentPrincipalResolver;
|
||||||
|
private final ClaimExtractorProperties claimExtractorProperties;
|
||||||
|
private final UserService userService;
|
||||||
|
private final AuditService auditService;
|
||||||
|
private final TenantEntityManager tenantEntityManager;
|
||||||
|
|
||||||
public UserTouchedIntegrationEventHandlerImpl(
|
public UserTouchedIntegrationEventHandlerImpl(
|
||||||
JsonHandlingService jsonHandlingService,
|
JsonHandlingService jsonHandlingService,
|
||||||
ApplicationContext applicationContext,
|
ValidatorFactory validatorFactory, QueryFactory queryFactory, TenantScope tenantScope, CurrentPrincipalResolver currentPrincipalResolver, ClaimExtractorProperties claimExtractorProperties, UserService userService, AuditService auditService, TenantEntityManager tenantEntityManager) {
|
||||||
ValidatorFactory validatorFactory) {
|
|
||||||
this.jsonHandlingService = jsonHandlingService;
|
this.jsonHandlingService = jsonHandlingService;
|
||||||
this.applicationContext = applicationContext;
|
|
||||||
this.validatorFactory = validatorFactory;
|
this.validatorFactory = validatorFactory;
|
||||||
|
this.queryFactory = queryFactory;
|
||||||
|
this.tenantScope = tenantScope;
|
||||||
|
this.currentPrincipalResolver = currentPrincipalResolver;
|
||||||
|
this.claimExtractorProperties = claimExtractorProperties;
|
||||||
|
this.userService = userService;
|
||||||
|
this.auditService = auditService;
|
||||||
|
this.tenantEntityManager = tenantEntityManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -63,71 +68,37 @@ public class UserTouchedIntegrationEventHandlerImpl implements UserTouchedIntegr
|
||||||
|
|
||||||
this.validatorFactory.validator(UserTouchedIntegrationEvent.UserTouchedIntegrationEventValidator.class).validateForce(event);
|
this.validatorFactory.validator(UserTouchedIntegrationEvent.UserTouchedIntegrationEventValidator.class).validateForce(event);
|
||||||
|
|
||||||
EntityManager entityManager = null;
|
EventProcessingStatus status = EventProcessingStatus.Success;
|
||||||
EntityTransaction transaction = null;
|
|
||||||
try (FakeRequestScope ignored = new FakeRequestScope()) {
|
|
||||||
try {
|
try {
|
||||||
QueryFactory queryFactory = this.applicationContext.getBean(QueryFactory.class);
|
if (this.tenantScope.isMultitenant() && properties.getTenantId() != null) {
|
||||||
TenantScope scope = this.applicationContext.getBean(TenantScope.class);
|
|
||||||
if (scope.isMultitenant() && properties.getTenantId() != null) {
|
|
||||||
TenantEntity tenant = queryFactory.query(TenantQuery.class).ids(properties.getTenantId()).firstAs(new BaseFieldSet().ensure(Tenant._id).ensure(Tenant._code));
|
TenantEntity tenant = queryFactory.query(TenantQuery.class).ids(properties.getTenantId()).firstAs(new BaseFieldSet().ensure(Tenant._id).ensure(Tenant._code));
|
||||||
if (tenant == null) {
|
if (tenant == null) {
|
||||||
logger.error("missing tenant from event message");
|
logger.error("missing tenant from event message");
|
||||||
return EventProcessingStatus.Error;
|
return EventProcessingStatus.Error;
|
||||||
}
|
}
|
||||||
scope.setTenant(properties.getTenantId(), tenant.getCode());
|
this.tenantScope.setTempTenant(tenantEntityManager.getEntityManager(), properties.getTenantId(), tenant.getCode());
|
||||||
} else if (scope.isMultitenant()) {
|
} else if (this.tenantScope.isMultitenant()) {
|
||||||
// logger.error("missing tenant from event message");
|
// logger.error("missing tenant from event message");
|
||||||
// return EventProcessingStatus.Error;
|
// return EventProcessingStatus.Error;
|
||||||
scope.setTenant(null, scope.getDefaultTenantCode());
|
this.tenantScope.setTempTenant(tenantEntityManager.getEntityManager(), null, this.tenantScope.getDefaultTenantCode());
|
||||||
}
|
}
|
||||||
|
|
||||||
CurrentPrincipalResolver currentPrincipalResolver = this.applicationContext.getBean(CurrentPrincipalResolver.class);
|
|
||||||
|
|
||||||
ClaimExtractorProperties claimExtractorProperties = this.applicationContext.getBean(ClaimExtractorProperties.class);
|
|
||||||
currentPrincipalResolver.push(InboxPrincipal.build(properties, claimExtractorProperties));
|
currentPrincipalResolver.push(InboxPrincipal.build(properties, claimExtractorProperties));
|
||||||
|
|
||||||
EntityManagerFactory entityManagerFactory = this.applicationContext.getBean(EntityManagerFactory.class);
|
|
||||||
entityManager = entityManagerFactory.createEntityManager();
|
|
||||||
|
|
||||||
transaction = entityManager.getTransaction();
|
|
||||||
transaction.begin();
|
|
||||||
|
|
||||||
try {
|
|
||||||
TenantEntityManager tenantEntityManager = this.applicationContext.getBean(TenantEntityManager.class);
|
|
||||||
tenantEntityManager.setEntityManager(entityManager);
|
|
||||||
UserService userService = this.applicationContext.getBean(UserService.class);
|
|
||||||
userService.persist(event, null);
|
userService.persist(event, null);
|
||||||
|
|
||||||
AuditService auditService = this.applicationContext.getBean(AuditService.class);
|
|
||||||
|
|
||||||
auditService.track(AuditableAction.User_Persist, Map.ofEntries(
|
auditService.track(AuditableAction.User_Persist, Map.ofEntries(
|
||||||
new AbstractMap.SimpleEntry<String, Object>("model", event)
|
new AbstractMap.SimpleEntry<String, Object>("model", event)
|
||||||
));
|
));
|
||||||
|
|
||||||
transaction.commit();
|
} catch (Exception ex) {
|
||||||
} catch (Exception e) {
|
status = EventProcessingStatus.Error;
|
||||||
transaction.rollback();
|
logger.error("Problem getting list of queue outbox. Skipping: {}", ex.getMessage(), ex);
|
||||||
throw e;
|
|
||||||
} finally {
|
} finally {
|
||||||
currentPrincipalResolver.pop();
|
currentPrincipalResolver.pop();
|
||||||
|
tenantScope.removeTempTenant(this.tenantEntityManager.getEntityManager());
|
||||||
}
|
}
|
||||||
} catch (OptimisticLockException ex) {
|
|
||||||
// we get this if/when someone else already modified the notifications. We want to essentially ignore this, and keep working
|
return status;
|
||||||
logger.debug("Concurrency exception getting queue outbox. Skipping: {} ", ex.getMessage());
|
|
||||||
if (transaction != null)
|
|
||||||
transaction.rollback();
|
|
||||||
} catch (Exception ex) {
|
|
||||||
logger.error("Problem getting list of queue outbox. Skipping: {}", ex.getMessage(), ex);
|
|
||||||
if (transaction != null)
|
|
||||||
transaction.rollback();
|
|
||||||
} finally {
|
|
||||||
if (entityManager != null)
|
|
||||||
entityManager.close();
|
|
||||||
}
|
|
||||||
} catch (Exception ex) {
|
|
||||||
logger.error("Problem getting list of queue outbox. Skipping: {}", ex.getMessage(), ex);
|
|
||||||
}
|
|
||||||
return EventProcessingStatus.Success;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -36,6 +36,12 @@ public final class Permission {
|
||||||
public static String EditLanguage = "EditLanguage";
|
public static String EditLanguage = "EditLanguage";
|
||||||
public static String DeleteLanguage = "DeleteLanguage";
|
public static String DeleteLanguage = "DeleteLanguage";
|
||||||
|
|
||||||
|
|
||||||
|
//NotificationTemplate
|
||||||
|
public static String BrowseNotificationTemplate = "BrowseNotificationTemplate";
|
||||||
|
public static String EditNotificationTemplate = "EditNotificationTemplate";
|
||||||
|
public static String DeleteNotificationTemplate = "DeleteNotificationTemplate";
|
||||||
|
|
||||||
//Language
|
//Language
|
||||||
public static String BrowseStatistics = "BrowseStatistics";
|
public static String BrowseStatistics = "BrowseStatistics";
|
||||||
public static String BrowsePublicStatistics = "BrowsePublicStatistics";
|
public static String BrowsePublicStatistics = "BrowsePublicStatistics";
|
||||||
|
|
|
@ -4,6 +4,7 @@ import eu.eudat.commons.JsonHandlingService;
|
||||||
import eu.eudat.commons.enums.IsActive;
|
import eu.eudat.commons.enums.IsActive;
|
||||||
import eu.eudat.commons.fake.FakeRequestScope;
|
import eu.eudat.commons.fake.FakeRequestScope;
|
||||||
import eu.eudat.data.QueueInboxEntity;
|
import eu.eudat.data.QueueInboxEntity;
|
||||||
|
import eu.eudat.data.TenantEntityManager;
|
||||||
import eu.eudat.integrationevent.TrackedEvent;
|
import eu.eudat.integrationevent.TrackedEvent;
|
||||||
import eu.eudat.query.QueueInboxQuery;
|
import eu.eudat.query.QueueInboxQuery;
|
||||||
import gr.cite.queueinbox.entity.QueueInbox;
|
import gr.cite.queueinbox.entity.QueueInbox;
|
||||||
|
@ -28,12 +29,10 @@ import java.util.List;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
|
|
||||||
public class InboxRepositoryImpl implements InboxRepository {
|
public class InboxRepositoryImpl implements InboxRepository { private static final LoggerService logger = new LoggerService(LoggerFactory.getLogger(InboxRepositoryImpl.class));
|
||||||
|
|
||||||
protected final ApplicationContext applicationContext;
|
protected final ApplicationContext applicationContext;
|
||||||
|
|
||||||
private static final LoggerService logger = new LoggerService(LoggerFactory.getLogger(InboxRepositoryImpl.class));
|
|
||||||
|
|
||||||
private final JsonHandlingService jsonHandlingService;
|
private final JsonHandlingService jsonHandlingService;
|
||||||
|
|
||||||
private final InboxProperties inboxProperties;
|
private final InboxProperties inboxProperties;
|
||||||
|
@ -234,10 +233,17 @@ public class InboxRepositoryImpl implements InboxRepository {
|
||||||
}
|
}
|
||||||
|
|
||||||
private QueueInboxEntity createQueueInboxEntity(InboxCreatorParams inboxCreatorParams) {
|
private QueueInboxEntity createQueueInboxEntity(InboxCreatorParams inboxCreatorParams) {
|
||||||
|
|
||||||
QueueInboxEntity queueMessage = new QueueInboxEntity();
|
QueueInboxEntity queueMessage = new QueueInboxEntity();
|
||||||
queueMessage.setId(UUID.randomUUID());
|
queueMessage.setId(UUID.randomUUID());
|
||||||
Object tenantId = inboxCreatorParams.getHeaders() != null ? inboxCreatorParams.getHeaders().getOrDefault(IntegrationEventMessageConstants.TENANT, null) : null;
|
Object tenantId = inboxCreatorParams.getHeaders() != null ? inboxCreatorParams.getHeaders().getOrDefault(IntegrationEventMessageConstants.TENANT, null) : null;
|
||||||
if (tenantId instanceof UUID) queueMessage.setTenantId((UUID) tenantId);
|
if (tenantId instanceof UUID) queueMessage.setTenantId((UUID) tenantId);
|
||||||
|
else if (tenantId instanceof String) {
|
||||||
|
try {
|
||||||
|
queueMessage.setTenantId(UUID.fromString((String) tenantId));
|
||||||
|
} catch (Exception e) {
|
||||||
|
}
|
||||||
|
}
|
||||||
queueMessage.setExchange(this.inboxProperties.getExchange());
|
queueMessage.setExchange(this.inboxProperties.getExchange());
|
||||||
queueMessage.setRoute(inboxCreatorParams.getRoutingKey());
|
queueMessage.setRoute(inboxCreatorParams.getRoutingKey());
|
||||||
queueMessage.setQueue(inboxCreatorParams.getQueueName());
|
queueMessage.setQueue(inboxCreatorParams.getQueueName());
|
||||||
|
@ -265,6 +271,10 @@ public class InboxRepositoryImpl implements InboxRepository {
|
||||||
|
|
||||||
entityManager = entityManagerFactory.createEntityManager();
|
entityManager = entityManagerFactory.createEntityManager();
|
||||||
transaction = entityManager.getTransaction();
|
transaction = entityManager.getTransaction();
|
||||||
|
|
||||||
|
TenantEntityManager tenantEntityManager = this.applicationContext.getBean(TenantEntityManager.class);
|
||||||
|
tenantEntityManager.setEntityManager(entityManager);
|
||||||
|
|
||||||
transaction.begin();
|
transaction.begin();
|
||||||
|
|
||||||
QueryFactory queryFactory = this.applicationContext.getBean(QueryFactory.class);
|
QueryFactory queryFactory = this.applicationContext.getBean(QueryFactory.class);
|
||||||
|
@ -274,7 +284,7 @@ public class InboxRepositoryImpl implements InboxRepository {
|
||||||
logger.warn("Could not lookup queue inbox {} to process. Continuing...", candidateInfo.getId());
|
logger.warn("Could not lookup queue inbox {} to process. Continuing...", candidateInfo.getId());
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
EventProcessingStatus status = this.processMessage(queueInboxMessage.getRoute(), queueInboxMessage.getMessageId().toString(), queueInboxMessage.getApplicationId(), queueInboxMessage.getMessage());
|
EventProcessingStatus status = this.processMessage(queueInboxMessage);
|
||||||
switch (status) {
|
switch (status) {
|
||||||
case Success: {
|
case Success: {
|
||||||
queueInboxMessage.setStatus(QueueInboxStatus.SUCCESSFUL);
|
queueInboxMessage.setStatus(QueueInboxStatus.SUCCESSFUL);
|
||||||
|
@ -317,29 +327,39 @@ public class InboxRepositoryImpl implements InboxRepository {
|
||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
|
|
||||||
private EventProcessingStatus processMessage(String routingKey, String messageId, String appId, String message) {
|
|
||||||
|
|
||||||
|
private EventProcessingStatus processMessage(QueueInboxEntity queueInboxMessage) {
|
||||||
IntegrationEventHandler handler = null;
|
IntegrationEventHandler handler = null;
|
||||||
|
logger.debug("Processing message with routing key '{}'", queueInboxMessage.getRoute());
|
||||||
|
// if (this.routingKeyMatched(queueInboxMessage.getRoute(), this.inboxProperties.getTenantRemovalTopic()))
|
||||||
|
// handler = this.applicationContext.getBean(TenantRemovalIntegrationEventHandler.class);
|
||||||
|
// else {
|
||||||
|
// logger.error("No handler found for message routing key '{}'. Discarding.", queueInboxMessage.getRoute());
|
||||||
|
// handler = null;
|
||||||
|
// }
|
||||||
|
|
||||||
if (handler == null)
|
if (handler == null)
|
||||||
return EventProcessingStatus.Discard;
|
return EventProcessingStatus.Discard;
|
||||||
|
|
||||||
IntegrationEventProperties properties = new IntegrationEventProperties();
|
IntegrationEventProperties properties = new IntegrationEventProperties();
|
||||||
properties.setAppId(appId);
|
properties.setAppId(queueInboxMessage.getApplicationId());
|
||||||
properties.setMessageId(messageId);
|
properties.setMessageId(queueInboxMessage.getMessageId().toString());
|
||||||
|
properties.setTenantId(queueInboxMessage.getTenantId());
|
||||||
|
|
||||||
TrackedEvent event = this.jsonHandlingService.fromJsonSafe(TrackedEvent.class, message);
|
TrackedEvent event = this.jsonHandlingService.fromJsonSafe(TrackedEvent.class, queueInboxMessage.getMessage());
|
||||||
// using (LogContext.PushProperty(this._logTrackingConfig.LogTrackingContextName, @event.TrackingContextTag))
|
// using (LogContext.PushProperty(this._logTrackingConfig.LogTrackingContextName, @event.TrackingContextTag))
|
||||||
// {
|
// {
|
||||||
try {
|
try {
|
||||||
return handler.handle(properties, message);
|
return handler.handle(properties, queueInboxMessage.getMessage());
|
||||||
} catch (Exception ex) {
|
} catch (Exception ex) {
|
||||||
logger.error("problem handling event from routing key " + routingKey + ". Setting nack and continuing...", ex);
|
logger.error("problem handling event from routing key " + queueInboxMessage.getRoute() + ". Setting nack and continuing...", ex);
|
||||||
return EventProcessingStatus.Error;
|
return EventProcessingStatus.Error;
|
||||||
}
|
}
|
||||||
// }
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
private Boolean RoutingKeyMatched(String routingKey, List<String> topics) {
|
private Boolean routingKeyMatched(String routingKey, List<String> topics) {
|
||||||
if (topics == null || topics.isEmpty())
|
if (topics == null || topics.isEmpty())
|
||||||
return false;
|
return false;
|
||||||
return topics.stream().anyMatch(x -> x.equals(routingKey));
|
return topics.stream().anyMatch(x -> x.equals(routingKey));
|
||||||
|
|
|
@ -1,10 +1,13 @@
|
||||||
package eu.eudat.integrationevent.inbox;
|
package eu.eudat.integrationevent.inbox;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
public class IntegrationEventProperties {
|
public class IntegrationEventProperties {
|
||||||
|
|
||||||
private String messageId;
|
private String messageId;
|
||||||
|
|
||||||
private String appId;
|
private String appId;
|
||||||
|
private UUID tenantId;
|
||||||
|
|
||||||
public String getMessageId() {
|
public String getMessageId() {
|
||||||
return messageId;
|
return messageId;
|
||||||
|
@ -22,4 +25,11 @@ public class IntegrationEventProperties {
|
||||||
this.appId = appId;
|
this.appId = appId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public UUID getTenantId() {
|
||||||
|
return tenantId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTenantId(UUID tenantId) {
|
||||||
|
this.tenantId = tenantId;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,7 +23,7 @@ public class TenantTouchedIntegrationEventHandlerImpl implements TenantTouchedIn
|
||||||
OutboxIntegrationEvent message = new OutboxIntegrationEvent();
|
OutboxIntegrationEvent message = new OutboxIntegrationEvent();
|
||||||
message.setMessageId(UUID.randomUUID());
|
message.setMessageId(UUID.randomUUID());
|
||||||
message.setType(OutboxIntegrationEvent.TENANT_TOUCH);
|
message.setType(OutboxIntegrationEvent.TENANT_TOUCH);
|
||||||
message.setTenantId(event.getId());
|
// message.setTenantId(event.getId()); //Hack Can not Queue inbox before tenant created
|
||||||
message.setEvent(event);
|
message.setEvent(event);
|
||||||
|
|
||||||
this.outboxService.publish(message);
|
this.outboxService.publish(message);
|
||||||
|
|
|
@ -167,11 +167,6 @@ public class StorageFileCleanupTask implements Closeable, ApplicationListener<A
|
||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Transactional
|
|
||||||
private void purgeSafe(StorageFileService storageFileService, UUID fileId){
|
|
||||||
storageFileService.purgeSafe(fileId);
|
|
||||||
}
|
|
||||||
|
|
||||||
private CandidateInfo candidate(Instant lastCandidateCreationTimestamp) {
|
private CandidateInfo candidate(Instant lastCandidateCreationTimestamp) {
|
||||||
EntityTransaction transaction = null;
|
EntityTransaction transaction = null;
|
||||||
EntityManager entityManager = null;
|
EntityManager entityManager = null;
|
||||||
|
|
|
@ -6,8 +6,10 @@ import eu.eudat.commons.enums.IsActive;
|
||||||
import eu.eudat.data.TenantEntity;
|
import eu.eudat.data.TenantEntity;
|
||||||
import eu.eudat.data.TenantEntityManager;
|
import eu.eudat.data.TenantEntityManager;
|
||||||
import eu.eudat.data.UserEntity;
|
import eu.eudat.data.UserEntity;
|
||||||
|
import eu.eudat.integrationevent.outbox.tenantremoval.TenantRemovalIntegrationEventHandler;
|
||||||
import eu.eudat.integrationevent.outbox.tenanttouched.TenantTouchedIntegrationEvent;
|
import eu.eudat.integrationevent.outbox.tenanttouched.TenantTouchedIntegrationEvent;
|
||||||
import eu.eudat.integrationevent.outbox.tenanttouched.TenantTouchedIntegrationEventHandler;
|
import eu.eudat.integrationevent.outbox.tenanttouched.TenantTouchedIntegrationEventHandler;
|
||||||
|
import eu.eudat.integrationevent.outbox.userremoval.UserRemovalIntegrationEventHandler;
|
||||||
import eu.eudat.integrationevent.outbox.usertouched.UserTouchedIntegrationEventHandler;
|
import eu.eudat.integrationevent.outbox.usertouched.UserTouchedIntegrationEventHandler;
|
||||||
import eu.eudat.query.TenantQuery;
|
import eu.eudat.query.TenantQuery;
|
||||||
import eu.eudat.query.UserQuery;
|
import eu.eudat.query.UserQuery;
|
||||||
|
@ -44,8 +46,12 @@ public class MaintenanceController {
|
||||||
|
|
||||||
private final UserTouchedIntegrationEventHandler userTouchedIntegrationEventHandler;
|
private final UserTouchedIntegrationEventHandler userTouchedIntegrationEventHandler;
|
||||||
|
|
||||||
|
private final UserRemovalIntegrationEventHandler userRemovalIntegrationEventHandler;
|
||||||
|
|
||||||
private final TenantTouchedIntegrationEventHandler tenantTouchedIntegrationEventHandler;
|
private final TenantTouchedIntegrationEventHandler tenantTouchedIntegrationEventHandler;
|
||||||
|
|
||||||
|
private final TenantRemovalIntegrationEventHandler tenantRemovalIntegrationEventHandler;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
public MaintenanceController(
|
public MaintenanceController(
|
||||||
AuthorizationService authorizationService,
|
AuthorizationService authorizationService,
|
||||||
|
@ -54,14 +60,18 @@ public class MaintenanceController {
|
||||||
QueryFactory queryFactory,
|
QueryFactory queryFactory,
|
||||||
TenantEntityManager entityManager,
|
TenantEntityManager entityManager,
|
||||||
UserTouchedIntegrationEventHandler userTouchedIntegrationEventHandler,
|
UserTouchedIntegrationEventHandler userTouchedIntegrationEventHandler,
|
||||||
TenantTouchedIntegrationEventHandler tenantTouchedIntegrationEventHandler) {
|
UserRemovalIntegrationEventHandler userRemovalIntegrationEventHandler,
|
||||||
|
TenantTouchedIntegrationEventHandler tenantTouchedIntegrationEventHandler,
|
||||||
|
TenantRemovalIntegrationEventHandler tenantRemovalIntegrationEventHandler) {
|
||||||
this.authorizationService = authorizationService;
|
this.authorizationService = authorizationService;
|
||||||
this.elasticService = elasticService;
|
this.elasticService = elasticService;
|
||||||
this.auditService = auditService;
|
this.auditService = auditService;
|
||||||
this.queryFactory = queryFactory;
|
this.queryFactory = queryFactory;
|
||||||
this.entityManager = entityManager;
|
this.entityManager = entityManager;
|
||||||
this.userTouchedIntegrationEventHandler = userTouchedIntegrationEventHandler;
|
this.userTouchedIntegrationEventHandler = userTouchedIntegrationEventHandler;
|
||||||
|
this.userRemovalIntegrationEventHandler = userRemovalIntegrationEventHandler;
|
||||||
this.tenantTouchedIntegrationEventHandler = tenantTouchedIntegrationEventHandler;
|
this.tenantTouchedIntegrationEventHandler = tenantTouchedIntegrationEventHandler;
|
||||||
|
this.tenantRemovalIntegrationEventHandler = tenantRemovalIntegrationEventHandler;
|
||||||
}
|
}
|
||||||
|
|
||||||
@RequestMapping(method = RequestMethod.POST, value = {"/index/elastic"})
|
@RequestMapping(method = RequestMethod.POST, value = {"/index/elastic"})
|
||||||
|
@ -92,13 +102,19 @@ public class MaintenanceController {
|
||||||
this.authorizationService.authorizeForce(Permission.ManageQueueEvents);
|
this.authorizationService.authorizeForce(Permission.ManageQueueEvents);
|
||||||
|
|
||||||
this.entityManager.disableTenantFilters();
|
this.entityManager.disableTenantFilters();
|
||||||
UserQuery userQuery = queryFactory.query(UserQuery.class).isActive(IsActive.Active);
|
UserQuery userQuery = queryFactory.query(UserQuery.class);
|
||||||
List<UserEntity> users = userQuery.collect();
|
userQuery.isActive(IsActive.Active);
|
||||||
|
List<UserEntity> activeUsers = userQuery.collect();
|
||||||
|
userQuery.isActive(IsActive.Inactive);
|
||||||
|
List<UserEntity> inactiveUsers = userQuery.collect();
|
||||||
this.entityManager.enableTenantFilters();
|
this.entityManager.enableTenantFilters();
|
||||||
|
|
||||||
for(UserEntity user : users)
|
for(UserEntity user : activeUsers)
|
||||||
this.userTouchedIntegrationEventHandler.handle(user.getId());
|
this.userTouchedIntegrationEventHandler.handle(user.getId());
|
||||||
|
|
||||||
|
for(UserEntity user : inactiveUsers)
|
||||||
|
this.userRemovalIntegrationEventHandler.handle(user.getId());
|
||||||
|
|
||||||
this.auditService.track(AuditableAction.Maintenance_SendUserTouchEvents);
|
this.auditService.track(AuditableAction.Maintenance_SendUserTouchEvents);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -108,17 +124,24 @@ public class MaintenanceController {
|
||||||
this.authorizationService.authorizeForce(Permission.ManageQueueEvents);
|
this.authorizationService.authorizeForce(Permission.ManageQueueEvents);
|
||||||
|
|
||||||
this.entityManager.disableTenantFilters();
|
this.entityManager.disableTenantFilters();
|
||||||
TenantQuery tenantQuery = queryFactory.query(TenantQuery.class).isActive(IsActive.Active);
|
TenantQuery tenantQuery = queryFactory.query(TenantQuery.class);
|
||||||
List<TenantEntity> tenants = tenantQuery.collect();
|
tenantQuery.isActive(IsActive.Active);
|
||||||
|
List<TenantEntity> activeTenants = tenantQuery.collect();
|
||||||
|
tenantQuery.isActive(IsActive.Inactive);
|
||||||
|
List<TenantEntity> inactiveTenants = tenantQuery.collect();
|
||||||
this.entityManager.enableTenantFilters();
|
this.entityManager.enableTenantFilters();
|
||||||
|
|
||||||
for (TenantEntity tenant : tenants) {
|
for (TenantEntity tenant : activeTenants) {
|
||||||
TenantTouchedIntegrationEvent event = new TenantTouchedIntegrationEvent();
|
TenantTouchedIntegrationEvent event = new TenantTouchedIntegrationEvent();
|
||||||
event.setId(tenant.getId());
|
event.setId(tenant.getId());
|
||||||
event.setCode(tenant.getCode());
|
event.setCode(tenant.getCode());
|
||||||
this.tenantTouchedIntegrationEventHandler.handle(event);
|
this.tenantTouchedIntegrationEventHandler.handle(event);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (TenantEntity tenant : inactiveTenants) {
|
||||||
|
this.tenantRemovalIntegrationEventHandler.handle(tenant.getId());
|
||||||
|
}
|
||||||
|
|
||||||
this.auditService.track(AuditableAction.Maintenance_SendTenantTouchEvents);
|
this.auditService.track(AuditableAction.Maintenance_SendTenantTouchEvents);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -110,7 +110,25 @@ permissions:
|
||||||
clients: [ ]
|
clients: [ ]
|
||||||
allowAnonymous: false
|
allowAnonymous: false
|
||||||
allowAuthenticated: false
|
allowAuthenticated: false
|
||||||
|
# NotificationTemplate
|
||||||
|
BrowseNotificationTemplate:
|
||||||
|
roles: [ ]
|
||||||
|
clients: [ ]
|
||||||
|
allowAnonymous: true
|
||||||
|
allowAuthenticated: true
|
||||||
|
EditNotificationTemplate:
|
||||||
|
roles:
|
||||||
|
- TenantAdmin
|
||||||
|
clients: [ ]
|
||||||
|
allowAnonymous: false
|
||||||
|
allowAuthenticated: false
|
||||||
|
DeleteNotificationTemplate:
|
||||||
|
roles:
|
||||||
|
- TenantAdmin
|
||||||
|
claims: [ ]
|
||||||
|
clients: [ ]
|
||||||
|
allowAnonymous: false
|
||||||
|
allowAuthenticated: false
|
||||||
# Language
|
# Language
|
||||||
BrowseLanguage:
|
BrowseLanguage:
|
||||||
roles: [ ]
|
roles: [ ]
|
||||||
|
|
|
@ -41,7 +41,7 @@ queue:
|
||||||
generate-file-topic: generate.file
|
generate-file-topic: generate.file
|
||||||
rabbitmq:
|
rabbitmq:
|
||||||
enable: true
|
enable: true
|
||||||
interval-seconds: 30
|
interval-seconds: 3
|
||||||
options:
|
options:
|
||||||
retry-threashold: 100
|
retry-threashold: 100
|
||||||
retry-delay-step-seconds: 300
|
retry-delay-step-seconds: 300
|
||||||
|
@ -54,7 +54,7 @@ queue:
|
||||||
exchange: null
|
exchange: null
|
||||||
rabbitmq:
|
rabbitmq:
|
||||||
enable: true
|
enable: true
|
||||||
interval-seconds: 30
|
interval-seconds: 3
|
||||||
options:
|
options:
|
||||||
retry-threashold: 100
|
retry-threashold: 100
|
||||||
retry-delay-step-seconds: 300
|
retry-delay-step-seconds: 300
|
||||||
|
|
|
@ -26,11 +26,11 @@ BEGIN
|
||||||
notified_with smallint,
|
notified_with smallint,
|
||||||
CONSTRAINT "ntf_Notification_pkey" PRIMARY KEY (id),
|
CONSTRAINT "ntf_Notification_pkey" PRIMARY KEY (id),
|
||||||
CONSTRAINT "ntf_Notification_tenant_fkey" FOREIGN KEY (tenant)
|
CONSTRAINT "ntf_Notification_tenant_fkey" FOREIGN KEY (tenant)
|
||||||
REFERENCES public."Tenant" (id) MATCH SIMPLE
|
REFERENCES public."ntf_Tenant" (id) MATCH SIMPLE
|
||||||
ON UPDATE NO ACTION
|
ON UPDATE NO ACTION
|
||||||
ON DELETE NO ACTION,
|
ON DELETE NO ACTION,
|
||||||
CONSTRAINT "ntf_Notification_user_fkey" FOREIGN KEY ("user")
|
CONSTRAINT "ntf_Notification_user_fkey" FOREIGN KEY ("user")
|
||||||
REFERENCES public."User" (id) MATCH SIMPLE
|
REFERENCES public."ntf_User" (id) MATCH SIMPLE
|
||||||
ON UPDATE NO ACTION
|
ON UPDATE NO ACTION
|
||||||
ON DELETE NO ACTION
|
ON DELETE NO ACTION
|
||||||
);
|
);
|
||||||
|
|
|
@ -10,20 +10,15 @@ BEGIN
|
||||||
channel smallint NOT NULL,
|
channel smallint NOT NULL,
|
||||||
notification_type uuid NOT NULL,
|
notification_type uuid NOT NULL,
|
||||||
kind smallint NOT NULL,
|
kind smallint NOT NULL,
|
||||||
language uuid NOT NULL,
|
language_code character varying(200) COLLATE pg_catalog."default" NOT NULL,
|
||||||
value text NOT NULL,
|
value text NOT NULL,
|
||||||
is_active smallint NOT NULL,
|
is_active smallint NOT NULL,
|
||||||
created_at timestamp without time zone NOT NULL,
|
created_at timestamp without time zone NOT NULL,
|
||||||
updated_at timestamp without time zone NOT NULL,
|
updated_at timestamp without time zone NOT NULL,
|
||||||
tenant uuid,
|
tenant uuid,
|
||||||
CONSTRAINT "NotificationTemplate_pkey" PRIMARY KEY (id),
|
CONSTRAINT "NotificationTemplate_pkey" PRIMARY KEY (id),
|
||||||
CONSTRAINT "NotificationTemplate_language_fkey" FOREIGN KEY (language)
|
|
||||||
REFERENCES public."Language" (id) MATCH SIMPLE
|
|
||||||
ON UPDATE NO ACTION
|
|
||||||
ON DELETE NO ACTION
|
|
||||||
NOT VALID,
|
|
||||||
CONSTRAINT "NotificationTemplate_tenant_fkey" FOREIGN KEY (tenant)
|
CONSTRAINT "NotificationTemplate_tenant_fkey" FOREIGN KEY (tenant)
|
||||||
REFERENCES public."Tenant" (id) MATCH SIMPLE
|
REFERENCES public."ntf_Tenant" (id) MATCH SIMPLE
|
||||||
ON UPDATE NO ACTION
|
ON UPDATE NO ACTION
|
||||||
ON DELETE NO ACTION
|
ON DELETE NO ACTION
|
||||||
NOT VALID
|
NOT VALID
|
||||||
|
|
|
@ -21,7 +21,7 @@ BEGIN
|
||||||
is_active smallint NOT NULL,
|
is_active smallint NOT NULL,
|
||||||
CONSTRAINT "ntf_QueryInbox_pkey" PRIMARY KEY (id),
|
CONSTRAINT "ntf_QueryInbox_pkey" PRIMARY KEY (id),
|
||||||
CONSTRAINT "ntf_QueryInbox_tenant_fkey" FOREIGN KEY (tenant)
|
CONSTRAINT "ntf_QueryInbox_tenant_fkey" FOREIGN KEY (tenant)
|
||||||
REFERENCES public."Tenant" (id) MATCH SIMPLE
|
REFERENCES public."ntf_Tenant" (id) MATCH SIMPLE
|
||||||
ON UPDATE NO ACTION
|
ON UPDATE NO ACTION
|
||||||
ON DELETE NO ACTION
|
ON DELETE NO ACTION
|
||||||
NOT VALID
|
NOT VALID
|
||||||
|
|
|
@ -21,7 +21,7 @@ BEGIN
|
||||||
is_active smallint NOT NULL,
|
is_active smallint NOT NULL,
|
||||||
CONSTRAINT "ntf_QueueOutbox_pkey" PRIMARY KEY (id),
|
CONSTRAINT "ntf_QueueOutbox_pkey" PRIMARY KEY (id),
|
||||||
CONSTRAINT "ntf_QueueOutbox_tenant_fkey" FOREIGN KEY (tenant)
|
CONSTRAINT "ntf_QueueOutbox_tenant_fkey" FOREIGN KEY (tenant)
|
||||||
REFERENCES public."Tenant" (id) MATCH SIMPLE
|
REFERENCES public."ntf_Tenant" (id) MATCH SIMPLE
|
||||||
ON UPDATE NO ACTION
|
ON UPDATE NO ACTION
|
||||||
ON DELETE NO ACTION
|
ON DELETE NO ACTION
|
||||||
);
|
);
|
||||||
|
|
|
@ -21,11 +21,11 @@ BEGIN
|
||||||
is_active smallint NOT NULL,
|
is_active smallint NOT NULL,
|
||||||
CONSTRAINT "ntf_InAppNotification_pkey" PRIMARY KEY (id),
|
CONSTRAINT "ntf_InAppNotification_pkey" PRIMARY KEY (id),
|
||||||
CONSTRAINT "ntf_InAppNotification_tenant_fkey" FOREIGN KEY (tenant)
|
CONSTRAINT "ntf_InAppNotification_tenant_fkey" FOREIGN KEY (tenant)
|
||||||
REFERENCES public."Tenant" (id) MATCH SIMPLE
|
REFERENCES public."ntf_tenant" (id) MATCH SIMPLE
|
||||||
ON UPDATE NO ACTION
|
ON UPDATE NO ACTION
|
||||||
ON DELETE NO ACTION,
|
ON DELETE NO ACTION,
|
||||||
CONSTRAINT "ntf_InAppNotification_user_fkey" FOREIGN KEY ("user")
|
CONSTRAINT "ntf_InAppNotification_user_fkey" FOREIGN KEY ("user")
|
||||||
REFERENCES public."User" (id) MATCH SIMPLE
|
REFERENCES public."ntf_User" (id) MATCH SIMPLE
|
||||||
ON UPDATE NO ACTION
|
ON UPDATE NO ACTION
|
||||||
ON DELETE NO ACTION
|
ON DELETE NO ACTION
|
||||||
);
|
);
|
||||||
|
|
|
@ -329,17 +329,6 @@ const appRoutes: Routes = [
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
|
||||||
path: 'index-managment',
|
|
||||||
loadChildren: () => import('./ui/admin/index-managment/index-managment.module').then(m => m.IndexManagmentModule),
|
|
||||||
data: {
|
|
||||||
authContext: {
|
|
||||||
permissions: [AppPermission.ViewMaintenancePage]
|
|
||||||
},
|
|
||||||
breadcrumb: true,
|
|
||||||
title: 'GENERAL.TITLES.INDEX-MANAGMENT'
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
path: 'maintenance-tasks',
|
path: 'maintenance-tasks',
|
||||||
loadChildren: () => import('./ui/admin/maintenance-tasks/maintenance-tasks.module').then(m => m.MaintenanceTasksModule),
|
loadChildren: () => import('./ui/admin/maintenance-tasks/maintenance-tasks.module').then(m => m.MaintenanceTasksModule),
|
||||||
|
@ -347,7 +336,8 @@ const appRoutes: Routes = [
|
||||||
authContext: {
|
authContext: {
|
||||||
permissions: [AppPermission.ViewMaintenancePage]
|
permissions: [AppPermission.ViewMaintenancePage]
|
||||||
},
|
},
|
||||||
breadcrumb: true
|
breadcrumb: true,
|
||||||
|
title: 'GENERAL.TITLES.MAINTENANCE-TASKS'
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
|
@ -2,7 +2,6 @@ import { NotificationTemplateChannel } from "@app/core/common/enum/notification-
|
||||||
import { NotificationTemplateKind } from "@app/core/common/enum/notification-template-kind";
|
import { NotificationTemplateKind } from "@app/core/common/enum/notification-template-kind";
|
||||||
import { BaseEntity, BaseEntityPersist } from "@common/base/base-entity.model";
|
import { BaseEntity, BaseEntityPersist } from "@common/base/base-entity.model";
|
||||||
import { Guid } from "@common/types/guid";
|
import { Guid } from "@common/types/guid";
|
||||||
import { Language } from "../language/language";
|
|
||||||
import { NotificationDataType } from "@app/core/common/enum/notification-data-type";
|
import { NotificationDataType } from "@app/core/common/enum/notification-data-type";
|
||||||
import { EmailOverrideMode } from "@app/core/common/enum/email-override-mode";
|
import { EmailOverrideMode } from "@app/core/common/enum/email-override-mode";
|
||||||
import { NotificationType } from "@app/core/common/enum/notification-type";
|
import { NotificationType } from "@app/core/common/enum/notification-type";
|
||||||
|
@ -11,7 +10,7 @@ export interface NotificationTemplate extends BaseEntity{
|
||||||
channel: NotificationTemplateChannel;
|
channel: NotificationTemplateChannel;
|
||||||
notificationType: NotificationType;
|
notificationType: NotificationType;
|
||||||
kind: NotificationTemplateKind;
|
kind: NotificationTemplateKind;
|
||||||
language: Language;
|
languageCode: string;
|
||||||
value: NotificationTemplateValue;
|
value: NotificationTemplateValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -49,7 +48,7 @@ export interface NotificationTemplatePersist extends BaseEntityPersist{
|
||||||
channel: NotificationTemplateChannel;
|
channel: NotificationTemplateChannel;
|
||||||
notificationType: NotificationType;
|
notificationType: NotificationType;
|
||||||
kind: NotificationTemplateKind;
|
kind: NotificationTemplateKind;
|
||||||
languageId: Guid;
|
languageCode: string;
|
||||||
value: NotificationTemplateValuePersist;
|
value: NotificationTemplateValuePersist;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -28,4 +28,18 @@ export class MaintenanceService extends BaseService {
|
||||||
.delete<any>(url).pipe(
|
.delete<any>(url).pipe(
|
||||||
catchError((error: any) => throwError(error)));
|
catchError((error: any) => throwError(error)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sendUserTouchEvents(): Observable<any> {
|
||||||
|
const url = `${this.apiBase}/events/users/touch`;
|
||||||
|
return this.http
|
||||||
|
.delete<any>(url).pipe(
|
||||||
|
catchError((error: any) => throwError(error)));
|
||||||
|
}
|
||||||
|
|
||||||
|
sendTenantTouchEvents(): Observable<any> {
|
||||||
|
const url = `${this.apiBase}/events/tenants/touch`;
|
||||||
|
return this.http
|
||||||
|
.delete<any>(url).pipe(
|
||||||
|
catchError((error: any) => throwError(error)));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,15 +0,0 @@
|
||||||
<div class="container-fluid">
|
|
||||||
<div class="row root">
|
|
||||||
<div class="col-md-10 offset-md-1">
|
|
||||||
<div class="mt-4 mb-4"></div>
|
|
||||||
<mat-card class="p-2">
|
|
||||||
<div class="mt-2">
|
|
||||||
<div style="color: red;">Warning: Danger zone. It might delete Dataset tags if not careful</div>
|
|
||||||
<button mat-raised-button color="primary" (click)="generateIndex($event)" class="lightblue-btn button">Generate Index</button>
|
|
||||||
<button mat-raised-button color="primary" (click)="clearIndex($event)" class="lightblue-btn button">Clear Index</button>
|
|
||||||
</div>
|
|
||||||
</mat-card>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
|
@ -1,7 +0,0 @@
|
||||||
.root {
|
|
||||||
// padding-bottom: 2em;
|
|
||||||
|
|
||||||
.button {
|
|
||||||
margin: 5px;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,87 +0,0 @@
|
||||||
import { Component, OnInit } from '@angular/core';
|
|
||||||
import { BaseComponent } from '@common/base/base.component';
|
|
||||||
import { takeUntil } from 'rxjs/operators';
|
|
||||||
import { UiNotificationService, SnackBarNotificationLevel } from '@app/core/services/notification/ui-notification-service';
|
|
||||||
import { TranslateService } from '@ngx-translate/core';
|
|
||||||
import { Router } from '@angular/router';
|
|
||||||
import { MaintenanceService } from '@app/core/services/maintenance/maintenance.service';
|
|
||||||
|
|
||||||
@Component({
|
|
||||||
selector: 'app-index-managment',
|
|
||||||
templateUrl: './index-managment.component.html',
|
|
||||||
styleUrls: ['./index-managment.component.scss']
|
|
||||||
})
|
|
||||||
export class IndexManagmentComponent extends BaseComponent implements OnInit {
|
|
||||||
|
|
||||||
constructor(
|
|
||||||
private uiNotificationService: UiNotificationService,
|
|
||||||
private translate: TranslateService,
|
|
||||||
private router: Router,
|
|
||||||
private maintenanceService: MaintenanceService
|
|
||||||
)
|
|
||||||
{
|
|
||||||
super();
|
|
||||||
}
|
|
||||||
|
|
||||||
ngOnInit() {
|
|
||||||
}
|
|
||||||
|
|
||||||
generateIndex(ev: Event) {
|
|
||||||
(ev.target as HTMLButtonElement).disabled = true;
|
|
||||||
// this.datasetService.generateIndex().pipe(takeUntil(this._destroyed)).subscribe(
|
|
||||||
// response => {
|
|
||||||
// (ev.target as HTMLButtonElement).disabled = false;
|
|
||||||
// this.onCallbackSuccess();
|
|
||||||
// },
|
|
||||||
// error => {
|
|
||||||
// (ev.target as HTMLButtonElement).disabled = false;
|
|
||||||
// this.onCallbackError(error);
|
|
||||||
// }
|
|
||||||
// );
|
|
||||||
this.maintenanceService.generateElasticIndex().pipe(takeUntil(this._destroyed)).subscribe(
|
|
||||||
response => {
|
|
||||||
(ev.target as HTMLButtonElement).disabled = false;
|
|
||||||
this.onCallbackSuccess();
|
|
||||||
},
|
|
||||||
error => {
|
|
||||||
(ev.target as HTMLButtonElement).disabled = false;
|
|
||||||
this.onCallbackError(error);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
clearIndex(ev: Event) {
|
|
||||||
(ev.target as HTMLButtonElement).disabled = true;
|
|
||||||
// this.datasetService.clearIndex().pipe(takeUntil(this._destroyed)).subscribe(
|
|
||||||
// response => {
|
|
||||||
// (ev.target as HTMLButtonElement).disabled = false;
|
|
||||||
// this.onCallbackSuccess();
|
|
||||||
// },
|
|
||||||
// error => {
|
|
||||||
// (ev.target as HTMLButtonElement).disabled = false;
|
|
||||||
// this.onCallbackError(error);
|
|
||||||
// }
|
|
||||||
// );
|
|
||||||
this.maintenanceService.clearElasticIndex().pipe(takeUntil(this._destroyed)).subscribe(
|
|
||||||
response => {
|
|
||||||
(ev.target as HTMLButtonElement).disabled = false;
|
|
||||||
this.onCallbackSuccess();
|
|
||||||
},
|
|
||||||
error => {
|
|
||||||
(ev.target as HTMLButtonElement).disabled = false;
|
|
||||||
this.onCallbackError(error);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
onCallbackSuccess(): void {
|
|
||||||
this.uiNotificationService.snackBarNotification( this.translate.instant('GENERAL.SNACK-BAR.SUCCESSFUL-UPDATE'), SnackBarNotificationLevel.Success);
|
|
||||||
this.router.navigate(['/reload']).then(() => this.router.navigate(['/index-managment']));
|
|
||||||
}
|
|
||||||
|
|
||||||
onCallbackError(error: any) {
|
|
||||||
this.uiNotificationService.snackBarNotification( error, SnackBarNotificationLevel.Error);
|
|
||||||
//this.validateAllFormFields(this.formGroup);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,20 +0,0 @@
|
||||||
import { NgModule } from '@angular/core';
|
|
||||||
import { CommonModule } from '@angular/common';
|
|
||||||
|
|
||||||
import { IndexManagmentRoutingModule } from './index-managment.routing';
|
|
||||||
import { IndexManagmentComponent } from './index-managment.component';
|
|
||||||
import { CommonUiModule } from '@common/ui/common-ui.module';
|
|
||||||
import { CommonFormsModule } from '@common/forms/common-forms.module';
|
|
||||||
import { ConfirmationDialogModule } from '@common/modules/confirmation-dialog/confirmation-dialog.module';
|
|
||||||
|
|
||||||
|
|
||||||
@NgModule({
|
|
||||||
declarations: [IndexManagmentComponent],
|
|
||||||
imports: [
|
|
||||||
CommonUiModule,
|
|
||||||
CommonFormsModule,
|
|
||||||
ConfirmationDialogModule,
|
|
||||||
IndexManagmentRoutingModule
|
|
||||||
]
|
|
||||||
})
|
|
||||||
export class IndexManagmentModule { }
|
|
|
@ -1,15 +0,0 @@
|
||||||
import { NgModule } from '@angular/core';
|
|
||||||
import { Routes, RouterModule } from '@angular/router';
|
|
||||||
import { IndexManagmentComponent } from './index-managment.component';
|
|
||||||
import { AdminAuthGuard } from '@app/core/admin-auth-guard.service';
|
|
||||||
|
|
||||||
|
|
||||||
const routes: Routes = [
|
|
||||||
{ path: '', component: IndexManagmentComponent, canActivate: [AdminAuthGuard] },
|
|
||||||
];
|
|
||||||
|
|
||||||
@NgModule({
|
|
||||||
imports: [RouterModule.forChild(routes)],
|
|
||||||
exports: [RouterModule]
|
|
||||||
})
|
|
||||||
export class IndexManagmentRoutingModule { }
|
|
|
@ -1,10 +1,47 @@
|
||||||
<!-- <div class="row root"> -->
|
<!-- <div class="row root">
|
||||||
<div class="d-flex justify-content-center">
|
<div class="d-flex justify-content-center">
|
||||||
<mat-card class="p-4 mt-4">
|
<mat-card class="p-4 mt-4">
|
||||||
<div style="color: red;">Warning: Danger zone. Irreversible actions!</div>
|
<div style="color: red;">Warning: Danger zone. Irreversible actions!</div>
|
||||||
<div>
|
<div>
|
||||||
<!-- <button mat-raised-button color="primary" (click)="migrateSemantics($event)" class="lightblue-btn button">Migrate semantics</button> -->
|
<button mat-raised-button color="primary" (click)="migrateSemantics($event)" class="lightblue-btn button">Migrate semantics</button>
|
||||||
<!-- <button mat-raised-button color="primary" (click)="addRdaInSemantics($event)" class="lightblue-btn button">Add rda in semantics</button> -->
|
<button mat-raised-button color="primary" (click)="addRdaInSemantics($event)" class="lightblue-btn button">Add rda in semantics</button>
|
||||||
</div>
|
</div>
|
||||||
</mat-card>
|
</mat-card>
|
||||||
|
</div> -->
|
||||||
|
<div class="container-fluid">
|
||||||
|
<div class="row root">
|
||||||
|
<div class="col-md-10 offset-md-1">
|
||||||
|
<div class="row mt-4 mb-4"></div>
|
||||||
|
<mat-accordion multi>
|
||||||
|
<mat-expansion-panel>
|
||||||
|
<mat-expansion-panel-header>
|
||||||
|
<mat-panel-title>
|
||||||
|
{{language.instant('MAINTENANCE-TASKS.SECTIONS.INDEXES.TITLE')}}
|
||||||
|
</mat-panel-title>
|
||||||
|
<mat-panel-description>
|
||||||
|
{{language.instant('MAINTENANCE-TASKS.SECTIONS.INDEXES.DESCRIPTION')}}
|
||||||
|
</mat-panel-description>
|
||||||
|
</mat-expansion-panel-header>
|
||||||
|
<div class="mt-2">
|
||||||
|
<button mat-raised-button color="primary" (click)="generateIndex($event)" class="lightblue-btn button">{{language.instant('MAINTENANCE-TASKS.SECTIONS.INDEXES.ACTIONS.GENERATE-INDEX')}}</button>
|
||||||
|
<button mat-raised-button color="primary" (click)="clearIndex($event)" class="lightblue-btn button">{{language.instant('MAINTENANCE-TASKS.SECTIONS.INDEXES.ACTIONS.CLEAR-INDEX')}}</button>
|
||||||
|
</div>
|
||||||
|
</mat-expansion-panel>
|
||||||
|
<mat-expansion-panel>
|
||||||
|
<mat-expansion-panel-header>
|
||||||
|
<mat-panel-title>
|
||||||
|
{{language.instant('MAINTENANCE-TASKS.SECTIONS.EVENTS.TITLE')}}
|
||||||
|
</mat-panel-title>
|
||||||
|
<mat-panel-description>
|
||||||
|
{{language.instant('MAINTENANCE-TASKS.SECTIONS.EVENTS.DESCRIPTION')}}
|
||||||
|
</mat-panel-description>
|
||||||
|
</mat-expansion-panel-header>
|
||||||
|
<div class="mt-2">
|
||||||
|
<button mat-raised-button color="primary" (click)="sendUserTouchEvents($event)" class="lightblue-btn button">{{language.instant('MAINTENANCE-TASKS.SECTIONS.EVENTS.ACTIONS.SEND-USER-TOUCH')}}</button>
|
||||||
|
<button mat-raised-button color="primary" (click)="sendTenantTouchEvents($event)" class="lightblue-btn button">{{language.instant('MAINTENANCE-TASKS.SECTIONS.EVENTS.ACTIONS.SEND-TENANT-TOUCH')}}</button>
|
||||||
|
</div>
|
||||||
|
</mat-expansion-panel>
|
||||||
|
</mat-accordion>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,9 +1,12 @@
|
||||||
import { Component, OnInit } from '@angular/core';
|
import { Component, OnInit } from '@angular/core';
|
||||||
|
import { MatDialog } from '@angular/material/dialog';
|
||||||
import { Router } from '@angular/router';
|
import { Router } from '@angular/router';
|
||||||
import { MaintenanceService } from '@app/core/services/maintenance/maintenance.service';
|
import { MaintenanceService } from '@app/core/services/maintenance/maintenance.service';
|
||||||
import { SnackBarNotificationLevel, UiNotificationService } from '@app/core/services/notification/ui-notification-service';
|
import { SnackBarNotificationLevel, UiNotificationService } from '@app/core/services/notification/ui-notification-service';
|
||||||
import { BaseComponent } from '@common/base/base.component';
|
import { BaseComponent } from '@common/base/base.component';
|
||||||
|
import { ConfirmationDialogComponent } from '@common/modules/confirmation-dialog/confirmation-dialog.component';
|
||||||
import { TranslateService } from '@ngx-translate/core';
|
import { TranslateService } from '@ngx-translate/core';
|
||||||
|
import { takeUntil } from 'rxjs/operators';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-maintenance-tasks',
|
selector: 'app-maintenance-tasks',
|
||||||
|
@ -13,6 +16,8 @@ import { TranslateService } from '@ngx-translate/core';
|
||||||
export class MaintenanceTasksComponent extends BaseComponent implements OnInit {
|
export class MaintenanceTasksComponent extends BaseComponent implements OnInit {
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
|
protected dialog: MatDialog,
|
||||||
|
protected language: TranslateService,
|
||||||
private maintenanceService: MaintenanceService,
|
private maintenanceService: MaintenanceService,
|
||||||
private uiNotificationService: UiNotificationService,
|
private uiNotificationService: UiNotificationService,
|
||||||
private translate: TranslateService,
|
private translate: TranslateService,
|
||||||
|
@ -53,6 +58,130 @@ export class MaintenanceTasksComponent extends BaseComponent implements OnInit {
|
||||||
// );
|
// );
|
||||||
// }
|
// }
|
||||||
|
|
||||||
|
generateIndex(ev: Event) {
|
||||||
|
this.dialog.open(ConfirmationDialogComponent, {
|
||||||
|
data: {
|
||||||
|
message: this.language.instant('MAINTENANCE-TASKS.CONFIRMATION.MESSAGE'),
|
||||||
|
confirmButton: this.language.instant('GENERAL.CONFIRMATION-DIALOG.ACTIONS.CONFIRM'),
|
||||||
|
cancelButton: this.language.instant('GENERAL.CONFIRMATION-DIALOG.ACTIONS.CANCEL')
|
||||||
|
},
|
||||||
|
maxWidth: '30em'
|
||||||
|
})
|
||||||
|
.afterClosed()
|
||||||
|
.subscribe(confirm => {
|
||||||
|
if (confirm) {
|
||||||
|
this.doGenerateIndex(ev);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private doGenerateIndex(ev: Event) {
|
||||||
|
(ev.target as HTMLButtonElement).disabled = true;
|
||||||
|
this.maintenanceService.generateElasticIndex().pipe(takeUntil(this._destroyed)).subscribe(
|
||||||
|
_ => {
|
||||||
|
(ev.target as HTMLButtonElement).disabled = false;
|
||||||
|
this.onCallbackSuccess();
|
||||||
|
},
|
||||||
|
error => {
|
||||||
|
(ev.target as HTMLButtonElement).disabled = false;
|
||||||
|
this.onCallbackError(error);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
clearIndex(ev: Event) {
|
||||||
|
this.dialog.open(ConfirmationDialogComponent, {
|
||||||
|
data: {
|
||||||
|
message: this.language.instant('MAINTENANCE-TASKS.CONFIRMATION.MESSAGE'),
|
||||||
|
confirmButton: this.language.instant('GENERAL.CONFIRMATION-DIALOG.ACTIONS.CONFIRM'),
|
||||||
|
cancelButton: this.language.instant('GENERAL.CONFIRMATION-DIALOG.ACTIONS.CANCEL')
|
||||||
|
},
|
||||||
|
maxWidth: '30em'
|
||||||
|
})
|
||||||
|
.afterClosed()
|
||||||
|
.subscribe(confirm => {
|
||||||
|
if (confirm) {
|
||||||
|
this.doClearIndex(ev);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private doClearIndex(ev: Event) {
|
||||||
|
(ev.target as HTMLButtonElement).disabled = true;
|
||||||
|
this.maintenanceService.clearElasticIndex().pipe(takeUntil(this._destroyed)).subscribe(
|
||||||
|
_ => {
|
||||||
|
(ev.target as HTMLButtonElement).disabled = false;
|
||||||
|
this.onCallbackSuccess();
|
||||||
|
},
|
||||||
|
error => {
|
||||||
|
(ev.target as HTMLButtonElement).disabled = false;
|
||||||
|
this.onCallbackError(error);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
sendUserTouchEvents(ev: Event) {
|
||||||
|
this.dialog.open(ConfirmationDialogComponent, {
|
||||||
|
data: {
|
||||||
|
message: this.language.instant('MAINTENANCE-TASKS.CONFIRMATION.MESSAGE'),
|
||||||
|
confirmButton: this.language.instant('GENERAL.CONFIRMATION-DIALOG.ACTIONS.CONFIRM'),
|
||||||
|
cancelButton: this.language.instant('GENERAL.CONFIRMATION-DIALOG.ACTIONS.CANCEL')
|
||||||
|
},
|
||||||
|
maxWidth: '30em'
|
||||||
|
})
|
||||||
|
.afterClosed()
|
||||||
|
.subscribe(confirm => {
|
||||||
|
if (confirm) {
|
||||||
|
this.doSendUserTouchEvents(ev);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private doSendUserTouchEvents(ev: Event) {
|
||||||
|
(ev.target as HTMLButtonElement).disabled = true;
|
||||||
|
this.maintenanceService.sendUserTouchEvents().pipe(takeUntil(this._destroyed)).subscribe(
|
||||||
|
_ => {
|
||||||
|
(ev.target as HTMLButtonElement).disabled = false;
|
||||||
|
this.onCallbackSuccess();
|
||||||
|
},
|
||||||
|
error => {
|
||||||
|
(ev.target as HTMLButtonElement).disabled = false;
|
||||||
|
this.onCallbackError(error);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
sendTenantTouchEvents(ev: Event) {
|
||||||
|
this.dialog.open(ConfirmationDialogComponent, {
|
||||||
|
data: {
|
||||||
|
message: this.language.instant('MAINTENANCE-TASKS.CONFIRMATION.MESSAGE'),
|
||||||
|
confirmButton: this.language.instant('GENERAL.CONFIRMATION-DIALOG.ACTIONS.CONFIRM'),
|
||||||
|
cancelButton: this.language.instant('GENERAL.CONFIRMATION-DIALOG.ACTIONS.CANCEL')
|
||||||
|
},
|
||||||
|
maxWidth: '30em'
|
||||||
|
})
|
||||||
|
.afterClosed()
|
||||||
|
.subscribe(confirm => {
|
||||||
|
if (confirm) {
|
||||||
|
this.doSendTenantTouchEvents(ev);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private doSendTenantTouchEvents(ev: Event) {
|
||||||
|
(ev.target as HTMLButtonElement).disabled = true;
|
||||||
|
this.maintenanceService.sendTenantTouchEvents().pipe(takeUntil(this._destroyed)).subscribe(
|
||||||
|
_ => {
|
||||||
|
(ev.target as HTMLButtonElement).disabled = false;
|
||||||
|
this.onCallbackSuccess();
|
||||||
|
},
|
||||||
|
error => {
|
||||||
|
(ev.target as HTMLButtonElement).disabled = false;
|
||||||
|
this.onCallbackError(error);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
onCallbackSuccess(): void {
|
onCallbackSuccess(): void {
|
||||||
this.uiNotificationService.snackBarNotification(this.translate.instant('GENERAL.SNACK-BAR.SUCCESSFUL-UPDATE'), SnackBarNotificationLevel.Success);
|
this.uiNotificationService.snackBarNotification(this.translate.instant('GENERAL.SNACK-BAR.SUCCESSFUL-UPDATE'), SnackBarNotificationLevel.Success);
|
||||||
this.router.navigate(['/reload']).then(() => this.router.navigate(['/maintenance-tasks']));
|
this.router.navigate(['/reload']).then(() => this.router.navigate(['/maintenance-tasks']));
|
||||||
|
|
|
@ -45,13 +45,13 @@
|
||||||
<div class="col-12 col-lg-4">
|
<div class="col-12 col-lg-4">
|
||||||
<mat-form-field class="w-100">
|
<mat-form-field class="w-100">
|
||||||
<mat-label>{{'NOTIFICATION-SERVICE.NOTIFICATION-TEMPLATE-EDITOR.FIELDS.LANGUAGE' | translate}}</mat-label>
|
<mat-label>{{'NOTIFICATION-SERVICE.NOTIFICATION-TEMPLATE-EDITOR.FIELDS.LANGUAGE' | translate}}</mat-label>
|
||||||
<mat-select [formControl]="formGroup.get('languageId')" name="language" required>
|
<mat-select [formControl]="formGroup.get('languageCode')" name="language" required>
|
||||||
<mat-option *ngFor="let language of languages" [value]="language.id">
|
<mat-option *ngFor="let language of languages" [value]="language.code">
|
||||||
{{language.code}}
|
{{language.code}}
|
||||||
</mat-option>
|
</mat-option>
|
||||||
</mat-select>
|
</mat-select>
|
||||||
<mat-error *ngIf="formGroup.get('languageId').hasError('backendError')">{{formGroup.get('languageId').getError('backendError').message}}</mat-error>
|
<mat-error *ngIf="formGroup.get('languageCode').hasError('backendError')">{{formGroup.get('languageCode').getError('backendError').message}}</mat-error>
|
||||||
<mat-error *ngIf="formGroup.get('languageId').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
|
<mat-error *ngIf="formGroup.get('languageCode').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-12 col-lg-4">
|
<div class="col-12 col-lg-4">
|
||||||
|
|
|
@ -15,7 +15,7 @@ export class NotificationTemplateEditorModel extends BaseEditorModel implements
|
||||||
channel: NotificationTemplateChannel;
|
channel: NotificationTemplateChannel;
|
||||||
notificationType: NotificationType;
|
notificationType: NotificationType;
|
||||||
kind: NotificationTemplateKind;
|
kind: NotificationTemplateKind;
|
||||||
languageId: Guid;
|
languageCode: string;
|
||||||
value: NotificationTemplateValueEditorModel = new NotificationTemplateValueEditorModel();
|
value: NotificationTemplateValueEditorModel = new NotificationTemplateValueEditorModel();
|
||||||
permissions: string[];
|
permissions: string[];
|
||||||
|
|
||||||
|
@ -30,7 +30,7 @@ export class NotificationTemplateEditorModel extends BaseEditorModel implements
|
||||||
this.channel = item.channel;
|
this.channel = item.channel;
|
||||||
this.notificationType = item.notificationType;
|
this.notificationType = item.notificationType;
|
||||||
this.kind = item.kind;
|
this.kind = item.kind;
|
||||||
if(item.language && item.language.id) this.languageId = item.language.id;
|
if(item.languageCode && item.languageCode) this.languageCode = item.languageCode;
|
||||||
if (item.value) { this.value = new NotificationTemplateValueEditorModel(this.validationErrorModel).fromModel(item.value); }
|
if (item.value) { this.value = new NotificationTemplateValueEditorModel(this.validationErrorModel).fromModel(item.value); }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -45,7 +45,7 @@ export class NotificationTemplateEditorModel extends BaseEditorModel implements
|
||||||
channel: [{ value: this.channel, disabled: disabled }, context.getValidation('channel').validators],
|
channel: [{ value: this.channel, disabled: disabled }, context.getValidation('channel').validators],
|
||||||
notificationType: [{ value: this.notificationType, disabled: disabled }, context.getValidation('notificationType').validators],
|
notificationType: [{ value: this.notificationType, disabled: disabled }, context.getValidation('notificationType').validators],
|
||||||
kind: [{ value: this.kind, disabled: disabled }, context.getValidation('kind').validators],
|
kind: [{ value: this.kind, disabled: disabled }, context.getValidation('kind').validators],
|
||||||
languageId: [{ value: this.languageId, disabled: disabled }, context.getValidation('languageId').validators],
|
languageCode: [{ value: this.languageCode, disabled: disabled }, context.getValidation('languageCode').validators],
|
||||||
value: this.value.buildForm({
|
value: this.value.buildForm({
|
||||||
rootPath: `value.`
|
rootPath: `value.`
|
||||||
}),
|
}),
|
||||||
|
@ -60,7 +60,7 @@ export class NotificationTemplateEditorModel extends BaseEditorModel implements
|
||||||
baseValidationArray.push({ key: 'channel', validators: [Validators.required, BackendErrorValidator(this.validationErrorModel, 'channel')] });
|
baseValidationArray.push({ key: 'channel', validators: [Validators.required, BackendErrorValidator(this.validationErrorModel, 'channel')] });
|
||||||
baseValidationArray.push({ key: 'notificationType', validators: [Validators.required, BackendErrorValidator(this.validationErrorModel, 'notificationType')] });
|
baseValidationArray.push({ key: 'notificationType', validators: [Validators.required, BackendErrorValidator(this.validationErrorModel, 'notificationType')] });
|
||||||
baseValidationArray.push({ key: 'kind', validators: [Validators.required, BackendErrorValidator(this.validationErrorModel, 'kind')] });
|
baseValidationArray.push({ key: 'kind', validators: [Validators.required, BackendErrorValidator(this.validationErrorModel, 'kind')] });
|
||||||
baseValidationArray.push({ key: 'languageId', validators: [Validators.required, BackendErrorValidator(this.validationErrorModel, 'languageId')] });
|
baseValidationArray.push({ key: 'languageCode', validators: [Validators.required, BackendErrorValidator(this.validationErrorModel, 'languageCode')] });
|
||||||
baseValidationArray.push({ key: 'value', validators: [Validators.required, BackendErrorValidator(this.validationErrorModel, 'value')] });
|
baseValidationArray.push({ key: 'value', validators: [Validators.required, BackendErrorValidator(this.validationErrorModel, 'value')] });
|
||||||
baseValidationArray.push({ key: 'hash', validators: [] });
|
baseValidationArray.push({ key: 'hash', validators: [] });
|
||||||
|
|
||||||
|
|
|
@ -24,8 +24,7 @@ export class NotificationTemplateEditorResolver extends BaseEditorResolver {
|
||||||
nameof<NotificationTemplate>(x => x.notificationType),
|
nameof<NotificationTemplate>(x => x.notificationType),
|
||||||
nameof<NotificationTemplate>(x => x.kind),
|
nameof<NotificationTemplate>(x => x.kind),
|
||||||
|
|
||||||
[nameof<NotificationTemplate>(x => x.language),nameof<Language>(x => x.id)].join('.'),
|
nameof<NotificationTemplate>(x => x.languageCode),
|
||||||
[nameof<NotificationTemplate>(x => x.language),nameof<Language>(x => x.code)].join('.'),
|
|
||||||
|
|
||||||
[nameof<NotificationTemplate>(x => x.value),nameof<NotificationTemplateValue>(x => x.subjectText)].join('.'),
|
[nameof<NotificationTemplate>(x => x.value),nameof<NotificationTemplateValue>(x => x.subjectText)].join('.'),
|
||||||
[nameof<NotificationTemplate>(x => x.value),nameof<NotificationTemplateValue>(x => x.subjectKey)].join('.'),
|
[nameof<NotificationTemplate>(x => x.value),nameof<NotificationTemplateValue>(x => x.subjectKey)].join('.'),
|
||||||
|
|
|
@ -119,7 +119,7 @@ export class SidebarComponent implements OnInit {
|
||||||
if (this.authentication.hasPermission(AppPermission.ViewSupportiveMaterialPage)) this.adminItems.routes.push({ path: '/supportive-material', title: 'SIDE-BAR.SUPPORTIVE-MATERIAL', icon: 'help_center' });
|
if (this.authentication.hasPermission(AppPermission.ViewSupportiveMaterialPage)) this.adminItems.routes.push({ path: '/supportive-material', title: 'SIDE-BAR.SUPPORTIVE-MATERIAL', icon: 'help_center' });
|
||||||
if (this.authentication.hasPermission(AppPermission.ViewNotificationTemplatePage)) this.adminItems.routes.push({ path: '/notification-templates', title: 'SIDE-BAR.NOTIFICATION-TEMPLATES', icon: 'grid_guides' });
|
if (this.authentication.hasPermission(AppPermission.ViewNotificationTemplatePage)) this.adminItems.routes.push({ path: '/notification-templates', title: 'SIDE-BAR.NOTIFICATION-TEMPLATES', icon: 'grid_guides' });
|
||||||
if (this.authentication.hasPermission(AppPermission.ViewNotificationPage)) this.adminItems.routes.push({ path: '/notifications', title: 'SIDE-BAR.NOTIFICATIONS', icon: 'notifications' });
|
if (this.authentication.hasPermission(AppPermission.ViewNotificationPage)) this.adminItems.routes.push({ path: '/notifications', title: 'SIDE-BAR.NOTIFICATIONS', icon: 'notifications' });
|
||||||
if (this.authentication.hasPermission(AppPermission.ViewMaintenancePage)) this.adminItems.routes.push({ path: '/index-managment', title: 'SIDE-BAR.MAINTENANCE', icon: 'build' });
|
if (this.authentication.hasPermission(AppPermission.ViewMaintenancePage)) this.adminItems.routes.push({ path: '/maintenance-tasks', title: 'SIDE-BAR.MAINTENANCE', icon: 'build' });
|
||||||
this.groupMenuItems.push(this.adminItems);
|
this.groupMenuItems.push(this.adminItems);
|
||||||
|
|
||||||
this.infoItems = {
|
this.infoItems = {
|
||||||
|
|
|
@ -90,7 +90,8 @@
|
||||||
"USERS": "Users",
|
"USERS": "Users",
|
||||||
"PROFILE": "My Profile",
|
"PROFILE": "My Profile",
|
||||||
"LOGIN": "Login",
|
"LOGIN": "Login",
|
||||||
"DATASET-OVERVIEW": "Description Overview"
|
"DATASET-OVERVIEW": "Description Overview",
|
||||||
|
"MAINTENANCE-TASKS": "Maintenance"
|
||||||
},
|
},
|
||||||
"FILE-TRANSFORMER": {
|
"FILE-TRANSFORMER": {
|
||||||
"PDF": "PDF",
|
"PDF": "PDF",
|
||||||
|
@ -271,6 +272,29 @@
|
||||||
"PRIVATE": "Hidden"
|
"PRIVATE": "Hidden"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"MAINTENANCE-TASKS": {
|
||||||
|
"SECTIONS": {
|
||||||
|
"INDEXES": {
|
||||||
|
"TITLE": "Manage indexes",
|
||||||
|
"DESCRIPTION": "From here you can manage the Elastic indexes",
|
||||||
|
"ACTIONS": {
|
||||||
|
"GENERATE-INDEX": "Generate Index",
|
||||||
|
"CLEAR-INDEX": "Clear Index"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"EVENTS": {
|
||||||
|
"TITLE": "Manage events",
|
||||||
|
"DESCRIPTION": "From here you can manage the Message Queue events",
|
||||||
|
"ACTIONS": {
|
||||||
|
"SEND-USER-TOUCH": "Send user touch events",
|
||||||
|
"SEND-TENANT-TOUCH": "Send tenant touch events"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"CONFIRMATION": {
|
||||||
|
"MESSAGE": "Are you sure you want to perform this action?"
|
||||||
|
}
|
||||||
|
},
|
||||||
"DESCRIPTION-TEMPLATE-EDITOR": {
|
"DESCRIPTION-TEMPLATE-EDITOR": {
|
||||||
"TITLE": {
|
"TITLE": {
|
||||||
"NEW": "New API Client",
|
"NEW": "New API Client",
|
||||||
|
|
|
@ -3,7 +3,7 @@ package gr.cite.notification.web;
|
||||||
import gr.cite.notification.web.scope.tenant.TenantInterceptor;
|
import gr.cite.notification.web.scope.tenant.TenantInterceptor;
|
||||||
import gr.cite.notification.web.scope.tenant.TenantScopeClaimInterceptor;
|
import gr.cite.notification.web.scope.tenant.TenantScopeClaimInterceptor;
|
||||||
import gr.cite.notification.web.scope.tenant.TenantScopeHeaderInterceptor;
|
import gr.cite.notification.web.scope.tenant.TenantScopeHeaderInterceptor;
|
||||||
import gr.cite.notification.web.interceptors.UserInterceptor;
|
import gr.cite.notification.web.scope.user.UserInterceptor;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
|
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
|
||||||
|
|
|
@ -26,6 +26,8 @@ import org.springframework.security.web.authentication.preauth.AbstractPreAuthen
|
||||||
|
|
||||||
import jakarta.servlet.Filter;
|
import jakarta.servlet.Filter;
|
||||||
import jakarta.servlet.http.HttpServletRequest;
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
|
@ -98,7 +100,7 @@ public class SecurityConfiguration {
|
||||||
//In the example below, the default client handler will be ignored by the resolver
|
//In the example below, the default client handler will be ignored by the resolver
|
||||||
@Override
|
@Override
|
||||||
public List<Class<? extends AuthorizationHandler<? extends AuthorizationRequirement>>> disableHandlers() {
|
public List<Class<? extends AuthorizationHandler<? extends AuthorizationRequirement>>> disableHandlers() {
|
||||||
return List.of(PermissionClientAuthorizationHandler.class);
|
return new ArrayList<>();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -75,17 +75,4 @@ public class PrincipalController {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping("my-tenants")
|
|
||||||
public List<String> myTenants() {
|
|
||||||
logger.debug("my-tenants");
|
|
||||||
|
|
||||||
MyPrincipal principal = this.currentPrincipalResolver.currentPrincipal();
|
|
||||||
List<String> tenants = this.claimExtractor.asStrings(principal, TenantScope.TenantCodesClaimName);
|
|
||||||
|
|
||||||
this.auditService.track(AuditableAction.Tenants_Lookup);
|
|
||||||
//auditService.trackIdentity(AuditableAction.IdentityTracking_Action);
|
|
||||||
|
|
||||||
return tenants == null ? null : tenants.stream().distinct().collect(Collectors.toList());
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,103 +0,0 @@
|
||||||
package gr.cite.notification.web.interceptors;
|
|
||||||
|
|
||||||
|
|
||||||
import gr.cite.commons.web.oidc.principal.CurrentPrincipalResolver;
|
|
||||||
import gr.cite.commons.web.oidc.principal.extractor.ClaimExtractor;
|
|
||||||
import gr.cite.notification.common.JsonHandlingService;
|
|
||||||
import gr.cite.notification.common.lock.LockByKeyManager;
|
|
||||||
import gr.cite.notification.common.scope.user.UserScope;
|
|
||||||
import gr.cite.notification.data.UserCredentialEntity;
|
|
||||||
import gr.cite.notification.model.UserCredential;
|
|
||||||
import gr.cite.notification.query.UserCredentialQuery;
|
|
||||||
import gr.cite.tools.data.query.QueryFactory;
|
|
||||||
import gr.cite.tools.exception.MyForbiddenException;
|
|
||||||
import gr.cite.tools.fieldset.BaseFieldSet;
|
|
||||||
import gr.cite.tools.logging.LoggerService;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
|
||||||
import org.springframework.lang.NonNull;
|
|
||||||
import org.springframework.stereotype.Component;
|
|
||||||
import org.springframework.transaction.PlatformTransactionManager;
|
|
||||||
import org.springframework.ui.ModelMap;
|
|
||||||
import org.springframework.web.context.request.WebRequest;
|
|
||||||
import org.springframework.web.context.request.WebRequestInterceptor;
|
|
||||||
|
|
||||||
import jakarta.persistence.EntityManager;
|
|
||||||
import jakarta.persistence.PersistenceContext;
|
|
||||||
|
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
@Component
|
|
||||||
public class UserInterceptor implements WebRequestInterceptor {
|
|
||||||
private static final LoggerService logger = new LoggerService(LoggerFactory.getLogger(UserInterceptor.class));
|
|
||||||
private final UserScope userScope;
|
|
||||||
private final ClaimExtractor claimExtractor;
|
|
||||||
private final CurrentPrincipalResolver currentPrincipalResolver;
|
|
||||||
private final PlatformTransactionManager transactionManager;
|
|
||||||
private final UserInterceptorCacheService userInterceptorCacheService;
|
|
||||||
private final JsonHandlingService jsonHandlingService;
|
|
||||||
private final QueryFactory queryFactory;
|
|
||||||
private final LockByKeyManager lockByKeyManager;
|
|
||||||
@PersistenceContext
|
|
||||||
public EntityManager entityManager;
|
|
||||||
|
|
||||||
@Autowired
|
|
||||||
public UserInterceptor(
|
|
||||||
UserScope userScope,
|
|
||||||
ClaimExtractor claimExtractor,
|
|
||||||
CurrentPrincipalResolver currentPrincipalResolver,
|
|
||||||
PlatformTransactionManager transactionManager,
|
|
||||||
UserInterceptorCacheService userInterceptorCacheService,
|
|
||||||
JsonHandlingService jsonHandlingService,
|
|
||||||
QueryFactory queryFactory,
|
|
||||||
LockByKeyManager lockByKeyManager) {
|
|
||||||
this.userScope = userScope;
|
|
||||||
this.currentPrincipalResolver = currentPrincipalResolver;
|
|
||||||
this.claimExtractor = claimExtractor;
|
|
||||||
this.transactionManager = transactionManager;
|
|
||||||
this.userInterceptorCacheService = userInterceptorCacheService;
|
|
||||||
this.jsonHandlingService = jsonHandlingService;
|
|
||||||
this.queryFactory = queryFactory;
|
|
||||||
this.lockByKeyManager = lockByKeyManager;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void preHandle(WebRequest request) {
|
|
||||||
UUID userId = null;
|
|
||||||
if (this.currentPrincipalResolver.currentPrincipal().isAuthenticated()) {
|
|
||||||
String subjectId = this.claimExtractor.subjectString(this.currentPrincipalResolver.currentPrincipal());
|
|
||||||
if (subjectId == null || subjectId.isBlank()) throw new MyForbiddenException("Empty subjects not allowed");
|
|
||||||
|
|
||||||
UserInterceptorCacheService.UserInterceptorCacheValue cacheValue = this.userInterceptorCacheService.lookup(this.userInterceptorCacheService.buildKey(subjectId));
|
|
||||||
if (cacheValue != null) {
|
|
||||||
userId = cacheValue.getUserId();
|
|
||||||
} else {
|
|
||||||
userId = this.findExistingUserFromDbForce(subjectId);
|
|
||||||
|
|
||||||
cacheValue = new UserInterceptorCacheService.UserInterceptorCacheValue(subjectId, userId);
|
|
||||||
|
|
||||||
this.userInterceptorCacheService.put(cacheValue);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
this.userScope.setUserId(userId);
|
|
||||||
}
|
|
||||||
|
|
||||||
private UUID findExistingUserFromDbForce(String subjectId){
|
|
||||||
UserCredentialEntity userCredential = this.queryFactory.query(UserCredentialQuery.class).externalIds(subjectId).firstAs(new BaseFieldSet().ensure(UserCredential._user));
|
|
||||||
if (userCredential != null) {
|
|
||||||
return userCredential.getUserId();
|
|
||||||
} else {
|
|
||||||
throw new MyForbiddenException("User not created try again.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void postHandle(@NonNull WebRequest request, ModelMap model) {
|
|
||||||
this.userScope.setUserId(null);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void afterCompletion(@NonNull WebRequest request, Exception ex) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,10 +0,0 @@
|
||||||
package gr.cite.notification.web.interceptors;
|
|
||||||
|
|
||||||
import gr.cite.tools.cache.CacheOptions;
|
|
||||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
|
||||||
import org.springframework.context.annotation.Configuration;
|
|
||||||
|
|
||||||
@Configuration
|
|
||||||
@ConfigurationProperties(prefix = "cache.user-by-subject-id")
|
|
||||||
public class UserInterceptorCacheOptions extends CacheOptions {
|
|
||||||
}
|
|
|
@ -1,68 +0,0 @@
|
||||||
package gr.cite.notification.web.interceptors;
|
|
||||||
|
|
||||||
import gr.cite.notification.convention.ConventionService;
|
|
||||||
import gr.cite.tools.cache.CacheService;
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
|
||||||
import org.springframework.stereotype.Service;
|
|
||||||
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
@Service
|
|
||||||
public class UserInterceptorCacheService extends CacheService<UserInterceptorCacheService.UserInterceptorCacheValue> {
|
|
||||||
|
|
||||||
public static class UserInterceptorCacheValue {
|
|
||||||
|
|
||||||
public UserInterceptorCacheValue() {
|
|
||||||
}
|
|
||||||
|
|
||||||
public UserInterceptorCacheValue(String subjectId, UUID userId) {
|
|
||||||
this.subjectId = subjectId;
|
|
||||||
this.userId = userId;
|
|
||||||
}
|
|
||||||
|
|
||||||
private String subjectId;
|
|
||||||
|
|
||||||
public String getSubjectId() {
|
|
||||||
return subjectId;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setSubjectId(String subjectId) {
|
|
||||||
this.subjectId = subjectId;
|
|
||||||
}
|
|
||||||
|
|
||||||
private UUID userId;
|
|
||||||
public UUID getUserId() {
|
|
||||||
return userId;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setUserId(UUID userId) {
|
|
||||||
this.userId = userId;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Autowired
|
|
||||||
public UserInterceptorCacheService(UserInterceptorCacheOptions options) {
|
|
||||||
super(options);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected Class<UserInterceptorCacheValue> valueClass() {
|
|
||||||
return UserInterceptorCacheValue.class;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String keyOf(UserInterceptorCacheValue value) {
|
|
||||||
return this.buildKey(value.getSubjectId());
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public String buildKey(String subject) {
|
|
||||||
HashMap<String, String> keyParts = new HashMap<>();
|
|
||||||
keyParts.put("$subject$", subject);
|
|
||||||
return this.generateKey(keyParts);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -54,8 +54,10 @@ public class TenantByCodeCacheService extends CacheService<TenantByCodeCacheServ
|
||||||
|
|
||||||
@EventListener
|
@EventListener
|
||||||
public void handleTenantTouchedEvent(TenantTouchedEvent event) {
|
public void handleTenantTouchedEvent(TenantTouchedEvent event) {
|
||||||
if (!this.conventionService.isNullOrEmpty(event.getTenantCode())) this.evict(this.buildKey(event.getTenantCode()));
|
if (!this.conventionService.isNullOrEmpty(event.getTenantCode()))
|
||||||
if (!this.conventionService.isNullOrEmpty(event.getPreviousTenantCode())) this.evict(this.buildKey(event.getPreviousTenantCode()));
|
this.evict(this.buildKey(event.getTenantCode()));
|
||||||
|
if (!this.conventionService.isNullOrEmpty(event.getPreviousTenantCode()))
|
||||||
|
this.evict(this.buildKey(event.getPreviousTenantCode()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -69,8 +71,8 @@ public class TenantByCodeCacheService extends CacheService<TenantByCodeCacheServ
|
||||||
}
|
}
|
||||||
|
|
||||||
public String buildKey(String code) {
|
public String buildKey(String code) {
|
||||||
return this.generateKey(new HashMap<>() {{
|
HashMap<String, String> keyParts = new HashMap<>();
|
||||||
put("$code$", code);
|
keyParts.put("$code$", code);
|
||||||
}});
|
return this.generateKey(keyParts);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -55,7 +55,8 @@ public class TenantByIdCacheService extends CacheService<TenantByIdCacheService.
|
||||||
|
|
||||||
@EventListener
|
@EventListener
|
||||||
public void handleTenantTouchedEvent(TenantTouchedEvent event) {
|
public void handleTenantTouchedEvent(TenantTouchedEvent event) {
|
||||||
if (!this.conventionService.isNullOrEmpty(event.getTenantCode())) this.evict(this.buildKey(event.getTenantId()));
|
if (!this.conventionService.isNullOrEmpty(event.getTenantCode()))
|
||||||
|
this.evict(this.buildKey(event.getTenantId()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -69,8 +70,8 @@ public class TenantByIdCacheService extends CacheService<TenantByIdCacheService.
|
||||||
}
|
}
|
||||||
|
|
||||||
public String buildKey(UUID id) {
|
public String buildKey(UUID id) {
|
||||||
return this.generateKey(new HashMap<>() {{
|
HashMap<String, String> keyParts = new HashMap<>();
|
||||||
put("$tenantId$", id.toString().toLowerCase(Locale.ROOT));
|
keyParts.put("$tenantId$", id.toString().toLowerCase(Locale.ROOT));
|
||||||
}});
|
return this.generateKey(keyParts);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@ package gr.cite.notification.web.scope.tenant;
|
||||||
import gr.cite.commons.web.authz.service.AuthorizationService;
|
import gr.cite.commons.web.authz.service.AuthorizationService;
|
||||||
import gr.cite.commons.web.oidc.principal.CurrentPrincipalResolver;
|
import gr.cite.commons.web.oidc.principal.CurrentPrincipalResolver;
|
||||||
import gr.cite.commons.web.oidc.principal.extractor.ClaimExtractor;
|
import gr.cite.commons.web.oidc.principal.extractor.ClaimExtractor;
|
||||||
|
import gr.cite.notification.authorization.ClaimNames;
|
||||||
import gr.cite.notification.authorization.Permission;
|
import gr.cite.notification.authorization.Permission;
|
||||||
import gr.cite.notification.common.enums.IsActive;
|
import gr.cite.notification.common.enums.IsActive;
|
||||||
import gr.cite.notification.common.scope.tenant.TenantScope;
|
import gr.cite.notification.common.scope.tenant.TenantScope;
|
||||||
|
@ -12,9 +13,17 @@ import gr.cite.notification.data.TenantUserEntity;
|
||||||
import gr.cite.notification.data.UserEntity;
|
import gr.cite.notification.data.UserEntity;
|
||||||
import gr.cite.notification.data.tenant.TenantScopedBaseEntity;
|
import gr.cite.notification.data.tenant.TenantScopedBaseEntity;
|
||||||
import gr.cite.notification.errorcode.ErrorThesaurusProperties;
|
import gr.cite.notification.errorcode.ErrorThesaurusProperties;
|
||||||
|
import gr.cite.notification.query.utils.BuildSubQueryInput;
|
||||||
|
import gr.cite.notification.query.utils.QueryUtilsService;
|
||||||
import gr.cite.tools.exception.MyForbiddenException;
|
import gr.cite.tools.exception.MyForbiddenException;
|
||||||
import gr.cite.tools.logging.LoggerService;
|
import gr.cite.tools.logging.LoggerService;
|
||||||
|
import jakarta.persistence.EntityManager;
|
||||||
|
import jakarta.persistence.PersistenceContext;
|
||||||
|
import jakarta.persistence.criteria.CriteriaBuilder;
|
||||||
|
import jakarta.persistence.criteria.CriteriaQuery;
|
||||||
|
import jakarta.persistence.criteria.Root;
|
||||||
import org.hibernate.Session;
|
import org.hibernate.Session;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.context.ApplicationContext;
|
import org.springframework.context.ApplicationContext;
|
||||||
|
@ -26,15 +35,9 @@ import org.springframework.web.context.request.WebRequest;
|
||||||
import org.springframework.web.context.request.WebRequestInterceptor;
|
import org.springframework.web.context.request.WebRequestInterceptor;
|
||||||
|
|
||||||
import javax.management.InvalidApplicationException;
|
import javax.management.InvalidApplicationException;
|
||||||
import jakarta.persistence.EntityManager;
|
|
||||||
import jakarta.persistence.PersistenceContext;
|
|
||||||
import jakarta.persistence.Tuple;
|
|
||||||
import jakarta.persistence.criteria.CriteriaBuilder;
|
|
||||||
import jakarta.persistence.criteria.CriteriaQuery;
|
|
||||||
import jakarta.persistence.criteria.Root;
|
|
||||||
import jakarta.persistence.criteria.Subquery;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
@Component
|
@Component
|
||||||
public class TenantInterceptor implements WebRequestInterceptor {
|
public class TenantInterceptor implements WebRequestInterceptor {
|
||||||
|
@ -45,11 +48,10 @@ public class TenantInterceptor implements WebRequestInterceptor {
|
||||||
private final CurrentPrincipalResolver currentPrincipalResolver;
|
private final CurrentPrincipalResolver currentPrincipalResolver;
|
||||||
private final ClaimExtractor claimExtractor;
|
private final ClaimExtractor claimExtractor;
|
||||||
private final ApplicationContext applicationContext;
|
private final ApplicationContext applicationContext;
|
||||||
private final ErrorThesaurusProperties errorThesaurusProperties;
|
|
||||||
private final TenantScopeProperties tenantScopeProperties;
|
private final TenantScopeProperties tenantScopeProperties;
|
||||||
private final UserAllowedTenantCacheService userAllowedTenantCacheService;
|
private final UserAllowedTenantCacheService userAllowedTenantCacheService;
|
||||||
private final ErrorThesaurusProperties errors;
|
private final ErrorThesaurusProperties errors;
|
||||||
|
private final QueryUtilsService queryUtilsService;
|
||||||
@PersistenceContext
|
@PersistenceContext
|
||||||
public EntityManager entityManager;
|
public EntityManager entityManager;
|
||||||
|
|
||||||
|
@ -60,35 +62,37 @@ public class TenantInterceptor implements WebRequestInterceptor {
|
||||||
CurrentPrincipalResolver currentPrincipalResolver,
|
CurrentPrincipalResolver currentPrincipalResolver,
|
||||||
ClaimExtractor claimExtractor,
|
ClaimExtractor claimExtractor,
|
||||||
ApplicationContext applicationContext,
|
ApplicationContext applicationContext,
|
||||||
ErrorThesaurusProperties errorThesaurusProperties,
|
|
||||||
TenantScopeProperties tenantScopeProperties,
|
TenantScopeProperties tenantScopeProperties,
|
||||||
UserAllowedTenantCacheService userAllowedTenantCacheService,
|
UserAllowedTenantCacheService userAllowedTenantCacheService,
|
||||||
ErrorThesaurusProperties errors) {
|
ErrorThesaurusProperties errors, QueryUtilsService queryUtilsService) {
|
||||||
this.tenantScope = tenantScope;
|
this.tenantScope = tenantScope;
|
||||||
this.userScope = userScope;
|
this.userScope = userScope;
|
||||||
this.currentPrincipalResolver = currentPrincipalResolver;
|
this.currentPrincipalResolver = currentPrincipalResolver;
|
||||||
this.claimExtractor = claimExtractor;
|
this.claimExtractor = claimExtractor;
|
||||||
this.applicationContext = applicationContext;
|
this.applicationContext = applicationContext;
|
||||||
this.errorThesaurusProperties = errorThesaurusProperties;
|
|
||||||
this.tenantScopeProperties = tenantScopeProperties;
|
this.tenantScopeProperties = tenantScopeProperties;
|
||||||
this.userAllowedTenantCacheService = userAllowedTenantCacheService;
|
this.userAllowedTenantCacheService = userAllowedTenantCacheService;
|
||||||
this.errors = errors;
|
this.errors = errors;
|
||||||
|
this.queryUtilsService = queryUtilsService;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void preHandle(WebRequest request) throws InvalidApplicationException {
|
public void preHandle(@NotNull WebRequest request) throws InvalidApplicationException, InterruptedException {
|
||||||
if (!this.currentPrincipalResolver.currentPrincipal().isAuthenticated()) return;
|
if (!this.currentPrincipalResolver.currentPrincipal().isAuthenticated()) return;
|
||||||
if (!this.tenantScope.isMultitenant()) return;
|
if (!this.tenantScope.isMultitenant()) return;
|
||||||
|
|
||||||
boolean isAllowedNoTenant = this.applicationContext.getBean(AuthorizationService.class).authorize(Permission.AllowNoTenant);
|
boolean isAllowedNoTenant = this.applicationContext.getBean(AuthorizationService.class).authorize(Permission.AllowNoTenant);
|
||||||
if (tenantScope.isSet() && this.entityManager != null) {
|
if (tenantScope.isSet() && this.entityManager != null) {
|
||||||
List<String> currentPrincipalTenantCodes = this.claimExtractor.asStrings(this.currentPrincipalResolver.currentPrincipal(), TenantScope.TenantCodesClaimName);
|
List<String> currentPrincipalTenantCodes = this.claimExtractor.asStrings(this.currentPrincipalResolver.currentPrincipal(), ClaimNames.TenantCodesClaimName);
|
||||||
if ((currentPrincipalTenantCodes == null || !currentPrincipalTenantCodes.contains(tenantScope.getTenantCode())) && !isAllowedNoTenant) {
|
if ((currentPrincipalTenantCodes == null || !currentPrincipalTenantCodes.contains(tenantScope.getTenantCode())) && !isAllowedNoTenant) {
|
||||||
logger.warn("tenant not allowed {}", this.tenantScope.getTenant());
|
logger.warn("tenant not allowed {}", this.tenantScope.getTenant());
|
||||||
//throw new MyForbiddenException(this.errors.getTenantNotAllowed().getCode(), this.errors.getTenantNotAllowed().getMessage());
|
throw new MyForbiddenException(this.errors.getTenantNotAllowed().getCode(), this.errors.getTenantNotAllowed().getMessage());
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean isUserAllowedTenant = false;
|
boolean isUserAllowedTenant = false;
|
||||||
|
if (this.tenantScope.isDefaultTenant()){
|
||||||
|
isUserAllowedTenant = true;
|
||||||
|
} else {
|
||||||
UserAllowedTenantCacheService.UserAllowedTenantCacheValue cacheValue = this.userAllowedTenantCacheService.lookup(this.userAllowedTenantCacheService.buildKey(this.userScope.getUserId(), this.tenantScope.getTenant()));
|
UserAllowedTenantCacheService.UserAllowedTenantCacheValue cacheValue = this.userAllowedTenantCacheService.lookup(this.userAllowedTenantCacheService.buildKey(this.userScope.getUserId(), this.tenantScope.getTenant()));
|
||||||
if (cacheValue != null) {
|
if (cacheValue != null) {
|
||||||
isUserAllowedTenant = cacheValue.isAllowed();
|
isUserAllowedTenant = cacheValue.isAllowed();
|
||||||
|
@ -96,24 +100,32 @@ public class TenantInterceptor implements WebRequestInterceptor {
|
||||||
isUserAllowedTenant = this.isUserAllowedTenant();
|
isUserAllowedTenant = this.isUserAllowedTenant();
|
||||||
this.userAllowedTenantCacheService.put(new UserAllowedTenantCacheService.UserAllowedTenantCacheValue(this.userScope.getUserId(), this.tenantScope.getTenant(), isUserAllowedTenant));
|
this.userAllowedTenantCacheService.put(new UserAllowedTenantCacheService.UserAllowedTenantCacheValue(this.userScope.getUserId(), this.tenantScope.getTenant(), isUserAllowedTenant));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (isUserAllowedTenant) {
|
if (isUserAllowedTenant) {
|
||||||
|
if(!tenantScope.isDefaultTenant()) {
|
||||||
this.entityManager
|
this.entityManager
|
||||||
.unwrap(Session.class)
|
.unwrap(Session.class)
|
||||||
.enableFilter(TenantScopedBaseEntity.tenantFilter).setParameter(TenantScopedBaseEntity.tenantFilterTenantParam, tenantScope.getTenant().toString());
|
.enableFilter(TenantScopedBaseEntity.TENANT_FILTER)
|
||||||
|
.setParameter(TenantScopedBaseEntity.TENANT_FILTER_TENANT_PARAM, tenantScope.getTenant().toString());
|
||||||
|
} else {
|
||||||
|
this.entityManager
|
||||||
|
.unwrap(Session.class)
|
||||||
|
.enableFilter(TenantScopedBaseEntity.DEFAULT_TENANT_FILTER);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
if (isAllowedNoTenant || this.isWhiteListedEndpoint(request)) {
|
if (isAllowedNoTenant || this.isWhiteListedEndpoint(request)) {
|
||||||
tenantScope.setTenant(null, null);
|
tenantScope.setTenant(null, null);
|
||||||
} else {
|
} else {
|
||||||
logger.warn("tenant not allowed {}", this.tenantScope.getTenant());
|
logger.warn("tenant not allowed {}", this.tenantScope.getTenant());
|
||||||
//throw new MyForbiddenException(this.errors.getTenantNotAllowed().getCode(), this.errors.getTenantNotAllowed().getMessage());
|
throw new MyForbiddenException(this.errors.getTenantNotAllowed().getCode(), this.errors.getTenantNotAllowed().getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (!isAllowedNoTenant) {
|
if (!isAllowedNoTenant) {
|
||||||
if (!this.isWhiteListedEndpoint(request)) {
|
if (!this.isWhiteListedEndpoint(request)) {
|
||||||
logger.warn("tenant scope not provided");
|
logger.warn("tenant scope not provided");
|
||||||
throw new MyForbiddenException(this.errorThesaurusProperties.getMissingTenant().getCode(), this.errorThesaurusProperties.getMissingTenant().getMessage());
|
throw new MyForbiddenException(this.errors.getMissingTenant().getCode(), this.errors.getMissingTenant().getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -131,26 +143,36 @@ public class TenantInterceptor implements WebRequestInterceptor {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isUserAllowedTenant() throws InvalidApplicationException {
|
private boolean isUserAllowedTenant() throws InvalidApplicationException, InterruptedException {
|
||||||
if (userScope.isSet()) {
|
if (userScope.isSet()) {
|
||||||
CriteriaBuilder criteriaBuilder = this.entityManager.getCriteriaBuilder();
|
CriteriaBuilder criteriaBuilder = this.entityManager.getCriteriaBuilder();
|
||||||
CriteriaQuery<Tuple> query = criteriaBuilder.createQuery(Tuple.class);
|
CriteriaQuery<UserEntity> query = criteriaBuilder.createQuery(UserEntity.class);
|
||||||
Root<UserEntity> root = query.from(UserEntity.class);
|
Root<UserEntity> root = query.from(UserEntity.class);
|
||||||
Subquery<TenantUserEntity> subQuery = query.subquery(TenantUserEntity.class);
|
|
||||||
Root<TenantUserEntity> subQueryRoot = subQuery.from(TenantUserEntity.class);
|
|
||||||
query.where(criteriaBuilder.and(
|
query.where(criteriaBuilder.and(
|
||||||
criteriaBuilder.equal(root.get(UserEntity._isActive), IsActive.Active),
|
criteriaBuilder.equal(root.get(UserEntity._isActive), IsActive.Active),
|
||||||
criteriaBuilder.in(root.get(UserEntity._id)).value(subQuery.where(
|
criteriaBuilder.in(root.get(UserEntity._id)).value(queryUtilsService.buildSubQuery(new BuildSubQueryInput<>(new BuildSubQueryInput.Builder<>(TenantUserEntity.class, UUID.class)
|
||||||
criteriaBuilder.and(
|
.query(query)
|
||||||
|
.criteriaBuilder(criteriaBuilder)
|
||||||
|
.keyPathFunc((subQueryRoot) -> subQueryRoot.get(TenantUserEntity._userId))
|
||||||
|
.filterFunc((subQueryRoot, cb) ->
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
return cb.and(
|
||||||
criteriaBuilder.equal(subQueryRoot.get(TenantUserEntity._tenantId), this.tenantScope.getTenant()),
|
criteriaBuilder.equal(subQueryRoot.get(TenantUserEntity._tenantId), this.tenantScope.getTenant()),
|
||||||
criteriaBuilder.equal(subQueryRoot.get(TenantUserEntity._userId), this.userScope.getUserId()),
|
criteriaBuilder.equal(subQueryRoot.get(TenantUserEntity._userId), this.userScope.getUserId()),
|
||||||
criteriaBuilder.equal(subQueryRoot.get(TenantUserEntity._isActive), IsActive.Active)
|
criteriaBuilder.equal(subQueryRoot.get(TenantUserEntity._isActive), IsActive.Active)
|
||||||
)).select(subQueryRoot.get(TenantUserEntity._userId)).distinct(true)
|
);
|
||||||
|
} catch (InvalidApplicationException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
))
|
||||||
)
|
)
|
||||||
));
|
));
|
||||||
query.multiselect(root.get(UserEntity._id).alias(UserEntity._id));
|
query.multiselect(root.get(UserEntity._id).alias(UserEntity._id));
|
||||||
List<Tuple> results = this.entityManager.createQuery(query).getResultList();
|
List<UserEntity> results = this.entityManager.createQuery(query).getResultList();
|
||||||
if (results.size() > 0) return true;
|
return !results.isEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -5,6 +5,7 @@ import gr.cite.commons.web.oidc.principal.CurrentPrincipalResolver;
|
||||||
import gr.cite.commons.web.oidc.principal.MyPrincipal;
|
import gr.cite.commons.web.oidc.principal.MyPrincipal;
|
||||||
import gr.cite.commons.web.oidc.principal.extractor.ClaimExtractor;
|
import gr.cite.commons.web.oidc.principal.extractor.ClaimExtractor;
|
||||||
import gr.cite.commons.web.oidc.principal.extractor.ClaimExtractorContext;
|
import gr.cite.commons.web.oidc.principal.extractor.ClaimExtractorContext;
|
||||||
|
import gr.cite.notification.authorization.ClaimNames;
|
||||||
import gr.cite.notification.common.enums.IsActive;
|
import gr.cite.notification.common.enums.IsActive;
|
||||||
import gr.cite.notification.common.scope.tenant.TenantScope;
|
import gr.cite.notification.common.scope.tenant.TenantScope;
|
||||||
import gr.cite.notification.convention.ConventionService;
|
import gr.cite.notification.convention.ConventionService;
|
||||||
|
@ -12,6 +13,11 @@ import gr.cite.notification.data.TenantEntity;
|
||||||
import gr.cite.notification.errorcode.ErrorThesaurusProperties;
|
import gr.cite.notification.errorcode.ErrorThesaurusProperties;
|
||||||
import gr.cite.tools.exception.MyForbiddenException;
|
import gr.cite.tools.exception.MyForbiddenException;
|
||||||
import gr.cite.tools.logging.LoggerService;
|
import gr.cite.tools.logging.LoggerService;
|
||||||
|
import jakarta.persistence.EntityManager;
|
||||||
|
import jakarta.persistence.PersistenceContext;
|
||||||
|
import jakarta.persistence.criteria.CriteriaBuilder;
|
||||||
|
import jakarta.persistence.criteria.CriteriaQuery;
|
||||||
|
import jakarta.persistence.criteria.Root;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
@ -22,12 +28,6 @@ import org.springframework.web.context.request.WebRequest;
|
||||||
import org.springframework.web.context.request.WebRequestInterceptor;
|
import org.springframework.web.context.request.WebRequestInterceptor;
|
||||||
|
|
||||||
import javax.management.InvalidApplicationException;
|
import javax.management.InvalidApplicationException;
|
||||||
import jakarta.persistence.EntityManager;
|
|
||||||
import jakarta.persistence.PersistenceContext;
|
|
||||||
import jakarta.persistence.Tuple;
|
|
||||||
import jakarta.persistence.criteria.CriteriaBuilder;
|
|
||||||
import jakarta.persistence.criteria.CriteriaQuery;
|
|
||||||
import jakarta.persistence.criteria.Root;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
|
@ -68,7 +68,7 @@ public class TenantScopeClaimInterceptor implements WebRequestInterceptor {
|
||||||
this.claimExtractorContext = claimExtractorContext;
|
this.claimExtractorContext = claimExtractorContext;
|
||||||
this.tenantByCodeCacheService = tenantByCodeCacheService;
|
this.tenantByCodeCacheService = tenantByCodeCacheService;
|
||||||
this.tenantByIdCacheService = tenantByIdCacheService;
|
this.tenantByIdCacheService = tenantByIdCacheService;
|
||||||
this.clientTenantClaimName = this.tenantScopeProperties.getClientClaimsPrefix() + TenantScope.TenantClaimName;
|
this.clientTenantClaimName = this.tenantScopeProperties.getClientClaimsPrefix() + ClaimNames.TenantClaimName;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -78,18 +78,26 @@ public class TenantScopeClaimInterceptor implements WebRequestInterceptor {
|
||||||
|
|
||||||
MyPrincipal principal = this.currentPrincipalResolver.currentPrincipal();
|
MyPrincipal principal = this.currentPrincipalResolver.currentPrincipal();
|
||||||
if (principal != null && principal.isAuthenticated() /* principal.Claims.Any() */) {
|
if (principal != null && principal.isAuthenticated() /* principal.Claims.Any() */) {
|
||||||
Boolean scoped = this.scopeByPrincipal(this.tenantScope, principal);
|
boolean scoped = this.scopeByPrincipal(principal);
|
||||||
if (!scoped) scoped = this.scopeByClient(this.tenantScope, principal);
|
if (!scoped) scoped = this.scopeByClient(principal);
|
||||||
if (!scoped && this.tenantScope.isSet() && this.tenantScopeProperties.getEnforceTrustedTenant()) throw new MyForbiddenException(this.errorThesaurusProperties.getMissingTenant().getCode(), this.errorThesaurusProperties.getMissingTenant().getMessage());
|
if (!scoped && this.tenantScope.isSet() && this.tenantScopeProperties.getEnforceTrustedTenant())
|
||||||
|
throw new MyForbiddenException(this.errorThesaurusProperties.getMissingTenant().getCode(), this.errorThesaurusProperties.getMissingTenant().getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private Boolean scopeByPrincipal(TenantScope scope, MyPrincipal principal) {
|
private boolean scopeByPrincipal(MyPrincipal principal) {
|
||||||
String tenantCode = this.claimExtractor.tenantString(principal);
|
String tenantCode = this.claimExtractor.tenantString(principal);
|
||||||
if (tenantCode == null || tenantCode.isBlank()) tenantCode = this.claimExtractor.asString(principal, this.clientTenantClaimName);
|
if (this.conventionService.isNullOrEmpty(tenantCode)) tenantCode = this.claimExtractor.asString(principal, this.clientTenantClaimName);
|
||||||
|
if (tenantCode == null || this.conventionService.isNullOrEmpty(tenantCode)) return false;
|
||||||
|
|
||||||
|
if (tenantCode.equalsIgnoreCase(this.tenantScope.getDefaultTenantCode())){
|
||||||
|
logger.debug("parsed tenant header and set tenant to default tenant");
|
||||||
|
this.tenantScope.setTenant(null, tenantCode);
|
||||||
|
this.claimExtractorContext.putReplaceParameter(TenantScope.TenantReplaceParameter, tenantCode);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
UUID tenantId = this.conventionService.parseUUIDSafe(tenantCode);
|
UUID tenantId = this.conventionService.parseUUIDSafe(tenantCode);
|
||||||
if (tenantId == null && tenantCode == null) return false;
|
|
||||||
if (tenantId == null) {
|
if (tenantId == null) {
|
||||||
TenantByCodeCacheService.TenantByCodeCacheValue cacheValue = this.tenantByCodeCacheService.lookup(this.tenantByCodeCacheService.buildKey(tenantCode));
|
TenantByCodeCacheService.TenantByCodeCacheValue cacheValue = this.tenantByCodeCacheService.lookup(this.tenantByCodeCacheService.buildKey(tenantCode));
|
||||||
if (cacheValue != null) {
|
if (cacheValue != null) {
|
||||||
|
@ -112,26 +120,27 @@ public class TenantScopeClaimInterceptor implements WebRequestInterceptor {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tenantId != null && tenantCode != null && !tenantCode.isBlank()) {
|
if (tenantId != null) {
|
||||||
logger.debug("parsed tenant header and set tenant id to {}", tenantId);
|
logger.debug("parsed tenant header and set tenant id to {}", tenantId);
|
||||||
this.tenantScope.setTenant(tenantId, tenantCode);
|
this.tenantScope.setTenant(tenantId, tenantCode);
|
||||||
this.claimExtractorContext.putReplaceParameter(TenantScope.TenantReplaceParameter, tenantCode);
|
this.claimExtractorContext.putReplaceParameter(TenantScope.TenantReplaceParameter, tenantCode);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
return tenantId != null;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Boolean scopeByClient(TenantScope scope, MyPrincipal principal) throws InvalidApplicationException {
|
private boolean scopeByClient(MyPrincipal principal) throws InvalidApplicationException {
|
||||||
String client = this.claimExtractor.client(principal);
|
String client = this.claimExtractor.client(principal);
|
||||||
|
|
||||||
Boolean isWhiteListed = this.tenantScopeProperties.getWhiteListedClients() != null && !this.conventionService.isNullOrEmpty(client) && this.tenantScopeProperties.getWhiteListedClients().contains(client);
|
Boolean isWhiteListed = this.tenantScopeProperties.getWhiteListedClients() != null && !this.conventionService.isNullOrEmpty(client) && this.tenantScopeProperties.getWhiteListedClients().contains(client);
|
||||||
logger.debug("client is whitelisted : {}, scope is set: {}, with value {}", isWhiteListed, scope.isSet(), (scope.isSet() ? scope.getTenant() : null));
|
logger.debug("client is whitelisted : {}, scope is set: {}, with value {}", isWhiteListed, this.tenantScope.isSet(), (this.tenantScope.isSet() ? this.tenantScope.getTenant() : null));
|
||||||
|
|
||||||
return isWhiteListed && scope.isSet();
|
return isWhiteListed && this.tenantScope.isSet();
|
||||||
}
|
}
|
||||||
|
|
||||||
private UUID getTenantIdFromDatabase(String tenantCode) {
|
private UUID getTenantIdFromDatabase(String tenantCode) {
|
||||||
CriteriaBuilder criteriaBuilder = this.entityManager.getCriteriaBuilder();
|
CriteriaBuilder criteriaBuilder = this.entityManager.getCriteriaBuilder();
|
||||||
CriteriaQuery<Tuple> query = criteriaBuilder.createQuery(Tuple.class);
|
CriteriaQuery<TenantEntity> query = criteriaBuilder.createQuery(TenantEntity.class);
|
||||||
Root<TenantEntity> root = query.from(TenantEntity.class);
|
Root<TenantEntity> root = query.from(TenantEntity.class);
|
||||||
query = query.where(
|
query = query.where(
|
||||||
criteriaBuilder.and(
|
criteriaBuilder.and(
|
||||||
|
@ -139,27 +148,16 @@ public class TenantScopeClaimInterceptor implements WebRequestInterceptor {
|
||||||
criteriaBuilder.equal(root.get(TenantEntity._isActive), IsActive.Active)
|
criteriaBuilder.equal(root.get(TenantEntity._isActive), IsActive.Active)
|
||||||
)
|
)
|
||||||
).multiselect(root.get(TenantEntity._id).alias(TenantEntity._id));
|
).multiselect(root.get(TenantEntity._id).alias(TenantEntity._id));
|
||||||
List<Tuple> results = this.entityManager.createQuery(query).getResultList();
|
List<TenantEntity> results = this.entityManager.createQuery(query).getResultList();
|
||||||
if (results.size() == 1) {
|
if (results.size() == 1) {
|
||||||
Object o;
|
return results.getFirst().getId();
|
||||||
try {
|
|
||||||
o = results.get(0).get(TenantEntity._id);
|
|
||||||
} catch (IllegalArgumentException e) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
if (o == null) return null;
|
|
||||||
try {
|
|
||||||
return (UUID) o;
|
|
||||||
} catch (ClassCastException e) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private String getTenantCodeFromDatabase(UUID tenantId) {
|
private String getTenantCodeFromDatabase(UUID tenantId) {
|
||||||
CriteriaBuilder criteriaBuilder = this.entityManager.getCriteriaBuilder();
|
CriteriaBuilder criteriaBuilder = this.entityManager.getCriteriaBuilder();
|
||||||
CriteriaQuery<Tuple> query = criteriaBuilder.createQuery(Tuple.class);
|
CriteriaQuery<TenantEntity> query = criteriaBuilder.createQuery(TenantEntity.class);
|
||||||
Root<TenantEntity> root = query.from(TenantEntity.class);
|
Root<TenantEntity> root = query.from(TenantEntity.class);
|
||||||
query = query.where(
|
query = query.where(
|
||||||
criteriaBuilder.and(
|
criteriaBuilder.and(
|
||||||
|
@ -167,20 +165,9 @@ public class TenantScopeClaimInterceptor implements WebRequestInterceptor {
|
||||||
criteriaBuilder.equal(root.get(TenantEntity._isActive), IsActive.Active)
|
criteriaBuilder.equal(root.get(TenantEntity._isActive), IsActive.Active)
|
||||||
)
|
)
|
||||||
).multiselect(root.get(TenantEntity._code).alias(TenantEntity._code));
|
).multiselect(root.get(TenantEntity._code).alias(TenantEntity._code));
|
||||||
List<Tuple> results = this.entityManager.createQuery(query).getResultList();
|
List<TenantEntity> results = this.entityManager.createQuery(query).getResultList();
|
||||||
if (results.size() == 1) {
|
if (results.size() == 1) {
|
||||||
Object o;
|
return results.getFirst().getCode();
|
||||||
try {
|
|
||||||
o = results.get(0).get(TenantEntity._code);
|
|
||||||
} catch (IllegalArgumentException e) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
if (o == null) return null;
|
|
||||||
try {
|
|
||||||
return (String) o;
|
|
||||||
} catch (ClassCastException e) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,11 +3,18 @@ package gr.cite.notification.web.scope.tenant;
|
||||||
|
|
||||||
import gr.cite.commons.web.oidc.principal.CurrentPrincipalResolver;
|
import gr.cite.commons.web.oidc.principal.CurrentPrincipalResolver;
|
||||||
import gr.cite.commons.web.oidc.principal.extractor.ClaimExtractorContext;
|
import gr.cite.commons.web.oidc.principal.extractor.ClaimExtractorContext;
|
||||||
|
import gr.cite.notification.authorization.ClaimNames;
|
||||||
import gr.cite.notification.common.enums.IsActive;
|
import gr.cite.notification.common.enums.IsActive;
|
||||||
import gr.cite.notification.common.scope.tenant.TenantScope;
|
import gr.cite.notification.common.scope.tenant.TenantScope;
|
||||||
import gr.cite.notification.convention.ConventionService;
|
import gr.cite.notification.convention.ConventionService;
|
||||||
import gr.cite.notification.data.TenantEntity;
|
import gr.cite.notification.data.TenantEntity;
|
||||||
import gr.cite.tools.logging.LoggerService;
|
import gr.cite.tools.logging.LoggerService;
|
||||||
|
import jakarta.persistence.EntityManager;
|
||||||
|
import jakarta.persistence.PersistenceContext;
|
||||||
|
import jakarta.persistence.criteria.CriteriaBuilder;
|
||||||
|
import jakarta.persistence.criteria.CriteriaQuery;
|
||||||
|
import jakarta.persistence.criteria.Root;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.lang.NonNull;
|
import org.springframework.lang.NonNull;
|
||||||
|
@ -16,13 +23,6 @@ import org.springframework.ui.ModelMap;
|
||||||
import org.springframework.web.context.request.WebRequest;
|
import org.springframework.web.context.request.WebRequest;
|
||||||
import org.springframework.web.context.request.WebRequestInterceptor;
|
import org.springframework.web.context.request.WebRequestInterceptor;
|
||||||
|
|
||||||
import javax.management.InvalidApplicationException;
|
|
||||||
import jakarta.persistence.EntityManager;
|
|
||||||
import jakarta.persistence.PersistenceContext;
|
|
||||||
import jakarta.persistence.Tuple;
|
|
||||||
import jakarta.persistence.criteria.CriteriaBuilder;
|
|
||||||
import jakarta.persistence.criteria.CriteriaQuery;
|
|
||||||
import jakarta.persistence.criteria.Root;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
|
@ -56,16 +56,22 @@ public class TenantScopeHeaderInterceptor implements WebRequestInterceptor {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void preHandle(WebRequest request) throws InvalidApplicationException {
|
public void preHandle(@NotNull WebRequest request) {
|
||||||
if (!this.currentPrincipalResolver.currentPrincipal().isAuthenticated()) return;
|
if (!this.currentPrincipalResolver.currentPrincipal().isAuthenticated()) return;
|
||||||
if (!this.tenantScope.isMultitenant()) return;
|
if (!this.tenantScope.isMultitenant()) return;
|
||||||
|
|
||||||
String tenantCode = request.getHeader(TenantScope.TenantClaimName);
|
String tenantCode = request.getHeader(ClaimNames.TenantClaimName);
|
||||||
logger.debug("retrieved request tenant header is: {header}", tenantCode);
|
logger.debug("retrieved request tenant header is: {}", tenantCode);
|
||||||
if (this.conventionService.isNullOrEmpty(tenantCode)) return;
|
if (tenantCode == null || this.conventionService.isNullOrEmpty(tenantCode)) return;
|
||||||
|
|
||||||
|
if (tenantCode.equalsIgnoreCase(this.tenantScope.getDefaultTenantCode())){
|
||||||
|
logger.debug("parsed tenant header and set tenant to default tenant");
|
||||||
|
this.tenantScope.setTenant(null, tenantCode);
|
||||||
|
this.claimExtractorContext.putReplaceParameter(TenantScope.TenantReplaceParameter, tenantCode);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
UUID tenantId = this.conventionService.parseUUIDSafe(tenantCode);
|
UUID tenantId = this.conventionService.parseUUIDSafe(tenantCode);
|
||||||
if (tenantId == null && tenantCode == null) return;
|
|
||||||
if (tenantId == null) {
|
if (tenantId == null) {
|
||||||
TenantByCodeCacheService.TenantByCodeCacheValue cacheValue = this.tenantByCodeCacheService.lookup(this.tenantByCodeCacheService.buildKey(tenantCode));
|
TenantByCodeCacheService.TenantByCodeCacheValue cacheValue = this.tenantByCodeCacheService.lookup(this.tenantByCodeCacheService.buildKey(tenantCode));
|
||||||
if (cacheValue != null) {
|
if (cacheValue != null) {
|
||||||
|
@ -86,8 +92,8 @@ public class TenantScopeHeaderInterceptor implements WebRequestInterceptor {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tenantId != null && tenantCode != null && !tenantCode.isBlank()) {
|
if (tenantId != null) {
|
||||||
logger.debug("parsed tenant header and set tenant id to {tenant}", tenantId);
|
logger.debug("parsed tenant header and set tenant id to {}", tenantId);
|
||||||
this.tenantScope.setTenant(tenantId, tenantCode);
|
this.tenantScope.setTenant(tenantId, tenantCode);
|
||||||
this.claimExtractorContext.putReplaceParameter(TenantScope.TenantReplaceParameter, tenantCode);
|
this.claimExtractorContext.putReplaceParameter(TenantScope.TenantReplaceParameter, tenantCode);
|
||||||
}
|
}
|
||||||
|
@ -95,7 +101,7 @@ public class TenantScopeHeaderInterceptor implements WebRequestInterceptor {
|
||||||
|
|
||||||
private UUID getTenantIdFromDatabase(String tenantCode) {
|
private UUID getTenantIdFromDatabase(String tenantCode) {
|
||||||
CriteriaBuilder criteriaBuilder = this.entityManager.getCriteriaBuilder();
|
CriteriaBuilder criteriaBuilder = this.entityManager.getCriteriaBuilder();
|
||||||
CriteriaQuery<Tuple> query = criteriaBuilder.createQuery(Tuple.class);
|
CriteriaQuery<TenantEntity> query = criteriaBuilder.createQuery(TenantEntity.class);
|
||||||
Root<TenantEntity> root = query.from(TenantEntity.class);
|
Root<TenantEntity> root = query.from(TenantEntity.class);
|
||||||
query = query.where(
|
query = query.where(
|
||||||
criteriaBuilder.and(
|
criteriaBuilder.and(
|
||||||
|
@ -103,27 +109,16 @@ public class TenantScopeHeaderInterceptor implements WebRequestInterceptor {
|
||||||
criteriaBuilder.equal(root.get(TenantEntity._isActive), IsActive.Active)
|
criteriaBuilder.equal(root.get(TenantEntity._isActive), IsActive.Active)
|
||||||
)
|
)
|
||||||
).multiselect(root.get(TenantEntity._id).alias(TenantEntity._id));
|
).multiselect(root.get(TenantEntity._id).alias(TenantEntity._id));
|
||||||
List<Tuple> results = this.entityManager.createQuery(query).getResultList();
|
List<TenantEntity> results = this.entityManager.createQuery(query).getResultList();
|
||||||
if (results.size() == 1) {
|
if (results.size() == 1) {
|
||||||
Object o;
|
return results.getFirst().getId();
|
||||||
try {
|
|
||||||
o = results.get(0).get(TenantEntity._id);
|
|
||||||
} catch (IllegalArgumentException e) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
if (o == null) return null;
|
|
||||||
try {
|
|
||||||
return UUID.class.cast(o);
|
|
||||||
} catch (ClassCastException e) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private String getTenantCodeFromDatabase(UUID tenantId) {
|
private String getTenantCodeFromDatabase(UUID tenantId) {
|
||||||
CriteriaBuilder criteriaBuilder = this.entityManager.getCriteriaBuilder();
|
CriteriaBuilder criteriaBuilder = this.entityManager.getCriteriaBuilder();
|
||||||
CriteriaQuery<Tuple> query = criteriaBuilder.createQuery(Tuple.class);
|
CriteriaQuery<TenantEntity> query = criteriaBuilder.createQuery(TenantEntity.class);
|
||||||
Root<TenantEntity> root = query.from(TenantEntity.class);
|
Root<TenantEntity> root = query.from(TenantEntity.class);
|
||||||
query = query.where(
|
query = query.where(
|
||||||
criteriaBuilder.and(
|
criteriaBuilder.and(
|
||||||
|
@ -131,20 +126,9 @@ public class TenantScopeHeaderInterceptor implements WebRequestInterceptor {
|
||||||
criteriaBuilder.equal(root.get(TenantEntity._isActive), IsActive.Active)
|
criteriaBuilder.equal(root.get(TenantEntity._isActive), IsActive.Active)
|
||||||
)
|
)
|
||||||
).multiselect(root.get(TenantEntity._code).alias(TenantEntity._code));
|
).multiselect(root.get(TenantEntity._code).alias(TenantEntity._code));
|
||||||
List<Tuple> results = this.entityManager.createQuery(query).getResultList();
|
List<TenantEntity> results = this.entityManager.createQuery(query).getResultList();
|
||||||
if (results.size() == 1) {
|
if (results.size() == 1) {
|
||||||
Object o;
|
return results.getFirst().getCode();
|
||||||
try {
|
|
||||||
o = results.get(0).get(TenantEntity._code);
|
|
||||||
} catch (IllegalArgumentException e) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
if (o == null) return null;
|
|
||||||
try {
|
|
||||||
return String.class.cast(o);
|
|
||||||
} catch (ClassCastException e) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,4 +40,5 @@ public class TenantScopeProperties {
|
||||||
public void setEnforceTrustedTenant(Boolean enforceTrustedTenant) {
|
public void setEnforceTrustedTenant(Boolean enforceTrustedTenant) {
|
||||||
this.enforceTrustedTenant = enforceTrustedTenant;
|
this.enforceTrustedTenant = enforceTrustedTenant;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,3 +8,5 @@ import org.springframework.context.annotation.Configuration;
|
||||||
@ConfigurationProperties(prefix = "cache.user-allowed-tenant")
|
@ConfigurationProperties(prefix = "cache.user-allowed-tenant")
|
||||||
public class UserAllowedTenantCacheOptions extends CacheOptions {
|
public class UserAllowedTenantCacheOptions extends CacheOptions {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -82,9 +82,10 @@ public class UserAllowedTenantCacheService extends CacheService<UserAllowedTenan
|
||||||
}
|
}
|
||||||
|
|
||||||
public String buildKey(UUID userId, UUID tenantId) {
|
public String buildKey(UUID userId, UUID tenantId) {
|
||||||
return this.generateKey(new HashMap<>() {{
|
HashMap<String, String> keyParts = new HashMap<>();
|
||||||
put("$user_id$", userId.toString().toLowerCase(Locale.ROOT));
|
keyParts.put("$user_id$", userId.toString().toLowerCase(Locale.ROOT));
|
||||||
put("$tenant_id$", tenantId.toString().toLowerCase(Locale.ROOT));
|
keyParts.put("$tenant_id$", tenantId.toString().toLowerCase(Locale.ROOT));
|
||||||
}});
|
return this.generateKey(keyParts);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,154 +1,81 @@
|
||||||
//package gr.cite.notification.web.scope.user;
|
package gr.cite.notification.web.scope.user;
|
||||||
//
|
|
||||||
//
|
|
||||||
//import gr.cite.commons.web.oidc.principal.CurrentPrincipalResolver;
|
import gr.cite.commons.web.oidc.principal.CurrentPrincipalResolver;
|
||||||
//import gr.cite.commons.web.oidc.principal.extractor.ClaimExtractor;
|
import gr.cite.commons.web.oidc.principal.extractor.ClaimExtractor;
|
||||||
//import gr.cite.notification.common.enums.IsActive;
|
import gr.cite.notification.common.scope.user.UserScope;
|
||||||
//import gr.cite.notification.common.scope.user.UserScope;
|
import gr.cite.notification.data.UserCredentialEntity;
|
||||||
//import gr.cite.notification.data.UserEntity;
|
import gr.cite.notification.model.UserCredential;
|
||||||
//import gr.cite.notification.locale.LocaleService;
|
import gr.cite.notification.query.UserCredentialQuery;
|
||||||
//import gr.cite.tools.logging.LoggerService;
|
import gr.cite.tools.data.query.QueryFactory;
|
||||||
//import org.slf4j.LoggerFactory;
|
import gr.cite.tools.exception.MyForbiddenException;
|
||||||
//import org.springframework.beans.factory.annotation.Autowired;
|
import gr.cite.tools.fieldset.BaseFieldSet;
|
||||||
//import org.springframework.lang.NonNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
//import org.springframework.stereotype.Component;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
//import org.springframework.transaction.PlatformTransactionManager;
|
import org.springframework.lang.NonNull;
|
||||||
//import org.springframework.transaction.TransactionDefinition;
|
import org.springframework.stereotype.Component;
|
||||||
//import org.springframework.transaction.TransactionStatus;
|
import org.springframework.ui.ModelMap;
|
||||||
//import org.springframework.transaction.support.DefaultTransactionDefinition;
|
import org.springframework.web.context.request.WebRequest;
|
||||||
//import org.springframework.ui.ModelMap;
|
import org.springframework.web.context.request.WebRequestInterceptor;
|
||||||
//import org.springframework.web.context.request.WebRequest;
|
|
||||||
//import org.springframework.web.context.request.WebRequestInterceptor;
|
import java.util.UUID;
|
||||||
//
|
|
||||||
//import javax.management.InvalidApplicationException;
|
@Component
|
||||||
//import jakarta.persistence.EntityManager;
|
public class UserInterceptor implements WebRequestInterceptor {
|
||||||
//import jakarta.persistence.PersistenceContext;
|
private final UserScope userScope;
|
||||||
//import jakarta.persistence.Tuple;
|
private final ClaimExtractor claimExtractor;
|
||||||
//import jakarta.persistence.criteria.CriteriaBuilder;
|
private final CurrentPrincipalResolver currentPrincipalResolver;
|
||||||
//import jakarta.persistence.criteria.CriteriaQuery;
|
private final UserInterceptorCacheService userInterceptorCacheService;
|
||||||
//import jakarta.persistence.criteria.Root;
|
private final QueryFactory queryFactory;
|
||||||
//import java.time.Instant;
|
|
||||||
//import java.util.List;
|
@Autowired
|
||||||
//import java.util.UUID;
|
public UserInterceptor(
|
||||||
//
|
UserScope userScope,
|
||||||
//@Component
|
ClaimExtractor claimExtractor,
|
||||||
//public class UserInterceptor implements WebRequestInterceptor {
|
CurrentPrincipalResolver currentPrincipalResolver,
|
||||||
// private static final LoggerService logger = new LoggerService(LoggerFactory.getLogger(UserInterceptor.class));
|
UserInterceptorCacheService userInterceptorCacheService,
|
||||||
// private final UserScope userScope;
|
QueryFactory queryFactory) {
|
||||||
// private final ClaimExtractor claimExtractor;
|
this.userScope = userScope;
|
||||||
// private final CurrentPrincipalResolver currentPrincipalResolver;
|
this.currentPrincipalResolver = currentPrincipalResolver;
|
||||||
// private final LocaleService localeService;
|
this.claimExtractor = claimExtractor;
|
||||||
// private final PlatformTransactionManager transactionManager;
|
this.userInterceptorCacheService = userInterceptorCacheService;
|
||||||
// private final UserInterceptorCacheService userInterceptorCacheService;
|
this.queryFactory = queryFactory;
|
||||||
// @PersistenceContext
|
}
|
||||||
// public EntityManager entityManager;
|
|
||||||
//
|
@Override
|
||||||
// @Autowired
|
public void preHandle(@NotNull WebRequest request) {
|
||||||
// public UserInterceptor(
|
UUID userId = null;
|
||||||
// UserScope userScope,
|
if (this.currentPrincipalResolver.currentPrincipal().isAuthenticated()) {
|
||||||
// LocaleService localeService,
|
String subjectId = this.claimExtractor.subjectString(this.currentPrincipalResolver.currentPrincipal());
|
||||||
// ClaimExtractor claimExtractor,
|
if (subjectId == null || subjectId.isBlank()) throw new MyForbiddenException("Empty subjects not allowed");
|
||||||
// CurrentPrincipalResolver currentPrincipalResolver,
|
|
||||||
// PlatformTransactionManager transactionManager,
|
UserInterceptorCacheService.UserInterceptorCacheValue cacheValue = this.userInterceptorCacheService.lookup(this.userInterceptorCacheService.buildKey(subjectId));
|
||||||
// UserInterceptorCacheService userInterceptorCacheService
|
if (cacheValue != null) {
|
||||||
// ) {
|
userId = cacheValue.getUserId();
|
||||||
// this.userScope = userScope;
|
} else {
|
||||||
// this.localeService = localeService;
|
userId = this.findExistingUserFromDb(subjectId);
|
||||||
// this.currentPrincipalResolver = currentPrincipalResolver;
|
if (userId != null) {
|
||||||
// this.claimExtractor = claimExtractor;
|
cacheValue = new UserInterceptorCacheService.UserInterceptorCacheValue(subjectId, userId);
|
||||||
// this.transactionManager = transactionManager;
|
this.userInterceptorCacheService.put(cacheValue);
|
||||||
// this.userInterceptorCacheService = userInterceptorCacheService;
|
}
|
||||||
// }
|
}
|
||||||
//
|
}
|
||||||
// @Override
|
this.userScope.setUserId(userId);
|
||||||
// public void preHandle(WebRequest request) throws InvalidApplicationException {
|
}
|
||||||
// UUID userId = null;
|
private UUID findExistingUserFromDb(String subjectId) {
|
||||||
// if (this.currentPrincipalResolver.currentPrincipal().isAuthenticated()) {
|
UserCredentialEntity userCredential = this.queryFactory.query(UserCredentialQuery.class).externalIds(subjectId).firstAs(new BaseFieldSet().ensure(UserCredential._user));
|
||||||
// String subjectId = this.claimExtractor.subjectString(this.currentPrincipalResolver.currentPrincipal());
|
if (userCredential != null) {
|
||||||
//
|
return userCredential.getUserId();
|
||||||
// UserInterceptorCacheService.UserInterceptorCacheValue cacheValue = this.userInterceptorCacheService.lookup(this.userInterceptorCacheService.buildKey(subjectId));
|
}
|
||||||
// if (cacheValue != null) {
|
return null;
|
||||||
// userId = cacheValue.getUserId();
|
}
|
||||||
// } else {
|
@Override
|
||||||
// userId = this.getUserIdFromDatabase(subjectId);
|
public void postHandle(@NonNull WebRequest request, ModelMap model) {
|
||||||
// if (userId == null) userId = this.createUser(subjectId);
|
this.userScope.setUserId(null);
|
||||||
//
|
}
|
||||||
// this.userInterceptorCacheService.put(new UserInterceptorCacheService.UserInterceptorCacheValue(subjectId, userId));
|
|
||||||
// }
|
@Override
|
||||||
// }
|
public void afterCompletion(@NonNull WebRequest request, Exception ex) {
|
||||||
// this.userScope.setUserId(userId);
|
}
|
||||||
// }
|
}
|
||||||
//
|
|
||||||
// private UUID getUserIdFromDatabase(String subjectId) throws InvalidApplicationException {
|
|
||||||
// CriteriaBuilder criteriaBuilder = this.entityManager.getCriteriaBuilder();
|
|
||||||
// CriteriaQuery<Tuple> query = criteriaBuilder.createQuery(Tuple.class);
|
|
||||||
// Root<UserEntity> root = query.from(UserEntity.class);
|
|
||||||
// query.where(
|
|
||||||
// criteriaBuilder.and(
|
|
||||||
//// criteriaBuilder.equal(root.get(UserEntity._subjectId), subjectId),
|
|
||||||
// criteriaBuilder.equal(root.get(UserEntity._isActive), IsActive.Active)
|
|
||||||
// ));
|
|
||||||
//
|
|
||||||
// query.multiselect(root.get(UserEntity._id).alias(UserEntity._id));
|
|
||||||
//
|
|
||||||
// List<Tuple> results = this.entityManager.createQuery(query).getResultList();
|
|
||||||
// if (results.size() == 1) {
|
|
||||||
// Object o;
|
|
||||||
// try {
|
|
||||||
// o = results.get(0).get(UserEntity._id);
|
|
||||||
// } catch (IllegalArgumentException e) {
|
|
||||||
// return null;
|
|
||||||
// }
|
|
||||||
// if (o == null) return null;
|
|
||||||
// try {
|
|
||||||
// return UUID.class.cast(o);
|
|
||||||
// } catch (ClassCastException e) {
|
|
||||||
// return null;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// return null;
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// private UUID createUser(String subjectId) {
|
|
||||||
// String name = this.claimExtractor.name(this.currentPrincipalResolver.currentPrincipal());
|
|
||||||
// String familyName = this.claimExtractor.familyName(this.currentPrincipalResolver.currentPrincipal());
|
|
||||||
// if (name == null) name = subjectId;
|
|
||||||
// UserEntity user = new UserEntity();
|
|
||||||
// user.setId(UUID.randomUUID());
|
|
||||||
// user.setCreatedAt(Instant.now());
|
|
||||||
// user.setUpdatedAt(Instant.now());
|
|
||||||
// user.setName(name);
|
|
||||||
//// user.setLastName(familyName == null ? name : familyName);
|
|
||||||
// user.setIsActive(IsActive.Active);
|
|
||||||
//// user.setSubjectId(subjectId);
|
|
||||||
//// user.setCulture(this.localeService.cultureName());
|
|
||||||
//// user.setTimezone(this.localeService.timezoneName());
|
|
||||||
//// user.setLanguage(this.localeService.language());
|
|
||||||
//
|
|
||||||
// DefaultTransactionDefinition definition = new DefaultTransactionDefinition();
|
|
||||||
// definition.setName(UUID.randomUUID().toString());
|
|
||||||
// definition.setIsolationLevel(TransactionDefinition.ISOLATION_READ_COMMITTED);
|
|
||||||
// definition.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
|
|
||||||
// TransactionStatus status = null;
|
|
||||||
// try {
|
|
||||||
// status = transactionManager.getTransaction(definition);
|
|
||||||
// this.entityManager.persist(user);
|
|
||||||
//
|
|
||||||
// this.entityManager.flush();
|
|
||||||
// transactionManager.commit(status);
|
|
||||||
// } catch (Exception ex) {
|
|
||||||
// if (status != null) transactionManager.rollback(status);
|
|
||||||
// throw ex;
|
|
||||||
// }
|
|
||||||
// return user.getId();
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// @Override
|
|
||||||
// public void postHandle(@NonNull WebRequest request, ModelMap model) {
|
|
||||||
// this.userScope.setUserId(null);
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// @Override
|
|
||||||
// public void afterCompletion(@NonNull WebRequest request, Exception ex) {
|
|
||||||
// }
|
|
||||||
//}
|
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
//package gr.cite.notification.web.scope.user;
|
package gr.cite.notification.web.scope.user;
|
||||||
//
|
|
||||||
//import gr.cite.tools.cache.CacheOptions;
|
import gr.cite.tools.cache.CacheOptions;
|
||||||
//import org.springframework.boot.context.properties.ConfigurationProperties;
|
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||||
//import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
//
|
|
||||||
//@Configuration
|
@Configuration
|
||||||
//@ConfigurationProperties(prefix = "cache.user-by-subject-id")
|
@ConfigurationProperties(prefix = "cache.user-by-subject-id")
|
||||||
//public class UserInterceptorCacheOptions extends CacheOptions {
|
public class UserInterceptorCacheOptions extends CacheOptions {
|
||||||
//}
|
}
|
||||||
|
|
|
@ -1,77 +1,67 @@
|
||||||
//package gr.cite.notification.web.scope.user;
|
package gr.cite.notification.web.scope.user;
|
||||||
//
|
|
||||||
//import gr.cite.notification.convention.ConventionService;
|
import gr.cite.notification.convention.ConventionService;
|
||||||
//import gr.cite.notification.event.UserTouchedEvent;
|
import gr.cite.tools.cache.CacheService;
|
||||||
//import gr.cite.tools.cache.CacheService;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
//import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.stereotype.Service;
|
||||||
//import org.springframework.context.event.EventListener;
|
|
||||||
//import org.springframework.stereotype.Service;
|
import java.util.HashMap;
|
||||||
//
|
import java.util.UUID;
|
||||||
//import java.util.HashMap;
|
|
||||||
//import java.util.UUID;
|
@Service
|
||||||
//
|
public class UserInterceptorCacheService extends CacheService<UserInterceptorCacheService.UserInterceptorCacheValue> {
|
||||||
//@Service
|
|
||||||
//public class UserInterceptorCacheService extends CacheService<UserInterceptorCacheService.UserInterceptorCacheValue> {
|
public static class UserInterceptorCacheValue {
|
||||||
//
|
|
||||||
// public static class UserInterceptorCacheValue {
|
public UserInterceptorCacheValue() {
|
||||||
//
|
}
|
||||||
// public UserInterceptorCacheValue() {
|
|
||||||
// }
|
public UserInterceptorCacheValue(String subjectId, UUID userId) {
|
||||||
//
|
this.subjectId = subjectId;
|
||||||
// public UserInterceptorCacheValue(String subjectId, UUID userId) {
|
this.userId = userId;
|
||||||
// this.subjectId = subjectId;
|
}
|
||||||
// this.userId = userId;
|
|
||||||
// }
|
|
||||||
//
|
public String getSubjectId() {
|
||||||
// private String subjectId;
|
return subjectId;
|
||||||
//
|
}
|
||||||
// public String getSubjectId() {
|
|
||||||
// return subjectId;
|
public void setSubjectId(String subjectId) {
|
||||||
// }
|
this.subjectId = subjectId;
|
||||||
//
|
}
|
||||||
// public void setSubjectId(String subjectId) {
|
|
||||||
// this.subjectId = subjectId;
|
private String subjectId;
|
||||||
// }
|
private UUID userId;
|
||||||
//
|
|
||||||
// private UUID userId;
|
public UUID getUserId() {
|
||||||
//
|
return userId;
|
||||||
// public UUID getUserId() {
|
}
|
||||||
// return userId;
|
|
||||||
// }
|
public void setUserId(UUID userId) {
|
||||||
//
|
this.userId = userId;
|
||||||
// public void setUserId(UUID userId) {
|
}
|
||||||
// this.userId = userId;
|
}
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
@Autowired
|
||||||
// private final ConventionService conventionService;
|
public UserInterceptorCacheService(UserInterceptorCacheOptions options, ConventionService conventionService) {
|
||||||
//
|
super(options);
|
||||||
// @Autowired
|
}
|
||||||
// public UserInterceptorCacheService(UserInterceptorCacheOptions options, ConventionService conventionService) {
|
|
||||||
// super(options);
|
@Override
|
||||||
// this.conventionService = conventionService;
|
protected Class<UserInterceptorCacheValue> valueClass() {
|
||||||
// }
|
return UserInterceptorCacheValue.class;
|
||||||
//
|
}
|
||||||
// @EventListener
|
|
||||||
// public void handleUserTouchedEvent(UserTouchedEvent event) {
|
@Override
|
||||||
// if (!this.conventionService.isNullOrEmpty(event.getSubjectId())) this.evict(this.buildKey(event.getSubjectId()));
|
public String keyOf(UserInterceptorCacheValue value) {
|
||||||
// if (!this.conventionService.isNullOrEmpty(event.getPreviousSubjectId())) this.evict(this.buildKey(event.getPreviousSubjectId()));
|
return this.buildKey(value.getSubjectId());
|
||||||
// }
|
}
|
||||||
//
|
|
||||||
// @Override
|
|
||||||
// protected Class<UserInterceptorCacheValue> valueClass() {
|
public String buildKey(String subject) {
|
||||||
// return UserInterceptorCacheValue.class;
|
HashMap<String, String> keyParts = new HashMap<>();
|
||||||
// }
|
keyParts.put("$subject$", subject);
|
||||||
//
|
return this.generateKey(keyParts);
|
||||||
// @Override
|
}
|
||||||
// public String keyOf(UserInterceptorCacheValue value) {
|
}
|
||||||
// return this.buildKey(value.getSubjectId());
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
//
|
|
||||||
// public String buildKey(String subject) {
|
|
||||||
// return this.generateKey(new HashMap<>() {{
|
|
||||||
// put("$subject$", subject);
|
|
||||||
// }});
|
|
||||||
// }
|
|
||||||
//}
|
|
||||||
|
|
|
@ -26,8 +26,11 @@ error-thesaurus:
|
||||||
non-person-principal:
|
non-person-principal:
|
||||||
code: 108
|
code: 108
|
||||||
message: the operation is available only to person users
|
message: the operation is available only to person users
|
||||||
blocking-consent:
|
tenant-not-allowed:
|
||||||
code: 113
|
code: 113
|
||||||
|
message: tenant not allowed
|
||||||
|
blocking-consent:
|
||||||
|
code: 114
|
||||||
message: user consents are not sufficient to complete the operation
|
message: user consents are not sufficient to complete the operation
|
||||||
single-tenant-configuration-per-type-supported:
|
single-tenant-configuration-per-type-supported:
|
||||||
code: 116
|
code: 116
|
||||||
|
@ -41,3 +44,6 @@ error-thesaurus:
|
||||||
overlapping-tenant-configuration-notifier-list:
|
overlapping-tenant-configuration-notifier-list:
|
||||||
code: 119
|
code: 119
|
||||||
message: Overlapping Tenant Configuration Notifier List
|
message: Overlapping Tenant Configuration Notifier List
|
||||||
|
tenant-tampering:
|
||||||
|
code: 123
|
||||||
|
message: Tenant tampering
|
||||||
|
|
|
@ -20,11 +20,25 @@ idpclient:
|
||||||
Roles:
|
Roles:
|
||||||
- type: resource_access
|
- type: resource_access
|
||||||
path: dmp_web.roles
|
path: dmp_web.roles
|
||||||
|
- type: tenant_roles
|
||||||
|
filterBy: "(.*):::TenantCode::"
|
||||||
|
extractByExpression: "(.*):(.*)"
|
||||||
|
extractExpressionValue: "[[g1]]"
|
||||||
|
GlobalRoles:
|
||||||
|
- type: resource_access
|
||||||
|
path: dmp_web.roles
|
||||||
|
TenantRoles:
|
||||||
|
- type: tenant_roles
|
||||||
|
filterBy: "(.*):::TenantCode::"
|
||||||
|
extractByExpression: "(.*):(.*)"
|
||||||
|
extractExpressionValue: "[[g1]]"
|
||||||
Scope:
|
Scope:
|
||||||
- type: scope
|
- type: scope
|
||||||
AccessToken:
|
AccessToken:
|
||||||
- type: x-access-token
|
- type: x-access-token
|
||||||
visibility: SENSITIVE
|
visibility: SENSITIVE
|
||||||
|
Tenant:
|
||||||
|
- type: x-tenant
|
||||||
IssuedAt:
|
IssuedAt:
|
||||||
- type: iat
|
- type: iat
|
||||||
Issuer:
|
Issuer:
|
||||||
|
@ -37,5 +51,8 @@ idpclient:
|
||||||
- type: azp
|
- type: azp
|
||||||
Authorities:
|
Authorities:
|
||||||
- type: authorities
|
- type: authorities
|
||||||
ExternalProviderName:
|
TenantCodes:
|
||||||
- type: identity_provider
|
- type: tenant_roles
|
||||||
|
filterBy: "(.*):(.*)"
|
||||||
|
extractByExpression: "(.*):(.*)"
|
||||||
|
extractExpressionValue: "[[g2]]"
|
|
@ -12,14 +12,14 @@ permissions:
|
||||||
EditTenant:
|
EditTenant:
|
||||||
roles:
|
roles:
|
||||||
- Admin
|
- Admin
|
||||||
clients: [ ]
|
clients: [ "opendmp-api-dev" ]
|
||||||
allowAnonymous: false
|
allowAnonymous: false
|
||||||
allowAuthenticated: false
|
allowAuthenticated: false
|
||||||
DeleteTenant:
|
DeleteTenant:
|
||||||
roles:
|
roles:
|
||||||
- Admin
|
- Admin
|
||||||
claims: [ ]
|
claims: [ ]
|
||||||
clients: [ ]
|
clients: [ "opendmp-api-dev" ]
|
||||||
allowAnonymous: false
|
allowAnonymous: false
|
||||||
allowAuthenticated: false
|
allowAuthenticated: false
|
||||||
AllowNoTenant:
|
AllowNoTenant:
|
||||||
|
@ -32,85 +32,85 @@ permissions:
|
||||||
# Users
|
# Users
|
||||||
BrowseUser:
|
BrowseUser:
|
||||||
roles:
|
roles:
|
||||||
- Admin
|
- TenantAdmin
|
||||||
clients: [ ]
|
clients: [ ]
|
||||||
allowAnonymous: true
|
allowAnonymous: true
|
||||||
allowAuthenticated: false
|
allowAuthenticated: false
|
||||||
EditUser:
|
EditUser:
|
||||||
roles:
|
roles:
|
||||||
- Admin
|
- TenantAdmin
|
||||||
clients: [ ]
|
clients: [ "opendmp-api-dev" ]
|
||||||
allowAnonymous: false
|
allowAnonymous: false
|
||||||
allowAuthenticated: false
|
allowAuthenticated: false
|
||||||
DeleteUser:
|
DeleteUser:
|
||||||
roles:
|
roles:
|
||||||
- Admin
|
- TenantAdmin
|
||||||
claims: [ ]
|
claims: [ ]
|
||||||
clients: [ ]
|
clients: [ "opendmp-api-dev" ]
|
||||||
allowAnonymous: false
|
allowAnonymous: false
|
||||||
allowAuthenticated: false
|
allowAuthenticated: false
|
||||||
# UserContactInfo
|
# UserContactInfo
|
||||||
BrowseUserContactInfo:
|
BrowseUserContactInfo:
|
||||||
roles:
|
roles:
|
||||||
- Admin
|
- TenantAdmin
|
||||||
clients: [ ]
|
clients: [ "opendmp-api-dev" ]
|
||||||
allowAnonymous: true
|
allowAnonymous: true
|
||||||
allowAuthenticated: false
|
allowAuthenticated: false
|
||||||
EditUserContactInfo:
|
EditUserContactInfo:
|
||||||
roles:
|
roles:
|
||||||
- Admin
|
- TenantAdmin
|
||||||
clients: [ ]
|
clients: [ ]
|
||||||
allowAnonymous: false
|
allowAnonymous: false
|
||||||
allowAuthenticated: false
|
allowAuthenticated: false
|
||||||
DeleteUserContactInfo:
|
DeleteUserContactInfo:
|
||||||
roles:
|
roles:
|
||||||
- Admin
|
- TenantAdmin
|
||||||
claims: [ ]
|
claims: [ ]
|
||||||
clients: [ ]
|
clients: [ "opendmp-api-dev" ]
|
||||||
allowAnonymous: false
|
allowAnonymous: false
|
||||||
allowAuthenticated: false
|
allowAuthenticated: false
|
||||||
#Notification
|
#Notification
|
||||||
BrowseNotification:
|
BrowseNotification:
|
||||||
roles:
|
roles:
|
||||||
- Admin
|
- TenantAdmin
|
||||||
clients: [ ]
|
clients: [ ]
|
||||||
allowAnonymous: true
|
allowAnonymous: true
|
||||||
allowAuthenticated: false
|
allowAuthenticated: false
|
||||||
EditNotification:
|
EditNotification:
|
||||||
roles:
|
roles:
|
||||||
- Admin
|
- TenantAdmin
|
||||||
clients: [ ]
|
clients: [ ]
|
||||||
allowAnonymous: true
|
allowAnonymous: true
|
||||||
allowAuthenticated: false
|
allowAuthenticated: false
|
||||||
DeleteNotification:
|
DeleteNotification:
|
||||||
roles:
|
roles:
|
||||||
- Admin
|
- TenantAdmin
|
||||||
clients: [ ]
|
clients: [ ]
|
||||||
allowAnonymous: false
|
allowAnonymous: false
|
||||||
allowAuthenticated: false
|
allowAuthenticated: false
|
||||||
#Tenant Configuration
|
#Tenant Configuration
|
||||||
BrowseTenantConfiguration:
|
BrowseTenantConfiguration:
|
||||||
roles:
|
roles:
|
||||||
- Admin
|
- TenantAdmin
|
||||||
clients: [ ]
|
clients: [ ]
|
||||||
allowAnonymous: false
|
allowAnonymous: false
|
||||||
allowAuthenticated: false
|
allowAuthenticated: false
|
||||||
EditTenantConfiguration:
|
EditTenantConfiguration:
|
||||||
roles:
|
roles:
|
||||||
- Admin
|
- TenantAdmin
|
||||||
clients: [ ]
|
clients: [ ]
|
||||||
allowAnonymous: false
|
allowAnonymous: false
|
||||||
allowAuthenticated: false
|
allowAuthenticated: false
|
||||||
#User Notification Preference
|
#User Notification Preference
|
||||||
BrowseUserNotificationPreference:
|
BrowseUserNotificationPreference:
|
||||||
roles:
|
roles:
|
||||||
- Admin
|
- TenantAdmin
|
||||||
clients: [ ]
|
clients: [ ]
|
||||||
allowAnonymous: true
|
allowAnonymous: true
|
||||||
allowAuthenticated: false
|
allowAuthenticated: false
|
||||||
EditUserNotificationPreference:
|
EditUserNotificationPreference:
|
||||||
roles:
|
roles:
|
||||||
- Admin
|
- TenantAdmin
|
||||||
clients: [ ]
|
clients: [ ]
|
||||||
allowAnonymous: false
|
allowAnonymous: false
|
||||||
allowAuthenticated: false
|
allowAuthenticated: false
|
||||||
|
@ -118,25 +118,25 @@ permissions:
|
||||||
# ViewPage Permissions
|
# ViewPage Permissions
|
||||||
ViewNotificationPage:
|
ViewNotificationPage:
|
||||||
roles:
|
roles:
|
||||||
- Admin
|
- TenantAdmin
|
||||||
clients: [ ]
|
clients: [ ]
|
||||||
allowAnonymous: false
|
allowAnonymous: false
|
||||||
allowAuthenticated: false
|
allowAuthenticated: false
|
||||||
ViewNotificationEventRulePage:
|
ViewNotificationEventRulePage:
|
||||||
roles:
|
roles:
|
||||||
- Admin
|
- TenantAdmin
|
||||||
clients: [ ]
|
clients: [ ]
|
||||||
allowAnonymous: false
|
allowAnonymous: false
|
||||||
allowAuthenticated: false
|
allowAuthenticated: false
|
||||||
ViewInAppNotificationPage:
|
ViewInAppNotificationPage:
|
||||||
roles:
|
roles:
|
||||||
- Admin
|
- TenantAdmin
|
||||||
clients: [ ]
|
clients: [ ]
|
||||||
allowAnonymous: false
|
allowAnonymous: false
|
||||||
allowAuthenticated: false
|
allowAuthenticated: false
|
||||||
ViewNotificationTemplatePage:
|
ViewNotificationTemplatePage:
|
||||||
roles:
|
roles:
|
||||||
- Admin
|
- TenantAdmin
|
||||||
clients: [ ]
|
clients: [ ]
|
||||||
allowAnonymous: false
|
allowAnonymous: false
|
||||||
allowAuthenticated: false
|
allowAuthenticated: false
|
||||||
|
@ -144,19 +144,19 @@ permissions:
|
||||||
# Notification Template Permissions
|
# Notification Template Permissions
|
||||||
BrowseNotificationTemplate:
|
BrowseNotificationTemplate:
|
||||||
roles:
|
roles:
|
||||||
- Admin
|
- TenantAdmin
|
||||||
clients: [ ]
|
clients: [ ]
|
||||||
allowAnonymous: false
|
allowAnonymous: false
|
||||||
allowAuthenticated: false
|
allowAuthenticated: false
|
||||||
EditNotificationTemplate:
|
EditNotificationTemplate:
|
||||||
roles:
|
roles:
|
||||||
- Admin
|
- TenantAdmin
|
||||||
clients: [ ]
|
clients: [ ]
|
||||||
allowAnonymous: false
|
allowAnonymous: false
|
||||||
allowAuthenticated: false
|
allowAuthenticated: false
|
||||||
DeleteNotificationTemplate:
|
DeleteNotificationTemplate:
|
||||||
roles:
|
roles:
|
||||||
- Admin
|
- TenantAdmin
|
||||||
clients: [ ]
|
clients: [ ]
|
||||||
allowAnonymous: false
|
allowAnonymous: false
|
||||||
allowAuthenticated: false
|
allowAuthenticated: false
|
||||||
|
@ -164,13 +164,13 @@ permissions:
|
||||||
# In App Notification Permissions
|
# In App Notification Permissions
|
||||||
BrowseInAppNotification:
|
BrowseInAppNotification:
|
||||||
roles:
|
roles:
|
||||||
- Admin
|
- TenantAdmin
|
||||||
clients: [ ]
|
clients: [ ]
|
||||||
allowAnonymous: false
|
allowAnonymous: false
|
||||||
allowAuthenticated: false
|
allowAuthenticated: false
|
||||||
DeleteInAppNotification:
|
DeleteInAppNotification:
|
||||||
roles:
|
roles:
|
||||||
- Admin
|
- TenantAdmin
|
||||||
clients: [ ]
|
clients: [ ]
|
||||||
allowAnonymous: false
|
allowAnonymous: false
|
||||||
allowAuthenticated: false
|
allowAuthenticated: false
|
|
@ -25,9 +25,6 @@ queue:
|
||||||
enable: false
|
enable: false
|
||||||
options:
|
options:
|
||||||
exchange: null
|
exchange: null
|
||||||
forget-me-completed-topic: forgetme.completed
|
|
||||||
what-you-know-about-me-completed-topic: whatyouknowaboutme.completed
|
|
||||||
generate-file-topic: generate.file
|
|
||||||
rabbitmq:
|
rabbitmq:
|
||||||
enable: false
|
enable: false
|
||||||
interval-seconds: 30
|
interval-seconds: 30
|
||||||
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
tenant:
|
||||||
|
multitenancy:
|
||||||
|
is-multitenant: true
|
||||||
|
default-tenant-code: default
|
||||||
|
interceptor:
|
||||||
|
client-claims-prefix: client_
|
||||||
|
enforce-trusted-tenant: false
|
|
@ -2,7 +2,6 @@ tenant:
|
||||||
multitenancy:
|
multitenancy:
|
||||||
is-multitenant: false
|
is-multitenant: false
|
||||||
interceptor:
|
interceptor:
|
||||||
client-claims-prefix: client_
|
|
||||||
white-listed-clients: [ ]
|
white-listed-clients: [ ]
|
||||||
enforce-trusted-tenant: false
|
enforce-trusted-tenant: false
|
||||||
white-listed-endpoints: [ '/api/principal/my-tenants', '/api/principal/me','/api/user/user-settings', '/error', '/api/tenant-request' ]
|
white-listed-endpoints: [ '/api/principal/me' ]
|
|
@ -0,0 +1,9 @@
|
||||||
|
package gr.cite.notification.authorization;
|
||||||
|
|
||||||
|
public class ClaimNames {
|
||||||
|
public static final String ExternalProviderName = "ExternalProviderName";
|
||||||
|
public static final String TenantCodesClaimName = "TenantCodes";
|
||||||
|
public static final String TenantClaimName = "x-tenant";
|
||||||
|
public static final String GlobalRolesClaimName = "GlobalRoles";
|
||||||
|
public static final String TenantRolesClaimName = "TenantRoles";
|
||||||
|
}
|
|
@ -5,6 +5,7 @@ import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||||
@ConfigurationProperties(prefix = "tenant.multitenancy")
|
@ConfigurationProperties(prefix = "tenant.multitenancy")
|
||||||
public class MultitenancyProperties {
|
public class MultitenancyProperties {
|
||||||
private boolean isMultitenant;
|
private boolean isMultitenant;
|
||||||
|
private String defaultTenantCode;
|
||||||
|
|
||||||
public boolean isMultitenant() {
|
public boolean isMultitenant() {
|
||||||
return isMultitenant;
|
return isMultitenant;
|
||||||
|
@ -13,4 +14,16 @@ public class MultitenancyProperties {
|
||||||
public void setIsMultitenant(boolean multitenant) {
|
public void setIsMultitenant(boolean multitenant) {
|
||||||
isMultitenant = multitenant;
|
isMultitenant = multitenant;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setMultitenant(boolean multitenant) {
|
||||||
|
isMultitenant = multitenant;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDefaultTenantCode() {
|
||||||
|
return defaultTenantCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDefaultTenantCode(String defaultTenantCode) {
|
||||||
|
this.defaultTenantCode = defaultTenantCode;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,34 +1,25 @@
|
||||||
package gr.cite.notification.common.scope.tenant;
|
package gr.cite.notification.common.scope.tenant;
|
||||||
|
|
||||||
import gr.cite.notification.data.tenant.TenantScopedBaseEntity;
|
import gr.cite.notification.data.tenant.TenantScopedBaseEntity;
|
||||||
import gr.cite.tools.logging.LoggerService;
|
import jakarta.persistence.EntityManager;
|
||||||
import org.hibernate.Session;
|
import org.hibernate.Session;
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.beans.factory.config.BeanDefinition;
|
|
||||||
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
|
|
||||||
import org.springframework.boot.BootstrapRegistry;
|
|
||||||
import org.springframework.context.annotation.Scope;
|
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
import org.springframework.web.context.annotation.RequestScope;
|
import org.springframework.web.context.annotation.RequestScope;
|
||||||
|
|
||||||
import javax.management.InvalidApplicationException;
|
import javax.management.InvalidApplicationException;
|
||||||
import jakarta.persistence.EntityManager;
|
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
import java.util.concurrent.atomic.AtomicReference;
|
||||||
|
|
||||||
@Component
|
@Component
|
||||||
@RequestScope
|
@RequestScope
|
||||||
public class TenantScope {
|
public class TenantScope {
|
||||||
public static final String TenantReplaceParameter = "::TenantCode::";
|
public static final String TenantReplaceParameter = "::TenantCode::";
|
||||||
public static final String TenantCodesClaimName = "TenantCodes";
|
private final MultitenancyProperties multitenancy;
|
||||||
public static final String TenantClaimName = "x-tenant";
|
private final AtomicReference<UUID> tenant = new AtomicReference<>();
|
||||||
|
private final AtomicReference<String> tenantCode = new AtomicReference<>();
|
||||||
private MultitenancyProperties multitenancy;
|
private final AtomicReference<UUID> initialTenant = new AtomicReference<>();
|
||||||
private static final LoggerService logger = new LoggerService(LoggerFactory.getLogger(TenantScope.class));
|
private final AtomicReference<String> initialTenantCode = new AtomicReference<>();
|
||||||
private UUID tenant = null;
|
|
||||||
private String tenantCode = null;
|
|
||||||
private UUID initialTenant = null;
|
|
||||||
private String initialTenantCode = null;
|
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
public TenantScope(MultitenancyProperties multitenancy) {
|
public TenantScope(MultitenancyProperties multitenancy) {
|
||||||
|
@ -39,49 +30,79 @@ public class TenantScope {
|
||||||
return multitenancy.isMultitenant();
|
return multitenancy.isMultitenant();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getDefaultTenantCode() {
|
||||||
|
return multitenancy.getDefaultTenantCode();
|
||||||
|
}
|
||||||
|
|
||||||
public Boolean isSet() {
|
public Boolean isSet() {
|
||||||
if (!this.isMultitenant()) return true;
|
if (!this.isMultitenant())
|
||||||
return this.tenant != null;
|
return Boolean.TRUE;
|
||||||
|
return this.tenant.get() != null || this.isDefaultTenant();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Boolean isDefaultTenant() {
|
||||||
|
if (!this.isMultitenant())
|
||||||
|
return Boolean.TRUE;
|
||||||
|
return this.multitenancy.getDefaultTenantCode().equalsIgnoreCase(this.tenantCode.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
public UUID getTenant() throws InvalidApplicationException {
|
public UUID getTenant() throws InvalidApplicationException {
|
||||||
if (!this.isMultitenant()) return null;
|
if (!this.isMultitenant())
|
||||||
if (this.tenant == null) throw new InvalidApplicationException("tenant not set");
|
return null;
|
||||||
return this.tenant;
|
if (this.tenant.get() == null && !this.isDefaultTenant())
|
||||||
|
throw new InvalidApplicationException("tenant not set");
|
||||||
|
return this.isDefaultTenant() ? null : this.tenant.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getTenantCode() throws InvalidApplicationException {
|
public String getTenantCode() throws InvalidApplicationException {
|
||||||
if (!this.isMultitenant()) return null;
|
if (!this.isMultitenant())
|
||||||
if (this.tenant == null) throw new InvalidApplicationException("tenant not set");
|
return null;
|
||||||
return this.tenantCode;
|
if (this.tenantCode.get() == null)
|
||||||
|
throw new InvalidApplicationException("tenant not set");
|
||||||
|
return this.tenantCode.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setTempTenant(EntityManager entityManager, UUID tenant, String tenantCode) {
|
public void setTempTenant(EntityManager entityManager, UUID tenant, String tenantCode) {
|
||||||
this.tenant = tenant;
|
this.tenant.set(tenant);
|
||||||
|
this.tenantCode.set(tenantCode);
|
||||||
|
|
||||||
if(this.tenant != null) {
|
if (this.tenant.get() != null && !this.isDefaultTenant()) {
|
||||||
|
if(!this.isDefaultTenant()) {
|
||||||
entityManager
|
entityManager
|
||||||
.unwrap(Session.class)
|
.unwrap(Session.class)
|
||||||
.enableFilter(TenantScopedBaseEntity.tenantFilter).setParameter(TenantScopedBaseEntity.tenantFilterTenantParam, this.tenant.toString());
|
.enableFilter(TenantScopedBaseEntity.TENANT_FILTER)
|
||||||
|
.setParameter(TenantScopedBaseEntity.TENANT_FILTER_TENANT_PARAM, this.tenant.get().toString());
|
||||||
|
} else {
|
||||||
|
entityManager
|
||||||
|
.unwrap(Session.class)
|
||||||
|
.enableFilter(TenantScopedBaseEntity.DEFAULT_TENANT_FILTER);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void removeTempTenant(EntityManager entityManager) {
|
public void removeTempTenant(EntityManager entityManager) {
|
||||||
this.tenant = this.initialTenant;
|
this.tenant.set(this.initialTenant.get());
|
||||||
this.tenantCode = this.initialTenantCode;
|
this.tenantCode.set(this.initialTenantCode.get());
|
||||||
if(this.initialTenant != null) {
|
if (this.initialTenant.get() != null && !this.isDefaultTenant()) {
|
||||||
|
if(!this.isDefaultTenant()) {
|
||||||
entityManager
|
entityManager
|
||||||
.unwrap(Session.class)
|
.unwrap(Session.class)
|
||||||
.enableFilter(TenantScopedBaseEntity.tenantFilter).setParameter(TenantScopedBaseEntity.tenantFilterTenantParam, this.initialTenant.toString());
|
.enableFilter(TenantScopedBaseEntity.TENANT_FILTER)
|
||||||
|
.setParameter(TenantScopedBaseEntity.TENANT_FILTER_TENANT_PARAM, this.tenant.get().toString());
|
||||||
|
} else {
|
||||||
|
entityManager
|
||||||
|
.unwrap(Session.class)
|
||||||
|
.enableFilter(TenantScopedBaseEntity.DEFAULT_TENANT_FILTER);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setTenant(UUID tenant, String tenantCode) {
|
public void setTenant(UUID tenant, String tenantCode) {
|
||||||
if (this.isMultitenant()) {
|
if (this.isMultitenant()) {
|
||||||
this.tenant = tenant;
|
this.tenant.set(tenant);
|
||||||
this.initialTenant = tenant;
|
this.initialTenant.set(tenant);
|
||||||
this.tenantCode = tenantCode;
|
this.tenantCode.set(tenantCode);
|
||||||
this.initialTenantCode = tenantCode;
|
this.initialTenantCode.set(tenantCode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,94 +0,0 @@
|
||||||
package gr.cite.notification.data;
|
|
||||||
|
|
||||||
import gr.cite.notification.common.enums.IsActive;
|
|
||||||
import gr.cite.notification.data.conventers.IsActiveConverter;
|
|
||||||
import gr.cite.notification.data.tenant.TenantScopedBaseEntity;
|
|
||||||
import jakarta.persistence.*;
|
|
||||||
|
|
||||||
import java.time.Instant;
|
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
@Entity
|
|
||||||
@Table(name = "\"Language\"")
|
|
||||||
public class LanguageEntity extends TenantScopedBaseEntity {
|
|
||||||
|
|
||||||
@Id
|
|
||||||
@Column(name = "id", columnDefinition = "uuid", updatable = false, nullable = false)
|
|
||||||
private UUID id;
|
|
||||||
|
|
||||||
public static final String _id = "id";
|
|
||||||
|
|
||||||
@Column(name = "code", length = 20, nullable = false)
|
|
||||||
private String code;
|
|
||||||
|
|
||||||
public static final String _code = "code";
|
|
||||||
|
|
||||||
@Column(name = "ordinal")
|
|
||||||
private Integer ordinal;
|
|
||||||
|
|
||||||
public static final String _ordinal = "ordinal";
|
|
||||||
|
|
||||||
@Column(name = "\"created_at\"", nullable = false)
|
|
||||||
private Instant createdAt;
|
|
||||||
|
|
||||||
public static final String _createdAt = "createdAt";
|
|
||||||
|
|
||||||
@Column(name = "\"updated_at\"", nullable = false)
|
|
||||||
private Instant updatedAt;
|
|
||||||
|
|
||||||
public static final String _updatedAt = "updatedAt";
|
|
||||||
|
|
||||||
@Column(name = "is_active", nullable = false)
|
|
||||||
@Convert(converter = IsActiveConverter.class)
|
|
||||||
private IsActive isActive;
|
|
||||||
|
|
||||||
public static final String _isActive = "isActive";
|
|
||||||
|
|
||||||
public UUID getId() {
|
|
||||||
return id;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setId(UUID id) {
|
|
||||||
this.id = id;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getCode() {
|
|
||||||
return code;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setCode(String code) {
|
|
||||||
this.code = code;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Integer getOrdinal() {
|
|
||||||
return ordinal;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setOrdinal(Integer ordinal) {
|
|
||||||
this.ordinal = ordinal;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Instant getCreatedAt() {
|
|
||||||
return createdAt;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setCreatedAt(Instant createdAt) {
|
|
||||||
this.createdAt = createdAt;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Instant getUpdatedAt() {
|
|
||||||
return updatedAt;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setUpdatedAt(Instant updatedAt) {
|
|
||||||
this.updatedAt = updatedAt;
|
|
||||||
}
|
|
||||||
|
|
||||||
public IsActive getIsActive() {
|
|
||||||
return isActive;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setIsActive(IsActive isActive) {
|
|
||||||
this.isActive = isActive;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -39,10 +39,10 @@ public class NotificationTemplateEntity extends TenantScopedBaseEntity {
|
||||||
|
|
||||||
public static final String _kind = "kind";
|
public static final String _kind = "kind";
|
||||||
|
|
||||||
@Column(name = "\"language\"", columnDefinition = "uuid", nullable = false)
|
@Column(name = "\"language_code\"", nullable = false, length = 200)
|
||||||
private UUID languageId;
|
private String languageCode;
|
||||||
|
|
||||||
public static final String _languageId = "languageId";
|
public static final String _languageCode = "languageCode";
|
||||||
|
|
||||||
@Column(name = "\"value\"", nullable = false)
|
@Column(name = "\"value\"", nullable = false)
|
||||||
private String value;
|
private String value;
|
||||||
|
@ -97,12 +97,12 @@ public class NotificationTemplateEntity extends TenantScopedBaseEntity {
|
||||||
this.kind = kind;
|
this.kind = kind;
|
||||||
}
|
}
|
||||||
|
|
||||||
public UUID getLanguageId() {
|
public String getLanguageCode() {
|
||||||
return languageId;
|
return languageCode;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setLanguageId(UUID languageId) {
|
public void setLanguageCode(String languageCode) {
|
||||||
this.languageId = languageId;
|
this.languageCode = languageCode;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getValue() {
|
public String getValue() {
|
||||||
|
|
|
@ -0,0 +1,116 @@
|
||||||
|
package gr.cite.notification.data;
|
||||||
|
|
||||||
|
import gr.cite.notification.common.scope.tenant.TenantScope;
|
||||||
|
import gr.cite.notification.common.scope.tenant.TenantScoped;
|
||||||
|
import gr.cite.notification.data.tenant.TenantScopedBaseEntity;
|
||||||
|
import gr.cite.notification.errorcode.ErrorThesaurusProperties;
|
||||||
|
import gr.cite.tools.exception.MyForbiddenException;
|
||||||
|
import jakarta.persistence.EntityManager;
|
||||||
|
import jakarta.persistence.FlushModeType;
|
||||||
|
import jakarta.persistence.PersistenceContext;
|
||||||
|
import org.hibernate.Session;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.web.context.annotation.RequestScope;
|
||||||
|
|
||||||
|
import javax.management.InvalidApplicationException;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
@RequestScope
|
||||||
|
public class TenantEntityManager {
|
||||||
|
@PersistenceContext
|
||||||
|
private EntityManager entityManager;
|
||||||
|
private final TenantScope tenantScope;
|
||||||
|
private final ErrorThesaurusProperties errors;
|
||||||
|
|
||||||
|
public TenantEntityManager(TenantScope tenantScope, ErrorThesaurusProperties errors) {
|
||||||
|
this.tenantScope = tenantScope;
|
||||||
|
this.errors = errors;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void persist(Object entity) {
|
||||||
|
this.entityManager.persist(entity);
|
||||||
|
}
|
||||||
|
|
||||||
|
public <T> T merge(T entity) throws InvalidApplicationException {
|
||||||
|
if (tenantScope.isMultitenant() && (entity instanceof TenantScoped tenantScopedEntity)) {
|
||||||
|
if (!tenantScope.isDefaultTenant()) {
|
||||||
|
if (tenantScopedEntity.getTenantId() == null || !tenantScopedEntity.getTenantId().equals(tenantScope.getTenant())) throw new MyForbiddenException(this.errors.getTenantTampering().getCode(), this.errors.getTenantTampering().getMessage());
|
||||||
|
} else if (tenantScopedEntity.getTenantId() != null) {
|
||||||
|
throw new MyForbiddenException(this.errors.getTenantTampering().getCode(), this.errors.getTenantTampering().getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return this.entityManager.merge(entity);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void remove(Object entity) throws InvalidApplicationException {
|
||||||
|
if (tenantScope.isMultitenant() && (entity instanceof TenantScoped tenantScopedEntity)) {
|
||||||
|
if (!tenantScope.isDefaultTenant()) {
|
||||||
|
if (tenantScopedEntity.getTenantId() == null || !tenantScopedEntity.getTenantId().equals(tenantScope.getTenant())) throw new MyForbiddenException(this.errors.getTenantTampering().getCode(), this.errors.getTenantTampering().getMessage());
|
||||||
|
} else if (tenantScopedEntity.getTenantId() != null) {
|
||||||
|
throw new MyForbiddenException(this.errors.getTenantTampering().getCode(), this.errors.getTenantTampering().getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.entityManager.remove(entity);
|
||||||
|
}
|
||||||
|
|
||||||
|
public <T> T find(Class<T> entityClass, Object primaryKey) throws InvalidApplicationException {
|
||||||
|
T entity = this.entityManager.find(entityClass, primaryKey);
|
||||||
|
|
||||||
|
if (tenantScope.isMultitenant() && (entity instanceof TenantScoped tenantScopedEntity)) {
|
||||||
|
if (tenantScopedEntity.getTenantId() != null && !tenantScopedEntity.getTenantId().equals(tenantScope.getTenant())) return null;
|
||||||
|
}
|
||||||
|
return entity;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void flush() {
|
||||||
|
this.entityManager.flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void setFlushMode(FlushModeType flushMode) {
|
||||||
|
this.entityManager.setFlushMode(flushMode);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public FlushModeType getFlushMode() {
|
||||||
|
return this.entityManager.getFlushMode();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void clear() {
|
||||||
|
this.entityManager.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void enableTenantFilters() throws InvalidApplicationException {
|
||||||
|
if (!tenantScope.isSet()) return;
|
||||||
|
if(!tenantScope.isDefaultTenant()) {
|
||||||
|
this.entityManager
|
||||||
|
.unwrap(Session.class)
|
||||||
|
.enableFilter(TenantScopedBaseEntity.TENANT_FILTER)
|
||||||
|
.setParameter(TenantScopedBaseEntity.TENANT_FILTER_TENANT_PARAM, tenantScope.getTenant().toString());
|
||||||
|
} else {
|
||||||
|
this.entityManager
|
||||||
|
.unwrap(Session.class)
|
||||||
|
.enableFilter(TenantScopedBaseEntity.DEFAULT_TENANT_FILTER);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void disableTenantFilters(){
|
||||||
|
this.entityManager
|
||||||
|
.unwrap(Session.class)
|
||||||
|
.disableFilter(TenantScopedBaseEntity.TENANT_FILTER);
|
||||||
|
|
||||||
|
this.entityManager
|
||||||
|
.unwrap(Session.class)
|
||||||
|
.disableFilter(TenantScopedBaseEntity.DEFAULT_TENANT_FILTER);
|
||||||
|
}
|
||||||
|
|
||||||
|
public EntityManager getEntityManager() {
|
||||||
|
return entityManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setEntityManager(EntityManager entityManager) {
|
||||||
|
this.entityManager = entityManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -1,97 +0,0 @@
|
||||||
package gr.cite.notification.data;
|
|
||||||
|
|
||||||
import gr.cite.commons.web.authz.service.AuthorizationService;
|
|
||||||
import gr.cite.notification.authorization.Permission;
|
|
||||||
import gr.cite.notification.common.scope.tenant.TenantScope;
|
|
||||||
import gr.cite.notification.common.scope.tenant.TenantScoped;
|
|
||||||
import gr.cite.tools.exception.MyForbiddenException;
|
|
||||||
import org.hibernate.Session;
|
|
||||||
import org.springframework.context.annotation.Scope;
|
|
||||||
import org.springframework.stereotype.Service;
|
|
||||||
|
|
||||||
import javax.management.InvalidApplicationException;
|
|
||||||
import jakarta.persistence.EntityManager;
|
|
||||||
import jakarta.persistence.FlushModeType;
|
|
||||||
import jakarta.persistence.PersistenceContext;
|
|
||||||
import jakarta.persistence.Query;
|
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
@Service
|
|
||||||
@Scope
|
|
||||||
public class TenantScopedEntityManager {
|
|
||||||
@PersistenceContext
|
|
||||||
private EntityManager entityManager;
|
|
||||||
private final AuthorizationService authorizationService;
|
|
||||||
|
|
||||||
private final TenantScope tenantScope;
|
|
||||||
|
|
||||||
public TenantScopedEntityManager(AuthorizationService authorizationService, TenantScope tenantScope) {
|
|
||||||
this.authorizationService = authorizationService;
|
|
||||||
this.tenantScope = tenantScope;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getBulkSize() {
|
|
||||||
Session session = this.entityManager.unwrap(Session.class);
|
|
||||||
return session.getJdbcBatchSize();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setBulkSize(int size) {
|
|
||||||
Session session = this.entityManager.unwrap(Session.class);
|
|
||||||
session.setJdbcBatchSize(size);
|
|
||||||
}
|
|
||||||
public Query createQuery(String query){
|
|
||||||
return this.entityManager.createQuery(query);
|
|
||||||
}
|
|
||||||
public void persist(Object entity) {
|
|
||||||
this.entityManager.persist(entity);
|
|
||||||
}
|
|
||||||
|
|
||||||
public <T> T merge(T entity) throws InvalidApplicationException {
|
|
||||||
if (tenantScope.isMultitenant() && (entity instanceof TenantScoped)) {
|
|
||||||
boolean isAllowedNoTenant = authorizationService.authorize(Permission.AllowNoTenant);
|
|
||||||
|
|
||||||
final UUID tenantId = !isAllowedNoTenant ? tenantScope.getTenant() : null;
|
|
||||||
if (!isAllowedNoTenant && !tenantId.equals(((TenantScoped) entity).getTenantId())) throw new MyForbiddenException("tenant tampering");
|
|
||||||
}
|
|
||||||
return this.entityManager.merge(entity);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void remove(Object entity) throws InvalidApplicationException {
|
|
||||||
if (tenantScope.isMultitenant() && (entity instanceof TenantScoped)) {
|
|
||||||
final UUID tenantId = tenantScope.getTenant();
|
|
||||||
if (!tenantId.equals(((TenantScoped) entity).getTenantId())) throw new MyForbiddenException("tenant tampering");
|
|
||||||
}
|
|
||||||
this.entityManager.remove(entity);
|
|
||||||
}
|
|
||||||
|
|
||||||
public <T> T find(Class<T> entityClass, Object primaryKey) throws InvalidApplicationException {
|
|
||||||
T entity = this.entityManager.find(entityClass, primaryKey);
|
|
||||||
|
|
||||||
if (tenantScope.isMultitenant() && (entity instanceof TenantScoped)) {
|
|
||||||
boolean isAllowedNoTenant = authorizationService.authorize(Permission.AllowNoTenant);
|
|
||||||
|
|
||||||
final UUID tenantId = !isAllowedNoTenant ? tenantScope.getTenant() : null;
|
|
||||||
if (!isAllowedNoTenant && !tenantId.equals(((TenantScoped) entity).getTenantId())) return null;
|
|
||||||
}
|
|
||||||
return entity;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void flush() {
|
|
||||||
this.entityManager.flush();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public void setFlushMode(FlushModeType flushMode) {
|
|
||||||
this.entityManager.setFlushMode(flushMode);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public FlushModeType getFlushMode() {
|
|
||||||
return this.entityManager.getFlushMode();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void clear() {
|
|
||||||
this.entityManager.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,48 +1,43 @@
|
||||||
package gr.cite.notification.data.tenant;
|
package gr.cite.notification.data.tenant;
|
||||||
|
|
||||||
import gr.cite.commons.web.oidc.principal.CurrentPrincipalResolver;
|
|
||||||
import gr.cite.commons.web.oidc.principal.extractor.ClaimExtractor;
|
|
||||||
import gr.cite.notification.common.scope.tenant.TenantScope;
|
import gr.cite.notification.common.scope.tenant.TenantScope;
|
||||||
|
import jakarta.persistence.EntityManager;
|
||||||
import org.aspectj.lang.JoinPoint;
|
import org.aspectj.lang.JoinPoint;
|
||||||
import org.aspectj.lang.annotation.AfterReturning;
|
import org.aspectj.lang.annotation.AfterReturning;
|
||||||
import org.aspectj.lang.annotation.Aspect;
|
import org.aspectj.lang.annotation.Aspect;
|
||||||
import org.hibernate.Session;
|
import org.hibernate.Session;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.context.ApplicationContext;
|
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
import javax.management.InvalidApplicationException;
|
import javax.management.InvalidApplicationException;
|
||||||
import jakarta.persistence.EntityManager;
|
|
||||||
|
|
||||||
@Aspect
|
@Aspect
|
||||||
@Component
|
@Component
|
||||||
public class TenantFilterAspect {
|
public class TenantFilterAspect {
|
||||||
|
|
||||||
private final TenantScope tenantScope;
|
private final TenantScope tenantScope;
|
||||||
private final ClaimExtractor claimExtractor;
|
|
||||||
private final CurrentPrincipalResolver currentPrincipalResolver;
|
|
||||||
private final ApplicationContext applicationContext;
|
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
public TenantFilterAspect(
|
public TenantFilterAspect(
|
||||||
TenantScope tenantScope,
|
TenantScope tenantScope
|
||||||
ClaimExtractor claimExtractor,
|
|
||||||
CurrentPrincipalResolver currentPrincipalResolver,
|
|
||||||
ApplicationContext applicationContext
|
|
||||||
) {
|
) {
|
||||||
this.tenantScope = tenantScope;
|
this.tenantScope = tenantScope;
|
||||||
this.currentPrincipalResolver = currentPrincipalResolver;
|
|
||||||
this.claimExtractor = claimExtractor;
|
|
||||||
this.applicationContext = applicationContext;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@AfterReturning(
|
@AfterReturning(
|
||||||
pointcut = "bean(entityManagerFactory) && execution(* createEntityManager(..))",
|
pointcut = "bean(entityManagerFactory) && execution(* createEntityManager(..))",
|
||||||
returning = "retVal")
|
returning = "retVal")
|
||||||
public void getSessionAfter(JoinPoint joinPoint, Object retVal) throws InvalidApplicationException {
|
public void getSessionAfter(JoinPoint joinPoint, Object retVal) throws InvalidApplicationException {
|
||||||
if (retVal != null && EntityManager.class.isInstance(retVal) && tenantScope.isSet() && tenantScope.isMultitenant()) {
|
if (retVal instanceof EntityManager && tenantScope.isSet()) {
|
||||||
Session session = ((EntityManager) retVal).unwrap(Session.class);
|
Session session = ((EntityManager) retVal).unwrap(Session.class);
|
||||||
session.enableFilter(TenantScopedBaseEntity.tenantFilter).setParameter(TenantScopedBaseEntity.tenantFilterTenantParam, tenantScope.getTenant().toString());
|
if(!tenantScope.isDefaultTenant()) {
|
||||||
|
session
|
||||||
|
.enableFilter(TenantScopedBaseEntity.TENANT_FILTER)
|
||||||
|
.setParameter(TenantScopedBaseEntity.TENANT_FILTER_TENANT_PARAM, tenantScope.getTenant().toString());
|
||||||
|
} else {
|
||||||
|
session
|
||||||
|
.enableFilter(TenantScopedBaseEntity.DEFAULT_TENANT_FILTER);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,33 +2,44 @@ package gr.cite.notification.data.tenant;
|
||||||
|
|
||||||
import gr.cite.notification.common.scope.tenant.TenantScope;
|
import gr.cite.notification.common.scope.tenant.TenantScope;
|
||||||
import gr.cite.notification.common.scope.tenant.TenantScoped;
|
import gr.cite.notification.common.scope.tenant.TenantScoped;
|
||||||
|
import gr.cite.notification.errorcode.ErrorThesaurusProperties;
|
||||||
import gr.cite.tools.exception.MyForbiddenException;
|
import gr.cite.tools.exception.MyForbiddenException;
|
||||||
import gr.cite.tools.logging.LoggerService;
|
import gr.cite.tools.logging.LoggerService;
|
||||||
|
import jakarta.persistence.PrePersist;
|
||||||
|
import jakarta.persistence.PreRemove;
|
||||||
|
import jakarta.persistence.PreUpdate;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
|
||||||
import javax.management.InvalidApplicationException;
|
import javax.management.InvalidApplicationException;
|
||||||
import jakarta.persistence.PrePersist;
|
|
||||||
import jakarta.persistence.PreRemove;
|
|
||||||
import jakarta.persistence.PreUpdate;
|
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
public class TenantListener {
|
public class TenantListener {
|
||||||
private static final LoggerService logger = new LoggerService(LoggerFactory.getLogger(TenantListener.class));
|
private static final LoggerService logger = new LoggerService(LoggerFactory.getLogger(TenantListener.class));
|
||||||
private final TenantScope tenantScope;
|
private final TenantScope tenantScope;
|
||||||
|
|
||||||
|
private final ErrorThesaurusProperties errors;
|
||||||
|
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
public TenantListener(
|
public TenantListener(
|
||||||
TenantScope tenantScope
|
TenantScope tenantScope, ErrorThesaurusProperties errors
|
||||||
) {
|
) {
|
||||||
this.tenantScope = tenantScope;
|
this.tenantScope = tenantScope;
|
||||||
|
this.errors = errors;
|
||||||
}
|
}
|
||||||
|
|
||||||
@PrePersist
|
@PrePersist
|
||||||
public void setTenantOnCreate(TenantScoped entity) throws InvalidApplicationException {
|
public void setTenantOnCreate(TenantScoped entity) throws InvalidApplicationException {
|
||||||
if (tenantScope.isMultitenant()) {
|
if (tenantScope.isMultitenant()) {
|
||||||
|
if (entity.getTenantId() != null && (this.tenantScope.isDefaultTenant() || entity.getTenantId().compareTo(tenantScope.getTenant()) != 0)) {
|
||||||
|
logger.error("somebody tried to set not login tenant");
|
||||||
|
throw new MyForbiddenException(this.errors.getTenantTampering().getCode(), this.errors.getTenantTampering().getMessage());
|
||||||
|
}
|
||||||
|
if (!tenantScope.isDefaultTenant()) {
|
||||||
final UUID tenantId = tenantScope.getTenant();
|
final UUID tenantId = tenantScope.getTenant();
|
||||||
entity.setTenantId(tenantId);
|
entity.setTenantId(tenantId);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
entity.setTenantId(null);
|
entity.setTenantId(null);
|
||||||
}
|
}
|
||||||
|
@ -38,22 +49,30 @@ public class TenantListener {
|
||||||
@PreRemove
|
@PreRemove
|
||||||
public void setTenantOnUpdate(TenantScoped entity) throws InvalidApplicationException {
|
public void setTenantOnUpdate(TenantScoped entity) throws InvalidApplicationException {
|
||||||
if (tenantScope.isMultitenant()) {
|
if (tenantScope.isMultitenant()) {
|
||||||
|
if (!tenantScope.isDefaultTenant()) {
|
||||||
if (entity.getTenantId() == null) {
|
if (entity.getTenantId() == null) {
|
||||||
logger.error("somebody tried to set null tenant");
|
logger.error("somebody tried to set null tenant");
|
||||||
throw new MyForbiddenException("tenant tampering");
|
throw new MyForbiddenException(this.errors.getTenantTampering().getCode(), this.errors.getTenantTampering().getMessage());
|
||||||
}
|
}
|
||||||
if (entity.getTenantId().compareTo(tenantScope.getTenant()) != 0) {
|
if (entity.getTenantId().compareTo(tenantScope.getTenant()) != 0) {
|
||||||
logger.error("somebody tried to change an entries tenant");
|
logger.error("somebody tried to change an entries tenant");
|
||||||
throw new MyForbiddenException("tenant tampering");
|
throw new MyForbiddenException(this.errors.getTenantTampering().getCode(), this.errors.getTenantTampering().getMessage());
|
||||||
}
|
}
|
||||||
|
|
||||||
final UUID tenantId = tenantScope.getTenant();
|
final UUID tenantId = tenantScope.getTenant();
|
||||||
entity.setTenantId(tenantId);
|
entity.setTenantId(tenantId);
|
||||||
} else {
|
} else {
|
||||||
if (entity.getTenantId() != null) {
|
if (entity.getTenantId() != null) {
|
||||||
logger.error("somebody tried to set non null tenant");
|
logger.error("somebody tried to set null tenant");
|
||||||
throw new MyForbiddenException("tenant tampering");
|
throw new MyForbiddenException(this.errors.getTenantTampering().getCode(), this.errors.getTenantTampering().getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
if (entity.getTenantId() != null && (!this.tenantScope.isDefaultTenant() ||entity.getTenantId().compareTo(tenantScope.getTenant()) != 0)) {
|
||||||
|
logger.error("somebody tried to change an entries tenant");
|
||||||
|
throw new MyForbiddenException(this.errors.getTenantTampering().getCode(), this.errors.getTenantTampering().getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,15 +1,13 @@
|
||||||
package gr.cite.notification.data.tenant;
|
package gr.cite.notification.data.tenant;
|
||||||
|
|
||||||
import gr.cite.notification.common.scope.tenant.TenantScoped;
|
import gr.cite.notification.common.scope.tenant.TenantScoped;
|
||||||
|
import jakarta.persistence.Column;
|
||||||
|
import jakarta.persistence.EntityListeners;
|
||||||
|
import jakarta.persistence.MappedSuperclass;
|
||||||
import org.hibernate.annotations.Filter;
|
import org.hibernate.annotations.Filter;
|
||||||
import org.hibernate.annotations.FilterDef;
|
import org.hibernate.annotations.FilterDef;
|
||||||
import org.hibernate.annotations.ParamDef;
|
import org.hibernate.annotations.ParamDef;
|
||||||
|
|
||||||
import jakarta.persistence.Column;
|
|
||||||
import jakarta.persistence.EntityListeners;
|
|
||||||
import jakarta.persistence.MappedSuperclass;
|
|
||||||
|
|
||||||
import java.io.Serial;
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
|
@ -17,23 +15,20 @@ import java.util.UUID;
|
||||||
//@Getter
|
//@Getter
|
||||||
//@Setter
|
//@Setter
|
||||||
//@NoArgsConstructor
|
//@NoArgsConstructor
|
||||||
@FilterDef(name = TenantScopedBaseEntity.tenantFilter, parameters = {@ParamDef(name = TenantScopedBaseEntity.tenantFilterTenantParam, type = String.class)})
|
@FilterDef(name = TenantScopedBaseEntity.TENANT_FILTER, parameters = {@ParamDef(name = TenantScopedBaseEntity.TENANT_FILTER_TENANT_PARAM, type = String.class)})
|
||||||
@Filter(name = "tenantFilter", condition = "tenant = (cast(:tenantId as uuid))")
|
@FilterDef(name = TenantScopedBaseEntity.DEFAULT_TENANT_FILTER)
|
||||||
|
@Filter(name = TenantScopedBaseEntity.DEFAULT_TENANT_FILTER, condition = "(tenant = tenant is null)")
|
||||||
|
@Filter(name = TenantScopedBaseEntity.TENANT_FILTER, condition = "(tenant = (cast(:tenantId as uuid)) or tenant is null)")
|
||||||
@EntityListeners(TenantListener.class)
|
@EntityListeners(TenantListener.class)
|
||||||
public abstract class TenantScopedBaseEntity implements TenantScoped, Serializable {
|
public abstract class TenantScopedBaseEntity implements TenantScoped, Serializable {
|
||||||
|
|
||||||
@Serial
|
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
public static final String TENANT_FILTER = "tenantFilter";
|
||||||
|
public static final String DEFAULT_TENANT_FILTER = "defaultTenantFilter";
|
||||||
|
public static final String TENANT_FILTER_TENANT_PARAM = "tenantId";
|
||||||
|
|
||||||
public static final String tenantFilter = "tenantFilter";
|
@Column(name = "tenant", columnDefinition = "uuid", nullable = true)
|
||||||
|
|
||||||
public static final String tenantFilterTenantParam = "tenantId";
|
|
||||||
|
|
||||||
@Column(name = "tenant", columnDefinition = "uuid")
|
|
||||||
private UUID tenantId;
|
private UUID tenantId;
|
||||||
|
|
||||||
public static final String _tenantId = "tenantId";
|
public static final String _tenantId = "tenantId";
|
||||||
|
|
||||||
public UUID getTenantId() {
|
public UUID getTenantId() {
|
||||||
return tenantId;
|
return tenantId;
|
||||||
}
|
}
|
||||||
|
@ -42,5 +37,5 @@ public abstract class TenantScopedBaseEntity implements TenantScoped, Serializab
|
||||||
public void setTenantId(UUID tenantId) {
|
public void setTenantId(UUID tenantId) {
|
||||||
this.tenantId = tenantId;
|
this.tenantId = tenantId;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -15,6 +15,8 @@ public class ErrorThesaurusProperties {
|
||||||
private ErrorDescription singleTenantConfigurationPerTypeSupported;
|
private ErrorDescription singleTenantConfigurationPerTypeSupported;
|
||||||
private ErrorDescription incompatibleTenantConfigurationTypes;
|
private ErrorDescription incompatibleTenantConfigurationTypes;
|
||||||
private ErrorDescription overlappingTenantConfigurationNotifierList;
|
private ErrorDescription overlappingTenantConfigurationNotifierList;
|
||||||
|
private ErrorDescription tenantNotAllowed;
|
||||||
|
private ErrorDescription tenantTampering;
|
||||||
|
|
||||||
public ErrorDescription getHashConflict() {
|
public ErrorDescription getHashConflict() {
|
||||||
return hashConflict;
|
return hashConflict;
|
||||||
|
@ -89,4 +91,19 @@ public class ErrorThesaurusProperties {
|
||||||
this.overlappingTenantConfigurationNotifierList = overlappingTenantConfigurationNotifierList;
|
this.overlappingTenantConfigurationNotifierList = overlappingTenantConfigurationNotifierList;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ErrorDescription getTenantNotAllowed() {
|
||||||
|
return tenantNotAllowed;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTenantNotAllowed(ErrorDescription tenantNotAllowed) {
|
||||||
|
this.tenantNotAllowed = tenantNotAllowed;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ErrorDescription getTenantTampering() {
|
||||||
|
return tenantTampering;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTenantTampering(ErrorDescription tenantTampering) {
|
||||||
|
this.tenantTampering = tenantTampering;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
package gr.cite.notification.integrationevent;
|
package gr.cite.notification.integrationevent;
|
||||||
|
|
||||||
|
import gr.cite.notification.data.QueueOutboxEntity;
|
||||||
import gr.cite.notification.integrationevent.outbox.OutboxProperties;
|
import gr.cite.notification.integrationevent.outbox.OutboxProperties;
|
||||||
import gr.cite.notification.integrationevent.outbox.OutboxRepositoryImpl;
|
import gr.cite.notification.integrationevent.outbox.OutboxRepositoryImpl;
|
||||||
import gr.cite.queueoutbox.IntegrationEventContextCreator;
|
import gr.cite.queueoutbox.IntegrationEventContextCreator;
|
||||||
|
@ -56,7 +57,11 @@ public class OutboxIntegrationEventConfigurer extends OutboxConfigurer {
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
public IntegrationEventContextCreator integrationEventContextCreator() {
|
public IntegrationEventContextCreator integrationEventContextCreator() {
|
||||||
return (message) -> new IntegrationEventContextImpl();
|
return (message) -> {
|
||||||
|
IntegrationEventContextImpl integrationEventContext = new IntegrationEventContextImpl();
|
||||||
|
if (message instanceof QueueOutboxEntity) integrationEventContext.setTenant(((QueueOutboxEntity)message).getTenantId());
|
||||||
|
return integrationEventContext;
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package gr.cite.notification.integrationevent.inbox;
|
package gr.cite.notification.integrationevent.inbox;
|
||||||
|
|
||||||
import gr.cite.commons.web.oidc.principal.MyPrincipal;
|
import gr.cite.commons.web.oidc.principal.MyPrincipal;
|
||||||
|
import gr.cite.commons.web.oidc.principal.extractor.ClaimExtractorProperties;
|
||||||
import org.springframework.security.oauth2.core.ClaimAccessor;
|
import org.springframework.security.oauth2.core.ClaimAccessor;
|
||||||
import org.springframework.security.oauth2.jwt.JwtClaimNames;
|
import org.springframework.security.oauth2.jwt.JwtClaimNames;
|
||||||
|
|
||||||
|
@ -22,12 +23,15 @@ public class InboxPrincipal implements MyPrincipal, ClaimAccessor {
|
||||||
this.isAuthenticated = isAuthenticated;
|
this.isAuthenticated = isAuthenticated;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static InboxPrincipal build(IntegrationEventProperties properties) {
|
public static InboxPrincipal build(IntegrationEventProperties properties, ClaimExtractorProperties claimExtractorProperties) {
|
||||||
InboxPrincipal inboxPrincipal = new InboxPrincipal(true, "IntegrationEventQueueAppId");
|
InboxPrincipal inboxPrincipal = new InboxPrincipal(true, "IntegrationEventQueueAppId");
|
||||||
inboxPrincipal.put("client_id", properties.getAppId());
|
List<ClaimExtractorProperties.KeyPath> clientKey = claimExtractorProperties.getMapping().getOrDefault("Client", null);
|
||||||
|
inboxPrincipal.put(clientKey != null && clientKey.getFirst() != null ? clientKey.getFirst().getType() : "client_id", properties.getAppId());
|
||||||
inboxPrincipal.put("active", "true");
|
inboxPrincipal.put("active", "true");
|
||||||
inboxPrincipal.put("nbf", Instant.now().minus(30, ChronoUnit.SECONDS).toString());
|
List<ClaimExtractorProperties.KeyPath> notBeforeKey = claimExtractorProperties.getMapping().getOrDefault("NotBefore", null);
|
||||||
inboxPrincipal.put("exp", Instant.now().plus(10, ChronoUnit.MINUTES).toString());
|
inboxPrincipal.put(notBeforeKey != null && notBeforeKey.getFirst() != null ? notBeforeKey.getFirst().getType() :"nbf", Instant.now().minus(30, ChronoUnit.SECONDS).toString());
|
||||||
|
List<ClaimExtractorProperties.KeyPath> expiresAt = claimExtractorProperties.getMapping().getOrDefault("ExpiresAt", null);
|
||||||
|
inboxPrincipal.put(expiresAt != null && expiresAt.getFirst() != null ? expiresAt.getFirst().getType() :"exp", Instant.now().plus(10, ChronoUnit.MINUTES).toString());
|
||||||
return inboxPrincipal;
|
return inboxPrincipal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -45,7 +49,10 @@ public class InboxPrincipal implements MyPrincipal, ClaimAccessor {
|
||||||
public List<String> getClaimAsStringList(String claim) {
|
public List<String> getClaimAsStringList(String claim) {
|
||||||
if (claims == null)
|
if (claims == null)
|
||||||
return null;
|
return null;
|
||||||
return this.getClaimAsStringList(claim);
|
if (this.claims.containsKey(claim)){
|
||||||
|
return List.of(this.claims.get(claim).toString());
|
||||||
|
}
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -4,6 +4,7 @@ import gr.cite.notification.common.JsonHandlingService;
|
||||||
import gr.cite.notification.common.enums.IsActive;
|
import gr.cite.notification.common.enums.IsActive;
|
||||||
import gr.cite.notification.common.scope.fake.FakeRequestScope;
|
import gr.cite.notification.common.scope.fake.FakeRequestScope;
|
||||||
import gr.cite.notification.data.QueueInboxEntity;
|
import gr.cite.notification.data.QueueInboxEntity;
|
||||||
|
import gr.cite.notification.data.TenantEntityManager;
|
||||||
import gr.cite.notification.integrationevent.TrackedEvent;
|
import gr.cite.notification.integrationevent.TrackedEvent;
|
||||||
import gr.cite.notification.integrationevent.inbox.notify.NotifyIntegrationEventHandler;
|
import gr.cite.notification.integrationevent.inbox.notify.NotifyIntegrationEventHandler;
|
||||||
import gr.cite.notification.integrationevent.inbox.tenantremoval.TenantRemovalIntegrationEventHandler;
|
import gr.cite.notification.integrationevent.inbox.tenantremoval.TenantRemovalIntegrationEventHandler;
|
||||||
|
@ -16,6 +17,7 @@ import gr.cite.queueinbox.entity.QueueInboxStatus;
|
||||||
import gr.cite.queueinbox.repository.CandidateInfo;
|
import gr.cite.queueinbox.repository.CandidateInfo;
|
||||||
import gr.cite.queueinbox.repository.InboxRepository;
|
import gr.cite.queueinbox.repository.InboxRepository;
|
||||||
import gr.cite.queueinbox.task.MessageOptions;
|
import gr.cite.queueinbox.task.MessageOptions;
|
||||||
|
import gr.cite.rabbitmq.IntegrationEventMessageConstants;
|
||||||
import gr.cite.rabbitmq.consumer.InboxCreatorParams;
|
import gr.cite.rabbitmq.consumer.InboxCreatorParams;
|
||||||
import gr.cite.tools.data.query.Ordering;
|
import gr.cite.tools.data.query.Ordering;
|
||||||
import gr.cite.tools.data.query.QueryFactory;
|
import gr.cite.tools.data.query.QueryFactory;
|
||||||
|
@ -241,7 +243,14 @@ public class InboxRepositoryImpl implements InboxRepository {
|
||||||
|
|
||||||
QueueInboxEntity queueMessage = new QueueInboxEntity();
|
QueueInboxEntity queueMessage = new QueueInboxEntity();
|
||||||
queueMessage.setId(UUID.randomUUID());
|
queueMessage.setId(UUID.randomUUID());
|
||||||
queueMessage.setTenantId(null);
|
Object tenantId = inboxCreatorParams.getHeaders() != null ? inboxCreatorParams.getHeaders().getOrDefault(IntegrationEventMessageConstants.TENANT, null) : null;
|
||||||
|
if (tenantId instanceof UUID) queueMessage.setTenantId((UUID) tenantId);
|
||||||
|
else if (tenantId instanceof String) {
|
||||||
|
try {
|
||||||
|
queueMessage.setTenantId(UUID.fromString((String) tenantId));
|
||||||
|
} catch (Exception e) {
|
||||||
|
}
|
||||||
|
}
|
||||||
queueMessage.setExchange(this.inboxProperties.getExchange());
|
queueMessage.setExchange(this.inboxProperties.getExchange());
|
||||||
queueMessage.setRoute(inboxCreatorParams.getRoutingKey());
|
queueMessage.setRoute(inboxCreatorParams.getRoutingKey());
|
||||||
queueMessage.setQueue(inboxCreatorParams.getQueueName());
|
queueMessage.setQueue(inboxCreatorParams.getQueueName());
|
||||||
|
@ -269,6 +278,10 @@ public class InboxRepositoryImpl implements InboxRepository {
|
||||||
|
|
||||||
entityManager = entityManagerFactory.createEntityManager();
|
entityManager = entityManagerFactory.createEntityManager();
|
||||||
transaction = entityManager.getTransaction();
|
transaction = entityManager.getTransaction();
|
||||||
|
|
||||||
|
TenantEntityManager tenantEntityManager = this.applicationContext.getBean(TenantEntityManager.class);
|
||||||
|
tenantEntityManager.setEntityManager(entityManager);
|
||||||
|
|
||||||
transaction.begin();
|
transaction.begin();
|
||||||
|
|
||||||
QueryFactory queryFactory = this.applicationContext.getBean(QueryFactory.class);
|
QueryFactory queryFactory = this.applicationContext.getBean(QueryFactory.class);
|
||||||
|
@ -278,7 +291,7 @@ public class InboxRepositoryImpl implements InboxRepository {
|
||||||
logger.warn("Could not lookup queue inbox {} to process. Continuing...", candidateInfo.getId());
|
logger.warn("Could not lookup queue inbox {} to process. Continuing...", candidateInfo.getId());
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
EventProcessingStatus status = this.processMessage(queueInboxMessage.getRoute(), queueInboxMessage.getMessageId().toString(), queueInboxMessage.getApplicationId(), queueInboxMessage.getMessage());
|
EventProcessingStatus status = this.processMessage(queueInboxMessage);
|
||||||
switch (status) {
|
switch (status) {
|
||||||
case Success: {
|
case Success: {
|
||||||
queueInboxMessage.setStatus(QueueInboxStatus.SUCCESSFUL);
|
queueInboxMessage.setStatus(QueueInboxStatus.SUCCESSFUL);
|
||||||
|
@ -321,21 +334,21 @@ public class InboxRepositoryImpl implements InboxRepository {
|
||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
|
|
||||||
private EventProcessingStatus processMessage(String routingKey, String messageId, String appId, String message) {
|
private EventProcessingStatus processMessage(QueueInboxEntity queueInboxMessage) {
|
||||||
IntegrationEventHandler handler;
|
IntegrationEventHandler handler;
|
||||||
logger.debug("Processing message with routing key '{}'", routingKey);
|
logger.debug("Processing message with routing key '{}'", queueInboxMessage.getRoute());
|
||||||
if (this.routingKeyMatched(routingKey, this.inboxProperties.getNotifyTopic()))
|
if (this.routingKeyMatched(queueInboxMessage.getRoute(), this.inboxProperties.getTenantRemovalTopic()))
|
||||||
handler = this.applicationContext.getBean(NotifyIntegrationEventHandler.class);
|
|
||||||
else if (this.routingKeyMatched(routingKey, this.inboxProperties.getTenantRemovalTopic()))
|
|
||||||
handler = this.applicationContext.getBean(TenantRemovalIntegrationEventHandler.class);
|
handler = this.applicationContext.getBean(TenantRemovalIntegrationEventHandler.class);
|
||||||
else if (this.routingKeyMatched(routingKey, this.inboxProperties.getTenantTouchedTopic()))
|
else if (this.routingKeyMatched(queueInboxMessage.getRoute(), this.inboxProperties.getTenantTouchedTopic()))
|
||||||
handler = this.applicationContext.getBean(TenantTouchedIntegrationEventHandler.class);
|
handler = this.applicationContext.getBean(TenantTouchedIntegrationEventHandler.class);
|
||||||
else if (this.routingKeyMatched(routingKey, this.inboxProperties.getUserRemovalTopic()))
|
else if (this.routingKeyMatched(queueInboxMessage.getRoute(), this.inboxProperties.getUserRemovalTopic()))
|
||||||
handler = this.applicationContext.getBean(UserRemovalIntegrationEventHandler.class);
|
handler = this.applicationContext.getBean(UserRemovalIntegrationEventHandler.class);
|
||||||
else if (this.routingKeyMatched(routingKey, this.inboxProperties.getUserTouchedTopic()))
|
else if (this.routingKeyMatched(queueInboxMessage.getRoute(), this.inboxProperties.getUserTouchedTopic()))
|
||||||
handler = this.applicationContext.getBean(UserTouchedIntegrationEventHandler.class);
|
handler = this.applicationContext.getBean(UserTouchedIntegrationEventHandler.class);
|
||||||
|
else if (this.routingKeyMatched(queueInboxMessage.getRoute(), this.inboxProperties.getNotifyTopic()))
|
||||||
|
handler = this.applicationContext.getBean(NotifyIntegrationEventHandler.class);
|
||||||
else {
|
else {
|
||||||
logger.error("No handler found for message routing key '{}'. Discarding.", routingKey);
|
logger.error("No handler found for message routing key '{}'. Discarding.", queueInboxMessage.getRoute());
|
||||||
handler = null;
|
handler = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -343,16 +356,17 @@ public class InboxRepositoryImpl implements InboxRepository {
|
||||||
return EventProcessingStatus.Discard;
|
return EventProcessingStatus.Discard;
|
||||||
|
|
||||||
IntegrationEventProperties properties = new IntegrationEventProperties();
|
IntegrationEventProperties properties = new IntegrationEventProperties();
|
||||||
properties.setAppId(appId);
|
properties.setAppId(queueInboxMessage.getApplicationId());
|
||||||
properties.setMessageId(messageId);
|
properties.setMessageId(queueInboxMessage.getMessageId().toString());
|
||||||
|
properties.setTenantId(queueInboxMessage.getTenantId());
|
||||||
|
|
||||||
TrackedEvent event = this.jsonHandlingService.fromJsonSafe(TrackedEvent.class, message);
|
TrackedEvent event = this.jsonHandlingService.fromJsonSafe(TrackedEvent.class, queueInboxMessage.getMessage());
|
||||||
// using (LogContext.PushProperty(this._logTrackingConfig.LogTrackingContextName, @event.TrackingContextTag))
|
// using (LogContext.PushProperty(this._logTrackingConfig.LogTrackingContextName, @event.TrackingContextTag))
|
||||||
// {
|
// {
|
||||||
try {
|
try {
|
||||||
return handler.handle(properties, message);
|
return handler.handle(properties, queueInboxMessage.getMessage());
|
||||||
} catch (Exception ex) {
|
} catch (Exception ex) {
|
||||||
logger.error("problem handling event from routing key " + routingKey + ". Setting nack and continuing...", ex);
|
logger.error("problem handling event from routing key " + queueInboxMessage.getRoute() + ". Setting nack and continuing...", ex);
|
||||||
return EventProcessingStatus.Error;
|
return EventProcessingStatus.Error;
|
||||||
}
|
}
|
||||||
// }
|
// }
|
||||||
|
|
|
@ -1,10 +1,13 @@
|
||||||
package gr.cite.notification.integrationevent.inbox;
|
package gr.cite.notification.integrationevent.inbox;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
public class IntegrationEventProperties {
|
public class IntegrationEventProperties {
|
||||||
|
|
||||||
private String messageId;
|
private String messageId;
|
||||||
|
|
||||||
private String appId;
|
private String appId;
|
||||||
|
private UUID tenantId;
|
||||||
|
|
||||||
public String getMessageId() {
|
public String getMessageId() {
|
||||||
return messageId;
|
return messageId;
|
||||||
|
@ -22,4 +25,11 @@ public class IntegrationEventProperties {
|
||||||
this.appId = appId;
|
this.appId = appId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public UUID getTenantId() {
|
||||||
|
return tenantId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTenantId(UUID tenantId) {
|
||||||
|
this.tenantId = tenantId;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,8 +9,6 @@ public class NotifyIntegrationEvent extends TrackedEvent {
|
||||||
|
|
||||||
private UUID userId;
|
private UUID userId;
|
||||||
|
|
||||||
private UUID tenantId;
|
|
||||||
|
|
||||||
private UUID notificationType;
|
private UUID notificationType;
|
||||||
|
|
||||||
private NotificationContactType contactTypeHint;
|
private NotificationContactType contactTypeHint;
|
||||||
|
@ -32,14 +30,6 @@ public class NotifyIntegrationEvent extends TrackedEvent {
|
||||||
this.userId = userId;
|
this.userId = userId;
|
||||||
}
|
}
|
||||||
|
|
||||||
public UUID getTenantId() {
|
|
||||||
return tenantId;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setTenantId(UUID tenantId) {
|
|
||||||
this.tenantId = tenantId;
|
|
||||||
}
|
|
||||||
|
|
||||||
public UUID getNotificationType() {
|
public UUID getNotificationType() {
|
||||||
return notificationType;
|
return notificationType;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package gr.cite.notification.integrationevent.inbox.notify;
|
package gr.cite.notification.integrationevent.inbox.notify;
|
||||||
|
|
||||||
import gr.cite.commons.web.oidc.principal.CurrentPrincipalResolver;
|
import gr.cite.commons.web.oidc.principal.CurrentPrincipalResolver;
|
||||||
|
import gr.cite.commons.web.oidc.principal.extractor.ClaimExtractorProperties;
|
||||||
import gr.cite.notification.audit.AuditableAction;
|
import gr.cite.notification.audit.AuditableAction;
|
||||||
import gr.cite.notification.common.JsonHandlingService;
|
import gr.cite.notification.common.JsonHandlingService;
|
||||||
import gr.cite.notification.common.enums.NotificationNotifyState;
|
import gr.cite.notification.common.enums.NotificationNotifyState;
|
||||||
|
@ -9,6 +10,7 @@ import gr.cite.notification.common.enums.NotificationTrackingState;
|
||||||
import gr.cite.notification.common.scope.fake.FakeRequestScope;
|
import gr.cite.notification.common.scope.fake.FakeRequestScope;
|
||||||
import gr.cite.notification.common.scope.tenant.TenantScope;
|
import gr.cite.notification.common.scope.tenant.TenantScope;
|
||||||
import gr.cite.notification.data.TenantEntity;
|
import gr.cite.notification.data.TenantEntity;
|
||||||
|
import gr.cite.notification.data.TenantEntityManager;
|
||||||
import gr.cite.notification.errorcode.ErrorThesaurusProperties;
|
import gr.cite.notification.errorcode.ErrorThesaurusProperties;
|
||||||
import gr.cite.notification.integrationevent.inbox.EventProcessingStatus;
|
import gr.cite.notification.integrationevent.inbox.EventProcessingStatus;
|
||||||
import gr.cite.notification.integrationevent.inbox.InboxPrincipal;
|
import gr.cite.notification.integrationevent.inbox.InboxPrincipal;
|
||||||
|
@ -46,17 +48,30 @@ public class NotifyIntegrationEventHandlerImpl implements NotifyIntegrationEvent
|
||||||
|
|
||||||
private final JsonHandlingService jsonHandlingService;
|
private final JsonHandlingService jsonHandlingService;
|
||||||
|
|
||||||
private final ApplicationContext applicationContext;
|
|
||||||
|
|
||||||
private final ErrorThesaurusProperties errors;
|
private final ErrorThesaurusProperties errors;
|
||||||
|
|
||||||
private final MessageSource messageSource;
|
private final MessageSource messageSource;
|
||||||
|
private final QueryFactory queryFactory;
|
||||||
public NotifyIntegrationEventHandlerImpl(JsonHandlingService jsonHandlingService, ApplicationContext applicationContext, ErrorThesaurusProperties errors, MessageSource messageSource) {
|
private final TenantScope tenantScope;
|
||||||
|
private final CurrentPrincipalResolver currentPrincipalResolver;
|
||||||
|
private final ClaimExtractorProperties claimExtractorProperties;
|
||||||
|
private final NotifyConsistencyHandler notifyConsistencyHandler;
|
||||||
|
private final NotificationService notificationService;
|
||||||
|
private final AuditService auditService;
|
||||||
|
private final TenantEntityManager tenantEntityManager;
|
||||||
|
public NotifyIntegrationEventHandlerImpl(JsonHandlingService jsonHandlingService, ErrorThesaurusProperties errors, MessageSource messageSource, QueryFactory queryFactory, TenantScope tenantScope, CurrentPrincipalResolver currentPrincipalResolver, ClaimExtractorProperties claimExtractorProperties, NotifyConsistencyHandler notifyConsistencyHandler, NotificationService notificationService, AuditService auditService, TenantEntityManager tenantEntityManager) {
|
||||||
this.jsonHandlingService = jsonHandlingService;
|
this.jsonHandlingService = jsonHandlingService;
|
||||||
this.applicationContext = applicationContext;
|
|
||||||
this.errors = errors;
|
this.errors = errors;
|
||||||
this.messageSource = messageSource;
|
this.messageSource = messageSource;
|
||||||
|
this.queryFactory = queryFactory;
|
||||||
|
this.tenantScope = tenantScope;
|
||||||
|
this.currentPrincipalResolver = currentPrincipalResolver;
|
||||||
|
this.claimExtractorProperties = claimExtractorProperties;
|
||||||
|
this.notifyConsistencyHandler = notifyConsistencyHandler;
|
||||||
|
this.notificationService = notificationService;
|
||||||
|
this.auditService = auditService;
|
||||||
|
this.tenantEntityManager = tenantEntityManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -84,72 +99,42 @@ public class NotifyIntegrationEventHandlerImpl implements NotifyIntegrationEvent
|
||||||
model.setProvenanceRef(event.getProvenanceRef());
|
model.setProvenanceRef(event.getProvenanceRef());
|
||||||
model.setNotifiedAt(Instant.now());
|
model.setNotifiedAt(Instant.now());
|
||||||
|
|
||||||
EntityManager entityManager = null;
|
EventProcessingStatus status = EventProcessingStatus.Success;
|
||||||
EntityTransaction transaction = null;
|
|
||||||
try (FakeRequestScope ignored = new FakeRequestScope()) {
|
|
||||||
try {
|
try {
|
||||||
QueryFactory queryFactory = this.applicationContext.getBean(QueryFactory.class);
|
if (this.tenantScope.isMultitenant() && properties.getTenantId() != null) {
|
||||||
TenantScope scope = this.applicationContext.getBean(TenantScope.class);
|
TenantEntity tenant = queryFactory.query(TenantQuery.class).ids(properties.getTenantId()).firstAs(new BaseFieldSet().ensure(Tenant._id).ensure(Tenant._code));
|
||||||
if (scope.isMultitenant() && event.getTenantId() != null) {
|
|
||||||
TenantEntity tenant = queryFactory.query(TenantQuery.class).ids(event.getTenantId()).firstAs(new BaseFieldSet().ensure(Tenant._id).ensure(Tenant._code));
|
|
||||||
if (tenant == null) {
|
if (tenant == null) {
|
||||||
logger.error("missing tenant from event message");
|
logger.error("missing tenant from event message");
|
||||||
return EventProcessingStatus.Error;
|
return EventProcessingStatus.Error;
|
||||||
}
|
}
|
||||||
scope.setTenant(event.getTenantId(), tenant.getCode());
|
this.tenantScope.setTempTenant(tenantEntityManager.getEntityManager(), properties.getTenantId(), tenant.getCode());
|
||||||
} else if (scope.isMultitenant()) {
|
} else if (this.tenantScope.isMultitenant()) {
|
||||||
logger.error("missing tenant from event message");
|
// logger.error("missing tenant from event message");
|
||||||
return EventProcessingStatus.Error;
|
// return EventProcessingStatus.Error;
|
||||||
|
this.tenantScope.setTempTenant(tenantEntityManager.getEntityManager(), null, this.tenantScope.getDefaultTenantCode());
|
||||||
}
|
}
|
||||||
|
|
||||||
CurrentPrincipalResolver currentPrincipalResolver = this.applicationContext.getBean(CurrentPrincipalResolver.class);
|
currentPrincipalResolver.push(InboxPrincipal.build(properties, claimExtractorProperties));
|
||||||
currentPrincipalResolver.push(InboxPrincipal.build(properties));
|
|
||||||
|
|
||||||
NotifyConsistencyHandler notifyConsistencyHandler = this.applicationContext.getBean(NotifyConsistencyHandler.class);
|
if (!(notifyConsistencyHandler.isConsistent(new NotifyConsistencyPredicates(event.getUserId(), event.getContactTypeHint(), event.getContactHint())))) {
|
||||||
if (!(notifyConsistencyHandler.isConsistent(new NotifyConsistencyPredicates(event.getUserId(), event.getContactTypeHint(), event.getContactHint()))))
|
status = EventProcessingStatus.Postponed;
|
||||||
return EventProcessingStatus.Postponed;
|
currentPrincipalResolver.pop();
|
||||||
|
tenantScope.removeTempTenant(this.tenantEntityManager.getEntityManager());
|
||||||
EntityManagerFactory entityManagerFactory = this.applicationContext.getBean(EntityManagerFactory.class);
|
return status;
|
||||||
entityManager = entityManagerFactory.createEntityManager();
|
}
|
||||||
|
|
||||||
transaction = entityManager.getTransaction();
|
|
||||||
transaction.begin();
|
|
||||||
|
|
||||||
try {
|
|
||||||
NotificationService notificationService = this.applicationContext.getBean(NotificationService.class);
|
|
||||||
notificationService.persist(model, new BaseFieldSet());
|
notificationService.persist(model, new BaseFieldSet());
|
||||||
|
|
||||||
AuditService auditService = this.applicationContext.getBean(AuditService.class);
|
|
||||||
|
|
||||||
auditService.track(AuditableAction.Notification_Persist, Map.ofEntries(
|
auditService.track(AuditableAction.Notification_Persist, Map.ofEntries(
|
||||||
new AbstractMap.SimpleEntry<String, Object>("id", event.getUserId())
|
new AbstractMap.SimpleEntry<String, Object>("id", event.getUserId())
|
||||||
));
|
));
|
||||||
//auditService.trackIdentity(AuditableAction.IdentityTracking_Action);
|
} catch (Exception ex) {
|
||||||
|
status = EventProcessingStatus.Error;
|
||||||
transaction.commit();
|
logger.error("Problem getting list of queue outbox. Skipping: {}", ex.getMessage(), ex);
|
||||||
} catch (Exception e) {
|
|
||||||
transaction.rollback();
|
|
||||||
throw e;
|
|
||||||
} finally {
|
} finally {
|
||||||
currentPrincipalResolver.pop();
|
currentPrincipalResolver.pop();
|
||||||
|
tenantScope.removeTempTenant(this.tenantEntityManager.getEntityManager());
|
||||||
}
|
}
|
||||||
} catch (OptimisticLockException ex) {
|
return status;
|
||||||
// we get this if/when someone else already modified the notifications. We want to essentially ignore this, and keep working
|
|
||||||
logger.debug("Concurrency exception getting queue outbox. Skipping: {} ", ex.getMessage());
|
|
||||||
if (transaction != null)
|
|
||||||
transaction.rollback();
|
|
||||||
} catch (Exception ex) {
|
|
||||||
logger.error("Problem getting list of queue outbox. Skipping: {}", ex.getMessage(), ex);
|
|
||||||
if (transaction != null)
|
|
||||||
transaction.rollback();
|
|
||||||
} finally {
|
|
||||||
if (entityManager != null)
|
|
||||||
entityManager.close();
|
|
||||||
}
|
|
||||||
} catch (Exception ex) {
|
|
||||||
logger.error("Problem getting list of queue outbox. Skipping: {}", ex.getMessage(), ex);
|
|
||||||
}
|
|
||||||
return EventProcessingStatus.Success;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
package gr.cite.notification.integrationevent.inbox.tenantremoval;
|
package gr.cite.notification.integrationevent.inbox.tenantremoval;
|
||||||
|
|
||||||
|
|
||||||
import gr.cite.notification.integrationevent.inbox.IntegrationEventHandler;
|
import gr.cite.notification.integrationevent.inbox.IntegrationEventHandler;
|
||||||
|
|
||||||
public interface TenantRemovalIntegrationEventHandler extends IntegrationEventHandler {
|
public interface TenantRemovalIntegrationEventHandler extends IntegrationEventHandler {
|
||||||
|
|
|
@ -1,24 +1,18 @@
|
||||||
package gr.cite.notification.integrationevent.inbox.tenantremoval;
|
package gr.cite.notification.integrationevent.inbox.tenantremoval;
|
||||||
|
|
||||||
import gr.cite.commons.web.oidc.principal.CurrentPrincipalResolver;
|
import gr.cite.commons.web.oidc.principal.CurrentPrincipalResolver;
|
||||||
|
import gr.cite.commons.web.oidc.principal.extractor.ClaimExtractorProperties;
|
||||||
import gr.cite.notification.audit.AuditableAction;
|
import gr.cite.notification.audit.AuditableAction;
|
||||||
import gr.cite.notification.common.JsonHandlingService;
|
import gr.cite.notification.common.JsonHandlingService;
|
||||||
import gr.cite.notification.common.scope.fake.FakeRequestScope;
|
import gr.cite.notification.data.TenantEntityManager;
|
||||||
import gr.cite.notification.errorcode.ErrorThesaurusProperties;
|
|
||||||
import gr.cite.notification.integrationevent.inbox.EventProcessingStatus;
|
import gr.cite.notification.integrationevent.inbox.EventProcessingStatus;
|
||||||
import gr.cite.notification.integrationevent.inbox.InboxPrincipal;
|
import gr.cite.notification.integrationevent.inbox.InboxPrincipal;
|
||||||
import gr.cite.notification.integrationevent.inbox.IntegrationEventProperties;
|
import gr.cite.notification.integrationevent.inbox.IntegrationEventProperties;
|
||||||
import gr.cite.notification.service.tenant.TenantService;
|
import gr.cite.notification.service.tenant.TenantService;
|
||||||
import gr.cite.tools.auditing.AuditService;
|
import gr.cite.tools.auditing.AuditService;
|
||||||
import gr.cite.tools.logging.LoggerService;
|
import gr.cite.tools.logging.LoggerService;
|
||||||
import jakarta.persistence.EntityManager;
|
|
||||||
import jakarta.persistence.EntityManagerFactory;
|
|
||||||
import jakarta.persistence.EntityTransaction;
|
|
||||||
import jakarta.persistence.OptimisticLockException;
|
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
|
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
|
||||||
import org.springframework.context.ApplicationContext;
|
|
||||||
import org.springframework.context.MessageSource;
|
|
||||||
import org.springframework.context.annotation.Scope;
|
import org.springframework.context.annotation.Scope;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
@ -32,18 +26,20 @@ public class TenantRemovalIntegrationEventHandlerImpl implements TenantRemovalIn
|
||||||
private static final LoggerService logger = new LoggerService(LoggerFactory.getLogger(TenantRemovalIntegrationEventHandlerImpl.class));
|
private static final LoggerService logger = new LoggerService(LoggerFactory.getLogger(TenantRemovalIntegrationEventHandlerImpl.class));
|
||||||
|
|
||||||
private final JsonHandlingService jsonHandlingService;
|
private final JsonHandlingService jsonHandlingService;
|
||||||
|
private final CurrentPrincipalResolver currentPrincipalResolver;
|
||||||
private final ApplicationContext applicationContext;
|
private final ClaimExtractorProperties claimExtractorProperties;
|
||||||
|
private final TenantService tenantService;
|
||||||
private final ErrorThesaurusProperties errors;
|
private final AuditService auditService;
|
||||||
|
private final TenantEntityManager tenantEntityManager;
|
||||||
private final MessageSource messageSource;
|
private final TenantRemovalConsistencyHandler tenantRemovalConsistencyHandler;
|
||||||
|
public TenantRemovalIntegrationEventHandlerImpl(JsonHandlingService jsonHandlingService, CurrentPrincipalResolver currentPrincipalResolver, ClaimExtractorProperties claimExtractorProperties, TenantService tenantService, AuditService auditService, TenantEntityManager tenantEntityManager, TenantRemovalConsistencyHandler tenantRemovalConsistencyHandler) {
|
||||||
public TenantRemovalIntegrationEventHandlerImpl(JsonHandlingService jsonHandlingService, ApplicationContext applicationContext, ErrorThesaurusProperties errors, MessageSource messageSource) {
|
|
||||||
this.jsonHandlingService = jsonHandlingService;
|
this.jsonHandlingService = jsonHandlingService;
|
||||||
this.applicationContext = applicationContext;
|
this.currentPrincipalResolver = currentPrincipalResolver;
|
||||||
this.errors = errors;
|
this.claimExtractorProperties = claimExtractorProperties;
|
||||||
this.messageSource = messageSource;
|
this.tenantService = tenantService;
|
||||||
|
this.auditService = auditService;
|
||||||
|
this.tenantEntityManager = tenantEntityManager;
|
||||||
|
this.tenantRemovalConsistencyHandler = tenantRemovalConsistencyHandler;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -52,60 +48,34 @@ public class TenantRemovalIntegrationEventHandlerImpl implements TenantRemovalIn
|
||||||
if (event == null)
|
if (event == null)
|
||||||
return EventProcessingStatus.Error;
|
return EventProcessingStatus.Error;
|
||||||
|
|
||||||
EntityManager entityManager = null;
|
EventProcessingStatus status = EventProcessingStatus.Success;
|
||||||
EntityTransaction transaction = null;
|
|
||||||
try (FakeRequestScope ignored = new FakeRequestScope()) {
|
|
||||||
try {
|
try {
|
||||||
CurrentPrincipalResolver currentPrincipalResolver = this.applicationContext.getBean(CurrentPrincipalResolver.class);
|
|
||||||
currentPrincipalResolver.push(InboxPrincipal.build(properties));
|
|
||||||
|
|
||||||
TenantRemovalConsistencyHandler tenantRemovalConsistencyHandler = this.applicationContext.getBean(TenantRemovalConsistencyHandler.class);
|
currentPrincipalResolver.push(InboxPrincipal.build(properties, claimExtractorProperties));
|
||||||
if (!(tenantRemovalConsistencyHandler.isConsistent(new TenantRemovalConsistencyPredicates(event.getId()))))
|
|
||||||
return EventProcessingStatus.Postponed;
|
|
||||||
|
|
||||||
EntityManagerFactory entityManagerFactory = this.applicationContext.getBean(EntityManagerFactory.class);
|
if (!(tenantRemovalConsistencyHandler.isConsistent(new TenantRemovalConsistencyPredicates(event.getId())))) {
|
||||||
entityManager = entityManagerFactory.createEntityManager();
|
status = EventProcessingStatus.Postponed;
|
||||||
|
currentPrincipalResolver.pop();
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
transaction = entityManager.getTransaction();
|
tenantEntityManager.disableTenantFilters();
|
||||||
transaction.begin();
|
|
||||||
|
|
||||||
try {
|
|
||||||
TenantService tenantService = this.applicationContext.getBean(TenantService.class);
|
|
||||||
tenantService.deleteAndSave(event.getId());
|
tenantService.deleteAndSave(event.getId());
|
||||||
|
|
||||||
AuditService auditService = this.applicationContext.getBean(AuditService.class);
|
|
||||||
|
|
||||||
auditService.track(AuditableAction.Tenant_Delete, Map.ofEntries(
|
auditService.track(AuditableAction.Tenant_Delete, Map.ofEntries(
|
||||||
new AbstractMap.SimpleEntry<String, Object>("id", event.getId())
|
new AbstractMap.SimpleEntry<String, Object>("id", event.getId())
|
||||||
));
|
));
|
||||||
//auditService.trackIdentity(AuditableAction.IdentityTracking_Action);
|
//auditService.trackIdentity(AuditableAction.IdentityTracking_Action);
|
||||||
|
|
||||||
transaction.commit();
|
|
||||||
} catch (Exception e) {
|
} catch (Exception ex) {
|
||||||
transaction.rollback();
|
status = EventProcessingStatus.Error;
|
||||||
throw e;
|
logger.error("Problem getting list of queue outbox. Skipping: {}", ex.getMessage(), ex);
|
||||||
} finally {
|
} finally {
|
||||||
currentPrincipalResolver.pop();
|
currentPrincipalResolver.pop();
|
||||||
}
|
}
|
||||||
|
return status;
|
||||||
transaction.commit();
|
|
||||||
} catch (OptimisticLockException ex) {
|
|
||||||
// we get this if/when someone else already modified the notifications. We want to essentially ignore this, and keep working
|
|
||||||
logger.debug("Concurrency exception getting queue outbox. Skipping: {} ", ex.getMessage());
|
|
||||||
if (transaction != null)
|
|
||||||
transaction.rollback();
|
|
||||||
} catch (Exception ex) {
|
|
||||||
logger.error("Problem getting list of queue outbox. Skipping: {}", ex.getMessage(), ex);
|
|
||||||
if (transaction != null)
|
|
||||||
transaction.rollback();
|
|
||||||
} finally {
|
|
||||||
if (entityManager != null)
|
|
||||||
entityManager.close();
|
|
||||||
}
|
|
||||||
} catch (Exception ex) {
|
|
||||||
logger.error("Problem getting list of queue outbox. Skipping: {}", ex.getMessage(), ex);
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
package gr.cite.notification.integrationevent.inbox.tenanttouched;
|
package gr.cite.notification.integrationevent.inbox.tenanttouched;
|
||||||
|
|
||||||
|
|
||||||
import gr.cite.notification.integrationevent.TrackedEvent;
|
import gr.cite.notification.integrationevent.TrackedEvent;
|
||||||
|
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
package gr.cite.notification.integrationevent.inbox.tenanttouched;
|
package gr.cite.notification.integrationevent.inbox.tenanttouched;
|
||||||
|
|
||||||
import gr.cite.commons.web.oidc.principal.CurrentPrincipalResolver;
|
import gr.cite.commons.web.oidc.principal.CurrentPrincipalResolver;
|
||||||
|
import gr.cite.commons.web.oidc.principal.extractor.ClaimExtractorProperties;
|
||||||
import gr.cite.notification.audit.AuditableAction;
|
import gr.cite.notification.audit.AuditableAction;
|
||||||
import gr.cite.notification.common.JsonHandlingService;
|
import gr.cite.notification.common.JsonHandlingService;
|
||||||
import gr.cite.notification.common.scope.fake.FakeRequestScope;
|
import gr.cite.notification.data.TenantEntityManager;
|
||||||
import gr.cite.notification.integrationevent.inbox.EventProcessingStatus;
|
import gr.cite.notification.integrationevent.inbox.EventProcessingStatus;
|
||||||
import gr.cite.notification.integrationevent.inbox.InboxPrincipal;
|
import gr.cite.notification.integrationevent.inbox.InboxPrincipal;
|
||||||
import gr.cite.notification.integrationevent.inbox.IntegrationEventProperties;
|
import gr.cite.notification.integrationevent.inbox.IntegrationEventProperties;
|
||||||
|
@ -12,13 +13,8 @@ import gr.cite.notification.service.tenant.TenantService;
|
||||||
import gr.cite.tools.auditing.AuditService;
|
import gr.cite.tools.auditing.AuditService;
|
||||||
import gr.cite.tools.logging.LoggerService;
|
import gr.cite.tools.logging.LoggerService;
|
||||||
import gr.cite.tools.validation.ValidatorFactory;
|
import gr.cite.tools.validation.ValidatorFactory;
|
||||||
import jakarta.persistence.EntityManager;
|
|
||||||
import jakarta.persistence.EntityManagerFactory;
|
|
||||||
import jakarta.persistence.EntityTransaction;
|
|
||||||
import jakarta.persistence.OptimisticLockException;
|
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
|
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
|
||||||
import org.springframework.context.ApplicationContext;
|
|
||||||
import org.springframework.context.annotation.Scope;
|
import org.springframework.context.annotation.Scope;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
@ -31,15 +27,23 @@ public class TenantTouchedIntegrationEventHandlerImpl implements TenantTouchedIn
|
||||||
|
|
||||||
private static final LoggerService logger = new LoggerService(LoggerFactory.getLogger(TenantTouchedIntegrationEventHandlerImpl.class));
|
private static final LoggerService logger = new LoggerService(LoggerFactory.getLogger(TenantTouchedIntegrationEventHandlerImpl.class));
|
||||||
|
|
||||||
protected final ApplicationContext applicationContext;
|
|
||||||
|
|
||||||
private final JsonHandlingService jsonHandlingService;
|
private final JsonHandlingService jsonHandlingService;
|
||||||
private final ValidatorFactory validatorFactory;
|
private final ValidatorFactory validatorFactory;
|
||||||
|
private final CurrentPrincipalResolver currentPrincipalResolver;
|
||||||
|
private final ClaimExtractorProperties claimExtractorProperties;
|
||||||
|
private final TenantService tenantService;
|
||||||
|
private final AuditService auditService;
|
||||||
|
private final TenantEntityManager tenantEntityManager;
|
||||||
|
|
||||||
public TenantTouchedIntegrationEventHandlerImpl(ApplicationContext applicationContext, JsonHandlingService jsonHandlingService, ValidatorFactory validatorFactory) {
|
public TenantTouchedIntegrationEventHandlerImpl(JsonHandlingService jsonHandlingService, ValidatorFactory validatorFactory, CurrentPrincipalResolver currentPrincipalResolver, ClaimExtractorProperties claimExtractorProperties, TenantService tenantService, AuditService auditService, TenantEntityManager tenantEntityManager) {
|
||||||
this.applicationContext = applicationContext;
|
|
||||||
this.jsonHandlingService = jsonHandlingService;
|
this.jsonHandlingService = jsonHandlingService;
|
||||||
this.validatorFactory = validatorFactory;
|
this.validatorFactory = validatorFactory;
|
||||||
|
this.currentPrincipalResolver = currentPrincipalResolver;
|
||||||
|
this.claimExtractorProperties = claimExtractorProperties;
|
||||||
|
this.tenantService = tenantService;
|
||||||
|
this.auditService = auditService;
|
||||||
|
this.tenantEntityManager = tenantEntityManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -53,55 +57,25 @@ public class TenantTouchedIntegrationEventHandlerImpl implements TenantTouchedIn
|
||||||
model.setCode(event.getCode());
|
model.setCode(event.getCode());
|
||||||
this.validatorFactory.validator(TenantTouchedIntegrationEventPersist.TenantTouchedIntegrationEventPersistValidator.class).validateForce(model);
|
this.validatorFactory.validator(TenantTouchedIntegrationEventPersist.TenantTouchedIntegrationEventPersistValidator.class).validateForce(model);
|
||||||
|
|
||||||
EntityManager entityManager = null;
|
EventProcessingStatus status = EventProcessingStatus.Success;
|
||||||
EntityTransaction transaction = null;
|
tenantEntityManager.disableTenantFilters();
|
||||||
try (FakeRequestScope ignored = new FakeRequestScope()) {
|
|
||||||
try {
|
try {
|
||||||
CurrentPrincipalResolver currentPrincipalResolver = this.applicationContext.getBean(CurrentPrincipalResolver.class);
|
currentPrincipalResolver.push(InboxPrincipal.build(properties, claimExtractorProperties));
|
||||||
currentPrincipalResolver.push(InboxPrincipal.build(properties));
|
|
||||||
|
|
||||||
EntityManagerFactory entityManagerFactory = this.applicationContext.getBean(EntityManagerFactory.class);
|
|
||||||
entityManager = entityManagerFactory.createEntityManager();
|
|
||||||
|
|
||||||
transaction = entityManager.getTransaction();
|
|
||||||
transaction.begin();
|
|
||||||
|
|
||||||
try {
|
|
||||||
TenantService tenantService = this.applicationContext.getBean(TenantService.class);
|
|
||||||
tenantService.persist(model, null);
|
tenantService.persist(model, null);
|
||||||
|
|
||||||
AuditService auditService = this.applicationContext.getBean(AuditService.class);
|
|
||||||
|
|
||||||
auditService.track(AuditableAction.Tenant_Persist, Map.ofEntries(
|
auditService.track(AuditableAction.Tenant_Persist, Map.ofEntries(
|
||||||
new AbstractMap.SimpleEntry<String, Object>("model", model)
|
new AbstractMap.SimpleEntry<String, Object>("model", model)
|
||||||
));
|
));
|
||||||
|
|
||||||
transaction.commit();
|
|
||||||
} catch (Exception e) {
|
} catch (Exception ex) {
|
||||||
transaction.rollback();
|
status = EventProcessingStatus.Error;
|
||||||
throw e;
|
logger.error("Problem getting list of queue outbox. Skipping: {}", ex.getMessage(), ex);
|
||||||
} finally {
|
} finally {
|
||||||
currentPrincipalResolver.pop();
|
currentPrincipalResolver.pop();
|
||||||
}
|
}
|
||||||
|
return status;
|
||||||
transaction.commit();
|
|
||||||
} catch (OptimisticLockException ex) {
|
|
||||||
// we get this if/when someone else already modified the notifications. We want to essentially ignore this, and keep working
|
|
||||||
logger.debug("Concurrency exception getting queue outbox. Skipping: {} ", ex.getMessage());
|
|
||||||
if (transaction != null)
|
|
||||||
transaction.rollback();
|
|
||||||
} catch (Exception ex) {
|
|
||||||
logger.error("Problem getting list of queue outbox. Skipping: {}", ex.getMessage(), ex);
|
|
||||||
if (transaction != null)
|
|
||||||
transaction.rollback();
|
|
||||||
} finally {
|
|
||||||
if (entityManager != null)
|
|
||||||
entityManager.close();
|
|
||||||
}
|
|
||||||
} catch (Exception ex) {
|
|
||||||
logger.error("Problem getting list of queue outbox. Skipping: {}", ex.getMessage(), ex);
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
package gr.cite.notification.integrationevent.inbox.userremoval;
|
package gr.cite.notification.integrationevent.inbox.userremoval;
|
||||||
|
|
||||||
|
|
||||||
import gr.cite.notification.integrationevent.inbox.ConsistencyPredicates;
|
import gr.cite.notification.integrationevent.inbox.ConsistencyPredicates;
|
||||||
|
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
|
@ -8,7 +8,6 @@ public class UserRemovalIntegrationEvent extends TrackedEvent {
|
||||||
|
|
||||||
private UUID userId;
|
private UUID userId;
|
||||||
|
|
||||||
private UUID tenant;
|
|
||||||
|
|
||||||
public UUID getUserId() {
|
public UUID getUserId() {
|
||||||
return userId;
|
return userId;
|
||||||
|
@ -17,12 +16,4 @@ public class UserRemovalIntegrationEvent extends TrackedEvent {
|
||||||
public void setUserId(UUID userId) {
|
public void setUserId(UUID userId) {
|
||||||
this.userId = userId;
|
this.userId = userId;
|
||||||
}
|
}
|
||||||
|
|
||||||
public UUID getTenant() {
|
|
||||||
return tenant;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setTenant(UUID tenant) {
|
|
||||||
this.tenant = tenant;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
package gr.cite.notification.integrationevent.inbox.userremoval;
|
package gr.cite.notification.integrationevent.inbox.userremoval;
|
||||||
|
|
||||||
|
|
||||||
import gr.cite.notification.integrationevent.inbox.IntegrationEventHandler;
|
import gr.cite.notification.integrationevent.inbox.IntegrationEventHandler;
|
||||||
|
|
||||||
public interface UserRemovalIntegrationEventHandler extends IntegrationEventHandler {
|
public interface UserRemovalIntegrationEventHandler extends IntegrationEventHandler {
|
||||||
|
|
|
@ -1,11 +1,12 @@
|
||||||
package gr.cite.notification.integrationevent.inbox.userremoval;
|
package gr.cite.notification.integrationevent.inbox.userremoval;
|
||||||
|
|
||||||
import gr.cite.commons.web.oidc.principal.CurrentPrincipalResolver;
|
import gr.cite.commons.web.oidc.principal.CurrentPrincipalResolver;
|
||||||
|
import gr.cite.commons.web.oidc.principal.extractor.ClaimExtractorProperties;
|
||||||
import gr.cite.notification.audit.AuditableAction;
|
import gr.cite.notification.audit.AuditableAction;
|
||||||
import gr.cite.notification.common.JsonHandlingService;
|
import gr.cite.notification.common.JsonHandlingService;
|
||||||
import gr.cite.notification.common.scope.fake.FakeRequestScope;
|
|
||||||
import gr.cite.notification.common.scope.tenant.TenantScope;
|
import gr.cite.notification.common.scope.tenant.TenantScope;
|
||||||
import gr.cite.notification.data.TenantEntity;
|
import gr.cite.notification.data.TenantEntity;
|
||||||
|
import gr.cite.notification.data.TenantEntityManager;
|
||||||
import gr.cite.notification.errorcode.ErrorThesaurusProperties;
|
import gr.cite.notification.errorcode.ErrorThesaurusProperties;
|
||||||
import gr.cite.notification.integrationevent.inbox.EventProcessingStatus;
|
import gr.cite.notification.integrationevent.inbox.EventProcessingStatus;
|
||||||
import gr.cite.notification.integrationevent.inbox.InboxPrincipal;
|
import gr.cite.notification.integrationevent.inbox.InboxPrincipal;
|
||||||
|
@ -18,13 +19,8 @@ import gr.cite.tools.data.query.QueryFactory;
|
||||||
import gr.cite.tools.exception.MyValidationException;
|
import gr.cite.tools.exception.MyValidationException;
|
||||||
import gr.cite.tools.fieldset.BaseFieldSet;
|
import gr.cite.tools.fieldset.BaseFieldSet;
|
||||||
import gr.cite.tools.logging.LoggerService;
|
import gr.cite.tools.logging.LoggerService;
|
||||||
import jakarta.persistence.EntityManager;
|
|
||||||
import jakarta.persistence.EntityManagerFactory;
|
|
||||||
import jakarta.persistence.EntityTransaction;
|
|
||||||
import jakarta.persistence.OptimisticLockException;
|
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
|
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
|
||||||
import org.springframework.context.ApplicationContext;
|
|
||||||
import org.springframework.context.MessageSource;
|
import org.springframework.context.MessageSource;
|
||||||
import org.springframework.context.annotation.Scope;
|
import org.springframework.context.annotation.Scope;
|
||||||
import org.springframework.context.i18n.LocaleContextHolder;
|
import org.springframework.context.i18n.LocaleContextHolder;
|
||||||
|
@ -41,22 +37,35 @@ public class UserRemovalIntegrationEventHandlerImpl implements UserRemovalIntegr
|
||||||
|
|
||||||
private final JsonHandlingService jsonHandlingService;
|
private final JsonHandlingService jsonHandlingService;
|
||||||
|
|
||||||
private final ApplicationContext applicationContext;
|
|
||||||
|
|
||||||
private final ErrorThesaurusProperties errors;
|
private final ErrorThesaurusProperties errors;
|
||||||
|
|
||||||
private final MessageSource messageSource;
|
private final MessageSource messageSource;
|
||||||
|
private final QueryFactory queryFactory;
|
||||||
|
private final TenantScope tenantScope;
|
||||||
|
private final CurrentPrincipalResolver currentPrincipalResolver;
|
||||||
|
private final ClaimExtractorProperties claimExtractorProperties;
|
||||||
|
private final UserRemovalConsistencyHandler userRemovalConsistencyHandler;
|
||||||
|
private final UserService userService;
|
||||||
|
private final AuditService auditService;
|
||||||
|
private final TenantEntityManager tenantEntityManager;
|
||||||
|
|
||||||
public UserRemovalIntegrationEventHandlerImpl(
|
public UserRemovalIntegrationEventHandlerImpl(
|
||||||
JsonHandlingService jsonHandlingService,
|
JsonHandlingService jsonHandlingService,
|
||||||
ApplicationContext applicationContext,
|
|
||||||
ErrorThesaurusProperties errors,
|
ErrorThesaurusProperties errors,
|
||||||
MessageSource messageSource
|
MessageSource messageSource, QueryFactory queryFactory, TenantScope tenantScope, CurrentPrincipalResolver currentPrincipalResolver, ClaimExtractorProperties claimExtractorProperties, UserRemovalConsistencyHandler userRemovalConsistencyHandler, UserService userService, AuditService auditService, TenantEntityManager tenantEntityManager
|
||||||
) {
|
) {
|
||||||
this.jsonHandlingService = jsonHandlingService;
|
this.jsonHandlingService = jsonHandlingService;
|
||||||
this.applicationContext = applicationContext;
|
|
||||||
this.errors = errors;
|
this.errors = errors;
|
||||||
this.messageSource = messageSource;
|
this.messageSource = messageSource;
|
||||||
|
this.queryFactory = queryFactory;
|
||||||
|
this.tenantScope = tenantScope;
|
||||||
|
this.currentPrincipalResolver = currentPrincipalResolver;
|
||||||
|
this.claimExtractorProperties = claimExtractorProperties;
|
||||||
|
this.userRemovalConsistencyHandler = userRemovalConsistencyHandler;
|
||||||
|
this.userService = userService;
|
||||||
|
this.auditService = auditService;
|
||||||
|
this.tenantEntityManager = tenantEntityManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -69,73 +78,44 @@ public class UserRemovalIntegrationEventHandlerImpl implements UserRemovalIntegr
|
||||||
|
|
||||||
logger.debug("Handling {}", UserRemovalIntegrationEvent.class.getSimpleName());
|
logger.debug("Handling {}", UserRemovalIntegrationEvent.class.getSimpleName());
|
||||||
|
|
||||||
EntityManager entityManager = null;
|
EventProcessingStatus status = EventProcessingStatus.Success;
|
||||||
EntityTransaction transaction = null;
|
|
||||||
try (FakeRequestScope ignored = new FakeRequestScope()) {
|
|
||||||
try {
|
try {
|
||||||
QueryFactory queryFactory = this.applicationContext.getBean(QueryFactory.class);
|
if (this.tenantScope.isMultitenant() && properties.getTenantId() != null) {
|
||||||
TenantScope scope = this.applicationContext.getBean(TenantScope.class);
|
TenantEntity tenant = queryFactory.query(TenantQuery.class).ids(properties.getTenantId()).firstAs(new BaseFieldSet().ensure(Tenant._id).ensure(Tenant._code));
|
||||||
if (scope.isMultitenant() && event.getTenant() != null) {
|
|
||||||
TenantEntity tenant = queryFactory.query(TenantQuery.class).ids(event.getTenant()).firstAs(new BaseFieldSet().ensure(Tenant._id).ensure(Tenant._code));
|
|
||||||
if (tenant == null) {
|
if (tenant == null) {
|
||||||
logger.error("missing tenant from event message");
|
logger.error("missing tenant from event message");
|
||||||
return EventProcessingStatus.Error;
|
return EventProcessingStatus.Error;
|
||||||
}
|
}
|
||||||
scope.setTenant(event.getTenant(), tenant.getCode());
|
this.tenantScope.setTempTenant(tenantEntityManager.getEntityManager(), properties.getTenantId(), tenant.getCode());
|
||||||
} else if (scope.isMultitenant()) {
|
} else if (this.tenantScope.isMultitenant()) {
|
||||||
logger.error("missing tenant from event message");
|
// logger.error("missing tenant from event message");
|
||||||
return EventProcessingStatus.Error;
|
// return EventProcessingStatus.Error;
|
||||||
|
this.tenantScope.setTempTenant(tenantEntityManager.getEntityManager(), null, this.tenantScope.getDefaultTenantCode());
|
||||||
}
|
}
|
||||||
|
|
||||||
CurrentPrincipalResolver currentPrincipalResolver = this.applicationContext.getBean(CurrentPrincipalResolver.class);
|
currentPrincipalResolver.push(InboxPrincipal.build(properties, claimExtractorProperties));
|
||||||
currentPrincipalResolver.push(InboxPrincipal.build(properties));
|
|
||||||
|
|
||||||
UserRemovalConsistencyHandler userRemovalConsistencyHandler = this.applicationContext.getBean(UserRemovalConsistencyHandler.class);
|
if (!(userRemovalConsistencyHandler.isConsistent(new UserRemovalConsistencyPredicates(event.getUserId())))) {
|
||||||
if (!(userRemovalConsistencyHandler.isConsistent(new UserRemovalConsistencyPredicates(event.getUserId()))))
|
status = EventProcessingStatus.Postponed;
|
||||||
return EventProcessingStatus.Postponed;
|
currentPrincipalResolver.pop();
|
||||||
|
tenantScope.removeTempTenant(this.tenantEntityManager.getEntityManager());
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
EntityManagerFactory entityManagerFactory = this.applicationContext.getBean(EntityManagerFactory.class);
|
|
||||||
entityManager = entityManagerFactory.createEntityManager();
|
|
||||||
|
|
||||||
transaction = entityManager.getTransaction();
|
|
||||||
transaction.begin();
|
|
||||||
|
|
||||||
try {
|
|
||||||
UserService userService = this.applicationContext.getBean(UserService.class);
|
|
||||||
userService.deleteAndSave(event.getUserId());
|
userService.deleteAndSave(event.getUserId());
|
||||||
|
|
||||||
AuditService auditService = this.applicationContext.getBean(AuditService.class);
|
|
||||||
|
|
||||||
auditService.track(AuditableAction.User_Delete, Map.ofEntries(
|
auditService.track(AuditableAction.User_Delete, Map.ofEntries(
|
||||||
new AbstractMap.SimpleEntry<String, Object>("id", event.getUserId())
|
new AbstractMap.SimpleEntry<String, Object>("id", event.getUserId())
|
||||||
));
|
));
|
||||||
//auditService.trackIdentity(AuditableAction.IdentityTracking_Action);
|
//auditService.trackIdentity(AuditableAction.IdentityTracking_Action);
|
||||||
|
} catch (Exception ex) {
|
||||||
transaction.commit();
|
status = EventProcessingStatus.Error;
|
||||||
} catch (Exception e) {
|
logger.error("Problem getting list of queue outbox. Skipping: {}", ex.getMessage(), ex);
|
||||||
transaction.rollback();
|
|
||||||
throw e;
|
|
||||||
} finally {
|
} finally {
|
||||||
currentPrincipalResolver.pop();
|
currentPrincipalResolver.pop();
|
||||||
|
tenantScope.removeTempTenant(this.tenantEntityManager.getEntityManager());
|
||||||
}
|
}
|
||||||
|
|
||||||
transaction.commit();
|
return status;
|
||||||
} catch (OptimisticLockException ex) {
|
|
||||||
// we get this if/when someone else already modified the notifications. We want to essentially ignore this, and keep working
|
|
||||||
logger.debug("Concurrency exception getting queue outbox. Skipping: {} ", ex.getMessage());
|
|
||||||
if (transaction != null)
|
|
||||||
transaction.rollback();
|
|
||||||
} catch (Exception ex) {
|
|
||||||
logger.error("Problem getting list of queue outbox. Skipping: {}", ex.getMessage(), ex);
|
|
||||||
if (transaction != null)
|
|
||||||
transaction.rollback();
|
|
||||||
} finally {
|
|
||||||
if (entityManager != null)
|
|
||||||
entityManager.close();
|
|
||||||
}
|
|
||||||
} catch (Exception ex) {
|
|
||||||
logger.error("Problem getting list of queue outbox. Skipping: {}", ex.getMessage(), ex);
|
|
||||||
}
|
|
||||||
return EventProcessingStatus.Success;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,7 @@ import gr.cite.notification.common.validation.BaseValidator;
|
||||||
import gr.cite.notification.convention.ConventionService;
|
import gr.cite.notification.convention.ConventionService;
|
||||||
import gr.cite.notification.errorcode.ErrorThesaurusProperties;
|
import gr.cite.notification.errorcode.ErrorThesaurusProperties;
|
||||||
import gr.cite.notification.integrationevent.TrackedEvent;
|
import gr.cite.notification.integrationevent.TrackedEvent;
|
||||||
import gr.cite.notification.model.persist.UserTouchedIntegrationEventPersist;
|
import gr.cite.tools.validation.ValidatorFactory;
|
||||||
import gr.cite.tools.validation.specification.Specification;
|
import gr.cite.tools.validation.specification.Specification;
|
||||||
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
|
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
|
||||||
import org.springframework.context.MessageSource;
|
import org.springframework.context.MessageSource;
|
||||||
|
@ -23,22 +23,24 @@ public class UserTouchedIntegrationEvent extends TrackedEvent {
|
||||||
|
|
||||||
public static final String _id = "id";
|
public static final String _id = "id";
|
||||||
|
|
||||||
private UUID tenant;
|
|
||||||
|
|
||||||
private String name;
|
private String name;
|
||||||
|
|
||||||
public static final String _name = "name";
|
public static final String _name = "name";
|
||||||
|
|
||||||
public static final int _nameLength = 200;
|
public static final int _nameLength = 200;
|
||||||
|
|
||||||
private String subjectId;
|
|
||||||
|
|
||||||
public static final String _subjectId = "subjectId";
|
|
||||||
|
|
||||||
private UserProfile profile;
|
private UserProfile profile;
|
||||||
|
|
||||||
private List<UserContactInfo> userContactInfo;
|
private List<UserContactInfo> userContactInfo;
|
||||||
|
|
||||||
|
public static final String _userContactInfo = "userContactInfo";
|
||||||
|
private List<TenantUser> tenantUsers;
|
||||||
|
|
||||||
|
public static final String _tenantUsers = "tenantUsers";
|
||||||
|
private List<UserCredential> credentials;
|
||||||
|
|
||||||
|
public static final String _credentials = "credentials";
|
||||||
|
|
||||||
public UUID getId() {
|
public UUID getId() {
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
@ -47,14 +49,6 @@ public class UserTouchedIntegrationEvent extends TrackedEvent {
|
||||||
this.id = id;
|
this.id = id;
|
||||||
}
|
}
|
||||||
|
|
||||||
public UUID getTenant() {
|
|
||||||
return tenant;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setTenant(UUID tenant) {
|
|
||||||
this.tenant = tenant;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getName() {
|
public String getName() {
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
@ -63,12 +57,20 @@ public class UserTouchedIntegrationEvent extends TrackedEvent {
|
||||||
this.name = name;
|
this.name = name;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getSubjectId() {
|
public List<TenantUser> getTenantUsers() {
|
||||||
return subjectId;
|
return tenantUsers;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setSubjectId(String subjectId) {
|
public void setTenantUsers(List<TenantUser> tenantUsers) {
|
||||||
this.subjectId = subjectId;
|
this.tenantUsers = tenantUsers;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<UserCredential> getCredentials() {
|
||||||
|
return credentials;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCredentials(List<UserCredential> credentials) {
|
||||||
|
this.credentials = credentials;
|
||||||
}
|
}
|
||||||
|
|
||||||
public UserProfile getProfile() {
|
public UserProfile getProfile() {
|
||||||
|
@ -124,9 +126,15 @@ public class UserTouchedIntegrationEvent extends TrackedEvent {
|
||||||
|
|
||||||
private ContactInfoType type;
|
private ContactInfoType type;
|
||||||
|
|
||||||
|
public static final String _type = "type";
|
||||||
|
|
||||||
private String value;
|
private String value;
|
||||||
|
|
||||||
private int ordinal;
|
public static final String _value = "value";
|
||||||
|
|
||||||
|
private Integer ordinal;
|
||||||
|
|
||||||
|
public static final String _ordinal = "ordinal";
|
||||||
|
|
||||||
public ContactInfoType getType() {
|
public ContactInfoType getType() {
|
||||||
return type;
|
return type;
|
||||||
|
@ -144,16 +152,135 @@ public class UserTouchedIntegrationEvent extends TrackedEvent {
|
||||||
this.value = value;
|
this.value = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getOrdinal() {
|
public Integer getOrdinal() {
|
||||||
return ordinal;
|
return ordinal;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setOrdinal(int ordinal) {
|
public void setOrdinal(Integer ordinal) {
|
||||||
this.ordinal = ordinal;
|
this.ordinal = ordinal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Component(UserTouchedIntegrationUserContactInfoEventValidator.ValidatorName)
|
||||||
|
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
|
||||||
|
public static class UserTouchedIntegrationUserContactInfoEventValidator extends BaseValidator<UserContactInfo> {
|
||||||
|
|
||||||
|
public static final String ValidatorName = "UserTouchedIntegrationUserContactInfoEventValidator";
|
||||||
|
|
||||||
|
private final MessageSource messageSource;
|
||||||
|
|
||||||
|
protected UserTouchedIntegrationUserContactInfoEventValidator(ConventionService conventionService, ErrorThesaurusProperties errors, MessageSource messageSource) {
|
||||||
|
super(conventionService, errors);
|
||||||
|
this.messageSource = messageSource;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Class<UserContactInfo> modelClass() {
|
||||||
|
return UserContactInfo.class;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected List<Specification> specifications(UserContactInfo item) {
|
||||||
|
return Arrays.asList(
|
||||||
|
this.spec()
|
||||||
|
.must(() -> !this.isEmpty(item.getValue()))
|
||||||
|
.failOn(UserContactInfo._value).failWith(messageSource.getMessage("Validation_Required", new Object[]{UserContactInfo._value}, LocaleContextHolder.getLocale())),
|
||||||
|
this.spec()
|
||||||
|
.must(() -> !this.isNull(item.getType()))
|
||||||
|
.failOn(UserContactInfo._type).failWith(messageSource.getMessage("Validation_Required", new Object[]{UserContactInfo._type}, LocaleContextHolder.getLocale())),
|
||||||
|
this.spec()
|
||||||
|
.must(() -> !this.isNull(item.getOrdinal()))
|
||||||
|
.failOn(UserContactInfo._ordinal).failWith(messageSource.getMessage("Validation_Required", new Object[]{UserContactInfo._ordinal}, LocaleContextHolder.getLocale()))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Component(UserTouchedIntegrationEvent.UserTouchedIntegrationEventValidator.ValidatorName)
|
public static class UserCredential {
|
||||||
|
|
||||||
|
private String subjectId;
|
||||||
|
|
||||||
|
public static final String _subjectId = "subjectId";
|
||||||
|
|
||||||
|
public String getSubjectId() {
|
||||||
|
return subjectId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSubjectId(String subjectId) {
|
||||||
|
this.subjectId = subjectId;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Component(UserTouchedIntegrationUserCredentialEventValidator.ValidatorName)
|
||||||
|
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
|
||||||
|
public static class UserTouchedIntegrationUserCredentialEventValidator extends BaseValidator<UserCredential> {
|
||||||
|
|
||||||
|
public static final String ValidatorName = "UserTouchedIntegrationUserCredentialEventValidator";
|
||||||
|
|
||||||
|
private final MessageSource messageSource;
|
||||||
|
|
||||||
|
protected UserTouchedIntegrationUserCredentialEventValidator(ConventionService conventionService, ErrorThesaurusProperties errors, MessageSource messageSource) {
|
||||||
|
super(conventionService, errors);
|
||||||
|
this.messageSource = messageSource;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Class<UserCredential> modelClass() {
|
||||||
|
return UserCredential.class;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected List<Specification> specifications(UserCredential item) {
|
||||||
|
return Arrays.asList(
|
||||||
|
this.spec()
|
||||||
|
.must(() -> !this.isEmpty(item.getSubjectId()))
|
||||||
|
.failOn(UserCredential._subjectId).failWith(messageSource.getMessage("Validation_Required", new Object[]{UserCredential._subjectId}, LocaleContextHolder.getLocale()))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class TenantUser {
|
||||||
|
|
||||||
|
private UUID tenant;
|
||||||
|
public static final String _tenant = "tenant";
|
||||||
|
|
||||||
|
public UUID getTenant() {
|
||||||
|
return tenant;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTenant(UUID tenant) {
|
||||||
|
this.tenant = tenant;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Component(UserTouchedIntegrationTenantUserEventValidator.ValidatorName)
|
||||||
|
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
|
||||||
|
public static class UserTouchedIntegrationTenantUserEventValidator extends BaseValidator<TenantUser> {
|
||||||
|
|
||||||
|
public static final String ValidatorName = "UserTouchedIntegrationTenantUserEventValidator";
|
||||||
|
|
||||||
|
private final MessageSource messageSource;
|
||||||
|
|
||||||
|
protected UserTouchedIntegrationTenantUserEventValidator(ConventionService conventionService, ErrorThesaurusProperties errors, MessageSource messageSource) {
|
||||||
|
super(conventionService, errors);
|
||||||
|
this.messageSource = messageSource;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Class<TenantUser> modelClass() {
|
||||||
|
return TenantUser.class;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected List<Specification> specifications(TenantUser item) {
|
||||||
|
return Arrays.asList(
|
||||||
|
this.spec()
|
||||||
|
.must(() -> !this.isNull(item.getTenant()))
|
||||||
|
.failOn(TenantUser._tenant).failWith(messageSource.getMessage("Validation_Required", new Object[]{TenantUser._tenant}, LocaleContextHolder.getLocale()))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Component(UserTouchedIntegrationEventValidator.ValidatorName)
|
||||||
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
|
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
|
||||||
public static class UserTouchedIntegrationEventValidator extends BaseValidator<UserTouchedIntegrationEvent> {
|
public static class UserTouchedIntegrationEventValidator extends BaseValidator<UserTouchedIntegrationEvent> {
|
||||||
|
|
||||||
|
@ -161,9 +288,12 @@ public class UserTouchedIntegrationEvent extends TrackedEvent {
|
||||||
|
|
||||||
private final MessageSource messageSource;
|
private final MessageSource messageSource;
|
||||||
|
|
||||||
protected UserTouchedIntegrationEventValidator(ConventionService conventionService, ErrorThesaurusProperties errors, MessageSource messageSource) {
|
private final ValidatorFactory validatorFactory;
|
||||||
|
|
||||||
|
protected UserTouchedIntegrationEventValidator(ConventionService conventionService, ErrorThesaurusProperties errors, MessageSource messageSource, ValidatorFactory validatorFactory) {
|
||||||
super(conventionService, errors);
|
super(conventionService, errors);
|
||||||
this.messageSource = messageSource;
|
this.messageSource = messageSource;
|
||||||
|
this.validatorFactory = validatorFactory;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -183,11 +313,13 @@ public class UserTouchedIntegrationEvent extends TrackedEvent {
|
||||||
.failOn(UserTouchedIntegrationEvent._name).failWith(messageSource.getMessage("Validation_Required", new Object[]{UserTouchedIntegrationEvent._name}, LocaleContextHolder.getLocale())),
|
.failOn(UserTouchedIntegrationEvent._name).failWith(messageSource.getMessage("Validation_Required", new Object[]{UserTouchedIntegrationEvent._name}, LocaleContextHolder.getLocale())),
|
||||||
this.spec()
|
this.spec()
|
||||||
.iff(() -> !this.isEmpty(item.getName()))
|
.iff(() -> !this.isEmpty(item.getName()))
|
||||||
.must(() -> this.lessEqualLength(item.getName(), UserTouchedIntegrationEventPersist._nameLength))
|
.must(() -> this.lessEqualLength(item.getName(), UserTouchedIntegrationEvent._nameLength))
|
||||||
.failOn(UserTouchedIntegrationEvent._name).failWith(messageSource.getMessage("Validation_MaxLength", new Object[]{UserTouchedIntegrationEvent._name}, LocaleContextHolder.getLocale())),
|
.failOn(UserTouchedIntegrationEvent._name).failWith(messageSource.getMessage("Validation_MaxLength", new Object[]{UserTouchedIntegrationEvent._name}, LocaleContextHolder.getLocale())),
|
||||||
this.spec()
|
this.navSpec()
|
||||||
.must(() -> !this.isEmpty(item.getSubjectId()))
|
.iff(() -> !this.isListNullOrEmpty(item.getUserContactInfo()))
|
||||||
.failOn(UserTouchedIntegrationEvent._subjectId).failWith(messageSource.getMessage("Validation_Required", new Object[]{UserTouchedIntegrationEvent._subjectId}, LocaleContextHolder.getLocale()))
|
.on(UserTouchedIntegrationEvent._userContactInfo)
|
||||||
|
.over(item.getUserContactInfo())
|
||||||
|
.using((i) -> this.validatorFactory.validator(UserContactInfo.UserTouchedIntegrationUserContactInfoEventValidator.class))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
package gr.cite.notification.integrationevent.inbox.usertouched;
|
package gr.cite.notification.integrationevent.inbox.usertouched;
|
||||||
|
|
||||||
|
|
||||||
import gr.cite.notification.integrationevent.inbox.IntegrationEventHandler;
|
import gr.cite.notification.integrationevent.inbox.IntegrationEventHandler;
|
||||||
|
|
||||||
public interface UserTouchedIntegrationEventHandler extends IntegrationEventHandler {
|
public interface UserTouchedIntegrationEventHandler extends IntegrationEventHandler {
|
||||||
|
|
|
@ -1,11 +1,12 @@
|
||||||
package gr.cite.notification.integrationevent.inbox.usertouched;
|
package gr.cite.notification.integrationevent.inbox.usertouched;
|
||||||
|
|
||||||
import gr.cite.commons.web.oidc.principal.CurrentPrincipalResolver;
|
import gr.cite.commons.web.oidc.principal.CurrentPrincipalResolver;
|
||||||
|
import gr.cite.commons.web.oidc.principal.extractor.ClaimExtractorProperties;
|
||||||
import gr.cite.notification.audit.AuditableAction;
|
import gr.cite.notification.audit.AuditableAction;
|
||||||
import gr.cite.notification.common.JsonHandlingService;
|
import gr.cite.notification.common.JsonHandlingService;
|
||||||
import gr.cite.notification.common.scope.fake.FakeRequestScope;
|
|
||||||
import gr.cite.notification.common.scope.tenant.TenantScope;
|
import gr.cite.notification.common.scope.tenant.TenantScope;
|
||||||
import gr.cite.notification.data.TenantEntity;
|
import gr.cite.notification.data.TenantEntity;
|
||||||
|
import gr.cite.notification.data.TenantEntityManager;
|
||||||
import gr.cite.notification.integrationevent.inbox.EventProcessingStatus;
|
import gr.cite.notification.integrationevent.inbox.EventProcessingStatus;
|
||||||
import gr.cite.notification.integrationevent.inbox.InboxPrincipal;
|
import gr.cite.notification.integrationevent.inbox.InboxPrincipal;
|
||||||
import gr.cite.notification.integrationevent.inbox.IntegrationEventProperties;
|
import gr.cite.notification.integrationevent.inbox.IntegrationEventProperties;
|
||||||
|
@ -17,13 +18,8 @@ import gr.cite.tools.data.query.QueryFactory;
|
||||||
import gr.cite.tools.fieldset.BaseFieldSet;
|
import gr.cite.tools.fieldset.BaseFieldSet;
|
||||||
import gr.cite.tools.logging.LoggerService;
|
import gr.cite.tools.logging.LoggerService;
|
||||||
import gr.cite.tools.validation.ValidatorFactory;
|
import gr.cite.tools.validation.ValidatorFactory;
|
||||||
import jakarta.persistence.EntityManager;
|
|
||||||
import jakarta.persistence.EntityManagerFactory;
|
|
||||||
import jakarta.persistence.EntityTransaction;
|
|
||||||
import jakarta.persistence.OptimisticLockException;
|
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
|
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
|
||||||
import org.springframework.context.ApplicationContext;
|
|
||||||
import org.springframework.context.annotation.Scope;
|
import org.springframework.context.annotation.Scope;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
@ -36,19 +32,30 @@ public class UserTouchedIntegrationEventHandlerImpl implements UserTouchedIntegr
|
||||||
|
|
||||||
private static final LoggerService logger = new LoggerService(LoggerFactory.getLogger(UserTouchedIntegrationEventHandlerImpl.class));
|
private static final LoggerService logger = new LoggerService(LoggerFactory.getLogger(UserTouchedIntegrationEventHandlerImpl.class));
|
||||||
|
|
||||||
protected final ApplicationContext applicationContext;
|
|
||||||
|
|
||||||
private final JsonHandlingService jsonHandlingService;
|
private final JsonHandlingService jsonHandlingService;
|
||||||
|
|
||||||
private final ValidatorFactory validatorFactory;
|
private final ValidatorFactory validatorFactory;
|
||||||
|
private final QueryFactory queryFactory;
|
||||||
|
private final TenantScope tenantScope;
|
||||||
|
private final CurrentPrincipalResolver currentPrincipalResolver;
|
||||||
|
private final ClaimExtractorProperties claimExtractorProperties;
|
||||||
|
private final UserService userService;
|
||||||
|
private final AuditService auditService;
|
||||||
|
private final TenantEntityManager tenantEntityManager;
|
||||||
|
|
||||||
public UserTouchedIntegrationEventHandlerImpl(
|
public UserTouchedIntegrationEventHandlerImpl(
|
||||||
JsonHandlingService jsonHandlingService,
|
JsonHandlingService jsonHandlingService,
|
||||||
ApplicationContext applicationContext,
|
ValidatorFactory validatorFactory, QueryFactory queryFactory, TenantScope tenantScope, CurrentPrincipalResolver currentPrincipalResolver, ClaimExtractorProperties claimExtractorProperties, UserService userService, AuditService auditService, TenantEntityManager tenantEntityManager) {
|
||||||
ValidatorFactory validatorFactory) {
|
|
||||||
this.jsonHandlingService = jsonHandlingService;
|
this.jsonHandlingService = jsonHandlingService;
|
||||||
this.applicationContext = applicationContext;
|
|
||||||
this.validatorFactory = validatorFactory;
|
this.validatorFactory = validatorFactory;
|
||||||
|
this.queryFactory = queryFactory;
|
||||||
|
this.tenantScope = tenantScope;
|
||||||
|
this.currentPrincipalResolver = currentPrincipalResolver;
|
||||||
|
this.claimExtractorProperties = claimExtractorProperties;
|
||||||
|
this.userService = userService;
|
||||||
|
this.auditService = auditService;
|
||||||
|
this.tenantEntityManager = tenantEntityManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -61,69 +68,37 @@ public class UserTouchedIntegrationEventHandlerImpl implements UserTouchedIntegr
|
||||||
|
|
||||||
this.validatorFactory.validator(UserTouchedIntegrationEvent.UserTouchedIntegrationEventValidator.class).validateForce(event);
|
this.validatorFactory.validator(UserTouchedIntegrationEvent.UserTouchedIntegrationEventValidator.class).validateForce(event);
|
||||||
|
|
||||||
EntityManager entityManager = null;
|
EventProcessingStatus status = EventProcessingStatus.Success;
|
||||||
EntityTransaction transaction = null;
|
|
||||||
try (FakeRequestScope ignored = new FakeRequestScope()) {
|
|
||||||
try {
|
try {
|
||||||
QueryFactory queryFactory = this.applicationContext.getBean(QueryFactory.class);
|
if (this.tenantScope.isMultitenant() && properties.getTenantId() != null) {
|
||||||
TenantScope scope = this.applicationContext.getBean(TenantScope.class);
|
TenantEntity tenant = queryFactory.query(TenantQuery.class).ids(properties.getTenantId()).firstAs(new BaseFieldSet().ensure(Tenant._id).ensure(Tenant._code));
|
||||||
if (scope.isMultitenant() && event.getTenant() != null) {
|
|
||||||
TenantEntity tenant = queryFactory.query(TenantQuery.class).ids(event.getTenant()).firstAs(new BaseFieldSet().ensure(Tenant._id).ensure(Tenant._code));
|
|
||||||
if (tenant == null) {
|
if (tenant == null) {
|
||||||
logger.error("missing tenant from event message");
|
logger.error("missing tenant from event message");
|
||||||
return EventProcessingStatus.Error;
|
return EventProcessingStatus.Error;
|
||||||
}
|
}
|
||||||
scope.setTenant(event.getTenant(), tenant.getCode());
|
this.tenantScope.setTempTenant(tenantEntityManager.getEntityManager(), properties.getTenantId(), tenant.getCode());
|
||||||
} else if (scope.isMultitenant()) {
|
} else if (this.tenantScope.isMultitenant()) {
|
||||||
logger.error("missing tenant from event message");
|
// logger.error("missing tenant from event message");
|
||||||
return EventProcessingStatus.Error;
|
// return EventProcessingStatus.Error;
|
||||||
|
this.tenantScope.setTempTenant(tenantEntityManager.getEntityManager(), null, this.tenantScope.getDefaultTenantCode());
|
||||||
}
|
}
|
||||||
//
|
|
||||||
// ValidationService validator = this.applicationContext.getBean(ValidationService.class);
|
|
||||||
// validator.validateForce(model);
|
|
||||||
|
|
||||||
CurrentPrincipalResolver currentPrincipalResolver = this.applicationContext.getBean(CurrentPrincipalResolver.class);
|
currentPrincipalResolver.push(InboxPrincipal.build(properties, claimExtractorProperties));
|
||||||
currentPrincipalResolver.push(InboxPrincipal.build(properties));
|
|
||||||
|
|
||||||
EntityManagerFactory entityManagerFactory = this.applicationContext.getBean(EntityManagerFactory.class);
|
|
||||||
entityManager = entityManagerFactory.createEntityManager();
|
|
||||||
|
|
||||||
transaction = entityManager.getTransaction();
|
|
||||||
transaction.begin();
|
|
||||||
|
|
||||||
try {
|
|
||||||
UserService userService = this.applicationContext.getBean(UserService.class);
|
|
||||||
userService.persist(event, null);
|
userService.persist(event, null);
|
||||||
|
|
||||||
AuditService auditService = this.applicationContext.getBean(AuditService.class);
|
|
||||||
|
|
||||||
auditService.track(AuditableAction.User_Persist, Map.ofEntries(
|
auditService.track(AuditableAction.User_Persist, Map.ofEntries(
|
||||||
new AbstractMap.SimpleEntry<String, Object>("model", event)
|
new AbstractMap.SimpleEntry<String, Object>("model", event)
|
||||||
));
|
));
|
||||||
|
|
||||||
transaction.commit();
|
} catch (Exception ex) {
|
||||||
} catch (Exception e) {
|
status = EventProcessingStatus.Error;
|
||||||
transaction.rollback();
|
logger.error("Problem getting list of queue outbox. Skipping: {}", ex.getMessage(), ex);
|
||||||
throw e;
|
|
||||||
} finally {
|
} finally {
|
||||||
currentPrincipalResolver.pop();
|
currentPrincipalResolver.pop();
|
||||||
|
tenantScope.removeTempTenant(this.tenantEntityManager.getEntityManager());
|
||||||
}
|
}
|
||||||
} catch (OptimisticLockException ex) {
|
|
||||||
// we get this if/when someone else already modified the notifications. We want to essentially ignore this, and keep working
|
return status;
|
||||||
logger.debug("Concurrency exception getting queue outbox. Skipping: {} ", ex.getMessage());
|
|
||||||
if (transaction != null)
|
|
||||||
transaction.rollback();
|
|
||||||
} catch (Exception ex) {
|
|
||||||
logger.error("Problem getting list of queue outbox. Skipping: {}", ex.getMessage(), ex);
|
|
||||||
if (transaction != null)
|
|
||||||
transaction.rollback();
|
|
||||||
} finally {
|
|
||||||
if (entityManager != null)
|
|
||||||
entityManager.close();
|
|
||||||
}
|
|
||||||
} catch (Exception ex) {
|
|
||||||
logger.error("Problem getting list of queue outbox. Skipping: {}", ex.getMessage(), ex);
|
|
||||||
}
|
|
||||||
return EventProcessingStatus.Success;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,52 +7,13 @@ public class OutboxProperties {
|
||||||
|
|
||||||
private final String exchange;
|
private final String exchange;
|
||||||
|
|
||||||
private final String tenantTouchTopic;
|
|
||||||
|
|
||||||
private final String tenantRemovalTopic;
|
public OutboxProperties(String exchange
|
||||||
|
|
||||||
private final String userTouchTopic;
|
|
||||||
|
|
||||||
private final String userRemovalTopic;
|
|
||||||
|
|
||||||
private final String notifyTopic;
|
|
||||||
|
|
||||||
public OutboxProperties(String exchange,
|
|
||||||
String tenantTouchTopic,
|
|
||||||
String tenantRemovalTopic,
|
|
||||||
String userTouchTopic,
|
|
||||||
String userRemovalTopic,
|
|
||||||
String notifyTopic
|
|
||||||
) {
|
) {
|
||||||
this.exchange = exchange;
|
this.exchange = exchange;
|
||||||
this.tenantTouchTopic = tenantTouchTopic;
|
|
||||||
this.tenantRemovalTopic = tenantRemovalTopic;
|
|
||||||
this.userTouchTopic = userTouchTopic;
|
|
||||||
this.userRemovalTopic = userRemovalTopic;
|
|
||||||
this.notifyTopic = notifyTopic;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getExchange() {
|
public String getExchange() {
|
||||||
return exchange;
|
return exchange;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getTenantTouchTopic() {
|
|
||||||
return tenantTouchTopic;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getTenantRemovalTopic() {
|
|
||||||
return tenantRemovalTopic;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getUserTouchTopic() {
|
|
||||||
return userTouchTopic;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getUserRemovalTopic() {
|
|
||||||
return userRemovalTopic;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getNotifyTopic() {
|
|
||||||
return notifyTopic;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,11 +20,9 @@ import jakarta.persistence.EntityTransaction;
|
||||||
import jakarta.persistence.OptimisticLockException;
|
import jakarta.persistence.OptimisticLockException;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.context.ApplicationContext;
|
import org.springframework.context.ApplicationContext;
|
||||||
import org.springframework.stereotype.Component;
|
|
||||||
|
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Random;
|
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
@ -32,9 +30,11 @@ import java.util.stream.Collectors;
|
||||||
public class OutboxRepositoryImpl implements OutboxRepository {
|
public class OutboxRepositoryImpl implements OutboxRepository {
|
||||||
|
|
||||||
protected final ApplicationContext applicationContext;
|
protected final ApplicationContext applicationContext;
|
||||||
private final Random random = new Random();
|
|
||||||
private static final LoggerService logger = new LoggerService(LoggerFactory.getLogger(OutboxRepositoryImpl.class));
|
private static final LoggerService logger = new LoggerService(LoggerFactory.getLogger(OutboxRepositoryImpl.class));
|
||||||
|
|
||||||
private final JsonHandlingService jsonHandlingService;
|
private final JsonHandlingService jsonHandlingService;
|
||||||
|
|
||||||
private final OutboxProperties outboxProperties;
|
private final OutboxProperties outboxProperties;
|
||||||
|
|
||||||
public OutboxRepositoryImpl(
|
public OutboxRepositoryImpl(
|
||||||
|
@ -88,14 +88,17 @@ public class OutboxRepositoryImpl implements OutboxRepository {
|
||||||
} catch (OptimisticLockException ex) {
|
} catch (OptimisticLockException ex) {
|
||||||
// we get this if/when someone else already modified the notifications. We want to essentially ignore this, and keep working
|
// we get this if/when someone else already modified the notifications. We want to essentially ignore this, and keep working
|
||||||
logger.debug("Concurrency exception getting queue outbox. Skipping: {} ", ex.getMessage());
|
logger.debug("Concurrency exception getting queue outbox. Skipping: {} ", ex.getMessage());
|
||||||
if (transaction != null) transaction.rollback();
|
if (transaction != null)
|
||||||
|
transaction.rollback();
|
||||||
candidate = null;
|
candidate = null;
|
||||||
} catch (Exception ex) {
|
} catch (Exception ex) {
|
||||||
logger.error("Problem getting list of queue outbox. Skipping: {}", ex.getMessage(), ex);
|
logger.error("Problem getting list of queue outbox. Skipping: {}", ex.getMessage(), ex);
|
||||||
if (transaction != null) transaction.rollback();
|
if (transaction != null)
|
||||||
|
transaction.rollback();
|
||||||
candidate = null;
|
candidate = null;
|
||||||
} finally {
|
} finally {
|
||||||
if (entityManager != null) entityManager.close();
|
if (entityManager != null)
|
||||||
|
entityManager.close();
|
||||||
}
|
}
|
||||||
} catch (Exception ex) {
|
} catch (Exception ex) {
|
||||||
logger.error("Problem getting list of queue outbox. Skipping: {}", ex.getMessage(), ex);
|
logger.error("Problem getting list of queue outbox. Skipping: {}", ex.getMessage(), ex);
|
||||||
|
@ -137,10 +140,12 @@ public class OutboxRepositoryImpl implements OutboxRepository {
|
||||||
transaction.commit();
|
transaction.commit();
|
||||||
} catch (Exception ex) {
|
} catch (Exception ex) {
|
||||||
logger.error("Problem executing purge. rolling back any db changes and marking error. Continuing...", ex);
|
logger.error("Problem executing purge. rolling back any db changes and marking error. Continuing...", ex);
|
||||||
if (transaction != null) transaction.rollback();
|
if (transaction != null)
|
||||||
|
transaction.rollback();
|
||||||
success = false;
|
success = false;
|
||||||
} finally {
|
} finally {
|
||||||
if (entityManager != null) entityManager.close();
|
if (entityManager != null)
|
||||||
|
entityManager.close();
|
||||||
}
|
}
|
||||||
} catch (Exception ex) {
|
} catch (Exception ex) {
|
||||||
logger.error("Problem executing purge. rolling back any db changes and marking error. Continuing...", ex);
|
logger.error("Problem executing purge. rolling back any db changes and marking error. Continuing...", ex);
|
||||||
|
@ -182,10 +187,12 @@ public class OutboxRepositoryImpl implements OutboxRepository {
|
||||||
transaction.commit();
|
transaction.commit();
|
||||||
} catch (Exception ex) {
|
} catch (Exception ex) {
|
||||||
logger.error("Problem executing purge. rolling back any db changes and marking error. Continuing...", ex);
|
logger.error("Problem executing purge. rolling back any db changes and marking error. Continuing...", ex);
|
||||||
if (transaction != null) transaction.rollback();
|
if (transaction != null)
|
||||||
|
transaction.rollback();
|
||||||
success = false;
|
success = false;
|
||||||
} finally {
|
} finally {
|
||||||
if (entityManager != null) entityManager.close();
|
if (entityManager != null)
|
||||||
|
entityManager.close();
|
||||||
}
|
}
|
||||||
} catch (Exception ex) {
|
} catch (Exception ex) {
|
||||||
logger.error("Problem executing purge. rolling back any db changes and marking error. Continuing...", ex);
|
logger.error("Problem executing purge. rolling back any db changes and marking error. Continuing...", ex);
|
||||||
|
@ -237,10 +244,12 @@ public class OutboxRepositoryImpl implements OutboxRepository {
|
||||||
transaction.commit();
|
transaction.commit();
|
||||||
} catch (Exception ex) {
|
} catch (Exception ex) {
|
||||||
logger.error("Problem executing purge. rolling back any db changes and marking error. Continuing...", ex);
|
logger.error("Problem executing purge. rolling back any db changes and marking error. Continuing...", ex);
|
||||||
if (transaction != null) transaction.rollback();
|
if (transaction != null)
|
||||||
|
transaction.rollback();
|
||||||
success = false;
|
success = false;
|
||||||
} finally {
|
} finally {
|
||||||
if (entityManager != null) entityManager.close();
|
if (entityManager != null)
|
||||||
|
entityManager.close();
|
||||||
}
|
}
|
||||||
} catch (Exception ex) {
|
} catch (Exception ex) {
|
||||||
logger.error("Problem executing purge. rolling back any db changes and marking error. Continuing...", ex);
|
logger.error("Problem executing purge. rolling back any db changes and marking error. Continuing...", ex);
|
||||||
|
@ -266,7 +275,7 @@ public class OutboxRepositoryImpl implements OutboxRepository {
|
||||||
List<QueueOutboxEntity> queueOutboxMessages = queryFactory.query(QueueOutboxQuery.class).ids(confirmedMessages).collect();
|
List<QueueOutboxEntity> queueOutboxMessages = queryFactory.query(QueueOutboxQuery.class).ids(confirmedMessages).collect();
|
||||||
|
|
||||||
if (queueOutboxMessages == null) {
|
if (queueOutboxMessages == null) {
|
||||||
logger.warn("Could not lookup messages {} to process. Continuing...", String.join(",", confirmedMessages.stream().map(x -> x.toString()).collect(Collectors.toList())));
|
logger.warn("Could not lookup messages {} to process. Continuing...", confirmedMessages.stream().map(UUID::toString).collect(Collectors.joining(",")));
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
for (QueueOutboxEntity queueOutboxMessage : queueOutboxMessages) {
|
for (QueueOutboxEntity queueOutboxMessage : queueOutboxMessages) {
|
||||||
|
@ -281,9 +290,11 @@ public class OutboxRepositoryImpl implements OutboxRepository {
|
||||||
transaction.commit();
|
transaction.commit();
|
||||||
} catch (Exception ex) {
|
} catch (Exception ex) {
|
||||||
logger.error("Problem executing purge. rolling back any db changes and marking error. Continuing...", ex);
|
logger.error("Problem executing purge. rolling back any db changes and marking error. Continuing...", ex);
|
||||||
if (transaction != null) transaction.rollback();
|
if (transaction != null)
|
||||||
|
transaction.rollback();
|
||||||
} finally {
|
} finally {
|
||||||
if (entityManager != null) entityManager.close();
|
if (entityManager != null)
|
||||||
|
entityManager.close();
|
||||||
}
|
}
|
||||||
} catch (Exception ex) {
|
} catch (Exception ex) {
|
||||||
logger.error("Problem executing purge. rolling back any db changes and marking error. Continuing...", ex);
|
logger.error("Problem executing purge. rolling back any db changes and marking error. Continuing...", ex);
|
||||||
|
@ -308,7 +319,7 @@ public class OutboxRepositoryImpl implements OutboxRepository {
|
||||||
List<QueueOutboxEntity> queueOutboxMessages = queryFactory.query(QueueOutboxQuery.class).ids(nackedMessages).collect();
|
List<QueueOutboxEntity> queueOutboxMessages = queryFactory.query(QueueOutboxQuery.class).ids(nackedMessages).collect();
|
||||||
|
|
||||||
if (queueOutboxMessages == null) {
|
if (queueOutboxMessages == null) {
|
||||||
logger.warn("Could not lookup messages {} to process. Continuing...", String.join(",", nackedMessages.stream().map(x -> x.toString()).collect(Collectors.toList())));
|
logger.warn("Could not lookup messages {} to process. Continuing...", nackedMessages.stream().map(UUID::toString).collect(Collectors.joining(",")));
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
for (QueueOutboxEntity queueOutboxMessage : queueOutboxMessages) {
|
for (QueueOutboxEntity queueOutboxMessage : queueOutboxMessages) {
|
||||||
|
@ -323,9 +334,11 @@ public class OutboxRepositoryImpl implements OutboxRepository {
|
||||||
transaction.commit();
|
transaction.commit();
|
||||||
} catch (Exception ex) {
|
} catch (Exception ex) {
|
||||||
logger.error("Problem executing purge. rolling back any db changes and marking error. Continuing...", ex);
|
logger.error("Problem executing purge. rolling back any db changes and marking error. Continuing...", ex);
|
||||||
if (transaction != null) transaction.rollback();
|
if (transaction != null)
|
||||||
|
transaction.rollback();
|
||||||
} finally {
|
} finally {
|
||||||
if (entityManager != null) entityManager.close();
|
if (entityManager != null)
|
||||||
|
entityManager.close();
|
||||||
}
|
}
|
||||||
} catch (Exception ex) {
|
} catch (Exception ex) {
|
||||||
logger.error("Problem executing purge. rolling back any db changes and marking error. Continuing...", ex);
|
logger.error("Problem executing purge. rolling back any db changes and marking error. Continuing...", ex);
|
||||||
|
@ -336,7 +349,6 @@ public class OutboxRepositoryImpl implements OutboxRepository {
|
||||||
public QueueOutbox create(IntegrationEvent item) {
|
public QueueOutbox create(IntegrationEvent item) {
|
||||||
EntityTransaction transaction = null;
|
EntityTransaction transaction = null;
|
||||||
EntityManager entityManager = null;
|
EntityManager entityManager = null;
|
||||||
boolean success = false;
|
|
||||||
QueueOutboxEntity queueMessage = null;
|
QueueOutboxEntity queueMessage = null;
|
||||||
try (FakeRequestScope ignored = new FakeRequestScope()) {
|
try (FakeRequestScope ignored = new FakeRequestScope()) {
|
||||||
try {
|
try {
|
||||||
|
@ -354,10 +366,11 @@ public class OutboxRepositoryImpl implements OutboxRepository {
|
||||||
transaction.commit();
|
transaction.commit();
|
||||||
} catch (Exception ex) {
|
} catch (Exception ex) {
|
||||||
logger.error("Problem executing purge. rolling back any db changes and marking error. Continuing...", ex);
|
logger.error("Problem executing purge. rolling back any db changes and marking error. Continuing...", ex);
|
||||||
if (transaction != null) transaction.rollback();
|
if (transaction != null)
|
||||||
success = false;
|
transaction.rollback();
|
||||||
} finally {
|
} finally {
|
||||||
if (entityManager != null) entityManager.close();
|
if (entityManager != null)
|
||||||
|
entityManager.close();
|
||||||
}
|
}
|
||||||
} catch (Exception ex) {
|
} catch (Exception ex) {
|
||||||
logger.error("Problem executing purge. rolling back any db changes and marking error. Continuing...", ex);
|
logger.error("Problem executing purge. rolling back any db changes and marking error. Continuing...", ex);
|
||||||
|
@ -375,13 +388,14 @@ public class OutboxRepositoryImpl implements OutboxRepository {
|
||||||
}
|
}
|
||||||
|
|
||||||
// UUID correlationId = UUID.randomUUID();
|
// UUID correlationId = UUID.randomUUID();
|
||||||
// if (event.getEvent() != null) event.getEvent().setTrackingContextTag(correlationId.toString());
|
// if (event.getEvent() != null)
|
||||||
|
// event.getEvent().setTrackingContextTag(correlationId.toString());
|
||||||
// event.setMessage(this.jsonHandlingService.toJsonSafe(event.getEvent()));
|
// event.setMessage(this.jsonHandlingService.toJsonSafe(event.getEvent()));
|
||||||
// //this._logTrackingService.Trace(correlationId.ToString(), $"Correlating current tracking context with new correlationId {correlationId}");
|
// //this._logTrackingService.Trace(correlationId.ToString(), $"Correlating current tracking context with new correlationId {correlationId}");
|
||||||
//
|
//
|
||||||
// QueueOutboxEntity queueMessage = new QueueOutboxEntity();
|
// QueueOutboxEntity queueMessage = new QueueOutboxEntity();
|
||||||
// queueMessage.setId(UUID.randomUUID());
|
// queueMessage.setId(UUID.randomUUID());
|
||||||
// queueMessage.setTenantId(null);
|
// queueMessage.setTenantId(event.getTenantId());
|
||||||
// queueMessage.setExchange(this.outboxProperties.getExchange());
|
// queueMessage.setExchange(this.outboxProperties.getExchange());
|
||||||
// queueMessage.setRoute(routingKey);
|
// queueMessage.setRoute(routingKey);
|
||||||
// queueMessage.setMessageId(event.getMessageId());
|
// queueMessage.setMessageId(event.getMessageId());
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
package gr.cite.notification.integrationevent.outbox;
|
||||||
|
|
||||||
|
public interface OutboxService {
|
||||||
|
void publish(OutboxIntegrationEvent event);
|
||||||
|
}
|
|
@ -0,0 +1,34 @@
|
||||||
|
package gr.cite.notification.integrationevent.outbox;
|
||||||
|
|
||||||
|
|
||||||
|
import gr.cite.tools.logging.LoggerService;
|
||||||
|
import gr.cite.tools.logging.MapLogEntry;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.context.ApplicationEventPublisher;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
import org.springframework.web.context.annotation.RequestScope;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
@RequestScope
|
||||||
|
public class OutboxServiceImpl implements OutboxService {
|
||||||
|
private static final LoggerService logger = new LoggerService(LoggerFactory.getLogger(OutboxServiceImpl.class));
|
||||||
|
|
||||||
|
private final ApplicationEventPublisher eventPublisher;
|
||||||
|
|
||||||
|
public OutboxServiceImpl(
|
||||||
|
ApplicationEventPublisher eventPublisher
|
||||||
|
) {
|
||||||
|
this.eventPublisher = eventPublisher;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void publish(OutboxIntegrationEvent event) {
|
||||||
|
try {
|
||||||
|
eventPublisher.publishEvent(event);
|
||||||
|
} catch (Exception ex) {
|
||||||
|
logger.error(new MapLogEntry(String.format("Could not save message ", event.getMessage())).And("message", event.getMessage()).And("ex", ex));
|
||||||
|
//Still want to skip it from processing
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,93 +0,0 @@
|
||||||
package gr.cite.notification.model;
|
|
||||||
|
|
||||||
import gr.cite.notification.common.enums.IsActive;
|
|
||||||
|
|
||||||
import java.time.Instant;
|
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
public class Language {
|
|
||||||
|
|
||||||
private UUID id;
|
|
||||||
|
|
||||||
public static final String _id = "id";
|
|
||||||
|
|
||||||
private String code;
|
|
||||||
|
|
||||||
public static final String _code = "code";
|
|
||||||
|
|
||||||
private Integer ordinal;
|
|
||||||
|
|
||||||
public static final String _ordinal = "ordinal";
|
|
||||||
|
|
||||||
private Instant createdAt;
|
|
||||||
|
|
||||||
public static final String _createdAt = "createdAt";
|
|
||||||
|
|
||||||
private Instant updatedAt;
|
|
||||||
|
|
||||||
public static final String _updatedAt = "updatedAt";
|
|
||||||
|
|
||||||
private IsActive isActive;
|
|
||||||
|
|
||||||
public static final String _isActive = "isActive";
|
|
||||||
|
|
||||||
private String hash;
|
|
||||||
|
|
||||||
public static final String _hash = "hash";
|
|
||||||
|
|
||||||
public UUID getId() {
|
|
||||||
return id;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setId(UUID id) {
|
|
||||||
this.id = id;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getCode() {
|
|
||||||
return code;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setCode(String code) {
|
|
||||||
this.code = code;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Integer getOrdinal() {
|
|
||||||
return ordinal;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setOrdinal(Integer ordinal) {
|
|
||||||
this.ordinal = ordinal;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Instant getCreatedAt() {
|
|
||||||
return createdAt;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setCreatedAt(Instant createdAt) {
|
|
||||||
this.createdAt = createdAt;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Instant getUpdatedAt() {
|
|
||||||
return updatedAt;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setUpdatedAt(Instant updatedAt) {
|
|
||||||
this.updatedAt = updatedAt;
|
|
||||||
}
|
|
||||||
|
|
||||||
public IsActive getIsActive() {
|
|
||||||
return isActive;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setIsActive(IsActive isActive) {
|
|
||||||
this.isActive = isActive;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getHash() {
|
|
||||||
return hash;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setHash(String hash) {
|
|
||||||
this.hash = hash;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -23,8 +23,8 @@ public class NotificationTemplate {
|
||||||
private NotificationTemplateKind kind;
|
private NotificationTemplateKind kind;
|
||||||
public static final String _kind = "kind";
|
public static final String _kind = "kind";
|
||||||
|
|
||||||
private Language language;
|
private String languageCode;
|
||||||
public static final String _language = "language";
|
public static final String _languageCode = "languageCode";
|
||||||
|
|
||||||
private NotificationTemplateValue value;
|
private NotificationTemplateValue value;
|
||||||
public static final String _value = "value";
|
public static final String _value = "value";
|
||||||
|
@ -76,12 +76,12 @@ public class NotificationTemplate {
|
||||||
this.kind = kind;
|
this.kind = kind;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Language getLanguage() {
|
public String getLanguageCode() {
|
||||||
return language;
|
return languageCode;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setLanguage(Language language) {
|
public void setLanguageCode(String languageCode) {
|
||||||
this.language = language;
|
this.languageCode = languageCode;
|
||||||
}
|
}
|
||||||
|
|
||||||
public NotificationTemplateValue getValue() {
|
public NotificationTemplateValue getValue() {
|
||||||
|
|
|
@ -0,0 +1,98 @@
|
||||||
|
package gr.cite.notification.model;
|
||||||
|
|
||||||
|
|
||||||
|
import gr.cite.notification.common.enums.IsActive;
|
||||||
|
|
||||||
|
import java.time.Instant;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
public class TenantUser {
|
||||||
|
|
||||||
|
private UUID id;
|
||||||
|
public final static String _id = "id";
|
||||||
|
|
||||||
|
private User user;
|
||||||
|
public final static String _user = "user";
|
||||||
|
|
||||||
|
private Tenant tenant;
|
||||||
|
public final static String _tenant = "tenant";
|
||||||
|
|
||||||
|
private IsActive isActive;
|
||||||
|
public final static String _isActive = "isActive";
|
||||||
|
|
||||||
|
private Instant createdAt;
|
||||||
|
public final static String _createdAt = "createdAt";
|
||||||
|
|
||||||
|
private Instant updatedAt;
|
||||||
|
public final static String _updatedAt = "updatedAt";
|
||||||
|
|
||||||
|
private String hash;
|
||||||
|
public final static String _hash = "hash";
|
||||||
|
|
||||||
|
private Boolean belongsToCurrentTenant;
|
||||||
|
public static final String _belongsToCurrentTenant = "belongsToCurrentTenant";
|
||||||
|
|
||||||
|
public UUID getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setId(UUID id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public User getUser() {
|
||||||
|
return user;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUser(User user) {
|
||||||
|
this.user = user;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Tenant getTenant() {
|
||||||
|
return tenant;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTenant(Tenant tenant) {
|
||||||
|
this.tenant = tenant;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IsActive getIsActive() {
|
||||||
|
return isActive;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setIsActive(IsActive isActive) {
|
||||||
|
this.isActive = isActive;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Instant getCreatedAt() {
|
||||||
|
return createdAt;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCreatedAt(Instant createdAt) {
|
||||||
|
this.createdAt = createdAt;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Instant getUpdatedAt() {
|
||||||
|
return updatedAt;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUpdatedAt(Instant updatedAt) {
|
||||||
|
this.updatedAt = updatedAt;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getHash() {
|
||||||
|
return hash;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setHash(String hash) {
|
||||||
|
this.hash = hash;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Boolean getBelongsToCurrentTenant() {
|
||||||
|
return belongsToCurrentTenant;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setBelongsToCurrentTenant(Boolean belongsToCurrentTenant) {
|
||||||
|
this.belongsToCurrentTenant = belongsToCurrentTenant;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,65 +0,0 @@
|
||||||
package gr.cite.notification.model.builder;
|
|
||||||
|
|
||||||
import gr.cite.notification.authorization.AuthorizationFlags;
|
|
||||||
import gr.cite.notification.convention.ConventionService;
|
|
||||||
import gr.cite.notification.data.LanguageEntity;
|
|
||||||
import gr.cite.notification.model.Language;
|
|
||||||
import gr.cite.tools.exception.MyApplicationException;
|
|
||||||
import gr.cite.tools.fieldset.FieldSet;
|
|
||||||
import gr.cite.tools.logging.DataLogEntry;
|
|
||||||
import gr.cite.tools.logging.LoggerService;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
|
||||||
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
|
|
||||||
import org.springframework.context.annotation.Scope;
|
|
||||||
import org.springframework.stereotype.Component;
|
|
||||||
|
|
||||||
import java.util.*;
|
|
||||||
|
|
||||||
@Component
|
|
||||||
@Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE)
|
|
||||||
public class LanguageBuilder extends BaseBuilder<Language, LanguageEntity> {
|
|
||||||
|
|
||||||
private EnumSet<AuthorizationFlags> authorize = EnumSet.of(AuthorizationFlags.None);
|
|
||||||
|
|
||||||
@Autowired
|
|
||||||
public LanguageBuilder(
|
|
||||||
ConventionService conventionService) {
|
|
||||||
super(conventionService, new LoggerService(LoggerFactory.getLogger(LanguageBuilder.class)));
|
|
||||||
}
|
|
||||||
|
|
||||||
public LanguageBuilder authorize(EnumSet<AuthorizationFlags> values) {
|
|
||||||
this.authorize = values;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<Language> build(FieldSet fields, List<LanguageEntity> data) throws MyApplicationException {
|
|
||||||
this.logger.debug("building for {} items requesting {} fields", Optional.ofNullable(data).map(List::size).orElse(0), Optional.ofNullable(fields).map(FieldSet::getFields).map(Set::size).orElse(0));
|
|
||||||
this.logger.trace(new DataLogEntry("requested fields", fields));
|
|
||||||
if (fields == null || data == null || fields.isEmpty())
|
|
||||||
return new ArrayList<>();
|
|
||||||
|
|
||||||
List<Language> models = new ArrayList<>();
|
|
||||||
for (LanguageEntity d : data) {
|
|
||||||
Language m = new Language();
|
|
||||||
if (fields.hasField(this.asIndexer(Language._id)))
|
|
||||||
m.setId(d.getId());
|
|
||||||
if (fields.hasField(this.asIndexer(Language._code)))
|
|
||||||
m.setCode(d.getCode());
|
|
||||||
if (fields.hasField(this.asIndexer(Language._ordinal)))
|
|
||||||
m.setOrdinal(d.getOrdinal());
|
|
||||||
if (fields.hasField(this.asIndexer(Language._createdAt)))
|
|
||||||
m.setCreatedAt(d.getCreatedAt());
|
|
||||||
if (fields.hasField(this.asIndexer(Language._updatedAt)))
|
|
||||||
m.setUpdatedAt(d.getUpdatedAt());
|
|
||||||
if (fields.hasField(this.asIndexer(Language._isActive)))
|
|
||||||
m.setIsActive(d.getIsActive());
|
|
||||||
if (fields.hasField(this.asIndexer(Language._hash)))
|
|
||||||
m.setHash(this.hashValue(d.getUpdatedAt()));
|
|
||||||
models.add(m);
|
|
||||||
}
|
|
||||||
this.logger.debug("build {} items", Optional.of(models).map(List::size).orElse(0));
|
|
||||||
return models;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -5,12 +5,9 @@ import gr.cite.notification.common.JsonHandlingService;
|
||||||
import gr.cite.notification.common.types.notificationtemplate.NotificationTemplateValueEntity;
|
import gr.cite.notification.common.types.notificationtemplate.NotificationTemplateValueEntity;
|
||||||
import gr.cite.notification.convention.ConventionService;
|
import gr.cite.notification.convention.ConventionService;
|
||||||
import gr.cite.notification.data.NotificationTemplateEntity;
|
import gr.cite.notification.data.NotificationTemplateEntity;
|
||||||
import gr.cite.notification.model.Language;
|
|
||||||
import gr.cite.notification.model.NotificationTemplate;
|
import gr.cite.notification.model.NotificationTemplate;
|
||||||
import gr.cite.notification.model.Tenant;
|
import gr.cite.notification.model.Tenant;
|
||||||
import gr.cite.notification.model.builder.notificationtemplate.NotificationTemplateValueBuilder;
|
import gr.cite.notification.model.builder.notificationtemplate.NotificationTemplateValueBuilder;
|
||||||
import gr.cite.notification.model.notificationtemplate.NotificationTemplateValue;
|
|
||||||
import gr.cite.notification.query.LanguageQuery;
|
|
||||||
import gr.cite.notification.query.TenantQuery;
|
import gr.cite.notification.query.TenantQuery;
|
||||||
import gr.cite.tools.data.builder.BuilderFactory;
|
import gr.cite.tools.data.builder.BuilderFactory;
|
||||||
import gr.cite.tools.data.query.QueryFactory;
|
import gr.cite.tools.data.query.QueryFactory;
|
||||||
|
@ -59,9 +56,6 @@ public class NotificationTemplateBuilder extends BaseBuilder<NotificationTemplat
|
||||||
FieldSet tenantFields = fields.extractPrefixed(this.asPrefix(NotificationTemplate._tenant));
|
FieldSet tenantFields = fields.extractPrefixed(this.asPrefix(NotificationTemplate._tenant));
|
||||||
Map<UUID, Tenant> tenantMap = this.collectTenants(tenantFields, data);
|
Map<UUID, Tenant> tenantMap = this.collectTenants(tenantFields, data);
|
||||||
|
|
||||||
FieldSet languageFields = fields.extractPrefixed(this.asPrefix(NotificationTemplate._language));
|
|
||||||
Map<UUID, Language> languageMap = this.collectLanguages(languageFields, data);
|
|
||||||
|
|
||||||
List<NotificationTemplate> models = new ArrayList<>();
|
List<NotificationTemplate> models = new ArrayList<>();
|
||||||
for(NotificationTemplateEntity d : data){
|
for(NotificationTemplateEntity d : data){
|
||||||
NotificationTemplate m = new NotificationTemplate();
|
NotificationTemplate m = new NotificationTemplate();
|
||||||
|
@ -69,7 +63,7 @@ public class NotificationTemplateBuilder extends BaseBuilder<NotificationTemplat
|
||||||
if(fields.hasField(this.asIndexer(NotificationTemplate._channel))) m.setChannel(d.getChannel());
|
if(fields.hasField(this.asIndexer(NotificationTemplate._channel))) m.setChannel(d.getChannel());
|
||||||
if(fields.hasField(this.asIndexer(NotificationTemplate._notificationType))) m.setNotificationType(d.getNotificationType());
|
if(fields.hasField(this.asIndexer(NotificationTemplate._notificationType))) m.setNotificationType(d.getNotificationType());
|
||||||
if(fields.hasField(this.asIndexer(NotificationTemplate._kind))) m.setKind(d.getKind());
|
if(fields.hasField(this.asIndexer(NotificationTemplate._kind))) m.setKind(d.getKind());
|
||||||
if (!languageFields.isEmpty() && languageMap != null && languageMap.containsKey(d.getLanguageId())) m.setLanguage(languageMap.get(d.getLanguageId()));
|
if(fields.hasField(this.asIndexer(NotificationTemplate._languageCode))) m.setLanguageCode(d.getLanguageCode());
|
||||||
if (!valueFields.isEmpty() && d.getValue() != null){
|
if (!valueFields.isEmpty() && d.getValue() != null){
|
||||||
NotificationTemplateValueEntity value = this.jsonHandlingService.fromJsonSafe(NotificationTemplateValueEntity.class, d.getValue());
|
NotificationTemplateValueEntity value = this.jsonHandlingService.fromJsonSafe(NotificationTemplateValueEntity.class, d.getValue());
|
||||||
m.setValue(this.builderFactory.builder(NotificationTemplateValueBuilder.class).authorize(this.authorize).build(valueFields, value));
|
m.setValue(this.builderFactory.builder(NotificationTemplateValueBuilder.class).authorize(this.authorize).build(valueFields, value));
|
||||||
|
@ -85,35 +79,6 @@ public class NotificationTemplateBuilder extends BaseBuilder<NotificationTemplat
|
||||||
return models;
|
return models;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Map<UUID, Language> collectLanguages(FieldSet fields, List<NotificationTemplateEntity> datas) throws MyApplicationException {
|
|
||||||
if (fields.isEmpty() || datas.isEmpty()) return null;
|
|
||||||
this.logger.debug("checking related - {}", NotificationTemplate.class.getSimpleName());
|
|
||||||
|
|
||||||
Map<UUID, Language> itemMap = null;
|
|
||||||
if (!fields.hasOtherField(this.asIndexer(Language._id))) {
|
|
||||||
itemMap = this.asEmpty(
|
|
||||||
datas.stream().map(x -> x.getLanguageId()).distinct().collect(Collectors.toList()),
|
|
||||||
x -> {
|
|
||||||
Language item = new Language();
|
|
||||||
item.setId(x);
|
|
||||||
return item;
|
|
||||||
},
|
|
||||||
x -> x.getId());
|
|
||||||
} else {
|
|
||||||
FieldSet clone = new BaseFieldSet(fields.getFields()).ensure(Language._id);
|
|
||||||
LanguageQuery q = this.queryFactory.query(LanguageQuery.class).authorize(this.authorize).ids(datas.stream().map(x -> x.getLanguageId()).distinct().collect(Collectors.toList()));
|
|
||||||
itemMap = this.builderFactory.builder(LanguageBuilder.class).authorize(this.authorize).asForeignKey(q, clone, x -> x.getId());
|
|
||||||
}
|
|
||||||
if (!fields.hasField(Tenant._id)) {
|
|
||||||
itemMap.values().stream().filter(x -> x != null).map(x -> {
|
|
||||||
x.setId(null);
|
|
||||||
return x;
|
|
||||||
}).collect(Collectors.toList());
|
|
||||||
}
|
|
||||||
|
|
||||||
return itemMap;
|
|
||||||
}
|
|
||||||
|
|
||||||
private Map<UUID, Tenant> collectTenants(FieldSet fields, List<NotificationTemplateEntity> datas) throws MyApplicationException {
|
private Map<UUID, Tenant> collectTenants(FieldSet fields, List<NotificationTemplateEntity> datas) throws MyApplicationException {
|
||||||
if (fields.isEmpty() || datas.isEmpty()) return null;
|
if (fields.isEmpty() || datas.isEmpty()) return null;
|
||||||
this.logger.debug("checking related - {}", NotificationTemplate.class.getSimpleName());
|
this.logger.debug("checking related - {}", NotificationTemplate.class.getSimpleName());
|
||||||
|
|
|
@ -2,7 +2,7 @@ package gr.cite.notification.model.deleter;
|
||||||
|
|
||||||
import gr.cite.notification.common.enums.IsActive;
|
import gr.cite.notification.common.enums.IsActive;
|
||||||
import gr.cite.notification.data.InAppNotificationEntity;
|
import gr.cite.notification.data.InAppNotificationEntity;
|
||||||
import gr.cite.notification.data.TenantScopedEntityManager;
|
import gr.cite.notification.data.TenantEntityManager;
|
||||||
import gr.cite.notification.query.InAppNotificationQuery;
|
import gr.cite.notification.query.InAppNotificationQuery;
|
||||||
import gr.cite.tools.data.deleter.Deleter;
|
import gr.cite.tools.data.deleter.Deleter;
|
||||||
import gr.cite.tools.data.deleter.DeleterFactory;
|
import gr.cite.tools.data.deleter.DeleterFactory;
|
||||||
|
@ -27,19 +27,16 @@ import java.util.stream.Collectors;
|
||||||
public class InAppNotificationDeleter implements Deleter {
|
public class InAppNotificationDeleter implements Deleter {
|
||||||
private static final LoggerService logger = new LoggerService(LoggerFactory.getLogger(InAppNotificationDeleter.class));
|
private static final LoggerService logger = new LoggerService(LoggerFactory.getLogger(InAppNotificationDeleter.class));
|
||||||
|
|
||||||
private final TenantScopedEntityManager entityManager;
|
private final TenantEntityManager entityManager;
|
||||||
protected final QueryFactory queryFactory;
|
protected final QueryFactory queryFactory;
|
||||||
private final DeleterFactory deleterFactory;
|
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
public InAppNotificationDeleter(
|
public InAppNotificationDeleter(
|
||||||
TenantScopedEntityManager entityManager,
|
TenantEntityManager entityManager,
|
||||||
QueryFactory queryFactory,
|
QueryFactory queryFactory
|
||||||
DeleterFactory deleterFactory
|
|
||||||
) {
|
) {
|
||||||
this.entityManager = entityManager;
|
this.entityManager = entityManager;
|
||||||
this.queryFactory = queryFactory;
|
this.queryFactory = queryFactory;
|
||||||
this.deleterFactory = deleterFactory;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void deleteAndSaveByIds(List<UUID> ids) throws InvalidApplicationException {
|
public void deleteAndSaveByIds(List<UUID> ids) throws InvalidApplicationException {
|
||||||
|
|
|
@ -2,7 +2,7 @@ package gr.cite.notification.model.deleter;
|
||||||
|
|
||||||
import gr.cite.notification.common.enums.IsActive;
|
import gr.cite.notification.common.enums.IsActive;
|
||||||
import gr.cite.notification.data.NotificationEntity;
|
import gr.cite.notification.data.NotificationEntity;
|
||||||
import gr.cite.notification.data.TenantScopedEntityManager;
|
import gr.cite.notification.data.TenantEntityManager;
|
||||||
import gr.cite.notification.query.NotificationQuery;
|
import gr.cite.notification.query.NotificationQuery;
|
||||||
import gr.cite.tools.data.deleter.Deleter;
|
import gr.cite.tools.data.deleter.Deleter;
|
||||||
import gr.cite.tools.data.deleter.DeleterFactory;
|
import gr.cite.tools.data.deleter.DeleterFactory;
|
||||||
|
@ -27,13 +27,13 @@ import java.util.stream.Collectors;
|
||||||
public class NotificationDeleter implements Deleter {
|
public class NotificationDeleter implements Deleter {
|
||||||
private static final LoggerService logger = new LoggerService(LoggerFactory.getLogger(NotificationDeleter.class));
|
private static final LoggerService logger = new LoggerService(LoggerFactory.getLogger(NotificationDeleter.class));
|
||||||
|
|
||||||
private final TenantScopedEntityManager entityManager;
|
private final TenantEntityManager entityManager;
|
||||||
protected final QueryFactory queryFactory;
|
protected final QueryFactory queryFactory;
|
||||||
private final DeleterFactory deleterFactory;
|
private final DeleterFactory deleterFactory;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
public NotificationDeleter(
|
public NotificationDeleter(
|
||||||
TenantScopedEntityManager entityManager,
|
TenantEntityManager entityManager,
|
||||||
QueryFactory queryFactory,
|
QueryFactory queryFactory,
|
||||||
DeleterFactory deleterFactory
|
DeleterFactory deleterFactory
|
||||||
) {
|
) {
|
||||||
|
|
|
@ -2,7 +2,7 @@ package gr.cite.notification.model.deleter;
|
||||||
|
|
||||||
import gr.cite.notification.common.enums.IsActive;
|
import gr.cite.notification.common.enums.IsActive;
|
||||||
import gr.cite.notification.data.NotificationTemplateEntity;
|
import gr.cite.notification.data.NotificationTemplateEntity;
|
||||||
import gr.cite.notification.data.TenantScopedEntityManager;
|
import gr.cite.notification.data.TenantEntityManager;
|
||||||
import gr.cite.notification.query.NotificationTemplateQuery;
|
import gr.cite.notification.query.NotificationTemplateQuery;
|
||||||
import gr.cite.tools.data.deleter.Deleter;
|
import gr.cite.tools.data.deleter.Deleter;
|
||||||
import gr.cite.tools.data.deleter.DeleterFactory;
|
import gr.cite.tools.data.deleter.DeleterFactory;
|
||||||
|
@ -27,13 +27,13 @@ import java.util.stream.Collectors;
|
||||||
public class NotificationTemplateDeleter implements Deleter {
|
public class NotificationTemplateDeleter implements Deleter {
|
||||||
private static final LoggerService logger = new LoggerService(LoggerFactory.getLogger(NotificationTemplateDeleter.class));
|
private static final LoggerService logger = new LoggerService(LoggerFactory.getLogger(NotificationTemplateDeleter.class));
|
||||||
|
|
||||||
private final TenantScopedEntityManager entityManager;
|
private final TenantEntityManager entityManager;
|
||||||
protected final QueryFactory queryFactory;
|
protected final QueryFactory queryFactory;
|
||||||
private final DeleterFactory deleterFactory;
|
private final DeleterFactory deleterFactory;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
public NotificationTemplateDeleter(
|
public NotificationTemplateDeleter(
|
||||||
TenantScopedEntityManager entityManager,
|
TenantEntityManager entityManager,
|
||||||
QueryFactory queryFactory,
|
QueryFactory queryFactory,
|
||||||
DeleterFactory deleterFactory
|
DeleterFactory deleterFactory
|
||||||
) {
|
) {
|
||||||
|
|
|
@ -2,7 +2,7 @@ package gr.cite.notification.model.deleter;
|
||||||
|
|
||||||
import gr.cite.notification.common.enums.IsActive;
|
import gr.cite.notification.common.enums.IsActive;
|
||||||
import gr.cite.notification.data.TenantConfigurationEntity;
|
import gr.cite.notification.data.TenantConfigurationEntity;
|
||||||
import gr.cite.notification.data.TenantScopedEntityManager;
|
import gr.cite.notification.data.TenantEntityManager;
|
||||||
import gr.cite.notification.query.TenantConfigurationQuery;
|
import gr.cite.notification.query.TenantConfigurationQuery;
|
||||||
import gr.cite.tools.data.deleter.Deleter;
|
import gr.cite.tools.data.deleter.Deleter;
|
||||||
import gr.cite.tools.data.deleter.DeleterFactory;
|
import gr.cite.tools.data.deleter.DeleterFactory;
|
||||||
|
@ -27,13 +27,13 @@ import java.util.stream.Collectors;
|
||||||
public class TenantConfigurationDeleter implements Deleter {
|
public class TenantConfigurationDeleter implements Deleter {
|
||||||
private static final LoggerService logger = new LoggerService(LoggerFactory.getLogger(TenantConfigurationDeleter.class));
|
private static final LoggerService logger = new LoggerService(LoggerFactory.getLogger(TenantConfigurationDeleter.class));
|
||||||
|
|
||||||
private final TenantScopedEntityManager entityManager;
|
private final TenantEntityManager entityManager;
|
||||||
protected final QueryFactory queryFactory;
|
protected final QueryFactory queryFactory;
|
||||||
private final DeleterFactory deleterFactory;
|
private final DeleterFactory deleterFactory;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
public TenantConfigurationDeleter(
|
public TenantConfigurationDeleter(
|
||||||
TenantScopedEntityManager entityManager,
|
TenantEntityManager entityManager,
|
||||||
QueryFactory queryFactory,
|
QueryFactory queryFactory,
|
||||||
DeleterFactory deleterFactory
|
DeleterFactory deleterFactory
|
||||||
) {
|
) {
|
||||||
|
|
|
@ -2,7 +2,7 @@ package gr.cite.notification.model.deleter;
|
||||||
|
|
||||||
import gr.cite.notification.common.enums.IsActive;
|
import gr.cite.notification.common.enums.IsActive;
|
||||||
import gr.cite.notification.data.TenantEntity;
|
import gr.cite.notification.data.TenantEntity;
|
||||||
import gr.cite.notification.data.TenantScopedEntityManager;
|
import gr.cite.notification.data.TenantEntityManager;
|
||||||
import gr.cite.notification.query.TenantQuery;
|
import gr.cite.notification.query.TenantQuery;
|
||||||
import gr.cite.tools.data.deleter.Deleter;
|
import gr.cite.tools.data.deleter.Deleter;
|
||||||
import gr.cite.tools.data.deleter.DeleterFactory;
|
import gr.cite.tools.data.deleter.DeleterFactory;
|
||||||
|
@ -26,13 +26,13 @@ import java.util.UUID;
|
||||||
public class TenantDeleter implements Deleter {
|
public class TenantDeleter implements Deleter {
|
||||||
private static final LoggerService logger = new LoggerService(LoggerFactory.getLogger(TenantDeleter.class));
|
private static final LoggerService logger = new LoggerService(LoggerFactory.getLogger(TenantDeleter.class));
|
||||||
|
|
||||||
private final TenantScopedEntityManager entityManager;
|
private final TenantEntityManager entityManager;
|
||||||
protected final QueryFactory queryFactory;
|
protected final QueryFactory queryFactory;
|
||||||
private final DeleterFactory deleterFactory;
|
private final DeleterFactory deleterFactory;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
public TenantDeleter(
|
public TenantDeleter(
|
||||||
TenantScopedEntityManager entityManager,
|
TenantEntityManager entityManager,
|
||||||
QueryFactory queryFactory,
|
QueryFactory queryFactory,
|
||||||
DeleterFactory deleterFactory
|
DeleterFactory deleterFactory
|
||||||
) {
|
) {
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue