multitenant integration changes

This commit is contained in:
Efstratios Giannopoulos 2024-04-03 18:35:37 +03:00
parent 424d18526b
commit 671f8f75ba
88 changed files with 2319 additions and 1135 deletions

View File

@ -1,5 +1,6 @@
package gr.cite.annotation.web.controllers; package gr.cite.annotation.web.controllers;
import gr.cite.annotation.authorization.ClaimNames;
import gr.cite.commons.web.oidc.principal.CurrentPrincipalResolver; 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;
@ -80,7 +81,7 @@ public class PrincipalController {
logger.debug("my-tenants"); logger.debug("my-tenants");
MyPrincipal principal = this.currentPrincipalResolver.currentPrincipal(); MyPrincipal principal = this.currentPrincipalResolver.currentPrincipal();
List<String> tenants = this.claimExtractor.asStrings(principal, TenantScope.TenantCodesClaimName); List<String> tenants = this.claimExtractor.asStrings(principal, ClaimNames.TenantCodesClaimName);
this.auditService.track(AuditableAction.Tenants_Lookup); this.auditService.track(AuditableAction.Tenants_Lookup);
//auditService.trackIdentity(AuditableAction.IdentityTracking_Action); //auditService.trackIdentity(AuditableAction.IdentityTracking_Action);

View File

@ -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);
} }
} }

View File

@ -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);
} }
} }

View File

@ -1,8 +1,7 @@
package gr.cite.annotation.web.scope.tenant; package gr.cite.annotation.web.scope.tenant;
import gr.cite.commons.web.authz.service.AuthorizationService;
import gr.cite.commons.web.oidc.principal.CurrentPrincipalResolver; import gr.cite.annotation.authorization.ClaimNames;
import gr.cite.commons.web.oidc.principal.extractor.ClaimExtractor;
import gr.cite.annotation.authorization.Permission; import gr.cite.annotation.authorization.Permission;
import gr.cite.annotation.common.enums.IsActive; import gr.cite.annotation.common.enums.IsActive;
import gr.cite.annotation.common.scope.tenant.TenantScope; import gr.cite.annotation.common.scope.tenant.TenantScope;
@ -11,16 +10,20 @@ import gr.cite.annotation.data.TenantUserEntity;
import gr.cite.annotation.data.UserEntity; import gr.cite.annotation.data.UserEntity;
import gr.cite.annotation.data.tenant.TenantScopedBaseEntity; import gr.cite.annotation.data.tenant.TenantScopedBaseEntity;
import gr.cite.annotation.errorcode.ErrorThesaurusProperties; import gr.cite.annotation.errorcode.ErrorThesaurusProperties;
import gr.cite.annotation.query.utils.BuildSubQueryInput;
import gr.cite.annotation.query.utils.QueryUtilsService;
import gr.cite.commons.web.authz.service.AuthorizationService;
import gr.cite.commons.web.oidc.principal.CurrentPrincipalResolver;
import gr.cite.commons.web.oidc.principal.extractor.ClaimExtractor;
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.EntityManager;
import jakarta.persistence.PersistenceContext; import jakarta.persistence.PersistenceContext;
import jakarta.persistence.Tuple;
import jakarta.persistence.criteria.CriteriaBuilder; import jakarta.persistence.criteria.CriteriaBuilder;
import jakarta.persistence.criteria.CriteriaQuery; import jakarta.persistence.criteria.CriteriaQuery;
import jakarta.persistence.criteria.Root; import jakarta.persistence.criteria.Root;
import jakarta.persistence.criteria.Subquery;
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;
@ -34,6 +37,7 @@ import org.springframework.web.context.request.WebRequestInterceptor;
import javax.management.InvalidApplicationException; import javax.management.InvalidApplicationException;
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 {
@ -44,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;
@ -59,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();
@ -95,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());
} }
} }
} }
@ -130,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;

View File

@ -1,19 +1,20 @@
package gr.cite.annotation.web.scope.tenant; package gr.cite.annotation.web.scope.tenant;
import gr.cite.commons.web.oidc.principal.CurrentPrincipalResolver;
import gr.cite.commons.web.oidc.principal.MyPrincipal; import gr.cite.annotation.authorization.ClaimNames;
import gr.cite.commons.web.oidc.principal.extractor.ClaimExtractor;
import gr.cite.commons.web.oidc.principal.extractor.ClaimExtractorContext;
import gr.cite.annotation.common.enums.IsActive; import gr.cite.annotation.common.enums.IsActive;
import gr.cite.annotation.common.scope.tenant.TenantScope; import gr.cite.annotation.common.scope.tenant.TenantScope;
import gr.cite.annotation.convention.ConventionService; import gr.cite.annotation.convention.ConventionService;
import gr.cite.annotation.data.TenantEntity; import gr.cite.annotation.data.TenantEntity;
import gr.cite.annotation.errorcode.ErrorThesaurusProperties; import gr.cite.annotation.errorcode.ErrorThesaurusProperties;
import gr.cite.commons.web.oidc.principal.CurrentPrincipalResolver;
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.ClaimExtractorContext;
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.EntityManager;
import jakarta.persistence.PersistenceContext; import jakarta.persistence.PersistenceContext;
import jakarta.persistence.Tuple;
import jakarta.persistence.criteria.CriteriaBuilder; import jakarta.persistence.criteria.CriteriaBuilder;
import jakarta.persistence.criteria.CriteriaQuery; import jakarta.persistence.criteria.CriteriaQuery;
import jakarta.persistence.criteria.Root; import jakarta.persistence.criteria.Root;
@ -67,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
@ -77,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) {
@ -111,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(
@ -138,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(
@ -166,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;
} }

View File

@ -1,18 +1,20 @@
package gr.cite.annotation.web.scope.tenant; package gr.cite.annotation.web.scope.tenant;
import gr.cite.commons.web.oidc.principal.CurrentPrincipalResolver;
import gr.cite.commons.web.oidc.principal.extractor.ClaimExtractorContext; import gr.cite.annotation.authorization.ClaimNames;
import gr.cite.annotation.common.enums.IsActive; import gr.cite.annotation.common.enums.IsActive;
import gr.cite.annotation.common.scope.tenant.TenantScope; import gr.cite.annotation.common.scope.tenant.TenantScope;
import gr.cite.annotation.convention.ConventionService; import gr.cite.annotation.convention.ConventionService;
import gr.cite.annotation.data.TenantEntity; import gr.cite.annotation.data.TenantEntity;
import gr.cite.commons.web.oidc.principal.CurrentPrincipalResolver;
import gr.cite.commons.web.oidc.principal.extractor.ClaimExtractorContext;
import gr.cite.tools.logging.LoggerService; import gr.cite.tools.logging.LoggerService;
import jakarta.persistence.EntityManager; import jakarta.persistence.EntityManager;
import jakarta.persistence.PersistenceContext; import jakarta.persistence.PersistenceContext;
import jakarta.persistence.Tuple;
import jakarta.persistence.criteria.CriteriaBuilder; import jakarta.persistence.criteria.CriteriaBuilder;
import jakarta.persistence.criteria.CriteriaQuery; import jakarta.persistence.criteria.CriteriaQuery;
import jakarta.persistence.criteria.Root; 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;
@ -21,7 +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 java.util.List; import java.util.List;
import java.util.UUID; import java.util.UUID;
@ -55,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) {
@ -85,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);
} }
@ -94,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(
@ -102,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(
@ -130,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;
} }

View File

@ -40,4 +40,5 @@ public class TenantScopeProperties {
public void setEnforceTrustedTenant(Boolean enforceTrustedTenant) { public void setEnforceTrustedTenant(Boolean enforceTrustedTenant) {
this.enforceTrustedTenant = enforceTrustedTenant; this.enforceTrustedTenant = enforceTrustedTenant;
} }
} }

View File

@ -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 {
} }

View File

@ -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);
} }
} }

View File

@ -1,154 +1,81 @@
//package gr.cite.notification.web.scope.user; package gr.cite.annotation.web.scope.user;
//
//
//import gr.cite.commons.web.oidc.principal.CurrentPrincipalResolver; import gr.cite.annotation.common.scope.user.UserScope;
//import gr.cite.commons.web.oidc.principal.extractor.ClaimExtractor; import gr.cite.annotation.data.UserCredentialEntity;
//import gr.cite.notification.common.enums.IsActive; import gr.cite.annotation.model.UserCredential;
//import gr.cite.notification.common.scope.user.UserScope; import gr.cite.annotation.query.UserCredentialQuery;
//import gr.cite.notification.data.UserEntity; import gr.cite.commons.web.oidc.principal.CurrentPrincipalResolver;
//import gr.cite.notification.locale.LocaleService; import gr.cite.commons.web.oidc.principal.extractor.ClaimExtractor;
//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) {
// }
//}

View File

@ -1,10 +1,10 @@
//package gr.cite.notification.web.scope.user; package gr.cite.annotation.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 {
//} }

View File

@ -1,77 +1,67 @@
//package gr.cite.notification.web.scope.user; package gr.cite.annotation.web.scope.user;
//
//import gr.cite.notification.convention.ConventionService; import gr.cite.annotation.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);
// }});
// }
//}

View File

@ -10,7 +10,7 @@ spring:
dialect: org.hibernate.dialect.PostgreSQLDialect dialect: org.hibernate.dialect.PostgreSQLDialect
hibernate: hibernate:
naming: naming:
physical-strategy: gr.cite.notification.config.db.PrefixPhysicalNamingStrategy physical-strategy: gr.cite.annotation.data.namingstrategy.PrefixPhysicalNamingStrategy
implicit-strategy: org.springframework.boot.orm.jpa.hibernate.SpringImplicitNamingStrategy implicit-strategy: org.springframework.boot.orm.jpa.hibernate.SpringImplicitNamingStrategy
datasource: datasource:
url: ${DB_CONNECTION_STRING} url: ${DB_CONNECTION_STRING}

View File

@ -41,3 +41,9 @@ 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-not-allowed:
code: 113
message: tenant not allowed
tenant-tampering:
code: 123
message: Tenant tampering

View File

@ -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

View File

@ -0,0 +1,7 @@
tenant:
multitenancy:
is-multitenant: true
default-tenant-code: default
interceptor:
client-claims-prefix: client_
enforce-trusted-tenant: false

View File

@ -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' ]

View File

@ -0,0 +1,9 @@
package gr.cite.annotation.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";
}

View File

@ -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;
}
} }

View File

@ -1,30 +1,25 @@
package gr.cite.annotation.common.scope.tenant; package gr.cite.annotation.common.scope.tenant;
import gr.cite.annotation.data.tenant.TenantScopedBaseEntity; import gr.cite.annotation.data.tenant.TenantScopedBaseEntity;
import gr.cite.tools.logging.LoggerService;
import jakarta.persistence.EntityManager; 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.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 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) {
@ -35,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);
} }
} }
} }

View File

@ -4,6 +4,7 @@ import gr.cite.annotation.common.enums.AnnotationProtectionType;
import gr.cite.annotation.common.enums.IsActive; import gr.cite.annotation.common.enums.IsActive;
import gr.cite.annotation.data.conventers.AnnotationProtectionTypeConverter; import gr.cite.annotation.data.conventers.AnnotationProtectionTypeConverter;
import gr.cite.annotation.data.conventers.IsActiveConverter; import gr.cite.annotation.data.conventers.IsActiveConverter;
import gr.cite.annotation.data.tenant.TenantScopedBaseEntity;
import jakarta.persistence.*; import jakarta.persistence.*;
import java.time.Instant; import java.time.Instant;
@ -11,7 +12,7 @@ import java.util.UUID;
@Entity @Entity
@Table(name = "\"Annotation\"") @Table(name = "\"Annotation\"")
public class AnnotationEntity { public class AnnotationEntity extends TenantScopedBaseEntity {
@Id @Id
@Column(name = "id", columnDefinition = "uuid", updatable = false, nullable = false) @Column(name = "id", columnDefinition = "uuid", updatable = false, nullable = false)

View File

@ -2,6 +2,7 @@ package gr.cite.annotation.data;
import gr.cite.annotation.common.enums.IsActive; import gr.cite.annotation.common.enums.IsActive;
import gr.cite.annotation.data.conventers.IsActiveConverter; import gr.cite.annotation.data.conventers.IsActiveConverter;
import gr.cite.annotation.data.tenant.TenantScopedBaseEntity;
import jakarta.persistence.*; import jakarta.persistence.*;
import java.time.Instant; import java.time.Instant;
@ -9,7 +10,7 @@ import java.util.UUID;
@Entity @Entity
@Table(name = "\"EntityUser\"") @Table(name = "\"EntityUser\"")
public class EntityUserEntity { public class EntityUserEntity extends TenantScopedBaseEntity {
@Id @Id
@Column(name = "\"id\"", columnDefinition = "uuid", updatable = false, nullable = false) @Column(name = "\"id\"", columnDefinition = "uuid", updatable = false, nullable = false)

View File

@ -0,0 +1,115 @@
package gr.cite.annotation.data;
import gr.cite.annotation.common.scope.tenant.TenantScope;
import gr.cite.annotation.common.scope.tenant.TenantScoped;
import gr.cite.annotation.data.tenant.TenantScopedBaseEntity;
import gr.cite.annotation.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.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;
}
}

View File

@ -1,97 +0,0 @@
package gr.cite.annotation.data;
import gr.cite.commons.web.authz.service.AuthorizationService;
import gr.cite.annotation.authorization.Permission;
import gr.cite.annotation.common.scope.tenant.TenantScope;
import gr.cite.annotation.common.scope.tenant.TenantScoped;
import gr.cite.tools.exception.MyForbiddenException;
import jakarta.persistence.EntityManager;
import jakarta.persistence.FlushModeType;
import jakarta.persistence.PersistenceContext;
import jakarta.persistence.Query;
import org.hibernate.Session;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Service;
import javax.management.InvalidApplicationException;
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();
}
}

View File

@ -12,7 +12,7 @@ import java.util.UUID;
@Entity @Entity
@Table(name = "\"UserContactInfo\"") @Table(name = "\"UserContactInfo\"")
public class UserContactInfoEntity extends TenantScopedBaseEntity { public class UserContactInfoEntity {
@Id @Id
@Column(name = "id", columnDefinition = "uuid", updatable = false, nullable = false) @Column(name = "id", columnDefinition = "uuid", updatable = false, nullable = false)

View File

@ -10,7 +10,7 @@ import java.util.UUID;
@Entity @Entity
@Table(name = "\"UserCredential\"") @Table(name = "\"UserCredential\"")
public class UserCredentialEntity extends TenantScopedBaseEntity { public class UserCredentialEntity {
@Id @Id
@Column(name = "id", columnDefinition = "uuid", updatable = false, nullable = false) @Column(name = "id", columnDefinition = "uuid", updatable = false, nullable = false)

View File

@ -1,4 +1,4 @@
package gr.cite.annotation.config.db; package gr.cite.annotation.data.namingstrategy;
import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.bind.ConstructorBinding; import org.springframework.boot.context.properties.bind.ConstructorBinding;

View File

@ -1,4 +1,4 @@
package gr.cite.annotation.config.db; package gr.cite.annotation.data.namingstrategy;
import gr.cite.annotation.common.StringUtils; import gr.cite.annotation.common.StringUtils;
import org.hibernate.boot.model.naming.Identifier; import org.hibernate.boot.model.naming.Identifier;

View File

@ -1,7 +1,5 @@
package gr.cite.annotation.data.tenant; package gr.cite.annotation.data.tenant;
import gr.cite.commons.web.oidc.principal.CurrentPrincipalResolver;
import gr.cite.commons.web.oidc.principal.extractor.ClaimExtractor;
import gr.cite.annotation.common.scope.tenant.TenantScope; import gr.cite.annotation.common.scope.tenant.TenantScope;
import jakarta.persistence.EntityManager; import jakarta.persistence.EntityManager;
import org.aspectj.lang.JoinPoint; import org.aspectj.lang.JoinPoint;
@ -9,7 +7,6 @@ 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;
@ -19,30 +16,28 @@ import javax.management.InvalidApplicationException;
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);
}
} }
} }

View File

@ -2,6 +2,7 @@ package gr.cite.annotation.data.tenant;
import gr.cite.annotation.common.scope.tenant.TenantScope; import gr.cite.annotation.common.scope.tenant.TenantScope;
import gr.cite.annotation.common.scope.tenant.TenantScoped; import gr.cite.annotation.common.scope.tenant.TenantScoped;
import gr.cite.annotation.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.PrePersist;
@ -17,18 +18,28 @@ 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());
}
}
} }
} }

View File

@ -16,23 +16,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;
} }
@ -41,5 +38,5 @@ public abstract class TenantScopedBaseEntity implements TenantScoped, Serializab
public void setTenantId(UUID tenantId) { public void setTenantId(UUID tenantId) {
this.tenantId = tenantId; this.tenantId = tenantId;
} }
} }

View File

@ -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;
}
} }

View File

@ -17,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;
@ -242,7 +243,8 @@ 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);
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());
@ -279,7 +281,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);
@ -322,23 +324,23 @@ 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.getTenantRemovalTopic())) if (this.routingKeyMatched(queueInboxMessage.getRoute(), this.inboxProperties.getTenantRemovalTopic()))
handler = this.applicationContext.getBean(TenantRemovalIntegrationEventHandler.class); handler = this.applicationContext.getBean(TenantRemovalIntegrationEventHandler.class);
else if (this.routingKeyMatched(routingKey, this.inboxProperties.getTenantTouchTopic())) else if (this.routingKeyMatched(queueInboxMessage.getRoute(), this.inboxProperties.getTenantTouchTopic()))
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.getUserTouchTopic())) else if (this.routingKeyMatched(queueInboxMessage.getRoute(), this.inboxProperties.getUserTouchTopic()))
handler = this.applicationContext.getBean(UserTouchedIntegrationEventHandler.class); handler = this.applicationContext.getBean(UserTouchedIntegrationEventHandler.class);
else if (this.routingKeyMatched(routingKey, this.inboxProperties.getAnnotationEntitiesTouchTopic())) else if (this.routingKeyMatched(queueInboxMessage.getRoute(), this.inboxProperties.getAnnotationEntitiesTouchTopic()))
handler = this.applicationContext.getBean(AnnotationEntitiesTouchedIntegrationEventHandler.class); handler = this.applicationContext.getBean(AnnotationEntitiesTouchedIntegrationEventHandler.class);
else if (this.routingKeyMatched(routingKey, this.inboxProperties.getAnnotationEntitiesRemovalTopic())) else if (this.routingKeyMatched(queueInboxMessage.getRoute(), this.inboxProperties.getAnnotationEntitiesRemovalTopic()))
handler = this.applicationContext.getBean(AnnotationEntitiesRemovalIntegrationEventHandler.class); handler = this.applicationContext.getBean(AnnotationEntitiesRemovalIntegrationEventHandler.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;
} }
@ -346,16 +348,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;
} }
// } // }

View File

@ -1,10 +1,13 @@
package gr.cite.annotation.integrationevent.inbox; package gr.cite.annotation.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;
}
} }

View File

@ -4,15 +4,21 @@ import gr.cite.annotation.audit.AuditableAction;
import gr.cite.annotation.common.JsonHandlingService; 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.common.scope.tenant.TenantScope;
import gr.cite.annotation.data.EntityUserEntity; import gr.cite.annotation.data.EntityUserEntity;
import gr.cite.annotation.data.TenantEntity;
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.Tenant;
import gr.cite.annotation.query.EntityUserQuery; import gr.cite.annotation.query.EntityUserQuery;
import gr.cite.annotation.query.TenantQuery;
import gr.cite.commons.web.oidc.principal.CurrentPrincipalResolver; import gr.cite.commons.web.oidc.principal.CurrentPrincipalResolver;
import gr.cite.tools.auditing.AuditService; import gr.cite.tools.auditing.AuditService;
import gr.cite.tools.data.deleter.DeleterFactory; import gr.cite.tools.data.deleter.DeleterFactory;
import gr.cite.tools.data.query.QueryFactory; import gr.cite.tools.data.query.QueryFactory;
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.EntityManager;
@ -62,6 +68,20 @@ public class AnnotationEntitiesRemovalIntegrationEventHandlerImpl implements Ann
EntityTransaction transaction = null; EntityTransaction transaction = null;
try (FakeRequestScope ignored = new FakeRequestScope()) { try (FakeRequestScope ignored = new FakeRequestScope()) {
try { try {
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));
if (tenant == null) {
logger.error("missing tenant from event message");
return EventProcessingStatus.Error;
}
scope.setTenant(properties.getTenantId(), tenant.getCode());
} else if (scope.isMultitenant()) {
// logger.error("missing tenant from event message");
// return EventProcessingStatus.Error;
scope.setTenant(null, scope.getDefaultTenantCode());
}
CurrentPrincipalResolver currentPrincipalResolver = this.applicationContext.getBean(CurrentPrincipalResolver.class); CurrentPrincipalResolver currentPrincipalResolver = this.applicationContext.getBean(CurrentPrincipalResolver.class);
currentPrincipalResolver.push(InboxPrincipal.build(properties)); currentPrincipalResolver.push(InboxPrincipal.build(properties));
@ -75,6 +95,9 @@ public class AnnotationEntitiesRemovalIntegrationEventHandlerImpl implements Ann
try { try {
TenantEntityManager tenantEntityManager = this.applicationContext.getBean(TenantEntityManager.class);
tenantEntityManager.setEntityManager(entityManager);
tenantEntityManager.disableTenantFilters();
EntityUserQuery entityUserQuery = this.queryFactory.query(EntityUserQuery.class); EntityUserQuery entityUserQuery = this.queryFactory.query(EntityUserQuery.class);
List<EntityUserEntity> items = entityUserQuery List<EntityUserEntity> items = entityUserQuery
.entityIds(event.getEntityIds()) .entityIds(event.getEntityIds())

View File

@ -4,15 +4,21 @@ import gr.cite.annotation.audit.AuditableAction;
import gr.cite.annotation.common.JsonHandlingService; 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.common.scope.tenant.TenantScope;
import gr.cite.annotation.data.EntityUserEntity; import gr.cite.annotation.data.EntityUserEntity;
import gr.cite.annotation.data.TenantEntity;
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.Tenant;
import gr.cite.annotation.query.EntityUserQuery; import gr.cite.annotation.query.EntityUserQuery;
import gr.cite.annotation.query.TenantQuery;
import gr.cite.commons.web.oidc.principal.CurrentPrincipalResolver; import gr.cite.commons.web.oidc.principal.CurrentPrincipalResolver;
import gr.cite.tools.auditing.AuditService; import gr.cite.tools.auditing.AuditService;
import gr.cite.tools.data.deleter.DeleterFactory; import gr.cite.tools.data.deleter.DeleterFactory;
import gr.cite.tools.data.query.QueryFactory; import gr.cite.tools.data.query.QueryFactory;
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.EntityManager;
@ -64,6 +70,20 @@ public class AnnotationEntitiesTouchedIntegrationEventHandlerImpl implements Ann
EntityTransaction transaction = null; EntityTransaction transaction = null;
try (FakeRequestScope ignored = new FakeRequestScope()) { try (FakeRequestScope ignored = new FakeRequestScope()) {
try { try {
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));
if (tenant == null) {
logger.error("missing tenant from event message");
return EventProcessingStatus.Error;
}
scope.setTenant(properties.getTenantId(), tenant.getCode());
} else if (scope.isMultitenant()) {
// logger.error("missing tenant from event message");
// return EventProcessingStatus.Error;
scope.setTenant(null, scope.getDefaultTenantCode());
}
CurrentPrincipalResolver currentPrincipalResolver = this.applicationContext.getBean(CurrentPrincipalResolver.class); CurrentPrincipalResolver currentPrincipalResolver = this.applicationContext.getBean(CurrentPrincipalResolver.class);
currentPrincipalResolver.push(InboxPrincipal.build(properties)); currentPrincipalResolver.push(InboxPrincipal.build(properties));
@ -76,6 +96,9 @@ public class AnnotationEntitiesTouchedIntegrationEventHandlerImpl implements Ann
transaction.begin(); transaction.begin();
try { try {
TenantEntityManager tenantEntityManager = this.applicationContext.getBean(TenantEntityManager.class);
tenantEntityManager.setEntityManager(entityManager);
tenantEntityManager.disableTenantFilters();
for (AnnotationEntitiesTouchedIntegrationEvent.AnnotationEntityTouchedIntegrationEvent entityEvent : event.getEvents()) { for (AnnotationEntitiesTouchedIntegrationEvent.AnnotationEntityTouchedIntegrationEvent entityEvent : event.getEvents()) {
EntityUserQuery entityUserQuery = this.queryFactory.query(EntityUserQuery.class); EntityUserQuery entityUserQuery = this.queryFactory.query(EntityUserQuery.class);

View File

@ -1,5 +1,6 @@
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.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;
@ -35,15 +36,10 @@ public class TenantRemovalIntegrationEventHandlerImpl implements TenantRemovalIn
private final ApplicationContext applicationContext; private final ApplicationContext applicationContext;
private final ErrorThesaurusProperties errors;
private final MessageSource messageSource; public TenantRemovalIntegrationEventHandlerImpl(JsonHandlingService jsonHandlingService, ApplicationContext applicationContext) {
public TenantRemovalIntegrationEventHandlerImpl(JsonHandlingService jsonHandlingService, ApplicationContext applicationContext, ErrorThesaurusProperties errors, MessageSource messageSource) {
this.jsonHandlingService = jsonHandlingService; this.jsonHandlingService = jsonHandlingService;
this.applicationContext = applicationContext; this.applicationContext = applicationContext;
this.errors = errors;
this.messageSource = messageSource;
} }
@Override @Override
@ -70,6 +66,9 @@ public class TenantRemovalIntegrationEventHandlerImpl implements TenantRemovalIn
transaction.begin(); transaction.begin();
try { try {
TenantEntityManager tenantEntityManager = this.applicationContext.getBean(TenantEntityManager.class);
tenantEntityManager.setEntityManager(entityManager);
tenantEntityManager.disableTenantFilters();
TenantService tenantService = this.applicationContext.getBean(TenantService.class); TenantService tenantService = this.applicationContext.getBean(TenantService.class);
tenantService.deleteAndSave(event.getId()); tenantService.deleteAndSave(event.getId());

View File

@ -1,5 +1,6 @@
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.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;
@ -67,6 +68,9 @@ public class TenantTouchedIntegrationEventHandlerImpl implements TenantTouchedIn
transaction.begin(); transaction.begin();
try { try {
TenantEntityManager tenantEntityManager = this.applicationContext.getBean(TenantEntityManager.class);
tenantEntityManager.setEntityManager(entityManager);
tenantEntityManager.disableTenantFilters();
TenantService tenantService = this.applicationContext.getBean(TenantService.class); TenantService tenantService = this.applicationContext.getBean(TenantService.class);
tenantService.persist(model, null); tenantService.persist(model, null);

View File

@ -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;
}
} }

View File

@ -1,5 +1,6 @@
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.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;
@ -75,16 +76,16 @@ public class UserRemovalIntegrationEventHandlerImpl implements UserRemovalIntegr
try { try {
QueryFactory queryFactory = this.applicationContext.getBean(QueryFactory.class); QueryFactory queryFactory = this.applicationContext.getBean(QueryFactory.class);
TenantScope scope = this.applicationContext.getBean(TenantScope.class); TenantScope scope = this.applicationContext.getBean(TenantScope.class);
if (scope.isMultitenant() && event.getTenant() != null) { if (scope.isMultitenant() && properties.getTenantId() != null) {
TenantEntity tenant = queryFactory.query(TenantQuery.class).ids(event.getTenant()).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(event.getTenant(), tenant.getCode()); scope.setTenant(properties.getTenantId(), tenant.getCode());
} else if (scope.isMultitenant()) { } else if (scope.isMultitenant()) {
logger.error("missing tenant from event message"); // logger.error("missing tenant from event message");
return EventProcessingStatus.Error; scope.setTenant(null, scope.getDefaultTenantCode());
} }
CurrentPrincipalResolver currentPrincipalResolver = this.applicationContext.getBean(CurrentPrincipalResolver.class); CurrentPrincipalResolver currentPrincipalResolver = this.applicationContext.getBean(CurrentPrincipalResolver.class);
@ -101,6 +102,8 @@ public class UserRemovalIntegrationEventHandlerImpl implements UserRemovalIntegr
transaction.begin(); transaction.begin();
try { try {
TenantEntityManager tenantEntityManager = this.applicationContext.getBean(TenantEntityManager.class);
tenantEntityManager.setEntityManager(entityManager);
UserService userService = this.applicationContext.getBean(UserService.class); UserService userService = this.applicationContext.getBean(UserService.class);
userService.deleteAndSave(event.getUserId()); userService.deleteAndSave(event.getUserId());

View File

@ -6,6 +6,7 @@ import gr.cite.annotation.convention.ConventionService;
import gr.cite.annotation.errorcode.ErrorThesaurusProperties; import gr.cite.annotation.errorcode.ErrorThesaurusProperties;
import gr.cite.annotation.integrationevent.TrackedEvent; import gr.cite.annotation.integrationevent.TrackedEvent;
import gr.cite.annotation.model.persist.UserTouchedIntegrationEventPersist; import gr.cite.annotation.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 +24,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 +50,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 +58,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 +127,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,13 +153,132 @@ 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(UserTouchedIntegrationEvent.UserContactInfo.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()))
);
}
}
}
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(UserCredential.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(TenantUser.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(UserTouchedIntegrationEvent.UserTouchedIntegrationEventValidator.ValidatorName) @Component(UserTouchedIntegrationEvent.UserTouchedIntegrationEventValidator.ValidatorName)
@ -161,9 +289,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
@ -185,9 +316,11 @@ public class UserTouchedIntegrationEvent extends TrackedEvent {
.iff(() -> !this.isEmpty(item.getName())) .iff(() -> !this.isEmpty(item.getName()))
.must(() -> this.lessEqualLength(item.getName(), UserTouchedIntegrationEventPersist._nameLength)) .must(() -> this.lessEqualLength(item.getName(), UserTouchedIntegrationEventPersist._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))
); );
} }
} }

View File

@ -1,5 +1,6 @@
package gr.cite.annotation.integrationevent.inbox.usertouch; package gr.cite.annotation.integrationevent.inbox.usertouch;
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;
@ -67,20 +68,18 @@ public class UserTouchedIntegrationEventHandlerImpl implements UserTouchedIntegr
try { try {
QueryFactory queryFactory = this.applicationContext.getBean(QueryFactory.class); QueryFactory queryFactory = this.applicationContext.getBean(QueryFactory.class);
TenantScope scope = this.applicationContext.getBean(TenantScope.class); TenantScope scope = this.applicationContext.getBean(TenantScope.class);
if (scope.isMultitenant() && event.getTenant() != null) { if (scope.isMultitenant() && properties.getTenantId() != null) {
TenantEntity tenant = queryFactory.query(TenantQuery.class).ids(event.getTenant()).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(event.getTenant(), tenant.getCode()); scope.setTenant(properties.getTenantId(), tenant.getCode());
} else if (scope.isMultitenant()) { } else if (scope.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());
} }
//
// ValidationService validator = this.applicationContext.getBean(ValidationService.class);
// validator.validateForce(model);
CurrentPrincipalResolver currentPrincipalResolver = this.applicationContext.getBean(CurrentPrincipalResolver.class); CurrentPrincipalResolver currentPrincipalResolver = this.applicationContext.getBean(CurrentPrincipalResolver.class);
currentPrincipalResolver.push(InboxPrincipal.build(properties)); currentPrincipalResolver.push(InboxPrincipal.build(properties));
@ -92,6 +91,8 @@ public class UserTouchedIntegrationEventHandlerImpl implements UserTouchedIntegr
transaction.begin(); transaction.begin();
try { try {
TenantEntityManager tenantEntityManager = this.applicationContext.getBean(TenantEntityManager.class);
tenantEntityManager.setEntityManager(entityManager);
UserService userService = this.applicationContext.getBean(UserService.class); UserService userService = this.applicationContext.getBean(UserService.class);
userService.persist(event, null); userService.persist(event, null);

View File

@ -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;
}
} }

View File

@ -23,7 +23,6 @@ import org.springframework.context.ApplicationContext;
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;
@ -31,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(
@ -87,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);
@ -136,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);
@ -181,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);
@ -236,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);
@ -265,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) {
@ -280,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);
@ -307,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) {
@ -322,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);
@ -335,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 {
@ -353,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);
@ -374,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());

View File

@ -0,0 +1,5 @@
package gr.cite.annotation.integrationevent.outbox;
public interface OutboxService {
void publish(OutboxIntegrationEvent event);
}

View File

@ -0,0 +1,34 @@
package gr.cite.annotation.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
}
}
}

View File

@ -75,6 +75,10 @@ public class Annotation {
private List<String> authorizationFlags; private List<String> authorizationFlags;
public static final String _authorizationFlags = "authorizationFlags"; public static final String _authorizationFlags = "authorizationFlags";
private Boolean belongsToCurrentTenant;
public static final String _belongsToCurrentTenant = "belongsToCurrentTenant";
public UUID getId() { public UUID getId() {
return id; return id;
} }
@ -202,4 +206,5 @@ public class Annotation {
public void setAuthorizationFlags(List<String> authorizationFlags) { public void setAuthorizationFlags(List<String> authorizationFlags) {
this.authorizationFlags = authorizationFlags; this.authorizationFlags = authorizationFlags;
} }
} }

View File

@ -0,0 +1,98 @@
package gr.cite.annotation.model;
import gr.cite.annotation.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;
}
}

View File

@ -0,0 +1,76 @@
package gr.cite.annotation.model;
import gr.cite.annotation.common.enums.ContactInfoType;
import java.time.Instant;
import java.util.UUID;
public class UserContactInfo {
private UUID id;
public static final String _id = "id";
private String value;
public static final String _value = "value";
private ContactInfoType type;
public static final String _type = "type";
private int ordinal;
public static final String _ordinal = "ordinal";
private User user;
public static final String _user = "user";
private Instant createdAt;
public static final String _createdAt = "createdAt";
public UUID getId() {
return id;
}
public void setId(UUID id) {
this.id = id;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
public ContactInfoType getType() {
return type;
}
public void setType(ContactInfoType type) {
this.type = type;
}
public int getOrdinal() {
return ordinal;
}
public void setOrdinal(int ordinal) {
this.ordinal = ordinal;
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
public Instant getCreatedAt() {
return createdAt;
}
public void setCreatedAt(Instant createdAt) {
this.createdAt = createdAt;
}
}

View File

@ -2,10 +2,8 @@ package gr.cite.annotation.model.deleter;
import gr.cite.annotation.common.enums.IsActive; import gr.cite.annotation.common.enums.IsActive;
import gr.cite.annotation.data.AnnotationEntity; import gr.cite.annotation.data.AnnotationEntity;
import gr.cite.annotation.data.TenantScopedEntityManager; import gr.cite.annotation.data.TenantEntityManager;
import gr.cite.annotation.data.UserCredentialEntity;
import gr.cite.annotation.query.AnnotationQuery; import gr.cite.annotation.query.AnnotationQuery;
import gr.cite.annotation.query.UserCredentialQuery;
import gr.cite.tools.data.deleter.Deleter; import gr.cite.tools.data.deleter.Deleter;
import gr.cite.tools.data.query.QueryFactory; import gr.cite.tools.data.query.QueryFactory;
import gr.cite.tools.logging.LoggerService; import gr.cite.tools.logging.LoggerService;
@ -28,13 +26,13 @@ public class AnnotationDeleter implements Deleter {
private static final LoggerService logger = new LoggerService(LoggerFactory.getLogger(UserCredentialDeleter.class)); private static final LoggerService logger = new LoggerService(LoggerFactory.getLogger(UserCredentialDeleter.class));
private final TenantScopedEntityManager entityManager; private final TenantEntityManager entityManager;
private final QueryFactory queryFactory; private final QueryFactory queryFactory;
@Autowired @Autowired
public AnnotationDeleter( public AnnotationDeleter(
TenantScopedEntityManager entityManager, TenantEntityManager entityManager,
QueryFactory queryFactory QueryFactory queryFactory
) { ) {
this.entityManager = entityManager; this.entityManager = entityManager;

View File

@ -2,7 +2,7 @@ package gr.cite.EntityUser.model.deleter;
import gr.cite.annotation.common.enums.IsActive; import gr.cite.annotation.common.enums.IsActive;
import gr.cite.annotation.data.EntityUserEntity; import gr.cite.annotation.data.EntityUserEntity;
import gr.cite.annotation.data.TenantScopedEntityManager; import gr.cite.annotation.data.TenantEntityManager;
import gr.cite.annotation.query.EntityUserQuery; import gr.cite.annotation.query.EntityUserQuery;
import gr.cite.tools.data.deleter.Deleter; import gr.cite.tools.data.deleter.Deleter;
import gr.cite.tools.data.query.QueryFactory; import gr.cite.tools.data.query.QueryFactory;
@ -26,13 +26,13 @@ public class EntityUserDeleter implements Deleter {
private static final LoggerService logger = new LoggerService(LoggerFactory.getLogger(EntityUserDeleter.class)); private static final LoggerService logger = new LoggerService(LoggerFactory.getLogger(EntityUserDeleter.class));
private final TenantScopedEntityManager entityManager; private final TenantEntityManager entityManager;
private final QueryFactory queryFactory; private final QueryFactory queryFactory;
@Autowired @Autowired
public EntityUserDeleter( public EntityUserDeleter(
TenantScopedEntityManager entityManager, TenantEntityManager entityManager,
QueryFactory queryFactory QueryFactory queryFactory
) { ) {
this.entityManager = entityManager; this.entityManager = entityManager;

View File

@ -2,7 +2,7 @@ package gr.cite.annotation.model.deleter;
import gr.cite.annotation.common.enums.IsActive; import gr.cite.annotation.common.enums.IsActive;
import gr.cite.annotation.data.TenantConfigurationEntity; import gr.cite.annotation.data.TenantConfigurationEntity;
import gr.cite.annotation.data.TenantScopedEntityManager; import gr.cite.annotation.data.TenantEntityManager;
import gr.cite.annotation.query.TenantConfigurationQuery; import gr.cite.annotation.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
) { ) {

View File

@ -2,7 +2,7 @@ package gr.cite.annotation.model.deleter;
import gr.cite.annotation.common.enums.IsActive; import gr.cite.annotation.common.enums.IsActive;
import gr.cite.annotation.data.TenantEntity; import gr.cite.annotation.data.TenantEntity;
import gr.cite.annotation.data.TenantScopedEntityManager; import gr.cite.annotation.data.TenantEntityManager;
import gr.cite.annotation.query.TenantQuery; import gr.cite.annotation.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
) { ) {

View File

@ -0,0 +1,74 @@
package gr.cite.annotation.model.deleter;
import gr.cite.annotation.common.enums.IsActive;
import gr.cite.annotation.data.TenantEntityManager;
import gr.cite.annotation.data.TenantUserEntity;
import gr.cite.annotation.query.TenantUserQuery;
import gr.cite.tools.data.deleter.Deleter;
import gr.cite.tools.data.deleter.DeleterFactory;
import gr.cite.tools.data.query.QueryFactory;
import gr.cite.tools.logging.LoggerService;
import gr.cite.tools.logging.MapLogEntry;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
import javax.management.InvalidApplicationException;
import java.time.Instant;
import java.util.List;
import java.util.Optional;
import java.util.UUID;
@Component
@Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public class TenantUserDeleter implements Deleter {
private static final LoggerService logger = new LoggerService(LoggerFactory.getLogger(TenantUserDeleter.class));
private final TenantEntityManager entityManager;
private final QueryFactory queryFactory;
private final DeleterFactory deleterFactory;
@Autowired
public TenantUserDeleter(
TenantEntityManager entityManager,
QueryFactory queryFactory,
DeleterFactory deleterFactory
) {
this.entityManager = entityManager;
this.queryFactory = queryFactory;
this.deleterFactory = deleterFactory;
}
public void deleteAndSaveByIds(List<UUID> ids) throws InvalidApplicationException {
logger.debug(new MapLogEntry("collecting to delete").And("count", Optional.ofNullable(ids).map(e -> e.size()).orElse(0)).And("ids", ids));
List<TenantUserEntity> datas = this.queryFactory.query(TenantUserQuery.class).ids(ids).collect();
logger.trace("retrieved {} items", Optional.ofNullable(datas).map(e -> e.size()).orElse(0));
this.deleteAndSave(datas);
}
public void deleteAndSave(List<TenantUserEntity> datas) throws InvalidApplicationException {
logger.debug("will delete {} items", Optional.ofNullable(datas).map(e -> e.size()).orElse(0));
this.delete(datas);
logger.trace("saving changes");
this.entityManager.flush();
logger.trace("changes saved");
}
public void delete(List<TenantUserEntity> datas) throws InvalidApplicationException {
logger.debug("will delete {} items", Optional.ofNullable(datas).map(x -> x.size()).orElse(0));
if (datas == null || datas.isEmpty()) return;
Instant now = Instant.now();
for (TenantUserEntity item : datas) {
logger.trace("deleting item {}", item.getId());
item.setIsActive(IsActive.Inactive);
item.setUpdatedAt(now);
logger.trace("updating item");
this.entityManager.merge(item);
logger.trace("updated item");
}
}
}

View File

@ -0,0 +1,68 @@
package gr.cite.annotation.model.deleter;
import gr.cite.annotation.data.TenantEntityManager;
import gr.cite.annotation.data.UserContactInfoEntity;
import gr.cite.annotation.query.UserContactInfoQuery;
import gr.cite.tools.data.deleter.Deleter;
import gr.cite.tools.data.query.QueryFactory;
import gr.cite.tools.logging.LoggerService;
import gr.cite.tools.logging.MapLogEntry;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
import javax.management.InvalidApplicationException;
import java.util.List;
import java.util.Optional;
import java.util.UUID;
@Component
@Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public class UserContactInfoDeleter implements Deleter {
private static final LoggerService logger = new LoggerService(LoggerFactory.getLogger(UserContactInfoDeleter.class));
private final TenantEntityManager entityManager;
protected final QueryFactory queryFactory;
@Autowired
public UserContactInfoDeleter(
TenantEntityManager entityManager,
QueryFactory queryFactory
) {
this.entityManager = entityManager;
this.queryFactory = queryFactory;
}
public void deleteAndSaveByIds(List<UUID> ids) throws InvalidApplicationException {
logger.debug(new MapLogEntry("collecting to delete").And("count", Optional.ofNullable(ids).map(List::size).orElse(0)).And("ids", ids));
List<UserContactInfoEntity> data = this.queryFactory.query(UserContactInfoQuery.class).ids(ids).collect();
logger.trace("retrieved {} items", Optional.ofNullable(data).map(List::size).orElse(0));
this.deleteAndSave(data);
}
public void deleteAndSave(List<UserContactInfoEntity> data) throws InvalidApplicationException {
logger.debug("will delete {} items", Optional.ofNullable(data).map(List::size).orElse(0));
this.delete(data);
logger.trace("saving changes");
this.entityManager.flush();
logger.trace("changes saved");
}
public void delete(List<UserContactInfoEntity> data) throws InvalidApplicationException {
logger.debug("will delete {} items", Optional.ofNullable(data).map(List::size).orElse(0));
if (data == null || data.isEmpty())
return;
for (UserContactInfoEntity item : data) {
logger.trace("deleting item {}", item.getId());
logger.trace("deleting item");
this.entityManager.remove(item);
logger.trace("deleted item");
}
}
}

View File

@ -1,7 +1,7 @@
package gr.cite.annotation.model.deleter; package gr.cite.annotation.model.deleter;
import gr.cite.annotation.common.enums.IsActive; import gr.cite.annotation.common.enums.IsActive;
import gr.cite.annotation.data.TenantScopedEntityManager; import gr.cite.annotation.data.TenantEntityManager;
import gr.cite.annotation.data.UserCredentialEntity; import gr.cite.annotation.data.UserCredentialEntity;
import gr.cite.annotation.query.UserCredentialQuery; import gr.cite.annotation.query.UserCredentialQuery;
import gr.cite.tools.data.deleter.Deleter; import gr.cite.tools.data.deleter.Deleter;
@ -26,13 +26,13 @@ public class UserCredentialDeleter implements Deleter {
private static final LoggerService logger = new LoggerService(LoggerFactory.getLogger(UserCredentialDeleter.class)); private static final LoggerService logger = new LoggerService(LoggerFactory.getLogger(UserCredentialDeleter.class));
private final TenantScopedEntityManager entityManager; private final TenantEntityManager entityManager;
private final QueryFactory queryFactory; private final QueryFactory queryFactory;
@Autowired @Autowired
public UserCredentialDeleter( public UserCredentialDeleter(
TenantScopedEntityManager entityManager, TenantEntityManager entityManager,
QueryFactory queryFactory QueryFactory queryFactory
) { ) {
this.entityManager = entityManager; this.entityManager = entityManager;

View File

@ -1,8 +1,9 @@
package gr.cite.annotation.model.deleter; package gr.cite.annotation.model.deleter;
import gr.cite.annotation.common.enums.IsActive; import gr.cite.annotation.common.enums.IsActive;
import gr.cite.annotation.data.UserCredentialEntity; import gr.cite.annotation.data.*;
import gr.cite.annotation.data.UserEntity; import gr.cite.annotation.query.TenantUserQuery;
import gr.cite.annotation.query.UserContactInfoQuery;
import gr.cite.annotation.query.UserCredentialQuery; import gr.cite.annotation.query.UserCredentialQuery;
import gr.cite.annotation.query.UserQuery; import gr.cite.annotation.query.UserQuery;
import gr.cite.tools.data.deleter.Deleter; import gr.cite.tools.data.deleter.Deleter;
@ -10,7 +11,6 @@ import gr.cite.tools.data.deleter.DeleterFactory;
import gr.cite.tools.data.query.QueryFactory; import gr.cite.tools.data.query.QueryFactory;
import gr.cite.tools.logging.LoggerService; import gr.cite.tools.logging.LoggerService;
import gr.cite.tools.logging.MapLogEntry; import gr.cite.tools.logging.MapLogEntry;
import jakarta.persistence.EntityManager;
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.beans.factory.config.ConfigurableBeanFactory; import org.springframework.beans.factory.config.ConfigurableBeanFactory;
@ -30,7 +30,7 @@ public class UserDeleter implements Deleter {
private static final LoggerService logger = new LoggerService(LoggerFactory.getLogger(UserDeleter.class)); private static final LoggerService logger = new LoggerService(LoggerFactory.getLogger(UserDeleter.class));
private final EntityManager entityManager; private final TenantEntityManager entityManager;
protected final QueryFactory queryFactory; protected final QueryFactory queryFactory;
@ -38,7 +38,7 @@ public class UserDeleter implements Deleter {
@Autowired @Autowired
public UserDeleter( public UserDeleter(
EntityManager entityManager, TenantEntityManager entityManager,
QueryFactory queryFactory, QueryFactory queryFactory,
DeleterFactory deleterFactory DeleterFactory deleterFactory
) { ) {
@ -76,6 +76,18 @@ public class UserDeleter implements Deleter {
deleter.delete(items); deleter.delete(items);
} }
{
logger.debug("checking related - {}", UserContactInfoEntity.class.getSimpleName());
List<UserContactInfoEntity> items = this.queryFactory.query(UserContactInfoQuery.class).userIds(ids).collect();
UserContactInfoDeleter deleter = this.deleterFactory.deleter(UserContactInfoDeleter.class);
deleter.delete(items);
}
{
logger.debug("checking related - {}", TenantUserEntity.class.getSimpleName());
List<TenantUserEntity> items = this.queryFactory.query(TenantUserQuery.class).userIds(ids).collect();
TenantUserDeleter deleter = this.deleterFactory.deleter(TenantUserDeleter.class);
deleter.delete(items);
}
Instant now = Instant.now(); Instant now = Instant.now();
for (UserEntity item : data) { for (UserEntity item : data) {

View File

@ -0,0 +1,209 @@
package gr.cite.annotation.query;
import gr.cite.annotation.authorization.AuthorizationFlags;
import gr.cite.annotation.authorization.Permission;
import gr.cite.annotation.common.enums.IsActive;
import gr.cite.annotation.common.scope.user.UserScope;
import gr.cite.annotation.data.TenantUserEntity;
import gr.cite.annotation.data.UserEntity;
import gr.cite.annotation.model.Tenant;
import gr.cite.annotation.model.TenantUser;
import gr.cite.commons.web.authz.service.AuthorizationService;
import gr.cite.tools.data.query.FieldResolver;
import gr.cite.tools.data.query.QueryBase;
import gr.cite.tools.data.query.QueryContext;
import jakarta.persistence.Tuple;
import jakarta.persistence.criteria.CriteriaBuilder;
import jakarta.persistence.criteria.Predicate;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
import java.time.Instant;
import java.util.*;
@Component
@Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public class TenantUserQuery extends QueryBase<TenantUserEntity> {
private Collection<UUID> ids;
private Collection<UUID> userIds;
private Collection<UUID> tenantIds;
private Collection<IsActive> isActives;
private UserQuery userQuery;
private EnumSet<AuthorizationFlags> authorize = EnumSet.of(AuthorizationFlags.None);
private final UserScope userScope;
private final AuthorizationService authService;
public TenantUserQuery(
UserScope userScope,
AuthorizationService authService
) {
this.userScope = userScope;
this.authService = authService;
}
public TenantUserQuery ids(UUID value) {
this.ids = List.of(value);
return this;
}
public TenantUserQuery ids(UUID... value) {
this.ids = Arrays.asList(value);
return this;
}
public TenantUserQuery ids(Collection<UUID> values) {
this.ids = values;
return this;
}
public TenantUserQuery userIds(UUID value) {
this.userIds = List.of(value);
return this;
}
public TenantUserQuery userIds(UUID... value) {
this.userIds = Arrays.asList(value);
return this;
}
public TenantUserQuery userIds(Collection<UUID> values) {
this.userIds = values;
return this;
}
public TenantUserQuery tenantIds(UUID value) {
this.tenantIds = List.of(value);
return this;
}
public TenantUserQuery tenantIds(UUID... value) {
this.tenantIds = Arrays.asList(value);
return this;
}
public TenantUserQuery tenantIds(Collection<UUID> values) {
this.tenantIds = values;
return this;
}
public TenantUserQuery isActive(IsActive value) {
this.isActives = List.of(value);
return this;
}
public TenantUserQuery isActive(IsActive... value) {
this.isActives = Arrays.asList(value);
return this;
}
public TenantUserQuery isActive(Collection<IsActive> values) {
this.isActives = values;
return this;
}
public TenantUserQuery userSubQuery(UserQuery subQuery) {
this.userQuery = subQuery;
return this;
}
public TenantUserQuery authorize(EnumSet<AuthorizationFlags> values) {
this.authorize = values;
return this;
}
@Override
protected Class<TenantUserEntity> entityClass() {
return TenantUserEntity.class;
}
@Override
protected Boolean isFalseQuery() {
return this.isEmpty(this.ids) || this.isEmpty(this.userIds) || this.isEmpty(this.tenantIds) || this.isEmpty(this.isActives) || this.isFalseQuery(this.userQuery);
}
@Override
protected <X, Y> Predicate applyAuthZ(QueryContext<X, Y> queryContext) {
if (this.authorize.contains(AuthorizationFlags.None)) return null;
if (this.authorize.contains(AuthorizationFlags.Permission) && this.authService.authorize(Permission.BrowseTenant)) return null;
UUID ownerId = null;
if (this.authorize.contains(AuthorizationFlags.Owner)) ownerId = this.userScope.getUserIdSafe();
List<Predicate> predicates = new ArrayList<>();
if (ownerId != null) {
predicates.add(queryContext.CriteriaBuilder.equal(queryContext.Root.get(TenantUserEntity._userId), ownerId));
}
if (!predicates.isEmpty()) {
Predicate[] predicatesArray = predicates.toArray(new Predicate[0]);
return queryContext.CriteriaBuilder.and(predicatesArray);
} else {
return queryContext.CriteriaBuilder.or(); //Creates a false query
}
}
@Override
protected <X, Y> Predicate applyFilters(QueryContext<X, Y> queryContext) {
List<Predicate> predicates = new ArrayList<>();
if (this.ids != null) {
CriteriaBuilder.In<UUID> inClause = queryContext.CriteriaBuilder.in(queryContext.Root.get(TenantUserEntity._id));
for (UUID item : this.ids) inClause.value(item);
predicates.add(inClause);
}
if (this.userIds != null) {
CriteriaBuilder.In<UUID> inClause = queryContext.CriteriaBuilder.in(queryContext.Root.get(TenantUserEntity._userId));
for (UUID item : this.userIds) inClause.value(item);
predicates.add(inClause);
}
if (this.tenantIds != null) {
CriteriaBuilder.In<UUID> inClause = queryContext.CriteriaBuilder.in(queryContext.Root.get(TenantUserEntity._tenantId));
for (UUID item : this.tenantIds) inClause.value(item);
predicates.add(inClause);
}
if (this.isActives != null) {
CriteriaBuilder.In<IsActive> inClause = queryContext.CriteriaBuilder.in(queryContext.Root.get(TenantUserEntity._isActive));
for (IsActive item : this.isActives) inClause.value(item);
predicates.add(inClause);
}
if (this.userQuery != null) {
QueryContext<UserEntity, UUID> subQuery = this.applySubQuery(this.userQuery, queryContext, UUID.class, root -> root.get(TenantUserEntity._userId));
predicates.add(queryContext.CriteriaBuilder.in(queryContext.Root.get(TenantUserEntity._userId)).value(subQuery.Query));
}
if (!predicates.isEmpty()) {
Predicate[] predicatesArray = predicates.toArray(new Predicate[0]);
return queryContext.CriteriaBuilder.and(predicatesArray);
} else {
return null;
}
}
@Override
protected TenantUserEntity convert(Tuple tuple, Set<String> columns) {
TenantUserEntity item = new TenantUserEntity();
item.setId(QueryBase.convertSafe(tuple, columns, TenantUserEntity._id, UUID.class));
item.setTenantId(QueryBase.convertSafe(tuple, columns, TenantUserEntity._tenantId, UUID.class));
item.setUserId(QueryBase.convertSafe(tuple, columns, TenantUserEntity._userId, UUID.class));
item.setTenantId(QueryBase.convertSafe(tuple, columns, TenantUserEntity._tenantId, UUID.class));
item.setCreatedAt(QueryBase.convertSafe(tuple, columns, TenantUserEntity._createdAt, Instant.class));
item.setUpdatedAt(QueryBase.convertSafe(tuple, columns, TenantUserEntity._updatedAt, Instant.class));
item.setIsActive(QueryBase.convertSafe(tuple, columns, TenantUserEntity._isActive, IsActive.class));
return item;
}
@Override
protected String fieldNameOf(FieldResolver item) {
if (item.match(TenantUser._id)) return TenantUserEntity._id;
else if (item.match(TenantUser._tenant, Tenant._id)) return TenantUserEntity._tenantId;
else if (item.prefix(TenantUser._tenant)) return TenantUserEntity._tenantId;
else if (item.match(TenantUser._isActive)) return TenantUserEntity._isActive;
else if (item.match(TenantUser._createdAt)) return TenantUserEntity._createdAt;
else if (item.match(TenantUser._updatedAt)) return TenantUserEntity._updatedAt;
else if (item.match(TenantUser._hash)) return TenantUserEntity._updatedAt;
else if (item.match(TenantUser._user, UserEntity._id)) return TenantUserEntity._userId;
else if (item.prefix(TenantUser._user)) return TenantUserEntity._userId;
else if (item.match(TenantUser._belongsToCurrentTenant)) return TenantUserEntity._tenantId;
else return null;
}
}

View File

@ -0,0 +1,236 @@
package gr.cite.annotation.query;
import gr.cite.annotation.authorization.AuthorizationFlags;
import gr.cite.annotation.authorization.Permission;
import gr.cite.annotation.common.enums.ContactInfoType;
import gr.cite.annotation.common.scope.user.UserScope;
import gr.cite.annotation.data.UserContactInfoEntity;
import gr.cite.annotation.model.UserContactInfo;
import gr.cite.commons.web.authz.service.AuthorizationService;
import gr.cite.tools.data.query.FieldResolver;
import gr.cite.tools.data.query.QueryBase;
import gr.cite.tools.data.query.QueryContext;
import jakarta.persistence.Tuple;
import jakarta.persistence.criteria.CriteriaBuilder;
import jakarta.persistence.criteria.Predicate;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
import java.time.Instant;
import java.util.*;
@Component
@Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public class UserContactInfoQuery extends QueryBase<UserContactInfoEntity> {
private Collection<UUID> ids;
private Collection<UUID> excludedIds;
private Collection<UUID> excludedUserIds;
private Collection<UUID> userIds;
private Collection<String> values;
private Collection<ContactInfoType> types;
private EnumSet<AuthorizationFlags> authorize = EnumSet.of(AuthorizationFlags.None);
private final UserScope userScope;
private final AuthorizationService authService;
public UserContactInfoQuery(UserScope userScope, AuthorizationService authService) {
this.userScope = userScope;
this.authService = authService;
}
public UserContactInfoQuery ids(UUID value) {
this.ids = List.of(value);
return this;
}
public UserContactInfoQuery ids(UUID... value) {
this.ids = Arrays.asList(value);
return this;
}
public UserContactInfoQuery ids(Collection<UUID> values) {
this.ids = values;
return this;
}
public UserContactInfoQuery excludedIds(Collection<UUID> values) {
this.excludedIds = values;
return this;
}
public UserContactInfoQuery excludedIds(UUID value) {
this.excludedIds = List.of(value);
return this;
}
public UserContactInfoQuery excludedIds(UUID... value) {
this.excludedIds = Arrays.asList(value);
return this;
}
public UserContactInfoQuery excludedUserIds(Collection<UUID> values) {
this.excludedUserIds = values;
return this;
}
public UserContactInfoQuery excludedUserIds(UUID value) {
this.excludedUserIds = List.of(value);
return this;
}
public UserContactInfoQuery excludedUserIds(UUID... value) {
this.excludedUserIds = Arrays.asList(value);
return this;
}
public UserContactInfoQuery userIds(UUID value) {
this.userIds = List.of(value);
return this;
}
public UserContactInfoQuery userIds(UUID... value) {
this.userIds = Arrays.asList(value);
return this;
}
public UserContactInfoQuery userIds(Collection<UUID> values) {
this.userIds = values;
return this;
}
public UserContactInfoQuery values(String value) {
this.values = List.of(value);
return this;
}
public UserContactInfoQuery values(String... value) {
this.values = Arrays.asList(value);
return this;
}
public UserContactInfoQuery values(Collection<String> values) {
this.values = values;
return this;
}
public UserContactInfoQuery types(ContactInfoType value) {
this.types = List.of(value);
return this;
}
public UserContactInfoQuery types(ContactInfoType... value) {
this.types = Arrays.asList(value);
return this;
}
public UserContactInfoQuery types(Collection<ContactInfoType> values) {
this.types = values;
return this;
}
public UserContactInfoQuery authorize(EnumSet<AuthorizationFlags> values) {
this.authorize = values;
return this;
}
@Override
protected Boolean isFalseQuery() {
return
this.isEmpty(this.ids) ||
this.isEmpty(this.userIds) ||
this.isEmpty(this.excludedIds) ||
this.isEmpty(this.values) ||
this.isEmpty(this.excludedIds);
}
@Override
protected Class<UserContactInfoEntity> entityClass() {
return UserContactInfoEntity.class;
}
@Override
protected <X, Y> Predicate applyAuthZ(QueryContext<X, Y> queryContext) {
if (this.authorize.contains(AuthorizationFlags.None)) return null;
if (this.authorize.contains(AuthorizationFlags.Permission) && this.authService.authorize(Permission.BrowseUser)) return null;
UUID userId;
if (this.authorize.contains(AuthorizationFlags.Owner)) userId = this.userScope.getUserIdSafe();
else userId = null;
List<Predicate> predicates = new ArrayList<>();
if (userId != null) {
predicates.add(queryContext.CriteriaBuilder.in(queryContext.Root.get(UserContactInfoEntity._userId)).value(userId));
}
if (!predicates.isEmpty()) {
Predicate[] predicatesArray = predicates.toArray(new Predicate[0]);
return queryContext.CriteriaBuilder.and(predicatesArray);
} else {
return queryContext.CriteriaBuilder.or(); //Creates a false query
}
}
@Override
protected <X, Y> Predicate applyFilters(QueryContext<X, Y> queryContext) {
List<Predicate> predicates = new ArrayList<>();
if (this.ids != null) {
CriteriaBuilder.In<UUID> inClause = queryContext.CriteriaBuilder.in(queryContext.Root.get(UserContactInfoEntity._id));
for (UUID item : this.ids)
inClause.value(item);
predicates.add(inClause);
}
if (this.userIds != null) {
CriteriaBuilder.In<UUID> inClause = queryContext.CriteriaBuilder.in(queryContext.Root.get(UserContactInfoEntity._userId));
for (UUID item : this.userIds)
inClause.value(item);
predicates.add(inClause);
}
if (this.excludedIds != null) {
CriteriaBuilder.In<UUID> notInClause = queryContext.CriteriaBuilder.in(queryContext.Root.get(UserContactInfoEntity._id));
for (UUID item : this.excludedIds)
notInClause.value(item);
predicates.add(notInClause.not());
}
if (this.excludedUserIds != null) {
CriteriaBuilder.In<UUID> notInClause = queryContext.CriteriaBuilder.in(queryContext.Root.get(UserContactInfoEntity._userId));
for (UUID item : this.excludedUserIds)
notInClause.value(item);
predicates.add(notInClause.not());
}
if (this.values != null) {
CriteriaBuilder.In<String> inClause = queryContext.CriteriaBuilder.in(queryContext.Root.get(UserContactInfoEntity._value));
for (String item : this.values)
inClause.value(item);
predicates.add(inClause);
}
if (!predicates.isEmpty()) {
Predicate[] predicatesArray = predicates.toArray(new Predicate[0]);
return queryContext.CriteriaBuilder.and(predicatesArray);
} else {
return null;
}
}
@Override
protected String fieldNameOf(FieldResolver item) {
if (item.match(UserContactInfo._id)) return UserContactInfoEntity._id;
else if (item.match(UserContactInfo._value)) return UserContactInfoEntity._value;
else if (item.match(UserContactInfo._ordinal)) return UserContactInfoEntity._ordinal;
else if (item.prefix(UserContactInfo._user)) return UserContactInfoEntity._userId;
else if (item.match(UserContactInfo._user)) return UserContactInfoEntity._userId;
else if (item.match(UserContactInfo._type)) return UserContactInfoEntity._type;
else if (item.match(UserContactInfo._createdAt) ) return UserContactInfoEntity._createdAt;
else return null;
}
@Override
protected UserContactInfoEntity convert(Tuple tuple, Set<String> columns) {
UserContactInfoEntity item = new UserContactInfoEntity();
item.setId(QueryBase.convertSafe(tuple, columns, UserContactInfoEntity._id, UUID.class));
item.setValue(QueryBase.convertSafe(tuple, columns, UserContactInfoEntity._value, String.class));
item.setType(QueryBase.convertSafe(tuple, columns, UserContactInfoEntity._type, ContactInfoType.class));
item.setOrdinal(QueryBase.convertSafe(tuple, columns, UserContactInfoEntity._ordinal, Integer.class));
item.setUserId(QueryBase.convertSafe(tuple, columns, UserContactInfoEntity._userId, UUID.class));
item.setCreatedAt(QueryBase.convertSafe(tuple, columns, UserContactInfoEntity._createdAt, Instant.class));
return item;
}
}

View File

@ -7,6 +7,7 @@ import gr.cite.annotation.authorization.authorizationcontentresolver.Authorizati
import gr.cite.annotation.common.enums.IsActive; import gr.cite.annotation.common.enums.IsActive;
import gr.cite.annotation.common.scope.user.UserScope; import gr.cite.annotation.common.scope.user.UserScope;
import gr.cite.annotation.data.AnnotationEntity; import gr.cite.annotation.data.AnnotationEntity;
import gr.cite.annotation.data.TenantEntityManager;
import gr.cite.annotation.model.Annotation; import gr.cite.annotation.model.Annotation;
import gr.cite.annotation.model.builder.AnnotationBuilder; import gr.cite.annotation.model.builder.AnnotationBuilder;
import gr.cite.annotation.model.deleter.AnnotationDeleter; import gr.cite.annotation.model.deleter.AnnotationDeleter;
@ -22,7 +23,6 @@ import gr.cite.tools.fieldset.BaseFieldSet;
import gr.cite.tools.fieldset.FieldSet; import gr.cite.tools.fieldset.FieldSet;
import gr.cite.tools.logging.LoggerService; import gr.cite.tools.logging.LoggerService;
import gr.cite.tools.logging.MapLogEntry; import gr.cite.tools.logging.MapLogEntry;
import jakarta.persistence.EntityManager;
import jakarta.transaction.Transactional; import jakarta.transaction.Transactional;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.context.MessageSource; import org.springframework.context.MessageSource;
@ -44,7 +44,7 @@ public class AnnotationServiceImpl implements AnnotationService {
private final DeleterFactory deleterFactory; private final DeleterFactory deleterFactory;
private final EntityManager entityManager; private final TenantEntityManager entityManager;
private final BuilderFactory builderFactory; private final BuilderFactory builderFactory;
@ -57,7 +57,7 @@ public class AnnotationServiceImpl implements AnnotationService {
public AnnotationServiceImpl( public AnnotationServiceImpl(
AuthorizationService authorizationService, AuthorizationService authorizationService,
DeleterFactory deleterFactory, DeleterFactory deleterFactory,
EntityManager entityManager, TenantEntityManager entityManager,
BuilderFactory builderFactory, UserScope userScope, AuthorizationContentResolver authorizationContentResolver, MessageSource messageSource) { BuilderFactory builderFactory, UserScope userScope, AuthorizationContentResolver authorizationContentResolver, MessageSource messageSource) {
this.authorizationService = authorizationService; this.authorizationService = authorizationService;
this.deleterFactory = deleterFactory; this.deleterFactory = deleterFactory;

View File

@ -1,6 +1,7 @@
package gr.cite.annotation.service.tenant; package gr.cite.annotation.service.tenant;
import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.core.JsonProcessingException;
import gr.cite.annotation.data.TenantEntityManager;
import gr.cite.commons.web.authz.service.AuthorizationService; import gr.cite.commons.web.authz.service.AuthorizationService;
import gr.cite.annotation.authorization.AuthorizationFlags; import gr.cite.annotation.authorization.AuthorizationFlags;
import gr.cite.annotation.authorization.Permission; import gr.cite.annotation.authorization.Permission;
@ -21,7 +22,6 @@ import gr.cite.tools.fieldset.BaseFieldSet;
import gr.cite.tools.fieldset.FieldSet; import gr.cite.tools.fieldset.FieldSet;
import gr.cite.tools.logging.LoggerService; import gr.cite.tools.logging.LoggerService;
import gr.cite.tools.logging.MapLogEntry; import gr.cite.tools.logging.MapLogEntry;
import jakarta.persistence.EntityManager;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
@ -42,14 +42,14 @@ public class TenantServiceImpl implements TenantService {
private final ConventionService conventionService; private final ConventionService conventionService;
private final EntityManager entityManager; private final TenantEntityManager entityManager;
private final BuilderFactory builderFactory; private final BuilderFactory builderFactory;
public TenantServiceImpl(AuthorizationService authorizationService, public TenantServiceImpl(AuthorizationService authorizationService,
DeleterFactory deleterFactory, DeleterFactory deleterFactory,
ConventionService conventionService, ConventionService conventionService,
EntityManager entityManager, TenantEntityManager entityManager,
BuilderFactory builderFactory) { BuilderFactory builderFactory) {
this.authorizationService = authorizationService; this.authorizationService = authorizationService;
this.deleterFactory = deleterFactory; this.deleterFactory = deleterFactory;

View File

@ -10,7 +10,7 @@ import gr.cite.annotation.common.types.tenantconfiguration.DefaultUserLocaleConf
import gr.cite.annotation.common.types.tenantconfiguration.EmailClientConfigurationDataContainer; import gr.cite.annotation.common.types.tenantconfiguration.EmailClientConfigurationDataContainer;
import gr.cite.annotation.convention.ConventionService; import gr.cite.annotation.convention.ConventionService;
import gr.cite.annotation.data.TenantConfigurationEntity; import gr.cite.annotation.data.TenantConfigurationEntity;
import gr.cite.annotation.data.TenantScopedEntityManager; import gr.cite.annotation.data.TenantEntityManager;
import gr.cite.annotation.errorcode.ErrorThesaurusProperties; import gr.cite.annotation.errorcode.ErrorThesaurusProperties;
import gr.cite.annotation.model.TenantConfiguration; import gr.cite.annotation.model.TenantConfiguration;
import gr.cite.annotation.model.builder.TenantConfigurationBuilder; import gr.cite.annotation.model.builder.TenantConfigurationBuilder;
@ -51,11 +51,11 @@ public class TenantConfigurationServiceImpl implements TenantConfigurationServic
private final MessageSource messageSource; private final MessageSource messageSource;
private final BuilderFactory builderFactory; private final BuilderFactory builderFactory;
private final TenantScopedEntityManager dbContext; private final TenantEntityManager dbContext;
private final DeleterFactory deleterFactory; private final DeleterFactory deleterFactory;
@Autowired @Autowired
public TenantConfigurationServiceImpl(ApplicationContext applicationContext, JsonHandlingService jsonHandlingService, AuthorizationService authorizationService, ConventionService conventionService, ErrorThesaurusProperties errors, MessageSource messageSource, BuilderFactory builderFactory, TenantScopedEntityManager dbContext, DeleterFactory deleterFactory) { public TenantConfigurationServiceImpl(ApplicationContext applicationContext, JsonHandlingService jsonHandlingService, AuthorizationService authorizationService, ConventionService conventionService, ErrorThesaurusProperties errors, MessageSource messageSource, BuilderFactory builderFactory, TenantEntityManager dbContext, DeleterFactory deleterFactory) {
this.applicationContext = applicationContext; this.applicationContext = applicationContext;
this.jsonHandlingService = jsonHandlingService; this.jsonHandlingService = jsonHandlingService;
this.authorizationService = authorizationService; this.authorizationService = authorizationService;

View File

@ -1,19 +1,23 @@
package gr.cite.annotation.service.user; package gr.cite.annotation.service.user;
import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.core.JsonProcessingException;
import gr.cite.commons.web.authz.service.AuthorizationService;
import gr.cite.annotation.authorization.AuthorizationFlags; import gr.cite.annotation.authorization.AuthorizationFlags;
import gr.cite.annotation.authorization.Permission; import gr.cite.annotation.authorization.Permission;
import gr.cite.annotation.common.JsonHandlingService; import gr.cite.annotation.common.JsonHandlingService;
import gr.cite.annotation.common.enums.IsActive; import gr.cite.annotation.common.enums.IsActive;
import gr.cite.annotation.convention.ConventionService; import gr.cite.annotation.convention.ConventionService;
import gr.cite.annotation.data.UserContactInfoEntity; import gr.cite.annotation.data.*;
import gr.cite.annotation.data.UserCredentialEntity;
import gr.cite.annotation.data.UserEntity;
import gr.cite.annotation.integrationevent.inbox.usertouch.UserTouchedIntegrationEvent; import gr.cite.annotation.integrationevent.inbox.usertouch.UserTouchedIntegrationEvent;
import gr.cite.annotation.model.User; import gr.cite.annotation.model.User;
import gr.cite.annotation.model.builder.UserBuilder; import gr.cite.annotation.model.builder.UserBuilder;
import gr.cite.annotation.model.deleter.TenantUserDeleter;
import gr.cite.annotation.model.deleter.UserContactInfoDeleter;
import gr.cite.annotation.model.deleter.UserCredentialDeleter;
import gr.cite.annotation.model.deleter.UserDeleter; import gr.cite.annotation.model.deleter.UserDeleter;
import gr.cite.annotation.query.TenantUserQuery;
import gr.cite.annotation.query.UserContactInfoQuery;
import gr.cite.annotation.query.UserCredentialQuery;
import gr.cite.commons.web.authz.service.AuthorizationService;
import gr.cite.tools.data.builder.BuilderFactory; import gr.cite.tools.data.builder.BuilderFactory;
import gr.cite.tools.data.deleter.DeleterFactory; import gr.cite.tools.data.deleter.DeleterFactory;
import gr.cite.tools.data.query.QueryFactory; import gr.cite.tools.data.query.QueryFactory;
@ -25,16 +29,17 @@ import gr.cite.tools.fieldset.BaseFieldSet;
import gr.cite.tools.fieldset.FieldSet; import gr.cite.tools.fieldset.FieldSet;
import gr.cite.tools.logging.LoggerService; import gr.cite.tools.logging.LoggerService;
import gr.cite.tools.logging.MapLogEntry; import gr.cite.tools.logging.MapLogEntry;
import jakarta.persistence.EntityManager;
import jakarta.transaction.Transactional; import jakarta.transaction.Transactional;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import javax.management.InvalidApplicationException; import javax.management.InvalidApplicationException;
import java.time.Instant; import java.time.Instant;
import java.util.ArrayList;
import java.util.EnumSet; import java.util.EnumSet;
import java.util.List; import java.util.List;
import java.util.UUID; import java.util.UUID;
import java.util.stream.Collectors;
@Service @Service
public class UserServiceImpl implements UserService { public class UserServiceImpl implements UserService {
@ -47,20 +52,20 @@ public class UserServiceImpl implements UserService {
private final ConventionService conventionService; private final ConventionService conventionService;
private final EntityManager entityManager; private final TenantEntityManager entityManager;
private final BuilderFactory builderFactory; private final BuilderFactory builderFactory;
private final QueryFactory queryFactory; private final QueryFactory queryFactory;
private final JsonHandlingService jsonHandlingService; private final JsonHandlingService jsonHandlingService;
public UserServiceImpl(AuthorizationService authorizationService, public UserServiceImpl(AuthorizationService authorizationService,
DeleterFactory deleterFactory, DeleterFactory deleterFactory,
ConventionService conventionService, ConventionService conventionService,
EntityManager entityManager, TenantEntityManager entityManager,
BuilderFactory builderFactory, BuilderFactory builderFactory, QueryFactory queryFactory,
QueryFactory queryFactory,
JsonHandlingService jsonHandlingService) { JsonHandlingService jsonHandlingService) {
this.authorizationService = authorizationService; this.authorizationService = authorizationService;
this.deleterFactory = deleterFactory; this.deleterFactory = deleterFactory;
@ -94,11 +99,6 @@ public class UserServiceImpl implements UserService {
this.entityManager.persist(data); this.entityManager.persist(data);
for (UserTouchedIntegrationEvent.UserContactInfo eventC : model.getUserContactInfo()) {
this.entityManager.persist(this.buildContactInfoEntityFromEventData(eventC, model.getId()));
}
this.entityManager.persist(this.buildUserCredentialEntityFromEventData(model));
} else { } else {
data.setName(model.getName()); data.setName(model.getName());
data.setAdditionalInfo(this.jsonHandlingService.toJson(model.getProfile())); data.setAdditionalInfo(this.jsonHandlingService.toJson(model.getProfile()));
@ -114,6 +114,12 @@ public class UserServiceImpl implements UserService {
this.entityManager.flush(); this.entityManager.flush();
this.persistContactInfo(model.getUserContactInfo(), data.getId());
this.persistUserCredential(model.getCredentials(), data.getId());
this.persistTenantUser(model.getTenantUsers(), data.getId());
this.entityManager.flush();
return this.builderFactory.builder(UserBuilder.class).authorize(EnumSet.of(AuthorizationFlags.None)).build(BaseFieldSet.build(fields, User._id), data); return this.builderFactory.builder(UserBuilder.class).authorize(EnumSet.of(AuthorizationFlags.None)).build(BaseFieldSet.build(fields, User._id), data);
} }
@ -126,30 +132,92 @@ public class UserServiceImpl implements UserService {
this.deleterFactory.deleter(UserDeleter.class).deleteAndSaveByIds(List.of(id)); this.deleterFactory.deleter(UserDeleter.class).deleteAndSaveByIds(List.of(id));
} }
private UserContactInfoEntity buildContactInfoEntityFromEventData(UserTouchedIntegrationEvent.UserContactInfo eventC, UUID userId) { private void persistContactInfo(List<UserTouchedIntegrationEvent.UserContactInfo> models, UUID userId) throws InvalidApplicationException {
UserContactInfoEntity contactInfo = new UserContactInfoEntity(); List<UserContactInfoEntity> items = this.queryFactory.query(UserContactInfoQuery.class)
contactInfo.setId(UUID.randomUUID()); .userIds(userId)
contactInfo.setUserId(userId); .collect();
contactInfo.setType(eventC.getType()); List<UUID> updatedCreatedIds = new ArrayList<>();
contactInfo.setValue(eventC.getValue()); if (models != null) {
contactInfo.setOrdinal(eventC.getOrdinal()); for (UserTouchedIntegrationEvent.UserContactInfo model : models) {
contactInfo.setCreatedAt(Instant.now()); UserContactInfoEntity data = items.stream().filter(x -> x.getType().equals(model.getType()) && x.getValue().equals(model.getValue())).findFirst().orElse(null);
contactInfo.setUpdatedAt(Instant.now()); if (data == null) {
contactInfo.setIsActive(IsActive.Active); data = new UserContactInfoEntity();
data.setId(UUID.randomUUID());
data.setUserId(userId);
data.setType(model.getType());
data.setValue(model.getValue());
data.setOrdinal(model.getOrdinal());
data.setCreatedAt(Instant.now());
data.setUpdatedAt(Instant.now());
data.setIsActive(IsActive.Active);
entityManager.persist(data);
} else {
data.setOrdinal(model.getOrdinal());
entityManager.merge(data);
}
updatedCreatedIds.add(data.getId());
}
}
List<UserContactInfoEntity> toDelete = items.stream().filter(x -> updatedCreatedIds.stream().noneMatch(y -> y.equals(x.getId()))).collect(Collectors.toList());
deleterFactory.deleter(UserContactInfoDeleter.class).delete(toDelete);
return contactInfo; entityManager.flush();
} }
private UserCredentialEntity buildUserCredentialEntityFromEventData(UserTouchedIntegrationEvent event) { private void persistUserCredential(List<UserTouchedIntegrationEvent.UserCredential> models, UUID userId) throws InvalidApplicationException {
UserCredentialEntity credentialEntity = new UserCredentialEntity(); List<UserCredentialEntity> items = this.queryFactory.query(UserCredentialQuery.class)
credentialEntity.setId(UUID.randomUUID()); .userIds(userId)
credentialEntity.setUserId(event.getId()); .isActive(IsActive.Active)
credentialEntity.setExternalId(event.getSubjectId()); .collect();
credentialEntity.setCreatedAt(Instant.now()); List<UUID> updatedCreatedIds = new ArrayList<>();
credentialEntity.setUpdatedAt(Instant.now()); if (models != null) {
credentialEntity.setIsActive(IsActive.Active); for (UserTouchedIntegrationEvent.UserCredential model : models) {
UserCredentialEntity data = items.stream().filter(x -> x.getExternalId().equals(model.getSubjectId())).findFirst().orElse(null);
if (data == null) {
data = new UserCredentialEntity();
data.setId(UUID.randomUUID());
data.setUserId(userId);
data.setExternalId(model.getSubjectId());
data.setCreatedAt(Instant.now());
data.setUpdatedAt(Instant.now());
data.setIsActive(IsActive.Active);
entityManager.persist(data);
}
updatedCreatedIds.add(data.getId());
}
}
List<UserCredentialEntity> toDelete = items.stream().filter(x -> updatedCreatedIds.stream().noneMatch(y -> y.equals(x.getId()))).collect(Collectors.toList());
deleterFactory.deleter(UserCredentialDeleter.class).delete(toDelete);
return credentialEntity; entityManager.flush();
}
private void persistTenantUser(List<UserTouchedIntegrationEvent.TenantUser> models, UUID userId) throws InvalidApplicationException {
List<TenantUserEntity> items = this.queryFactory.query(TenantUserQuery.class)
.userIds(userId)
.isActive(IsActive.Active)
.collect();
List<UUID> updatedCreatedIds = new ArrayList<>();
if (models != null) {
for (UserTouchedIntegrationEvent.TenantUser model : models) {
TenantUserEntity data = items.stream().filter(x -> x.getTenantId().equals(model.getTenant())).findFirst().orElse(null);
if (data == null) {
data = new TenantUserEntity();
data.setId(UUID.randomUUID());
data.setUserId(userId);
data.setTenantId(model.getTenant());
data.setCreatedAt(Instant.now());
data.setUpdatedAt(Instant.now());
data.setIsActive(IsActive.Active);
entityManager.persist(data);
}
updatedCreatedIds.add(data.getId());
}
}
List<TenantUserEntity> toDelete = items.stream().filter(x -> updatedCreatedIds.stream().noneMatch(y -> y.equals(x.getId()))).collect(Collectors.toList());
deleterFactory.deleter(TenantUserDeleter.class).delete(toDelete);
entityManager.flush();
} }
} }

View File

@ -109,4 +109,12 @@ public class TenantEntityManager {
.disableFilter(TenantScopedBaseEntity.DEFAULT_TENANT_FILTER); .disableFilter(TenantScopedBaseEntity.DEFAULT_TENANT_FILTER);
} }
public EntityManager getEntityManager() {
return entityManager;
}
public void setEntityManager(EntityManager entityManager) {
this.entityManager = entityManager;
}
} }

View File

@ -21,11 +21,9 @@ public class AppRabbitConfigurer extends RabbitConfigurer {
private ApplicationContext applicationContext; private ApplicationContext applicationContext;
private InboxProperties inboxProperties;
public AppRabbitConfigurer(ApplicationContext applicationContext, InboxProperties inboxProperties) { public AppRabbitConfigurer(ApplicationContext applicationContext) {
this.applicationContext = applicationContext; this.applicationContext = applicationContext;
this.inboxProperties = inboxProperties;
} }
// @Bean // @Bean

View File

@ -11,6 +11,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;
@ -233,10 +234,10 @@ 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());
queueMessage.setTenantId(null); Object tenantId = inboxCreatorParams.getHeaders() != null ? inboxCreatorParams.getHeaders().getOrDefault(IntegrationEventMessageConstants.TENANT, null) : null;
if (tenantId instanceof UUID) queueMessage.setTenantId((UUID) tenantId);
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());

View File

@ -275,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) {
@ -319,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) {
@ -349,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 {
@ -369,7 +368,6 @@ public class OutboxRepositoryImpl implements OutboxRepository {
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) if (transaction != null)
transaction.rollback(); transaction.rollback();
success = false;
} finally { } finally {
if (entityManager != null) if (entityManager != null)
entityManager.close(); entityManager.close();
@ -453,7 +451,7 @@ public class OutboxRepositoryImpl implements OutboxRepository {
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());

View File

@ -14,17 +14,11 @@ import org.springframework.web.context.annotation.RequestScope;
public class OutboxServiceImpl implements OutboxService { public class OutboxServiceImpl implements OutboxService {
private static final LoggerService logger = new LoggerService(LoggerFactory.getLogger(OutboxServiceImpl.class)); private static final LoggerService logger = new LoggerService(LoggerFactory.getLogger(OutboxServiceImpl.class));
private final OutboxProperties config;
private final JsonHandlingService jsonHandlingService;
private final ApplicationEventPublisher eventPublisher; private final ApplicationEventPublisher eventPublisher;
public OutboxServiceImpl( public OutboxServiceImpl(
OutboxProperties config,
JsonHandlingService jsonHandlingService,
ApplicationEventPublisher eventPublisher ApplicationEventPublisher eventPublisher
) { ) {
this.config = config;
this.jsonHandlingService = jsonHandlingService;
this.eventPublisher = eventPublisher; this.eventPublisher = eventPublisher;
} }

View File

@ -1,9 +1,10 @@
package eu.eudat.integrationevent.outbox.annotationentityremoval; package eu.eudat.integrationevent.outbox.annotationentityremoval;
import javax.management.InvalidApplicationException;
import java.util.UUID; import java.util.UUID;
public interface AnnotationEntityRemovalIntegrationEventHandler { public interface AnnotationEntityRemovalIntegrationEventHandler {
void handleDescription(UUID descriptionId); void handleDescription(UUID descriptionId) throws InvalidApplicationException;
void handleDmp(UUID dmpId); void handleDmp(UUID dmpId) throws InvalidApplicationException;
} }

View File

@ -1,6 +1,7 @@
package eu.eudat.integrationevent.outbox.annotationentityremoval; package eu.eudat.integrationevent.outbox.annotationentityremoval;
import eu.eudat.commons.enums.IsActive; import eu.eudat.commons.enums.IsActive;
import eu.eudat.commons.scope.tenant.TenantScope;
import eu.eudat.data.DescriptionEntity; import eu.eudat.data.DescriptionEntity;
import eu.eudat.data.DmpUserEntity; import eu.eudat.data.DmpUserEntity;
import eu.eudat.integrationevent.outbox.OutboxIntegrationEvent; import eu.eudat.integrationevent.outbox.OutboxIntegrationEvent;
@ -17,6 +18,7 @@ import org.springframework.beans.factory.config.ConfigurableBeanFactory;
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.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.UUID; import java.util.UUID;
@ -30,22 +32,25 @@ public class AnnotationEntityRemovalIntegrationEventHandlerImpl implements Annot
private final OutboxService outboxService; private final OutboxService outboxService;
private final QueryFactory queryFactory; private final QueryFactory queryFactory;
private final TenantScope tenantScope;
public AnnotationEntityRemovalIntegrationEventHandlerImpl(OutboxService outboxService, QueryFactory queryFactory) { public AnnotationEntityRemovalIntegrationEventHandlerImpl(OutboxService outboxService, QueryFactory queryFactory, TenantScope tenantScope) {
this.outboxService = outboxService; this.outboxService = outboxService;
this.queryFactory = queryFactory; this.queryFactory = queryFactory;
this.tenantScope = tenantScope;
} }
private void handle(AnnotationEntitiesRemovalIntegrationEvent event) { private void handle(AnnotationEntitiesRemovalIntegrationEvent event) throws InvalidApplicationException {
OutboxIntegrationEvent message = new OutboxIntegrationEvent(); OutboxIntegrationEvent message = new OutboxIntegrationEvent();
message.setMessageId(UUID.randomUUID()); message.setMessageId(UUID.randomUUID());
message.setType(OutboxIntegrationEvent.ANNOTATION_ENTITY_REMOVE); message.setType(OutboxIntegrationEvent.ANNOTATION_ENTITY_REMOVE);
message.setEvent(event); message.setEvent(event);
if (this.tenantScope.isSet()) message.setTenantId(tenantScope.getTenant());
this.outboxService.publish(message); this.outboxService.publish(message);
} }
@Override @Override
public void handleDescription(UUID descriptionId) { public void handleDescription(UUID descriptionId) throws InvalidApplicationException {
AnnotationEntitiesRemovalIntegrationEvent event = new AnnotationEntitiesRemovalIntegrationEvent(); AnnotationEntitiesRemovalIntegrationEvent event = new AnnotationEntitiesRemovalIntegrationEvent();
event.setEntityIds(List.of(descriptionId)); event.setEntityIds(List.of(descriptionId));
@ -53,7 +58,7 @@ public class AnnotationEntityRemovalIntegrationEventHandlerImpl implements Annot
} }
@Override @Override
public void handleDmp(UUID dmpId) { public void handleDmp(UUID dmpId) throws InvalidApplicationException {
List<DescriptionEntity> descriptionEntities = this.queryFactory.query(DescriptionQuery.class).dmpIds(dmpId).collectAs(new BaseFieldSet().ensure(Description._id)); List<DescriptionEntity> descriptionEntities = this.queryFactory.query(DescriptionQuery.class).dmpIds(dmpId).collectAs(new BaseFieldSet().ensure(Description._id));
AnnotationEntitiesRemovalIntegrationEvent event = new AnnotationEntitiesRemovalIntegrationEvent(); AnnotationEntitiesRemovalIntegrationEvent event = new AnnotationEntitiesRemovalIntegrationEvent();

View File

@ -36,29 +36,31 @@ public class AnnotationEntityTouchedIntegrationEventHandlerImpl implements Annot
this.queryFactory = queryFactory; this.queryFactory = queryFactory;
} }
private void handle(AnnotationEntitiesTouchedIntegrationEvent event) { private void handle(AnnotationEntitiesTouchedIntegrationEvent event, UUID tenantId) {
OutboxIntegrationEvent message = new OutboxIntegrationEvent(); OutboxIntegrationEvent message = new OutboxIntegrationEvent();
message.setMessageId(UUID.randomUUID()); message.setMessageId(UUID.randomUUID());
message.setType(OutboxIntegrationEvent.ANNOTATION_ENTITY_TOUCH); message.setType(OutboxIntegrationEvent.ANNOTATION_ENTITY_TOUCH);
message.setEvent(event); message.setEvent(event);
message.setTenantId(tenantId);
this.outboxService.publish(message); this.outboxService.publish(message);
} }
@Override @Override
public void handleDescription(UUID descriptionId) { public void handleDescription(UUID descriptionId) {
DescriptionEntity entity = this.queryFactory.query(DescriptionQuery.class).ids(descriptionId).firstAs(new BaseFieldSet().ensure(Description._dmp)); DescriptionEntity entity = this.queryFactory.query(DescriptionQuery.class).ids(descriptionId).firstAs(new BaseFieldSet().ensure(Description._dmp).ensure(DescriptionEntity._tenantId));
if (entity == null) return; if (entity == null) return;
List<DmpUserEntity> dmpUsers = this.queryFactory.query(DmpUserQuery.class).dmpIds(entity.getDmpId()).isActives(IsActive.Active).collectAs(new BaseFieldSet().ensure(DmpUser._user)); List<DmpUserEntity> dmpUsers = this.queryFactory.query(DmpUserQuery.class).dmpIds(entity.getDmpId()).isActives(IsActive.Active).collectAs(new BaseFieldSet().ensure(DmpUser._user));
AnnotationEntitiesTouchedIntegrationEvent event = new AnnotationEntitiesTouchedIntegrationEvent(); AnnotationEntitiesTouchedIntegrationEvent event = new AnnotationEntitiesTouchedIntegrationEvent();
event.setEvents(List.of(this.buildEventItem(descriptionId, dmpUsers))); event.setEvents(List.of(this.buildEventItem(descriptionId, dmpUsers)));
this.handle(event); this.handle(event, entity.getTenantId());
} }
@Override @Override
public void handleDmp(UUID dmpId) { public void handleDmp(UUID dmpId) {
List<DescriptionEntity> descriptionEntities = this.queryFactory.query(DescriptionQuery.class).dmpIds(dmpId).collectAs(new BaseFieldSet().ensure(Description._id)); List<DescriptionEntity> descriptionEntities = this.queryFactory.query(DescriptionQuery.class).dmpIds(dmpId).collectAs(new BaseFieldSet().ensure(Description._id));
if (descriptionEntities == null || descriptionEntities.isEmpty()) return;
List<DmpUserEntity> dmpUsers = this.queryFactory.query(DmpUserQuery.class).dmpIds(dmpId).isActives(IsActive.Active).collectAs(new BaseFieldSet().ensure(DmpUser._user)); List<DmpUserEntity> dmpUsers = this.queryFactory.query(DmpUserQuery.class).dmpIds(dmpId).isActives(IsActive.Active).collectAs(new BaseFieldSet().ensure(DmpUser._user));
AnnotationEntitiesTouchedIntegrationEvent event = new AnnotationEntitiesTouchedIntegrationEvent(); AnnotationEntitiesTouchedIntegrationEvent event = new AnnotationEntitiesTouchedIntegrationEvent();
@ -67,7 +69,7 @@ public class AnnotationEntityTouchedIntegrationEventHandlerImpl implements Annot
for (DescriptionEntity description : descriptionEntities) event.getEvents().add(this.buildEventItem(description.getId(), dmpUsers)); for (DescriptionEntity description : descriptionEntities) event.getEvents().add(this.buildEventItem(description.getId(), dmpUsers));
this.handle(event); this.handle(event, descriptionEntities.getFirst().getTenantId());
} }
private AnnotationEntitiesTouchedIntegrationEvent.AnnotationEntityTouchedIntegrationEvent buildEventItem(UUID entityId, List<DmpUserEntity> dmpUsers){ private AnnotationEntitiesTouchedIntegrationEvent.AnnotationEntityTouchedIntegrationEvent buildEventItem(UUID entityId, List<DmpUserEntity> dmpUsers){

View File

@ -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;
} }

View File

@ -1,5 +1,6 @@
package eu.eudat.integrationevent.outbox.notification; package eu.eudat.integrationevent.outbox.notification;
import eu.eudat.commons.scope.tenant.TenantScope;
import eu.eudat.integrationevent.outbox.OutboxIntegrationEvent; import eu.eudat.integrationevent.outbox.OutboxIntegrationEvent;
import eu.eudat.integrationevent.outbox.OutboxService; import eu.eudat.integrationevent.outbox.OutboxService;
import gr.cite.tools.logging.LoggerService; import gr.cite.tools.logging.LoggerService;
@ -8,6 +9,7 @@ import org.springframework.beans.factory.annotation.Autowired;
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 java.util.UUID; import java.util.UUID;
@Component @Component
@ -17,19 +19,22 @@ public class NotifyIntegrationEventHandlerImpl implements NotifyIntegrationEvent
private static final LoggerService logger = new LoggerService(LoggerFactory.getLogger(NotifyIntegrationEventHandlerImpl.class)); private static final LoggerService logger = new LoggerService(LoggerFactory.getLogger(NotifyIntegrationEventHandlerImpl.class));
private final OutboxService outboxService; private final OutboxService outboxService;
private final TenantScope tenantScope;
@Autowired @Autowired
public NotifyIntegrationEventHandlerImpl( public NotifyIntegrationEventHandlerImpl(
OutboxService outboxService) { OutboxService outboxService, TenantScope tenantScope) {
this.outboxService = outboxService; this.outboxService = outboxService;
this.tenantScope = tenantScope;
} }
@Override @Override
public void handle(NotifyIntegrationEvent event) { public void handle(NotifyIntegrationEvent event) throws InvalidApplicationException {
OutboxIntegrationEvent message = new OutboxIntegrationEvent(); OutboxIntegrationEvent message = new OutboxIntegrationEvent();
message.setMessageId(UUID.randomUUID()); message.setMessageId(UUID.randomUUID());
message.setType(OutboxIntegrationEvent.NOTIFY); message.setType(OutboxIntegrationEvent.NOTIFY);
message.setEvent(event); message.setEvent(event);
if (this.tenantScope.isSet()) message.setTenantId(tenantScope.getTenant());
this.outboxService.publish(message); this.outboxService.publish(message);
} }
} }

View File

@ -40,6 +40,7 @@ public class TenantRemovalIntegrationEventHandlerImpl implements TenantRemovalIn
message.setMessageId(UUID.randomUUID()); message.setMessageId(UUID.randomUUID());
message.setType(OutboxIntegrationEvent.TENANT_REMOVE); message.setType(OutboxIntegrationEvent.TENANT_REMOVE);
message.setEvent(event); message.setEvent(event);
message.setTenantId(event.getId());
this.outboxService.publish(message); this.outboxService.publish(message);
} }
@ -55,6 +56,7 @@ public class TenantRemovalIntegrationEventHandlerImpl implements TenantRemovalIn
TenantRemovalIntegrationEvent event = new TenantRemovalIntegrationEvent(); TenantRemovalIntegrationEvent event = new TenantRemovalIntegrationEvent();
event.setId(tenantId); event.setId(tenantId);
message.setEvent(event); message.setEvent(event);
message.setTenantId(event.getId());
this.outboxService.publish(message); this.outboxService.publish(message);
} }

View File

@ -1,5 +1,7 @@
package eu.eudat.integrationevent.outbox.tenanttouched; package eu.eudat.integrationevent.outbox.tenanttouched;
import javax.management.InvalidApplicationException;
public interface TenantTouchedIntegrationEventHandler { public interface TenantTouchedIntegrationEventHandler {
void handle(TenantTouchedIntegrationEvent event); void handle(TenantTouchedIntegrationEvent event);

View File

@ -1,10 +1,26 @@
package eu.eudat.integrationevent.outbox.tenanttouched; package eu.eudat.integrationevent.outbox.tenanttouched;
import eu.eudat.commons.scope.tenant.TenantScope;
import eu.eudat.integrationevent.outbox.OutboxIntegrationEvent;
import eu.eudat.integrationevent.outbox.OutboxService;
import java.util.UUID;
public class TenantTouchedIntegrationEventHandlerImpl implements TenantTouchedIntegrationEventHandler { public class TenantTouchedIntegrationEventHandlerImpl implements TenantTouchedIntegrationEventHandler {
private final OutboxService outboxService;
public TenantTouchedIntegrationEventHandlerImpl(OutboxService outboxService) {
this.outboxService = outboxService;
}
@Override @Override
public void handle(TenantTouchedIntegrationEvent event) { public void handle(TenantTouchedIntegrationEvent event) {
OutboxIntegrationEvent message = new OutboxIntegrationEvent();
message.setMessageId(UUID.randomUUID());
message.setType(OutboxIntegrationEvent.TENANT_TOUCH);
message.setTenantId(event.getId());
message.setEvent(event);
this.outboxService.publish(message);
} }
} }

View File

@ -8,8 +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;
} }
@ -18,11 +16,4 @@ public class UserRemovalIntegrationEvent extends TrackedEvent {
this.userId = userId; this.userId = userId;
} }
public UUID getTenant() {
return tenant;
}
public void setTenant(UUID tenant) {
this.tenant = tenant;
}
} }

View File

@ -1,9 +1,10 @@
package eu.eudat.integrationevent.outbox.userremoval; package eu.eudat.integrationevent.outbox.userremoval;
import javax.management.InvalidApplicationException;
import java.util.UUID; import java.util.UUID;
public interface UserRemovalIntegrationEventHandler { public interface UserRemovalIntegrationEventHandler {
void handle(UUID userId); void handle(UUID userId) throws InvalidApplicationException;
} }

View File

@ -1,5 +1,6 @@
package eu.eudat.integrationevent.outbox.userremoval; package eu.eudat.integrationevent.outbox.userremoval;
import eu.eudat.commons.scope.tenant.TenantScope;
import eu.eudat.data.UserEntity; import eu.eudat.data.UserEntity;
import eu.eudat.integrationevent.outbox.OutboxIntegrationEvent; import eu.eudat.integrationevent.outbox.OutboxIntegrationEvent;
import eu.eudat.integrationevent.outbox.OutboxService; import eu.eudat.integrationevent.outbox.OutboxService;
@ -14,6 +15,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.UUID; import java.util.UUID;
@Component("outboxuserremovalintegrationeventhandler") @Component("outboxuserremovalintegrationeventhandler")
@ -25,14 +27,16 @@ public class UserRemovalIntegrationEventHandlerImpl implements UserRemovalIntegr
private final OutboxService outboxService; private final OutboxService outboxService;
private final ApplicationContext applicationContext; private final ApplicationContext applicationContext;
private final TenantScope tenantScope;
public UserRemovalIntegrationEventHandlerImpl(OutboxService outboxService, ApplicationContext applicationContext) { public UserRemovalIntegrationEventHandlerImpl(OutboxService outboxService, ApplicationContext applicationContext, TenantScope tenantScope) {
this.outboxService = outboxService; this.outboxService = outboxService;
this.applicationContext = applicationContext; this.applicationContext = applicationContext;
this.tenantScope = tenantScope;
} }
@Override @Override
public void handle(UUID userId) { public void handle(UUID userId) throws InvalidApplicationException {
UserRemovalConsistencyHandler userRemovalConsistencyHandler = this.applicationContext.getBean(UserRemovalConsistencyHandler.class); UserRemovalConsistencyHandler userRemovalConsistencyHandler = this.applicationContext.getBean(UserRemovalConsistencyHandler.class);
if (!userRemovalConsistencyHandler.isConsistent(new UserRemovalConsistencyPredicates(userId))) if (!userRemovalConsistencyHandler.isConsistent(new UserRemovalConsistencyPredicates(userId)))
return; return;
@ -40,9 +44,9 @@ public class UserRemovalIntegrationEventHandlerImpl implements UserRemovalIntegr
OutboxIntegrationEvent message = new OutboxIntegrationEvent(); OutboxIntegrationEvent message = new OutboxIntegrationEvent();
message.setMessageId(UUID.randomUUID()); message.setMessageId(UUID.randomUUID());
message.setType(OutboxIntegrationEvent.USER_REMOVE); message.setType(OutboxIntegrationEvent.USER_REMOVE);
if (this.tenantScope.isSet()) message.setTenantId(tenantScope.getTenant());
UserRemovalIntegrationEvent event = new UserRemovalIntegrationEvent(); UserRemovalIntegrationEvent event = new UserRemovalIntegrationEvent();
event.setUserId(userId); event.setUserId(userId);
event.setTenant(null); //TODO
message.setEvent(event); message.setEvent(event);
this.outboxService.publish(message); this.outboxService.publish(message);

View File

@ -2,6 +2,7 @@ package eu.eudat.integrationevent.outbox.usertouched;
import eu.eudat.commons.enums.ContactInfoType; import eu.eudat.commons.enums.ContactInfoType;
import eu.eudat.integrationevent.TrackedEvent; import eu.eudat.integrationevent.TrackedEvent;
import eu.eudat.model.UserContactInfo;
import java.util.List; import java.util.List;
import java.util.UUID; import java.util.UUID;
@ -10,15 +11,13 @@ public class UserTouchedIntegrationEvent extends TrackedEvent {
private UUID id; private UUID id;
private UUID tenant;
private String name; private String name;
private String subjectId;
private UserProfile profile; private UserProfile profile;
private List<UserContactInfo> userContactInfo; private List<UserContactInfo> userContactInfo;
private List<TenantUser> tenantUsers;
private List<UserCredential> credentials;
public UUID getId() { public UUID getId() {
return id; return id;
@ -28,14 +27,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;
} }
@ -44,13 +35,6 @@ public class UserTouchedIntegrationEvent extends TrackedEvent {
this.name = name; this.name = name;
} }
public String getSubjectId() {
return subjectId;
}
public void setSubjectId(String subjectId) {
this.subjectId = subjectId;
}
public UserProfile getProfile() { public UserProfile getProfile() {
return profile; return profile;
@ -68,6 +52,22 @@ public class UserTouchedIntegrationEvent extends TrackedEvent {
this.userContactInfo = userContactInfo; this.userContactInfo = userContactInfo;
} }
public List<TenantUser> getTenantUsers() {
return tenantUsers;
}
public void setTenantUsers(List<TenantUser> tenantUsers) {
this.tenantUsers = tenantUsers;
}
public List<UserCredential> getCredentials() {
return credentials;
}
public void setCredentials(List<UserCredential> credentials) {
this.credentials = credentials;
}
public static class UserProfile { public static class UserProfile {
private String timezone; private String timezone;
@ -133,4 +133,32 @@ public class UserTouchedIntegrationEvent extends TrackedEvent {
} }
} }
public static class UserCredential {
private String subjectId;
public String getSubjectId() {
return subjectId;
}
public void setSubjectId(String subjectId) {
this.subjectId = subjectId;
}
}
public static class TenantUser {
private UUID tenant;
public UUID getTenant() {
return tenant;
}
public void setTenant(UUID tenant) {
this.tenant = tenant;
}
}
} }

View File

@ -1,9 +1,10 @@
package eu.eudat.integrationevent.outbox.usertouched; package eu.eudat.integrationevent.outbox.usertouched;
import javax.management.InvalidApplicationException;
import java.util.UUID; import java.util.UUID;
public interface UserTouchedIntegrationEventHandler { public interface UserTouchedIntegrationEventHandler {
void handle(UUID userId); void handle(UUID userId) throws InvalidApplicationException;
} }

View File

@ -1,20 +1,18 @@
package eu.eudat.integrationevent.outbox.usertouched; package eu.eudat.integrationevent.outbox.usertouched;
import eu.eudat.commons.JsonHandlingService; import eu.eudat.commons.JsonHandlingService;
import eu.eudat.commons.scope.tenant.TenantScope;
import eu.eudat.commons.types.user.AdditionalInfoEntity; import eu.eudat.commons.types.user.AdditionalInfoEntity;
import eu.eudat.data.UserContactInfoEntity; import eu.eudat.data.*;
import eu.eudat.data.UserCredentialEntity; import eu.eudat.elastic.data.DmpElasticEntity;
import eu.eudat.data.UserEntity; import eu.eudat.elastic.elasticbuilder.DmpElasticBuilder;
import eu.eudat.integrationevent.outbox.OutboxIntegrationEvent; import eu.eudat.integrationevent.outbox.OutboxIntegrationEvent;
import eu.eudat.integrationevent.outbox.OutboxService; import eu.eudat.integrationevent.outbox.OutboxService;
import eu.eudat.model.Reference; import eu.eudat.model.*;
import eu.eudat.model.User;
import eu.eudat.model.UserContactInfo;
import eu.eudat.model.UserCredential;
import eu.eudat.model.builder.UserAdditionalInfoBuilder; import eu.eudat.model.builder.UserAdditionalInfoBuilder;
import eu.eudat.query.UserContactInfoQuery; import eu.eudat.query.*;
import eu.eudat.query.UserCredentialQuery; import gr.cite.tools.data.query.Ordering;
import eu.eudat.query.UserQuery; import gr.cite.tools.data.query.Paging;
import gr.cite.tools.data.query.QueryFactory; import gr.cite.tools.data.query.QueryFactory;
import gr.cite.tools.exception.MyNotFoundException; import gr.cite.tools.exception.MyNotFoundException;
import gr.cite.tools.fieldset.BaseFieldSet; import gr.cite.tools.fieldset.BaseFieldSet;
@ -24,8 +22,10 @@ import org.springframework.beans.factory.config.ConfigurableBeanFactory;
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;
import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import javax.management.InvalidApplicationException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.UUID; import java.util.UUID;
@ -39,21 +39,29 @@ public class UserTouchedIntegrationEventHandlerImpl implements UserTouchedIntegr
private final OutboxService outboxService; private final OutboxService outboxService;
private final JsonHandlingService jsonHandlingService; private final JsonHandlingService jsonHandlingService;
private final MessageSource messageSource; private final MessageSource messageSource;
private final TenantScope tenantScope;
private final TenantEntityManager entityManager;
private final QueryFactory queryFactory; private final QueryFactory queryFactory;
public UserTouchedIntegrationEventHandlerImpl( public UserTouchedIntegrationEventHandlerImpl(
OutboxService outboxService, JsonHandlingService jsonHandlingService, MessageSource messageSource, QueryFactory queryFactory) { OutboxService outboxService, JsonHandlingService jsonHandlingService, MessageSource messageSource, TenantScope tenantScope, TenantEntityManager entityManager, QueryFactory queryFactory) {
this.outboxService = outboxService; this.outboxService = outboxService;
this.jsonHandlingService = jsonHandlingService; this.jsonHandlingService = jsonHandlingService;
this.messageSource = messageSource; this.messageSource = messageSource;
this.tenantScope = tenantScope;
this.entityManager = entityManager;
this.queryFactory = queryFactory; this.queryFactory = queryFactory;
} }
@Override @Override
public void handle(UUID userId) { public void handle(UUID userId) throws InvalidApplicationException {
OutboxIntegrationEvent message = new OutboxIntegrationEvent(); OutboxIntegrationEvent message = new OutboxIntegrationEvent();
message.setMessageId(UUID.randomUUID()); message.setMessageId(UUID.randomUUID());
message.setType(OutboxIntegrationEvent.USER_TOUCH); message.setType(OutboxIntegrationEvent.USER_TOUCH);
if (this.tenantScope.isSet()) message.setTenantId(tenantScope.getTenant());
try {
this.entityManager.disableTenantFilters();
UserEntity user = this.queryFactory.query(UserQuery.class).ids(userId) UserEntity user = this.queryFactory.query(UserQuery.class).ids(userId)
.firstAs(new BaseFieldSet().ensure(User._name).ensure(User._additionalInfo)); .firstAs(new BaseFieldSet().ensure(User._name).ensure(User._additionalInfo));
@ -65,22 +73,40 @@ public class UserTouchedIntegrationEventHandlerImpl implements UserTouchedIntegr
List<UserCredentialEntity> userCredentialEntities = this.queryFactory.query(UserCredentialQuery.class).userIds(userId) List<UserCredentialEntity> userCredentialEntities = this.queryFactory.query(UserCredentialQuery.class).userIds(userId)
.collectAs(new BaseFieldSet().ensure(UserCredential._id, UserCredential._externalId)); .collectAs(new BaseFieldSet().ensure(UserCredential._id, UserCredential._externalId));
List<TenantUserEntity> tenantUserEntities = this.queryFactory.query(TenantUserQuery.class).userIds(userId)
.collectAs(new BaseFieldSet().ensure(TenantUser._id, TenantUser._tenant));
UserTouchedIntegrationEvent event = new UserTouchedIntegrationEvent(); UserTouchedIntegrationEvent event = new UserTouchedIntegrationEvent();
event.setId(userId); event.setId(userId);
event.setTenant(null); //TODO
event.setName(user.getName()); event.setName(user.getName());
if (userCredentialEntities != null && !userCredentialEntities.isEmpty()) if (userCredentialEntities != null && !userCredentialEntities.isEmpty()) {
event.setSubjectId(userCredentialEntities.getFirst().getExternalId()); event.setCredentials(new ArrayList<>());
event.setProfile(new UserTouchedIntegrationEvent.UserProfile()); for (UserCredentialEntity userCredential : userCredentialEntities){
UserTouchedIntegrationEvent.UserCredential userCredentialEvent = new UserTouchedIntegrationEvent.UserCredential();
userCredentialEvent.setSubjectId(userCredential.getExternalId());
event.getCredentials().add(userCredentialEvent);
}
}
if (tenantUserEntities != null && !tenantUserEntities.isEmpty()) {
event.setTenantUsers(new ArrayList<>());
for (TenantUserEntity tenantUserEntity : tenantUserEntities){
UserTouchedIntegrationEvent.TenantUser tenantUser = new UserTouchedIntegrationEvent.TenantUser();
tenantUser.setTenant(tenantUserEntity.getTenantId());
event.getTenantUsers().add(tenantUser);
}
}
AdditionalInfoEntity definition = this.jsonHandlingService.fromJsonSafe(AdditionalInfoEntity.class, user.getAdditionalInfo()); AdditionalInfoEntity definition = this.jsonHandlingService.fromJsonSafe(AdditionalInfoEntity.class, user.getAdditionalInfo());
if (definition != null) { if (definition != null) {
event.setProfile(new UserTouchedIntegrationEvent.UserProfile());
event.getProfile().setCulture(definition.getCulture()); event.getProfile().setCulture(definition.getCulture());
event.getProfile().setLanguage(definition.getLanguage()); event.getProfile().setLanguage(definition.getLanguage());
event.getProfile().setTimezone(definition.getTimezone()); event.getProfile().setTimezone(definition.getTimezone());
} }
if (userContactInfoEntities != null&& !userContactInfoEntities.isEmpty()){
event.setUserContactInfo(new ArrayList<>()); event.setUserContactInfo(new ArrayList<>());
if (userContactInfoEntities != null){
for (UserContactInfoEntity contactInfoEntity : userContactInfoEntities){ for (UserContactInfoEntity contactInfoEntity : userContactInfoEntities){
UserTouchedIntegrationEvent.UserContactInfo contactInfo = new UserTouchedIntegrationEvent.UserContactInfo(); UserTouchedIntegrationEvent.UserContactInfo contactInfo = new UserTouchedIntegrationEvent.UserContactInfo();
contactInfo.setType(contactInfoEntity.getType()); contactInfo.setType(contactInfoEntity.getType());
@ -91,6 +117,11 @@ public class UserTouchedIntegrationEventHandlerImpl implements UserTouchedIntegr
} }
message.setEvent(event); message.setEvent(event);
}finally {
this.entityManager.enableTenantFilters();
}
this.outboxService.publish(message); this.outboxService.publish(message);
} }
} }

View File

@ -316,6 +316,7 @@ public class DescriptionQuery extends QueryBase<DescriptionEntity> {
else if (item.prefix(Description._dmp)) return DescriptionEntity._dmpId; else if (item.prefix(Description._dmp)) return DescriptionEntity._dmpId;
else if (item.match(Description._dmp)) return DescriptionEntity._dmpId; else if (item.match(Description._dmp)) return DescriptionEntity._dmpId;
else if (item.match(Description._belongsToCurrentTenant)) return DescriptionEntity._tenantId; else if (item.match(Description._belongsToCurrentTenant)) return DescriptionEntity._tenantId;
else if (item.match(DescriptionEntity._tenantId)) return DescriptionEntity._tenantId;
else return null; else return null;
} }

View File

@ -164,16 +164,25 @@ public class StorageFileQuery extends QueryBase<StorageFileEntity> {
predicates.add(queryContext.CriteriaBuilder.greaterThan(queryContext.Root.get(StorageFileEntity._createdAt), this.createdAfter)); predicates.add(queryContext.CriteriaBuilder.greaterThan(queryContext.Root.get(StorageFileEntity._createdAt), this.createdAfter));
} }
if (this.canPurge != null) { if (this.canPurge != null) {
if (this.canPurge) {
predicates.add( predicates.add(
queryContext.CriteriaBuilder.and( queryContext.CriteriaBuilder.and(
queryContext.CriteriaBuilder.isNull(queryContext.Root.get(StorageFileEntity._purgeAt)).not(), queryContext.CriteriaBuilder.isNotNull(queryContext.Root.get(StorageFileEntity._purgeAt)),
queryContext.CriteriaBuilder.lessThan(queryContext.Root.get(StorageFileEntity._purgeAt), Instant.now()) queryContext.CriteriaBuilder.lessThan(queryContext.Root.get(StorageFileEntity._purgeAt), Instant.now())
) )
); );
} else {
predicates.add(
queryContext.CriteriaBuilder.or(
queryContext.CriteriaBuilder.isNull(queryContext.Root.get(StorageFileEntity._purgeAt)),
queryContext.CriteriaBuilder.greaterThan(queryContext.Root.get(StorageFileEntity._purgeAt), Instant.now())
)
);
}
} }
if (this.isPurged != null) { if (this.isPurged != null) {
if (!this.isPurged){ if (this.isPurged){
predicates.add(queryContext.CriteriaBuilder.isNull(queryContext.Root.get(StorageFileEntity._purgedAt)).not()); predicates.add(queryContext.CriteriaBuilder.isNotNull(queryContext.Root.get(StorageFileEntity._purgedAt)));
} else { } else {
predicates.add(queryContext.CriteriaBuilder.isNull(queryContext.Root.get(StorageFileEntity._purgedAt))); predicates.add(queryContext.CriteriaBuilder.isNull(queryContext.Root.get(StorageFileEntity._purgedAt)));
} }

View File

@ -260,7 +260,6 @@ public class DescriptionTemplateServiceImpl implements DescriptionTemplateServic
private void sendDescriptionTemplateInvitationEvent(UserDescriptionTemplateEntity userDescriptionTemplate, NotificationContactType type) throws InvalidApplicationException { private void sendDescriptionTemplateInvitationEvent(UserDescriptionTemplateEntity userDescriptionTemplate, NotificationContactType type) throws InvalidApplicationException {
NotifyIntegrationEvent event = new NotifyIntegrationEvent(); NotifyIntegrationEvent event = new NotifyIntegrationEvent();
event.setTenantId(tenantScope.getTenant());
event.setUserId(userScope.getUserIdSafe()); event.setUserId(userScope.getUserIdSafe());
UserEntity user = this.entityManager.find(UserEntity.class, userDescriptionTemplate.getUserId()); UserEntity user = this.entityManager.find(UserEntity.class, userDescriptionTemplate.getUserId());

View File

@ -3,8 +3,11 @@ package eu.eudat.service.storage;
import eu.eudat.commons.fake.FakeRequestScope; import eu.eudat.commons.fake.FakeRequestScope;
import eu.eudat.commons.scope.tenant.TenantScope; import eu.eudat.commons.scope.tenant.TenantScope;
import eu.eudat.data.StorageFileEntity; import eu.eudat.data.StorageFileEntity;
import eu.eudat.data.TenantEntity;
import eu.eudat.data.TenantEntityManager;
import eu.eudat.model.StorageFile; import eu.eudat.model.StorageFile;
import eu.eudat.query.StorageFileQuery; import eu.eudat.query.StorageFileQuery;
import eu.eudat.query.TenantQuery;
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;
import gr.cite.tools.logging.LoggerService; import gr.cite.tools.logging.LoggerService;
@ -19,6 +22,7 @@ import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationListener; import org.springframework.context.ApplicationListener;
import org.springframework.context.annotation.Scope; import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.io.Closeable; import java.io.Closeable;
import java.io.IOException; import java.io.IOException;
@ -115,11 +119,9 @@ public class StorageFileCleanupTask implements Closeable, ApplicationListener<A
try { try {
QueryFactory queryFactory = this.applicationContext.getBean(QueryFactory.class); QueryFactory queryFactory = this.applicationContext.getBean(QueryFactory.class);
EntityManagerFactory entityManagerFactory = this.applicationContext.getBean(EntityManagerFactory.class); EntityManagerFactory entityManagerFactory = this.applicationContext.getBean(EntityManagerFactory.class);
StorageFileService storageFileService = this.applicationContext.getBean(StorageFileService.class);
entityManager = entityManagerFactory.createEntityManager(); entityManager = entityManagerFactory.createEntityManager();
transaction = entityManager.getTransaction(); transaction = entityManager.getTransaction();
transaction.begin(); transaction.begin();
@ -127,7 +129,22 @@ public class StorageFileCleanupTask implements Closeable, ApplicationListener<A
success = true; success = true;
if (item != null) { if (item != null) {
TenantScope tenantScope = this.applicationContext.getBean(TenantScope.class);
TenantEntityManager tenantEntityManager = this.applicationContext.getBean(TenantEntityManager.class);
tenantEntityManager.setEntityManager(entityManager);
StorageFileService storageFileService = this.applicationContext.getBean(StorageFileService.class);
try {
if (item.getTenantId() != null) {
TenantEntity tenant = queryFactory.query(TenantQuery.class).ids(item.getTenantId()).first();
tenantScope.setTempTenant(entityManager, tenant.getId(), tenant.getCode());
} else {
tenantScope.setTempTenant(entityManager, null, tenantScope.getDefaultTenantCode());
}
storageFileService.purgeSafe(fileId); storageFileService.purgeSafe(fileId);
} finally {
tenantScope.removeTempTenant(entityManager);
}
} }
transaction.commit(); transaction.commit();
@ -150,6 +167,11 @@ 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;

View File

@ -142,7 +142,7 @@ public class TenantScopeClaimInterceptor implements WebRequestInterceptor {
private UUID getTenantIdFromDatabase(String tenantCode) { private UUID getTenantIdFromDatabase(String tenantCode) {
CriteriaBuilder criteriaBuilder = this.entityManager.getCriteriaBuilder(); CriteriaBuilder criteriaBuilder = this.entityManager.getCriteriaBuilder();
CriteriaQuery<UserEntity> query = criteriaBuilder.createQuery(UserEntity.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(
@ -150,7 +150,7 @@ 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<UserEntity> results = this.entityManager.createQuery(query).getResultList(); List<TenantEntity> results = this.entityManager.createQuery(query).getResultList();
if (results.size() == 1) { if (results.size() == 1) {
return results.getFirst().getId(); return results.getFirst().getId();
} }

View File

@ -43,6 +43,7 @@ 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 java.time.Instant; import java.time.Instant;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@ -93,7 +94,7 @@ public class UserInterceptor implements WebRequestInterceptor {
} }
@Override @Override
public void preHandle(WebRequest request) throws InterruptedException { public void preHandle(WebRequest request) throws InterruptedException, InvalidApplicationException {
UUID userId = null; UUID userId = null;
if (this.currentPrincipalResolver.currentPrincipal().isAuthenticated()) { if (this.currentPrincipalResolver.currentPrincipal().isAuthenticated()) {
String subjectId = this.claimExtractor.subjectString(this.currentPrincipalResolver.currentPrincipal()); String subjectId = this.claimExtractor.subjectString(this.currentPrincipalResolver.currentPrincipal());