Adding annotation entity touch event

This commit is contained in:
Thomas Georgios Giannos 2024-03-11 15:55:52 +02:00
parent 06e6ee406b
commit 7347fbbd5a
27 changed files with 704 additions and 143 deletions

View File

@ -42,9 +42,10 @@ queue:
options: options:
exchange: null exchange: null
tenant-removal-topic: tenant.remove tenant-removal-topic: tenant.remove
tenant-touched-topic: tenant.touch tenant-touch-topic: tenant.touch
user-removal-topic: user.remove user-removal-topic: user.remove
user-touched-topic: user.touch user-touch-topic: user.touch
annotation-entity-touch-topic: annotation.entity.touch
rabbitmq: rabbitmq:
enable: false enable: false
interval-seconds: 30 interval-seconds: 30

View File

@ -51,4 +51,9 @@ public class AuditableAction {
public static final EventId Annotation_Persist = new EventId(24002, "Annotation_Persist"); public static final EventId Annotation_Persist = new EventId(24002, "Annotation_Persist");
public static final EventId Annotation_Delete = new EventId(24003, "Annotation_Delete"); public static final EventId Annotation_Delete = new EventId(24003, "Annotation_Delete");
public static final EventId Entity_User_Query = new EventId(25000, "Entity_User_Query");
public static final EventId Entity_User_Lookup = new EventId(25001, "Entity_User_Lookup");
public static final EventId Entity_User_Persist = new EventId(25002, "Entity_User_Persist");
public static final EventId Entity_User_Delete = new EventId(25003, "Entity_User_Delete");
} }

View File

@ -0,0 +1,35 @@
package gr.cite.annotation.common.validation;
import gr.cite.annotation.convention.ConventionService;
import gr.cite.annotation.errorcode.ErrorThesaurusProperties;
import gr.cite.tools.validation.specification.Specification;
import org.springframework.context.MessageSource;
import org.springframework.context.i18n.LocaleContextHolder;
import java.util.Arrays;
import java.util.List;
import java.util.UUID;
public class UuidValidator extends BaseValidator<UUID> {
private final MessageSource messageSource;
protected UuidValidator(ConventionService conventionService, ErrorThesaurusProperties errors, MessageSource messageSource) {
super(conventionService, errors);
this.messageSource = messageSource;
}
@Override
protected Class<UUID> modelClass() {
return UUID.class;
}
@Override
protected List<Specification> specifications(UUID item) {
return Arrays.asList(
this.spec()
.must(() -> this.isValidGuid(item))
.failOn("uuid").failWith(messageSource.getMessage("Validation_Required", new Object[]{"uuid"}, LocaleContextHolder.getLocale()))
);
}
}

View File

@ -33,9 +33,10 @@ public class AppRabbitConfigurer extends RabbitConfigurer {
public InboxBindings inboxBindingsCreator() { public InboxBindings inboxBindingsCreator() {
List<String> bindingItems = new ArrayList<>(); List<String> bindingItems = new ArrayList<>();
bindingItems.addAll(this.inboxProperties.getTenantRemovalTopic()); bindingItems.addAll(this.inboxProperties.getTenantRemovalTopic());
bindingItems.addAll(this.inboxProperties.getTenantTouchedTopic()); bindingItems.addAll(this.inboxProperties.getTenantTouchTopic());
bindingItems.addAll(this.inboxProperties.getUserRemovalTopic()); bindingItems.addAll(this.inboxProperties.getUserRemovalTopic());
bindingItems.addAll(this.inboxProperties.getUserTouchedTopic()); bindingItems.addAll(this.inboxProperties.getUserTouchTopic());
bindingItems.addAll(this.inboxProperties.getAnnotationEntityTouchTopic());
return new InboxBindings(bindingItems); return new InboxBindings(bindingItems);
} }

View File

@ -11,39 +11,47 @@ public class InboxProperties {
private final List<String> tenantRemovalTopic; private final List<String> tenantRemovalTopic;
private final List<String> tenantTouchedTopic; private final List<String> tenantTouchTopic;
private final List<String> userRemovalTopic; private final List<String> userRemovalTopic;
private final List<String> userTouchedTopic; private final List<String> userTouchTopic;
private final List<String> annotationEntityTouchTopic;
public InboxProperties( public InboxProperties(
String exchange, String exchange,
List<String> tenantRemovalTopic, List<String> tenantRemovalTopic,
List<String> tenantTouchedTopic, List<String> tenantTouchTopic,
List<String> userRemovalTopic, List<String> userRemovalTopic,
List<String> userTouchedTopic) { List<String> userTouchTopic,
List<String> annotationEntityTouchTopic) {
this.exchange = exchange; this.exchange = exchange;
this.tenantRemovalTopic = tenantRemovalTopic; this.tenantRemovalTopic = tenantRemovalTopic;
this.tenantTouchedTopic = tenantTouchedTopic; this.tenantTouchTopic = tenantTouchTopic;
this.userRemovalTopic = userRemovalTopic; this.userRemovalTopic = userRemovalTopic;
this.userTouchedTopic = userTouchedTopic; this.userTouchTopic = userTouchTopic;
this.annotationEntityTouchTopic = annotationEntityTouchTopic;
} }
public List<String> getTenantRemovalTopic() { public List<String> getTenantRemovalTopic() {
return tenantRemovalTopic; return tenantRemovalTopic;
} }
public List<String> getTenantTouchedTopic() { public List<String> getTenantTouchTopic() {
return tenantTouchedTopic; return tenantTouchTopic;
} }
public List<String> getUserRemovalTopic() { public List<String> getUserRemovalTopic() {
return userRemovalTopic; return userRemovalTopic;
} }
public List<String> getUserTouchedTopic() { public List<String> getUserTouchTopic() {
return userTouchedTopic; return userTouchTopic;
}
public List<String> getAnnotationEntityTouchTopic() {
return annotationEntityTouchTopic;
} }
public String getExchange() { public String getExchange() {

View File

@ -5,10 +5,11 @@ import gr.cite.annotation.common.enums.IsActive;
import gr.cite.annotation.common.scope.fake.FakeRequestScope; import gr.cite.annotation.common.scope.fake.FakeRequestScope;
import gr.cite.annotation.data.QueueInboxEntity; import gr.cite.annotation.data.QueueInboxEntity;
import gr.cite.annotation.integrationevent.TrackedEvent; import gr.cite.annotation.integrationevent.TrackedEvent;
import gr.cite.annotation.integrationevent.inbox.annotationentitytouch.AnnotationEntityTouchedIntegrationEventHandler;
import gr.cite.annotation.integrationevent.inbox.tenantremoval.TenantRemovalIntegrationEventHandler; import gr.cite.annotation.integrationevent.inbox.tenantremoval.TenantRemovalIntegrationEventHandler;
import gr.cite.annotation.integrationevent.inbox.tenanttouched.TenantTouchedIntegrationEventHandler; import gr.cite.annotation.integrationevent.inbox.tenanttouch.TenantTouchedIntegrationEventHandler;
import gr.cite.annotation.integrationevent.inbox.userremoval.UserRemovalIntegrationEventHandler; import gr.cite.annotation.integrationevent.inbox.userremoval.UserRemovalIntegrationEventHandler;
import gr.cite.annotation.integrationevent.inbox.usertouched.UserTouchedIntegrationEventHandler; import gr.cite.annotation.integrationevent.inbox.usertouch.UserTouchedIntegrationEventHandler;
import gr.cite.annotation.query.QueueInboxQuery; import gr.cite.annotation.query.QueueInboxQuery;
import gr.cite.queueinbox.entity.QueueInbox; import gr.cite.queueinbox.entity.QueueInbox;
import gr.cite.queueinbox.entity.QueueInboxStatus; import gr.cite.queueinbox.entity.QueueInboxStatus;
@ -325,12 +326,14 @@ public class InboxRepositoryImpl implements InboxRepository {
logger.debug("Processing message with routing key '{}'", routingKey); logger.debug("Processing message with routing key '{}'", routingKey);
if (this.routingKeyMatched(routingKey, this.inboxProperties.getTenantRemovalTopic())) if (this.routingKeyMatched(routingKey, this.inboxProperties.getTenantRemovalTopic()))
handler = this.applicationContext.getBean(TenantRemovalIntegrationEventHandler.class); handler = this.applicationContext.getBean(TenantRemovalIntegrationEventHandler.class);
else if (this.routingKeyMatched(routingKey, this.inboxProperties.getTenantTouchedTopic())) else if (this.routingKeyMatched(routingKey, 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(routingKey, this.inboxProperties.getUserRemovalTopic()))
handler = this.applicationContext.getBean(UserRemovalIntegrationEventHandler.class); handler = this.applicationContext.getBean(UserRemovalIntegrationEventHandler.class);
else if (this.routingKeyMatched(routingKey, this.inboxProperties.getUserTouchedTopic())) else if (this.routingKeyMatched(routingKey, this.inboxProperties.getUserTouchTopic()))
handler = this.applicationContext.getBean(UserTouchedIntegrationEventHandler.class); handler = this.applicationContext.getBean(UserTouchedIntegrationEventHandler.class);
else if (this.routingKeyMatched(routingKey, this.inboxProperties.getAnnotationEntityTouchTopic()))
handler = this.applicationContext.getBean(AnnotationEntityTouchedIntegrationEventHandler.class);
else { else {
logger.error("No handler found for message routing key '{}'. Discarding.", routingKey); logger.error("No handler found for message routing key '{}'. Discarding.", routingKey);
handler = null; handler = null;

View File

@ -0,0 +1,85 @@
package gr.cite.annotation.integrationevent.inbox.annotationentitytouch;
import gr.cite.annotation.common.validation.BaseValidator;
import gr.cite.annotation.common.validation.UuidValidator;
import gr.cite.annotation.convention.ConventionService;
import gr.cite.annotation.errorcode.ErrorThesaurusProperties;
import gr.cite.tools.validation.ValidatorFactory;
import gr.cite.tools.validation.specification.Specification;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.context.MessageSource;
import org.springframework.context.annotation.Scope;
import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.stereotype.Component;
import java.util.Arrays;
import java.util.List;
import java.util.UUID;
public class AnnotationEntityTouchedIntegrationEvent {
private UUID entityId;
public static final String _entityId = "entityId";
private List<UUID> userIds;
public static final String _userIds = "userIds";
public UUID getEntityId() {
return entityId;
}
public void setEntityId(UUID entityId) {
this.entityId = entityId;
}
public List<UUID> getUserIds() {
return userIds;
}
public void setUserIds(List<UUID> userIds) {
this.userIds = userIds;
}
@Component(AnnotationEntityTouchedIntegrationEvent.AnnotationEntityTouchedIntegrationEventValidator.ValidatorName)
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public static class AnnotationEntityTouchedIntegrationEventValidator extends BaseValidator<AnnotationEntityTouchedIntegrationEvent> {
public static final String ValidatorName = "AnnotationEntityTouchedIntegrationEventValidator";
private final MessageSource messageSource;
private final ValidatorFactory validatorFactory;
protected AnnotationEntityTouchedIntegrationEventValidator(ConventionService conventionService, ErrorThesaurusProperties errors, MessageSource messageSource, ValidatorFactory validatorFactory) {
super(conventionService, errors);
this.messageSource = messageSource;
this.validatorFactory = validatorFactory;
}
@Override
protected Class<AnnotationEntityTouchedIntegrationEvent> modelClass() {
return AnnotationEntityTouchedIntegrationEvent.class;
}
@Override
protected List<Specification> specifications(AnnotationEntityTouchedIntegrationEvent item) {
return Arrays.asList(
this.spec()
.iff(() -> !this.isNull(item.getEntityId()))
.must(() -> this.isValidGuid(item.getEntityId()))
.failOn(AnnotationEntityTouchedIntegrationEvent._entityId).failWith(messageSource.getMessage("Validation_Required", new Object[]{AnnotationEntityTouchedIntegrationEvent._entityId}, LocaleContextHolder.getLocale())),
this.spec()
.must(() -> !this.isListNullOrEmpty(item.getUserIds()))
.failOn(AnnotationEntityTouchedIntegrationEvent._userIds).failWith(messageSource.getMessage("Validation_Required", new Object[]{AnnotationEntityTouchedIntegrationEvent._userIds}, LocaleContextHolder.getLocale())),
this.navSpec()
.iff(() -> !this.isListNullOrEmpty(item.getUserIds()))
.on(AnnotationEntityTouchedIntegrationEvent._userIds)
.over(item.getUserIds())
.using((i) -> this.validatorFactory.validator(UuidValidator.class))
);
}
}
}

View File

@ -0,0 +1,7 @@
package gr.cite.annotation.integrationevent.inbox.annotationentitytouch;
import gr.cite.annotation.integrationevent.inbox.IntegrationEventHandler;
public interface AnnotationEntityTouchedIntegrationEventHandler extends IntegrationEventHandler {
}

View File

@ -0,0 +1,149 @@
package gr.cite.annotation.integrationevent.inbox.annotationentitytouch;
import gr.cite.annotation.audit.AuditableAction;
import gr.cite.annotation.common.JsonHandlingService;
import gr.cite.annotation.common.enums.IsActive;
import gr.cite.annotation.common.scope.fake.FakeRequestScope;
import gr.cite.annotation.data.EntityUserEntity;
import gr.cite.annotation.integrationevent.inbox.EventProcessingStatus;
import gr.cite.annotation.integrationevent.inbox.InboxPrincipal;
import gr.cite.annotation.integrationevent.inbox.IntegrationEventProperties;
import gr.cite.annotation.query.EntityUserQuery;
import gr.cite.commons.web.oidc.principal.CurrentPrincipalResolver;
import gr.cite.tools.auditing.AuditService;
import gr.cite.tools.data.query.QueryFactory;
import gr.cite.tools.logging.LoggerService;
import gr.cite.tools.validation.ValidatorFactory;
import jakarta.persistence.EntityManager;
import jakarta.persistence.EntityManagerFactory;
import jakarta.persistence.EntityTransaction;
import jakarta.persistence.OptimisticLockException;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
import java.time.Instant;
import java.util.AbstractMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
@Component
@Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public class AnnotationEntityTouchedIntegrationEventHandlerImpl implements AnnotationEntityTouchedIntegrationEventHandler {
private static final LoggerService logger = new LoggerService(LoggerFactory.getLogger(AnnotationEntityTouchedIntegrationEventHandlerImpl.class));
private final JsonHandlingService jsonHandlingService;
private final ValidatorFactory validatorFactory;
private final ApplicationContext applicationContext;
private final QueryFactory queryFactory;
public AnnotationEntityTouchedIntegrationEventHandlerImpl(JsonHandlingService jsonHandlingService, ValidatorFactory validatorFactory, ApplicationContext applicationContext, QueryFactory queryFactory) {
this.jsonHandlingService = jsonHandlingService;
this.validatorFactory = validatorFactory;
this.applicationContext = applicationContext;
this.queryFactory = queryFactory;
}
@Override
public EventProcessingStatus handle(IntegrationEventProperties properties, String message) {
AnnotationEntityTouchedIntegrationEvent event = this.jsonHandlingService.fromJsonSafe(AnnotationEntityTouchedIntegrationEvent.class, message);
if (event == null)
return EventProcessingStatus.Error;
logger.debug("Handling {}", AnnotationEntityTouchedIntegrationEvent.class.getSimpleName());
this.validatorFactory.validator(AnnotationEntityTouchedIntegrationEvent.AnnotationEntityTouchedIntegrationEventValidator.class).validateForce(event);
EntityManager entityManager = null;
EntityTransaction transaction = null;
try (FakeRequestScope ignored = new FakeRequestScope()) {
try {
// QueryFactory queryFactory = this.applicationContext.getBean(QueryFactory.class);
// TenantScope scope = this.applicationContext.getBean(TenantScope.class);
// if (scope.isMultitenant() && event.getTenant() != null) {
// TenantEntity tenant = queryFactory.query(TenantQuery.class).ids(event.getTenant()).firstAs(new BaseFieldSet().ensure(Tenant._id).ensure(Tenant._code));
// if (tenant == null) {
// logger.error("missing tenant from event message");
// return EventProcessingStatus.Error;
// }
// scope.setTenant(event.getTenant(), tenant.getCode());
// } else if (scope.isMultitenant()) {
// logger.error("missing tenant from event message");
// return EventProcessingStatus.Error;
// }
//
// ValidationService validator = this.applicationContext.getBean(ValidationService.class);
// validator.validateForce(model);
CurrentPrincipalResolver currentPrincipalResolver = this.applicationContext.getBean(CurrentPrincipalResolver.class);
currentPrincipalResolver.push(InboxPrincipal.build(properties));
EntityManagerFactory entityManagerFactory = this.applicationContext.getBean(EntityManagerFactory.class);
entityManager = entityManagerFactory.createEntityManager();
transaction = entityManager.getTransaction();
transaction.begin();
try {
EntityUserQuery entityUserQuery = this.queryFactory.query(EntityUserQuery.class);
List<EntityUserEntity> associatedUsersEntities = entityUserQuery
.entityIds(event.getEntityId())
.isActive(IsActive.Active)
.collect();
List<UUID> associatedUsers = associatedUsersEntities.stream()
.map(EntityUserEntity::getUserId)
.toList();
for (UUID user : event.getUserIds()) {
if (!associatedUsers.contains(user)) {
EntityUserEntity entityUserEntity = new EntityUserEntity();
entityUserEntity.setId(UUID.randomUUID());
entityUserEntity.setEntityId(event.getEntityId());
entityUserEntity.setUserId(user);
entityUserEntity.setCreatedAt(Instant.now());
entityUserEntity.setUpdatedAt(Instant.now());
entityUserEntity.setIsActive(IsActive.Active);
entityManager.persist(entityUserEntity);
}
}
AuditService auditService = this.applicationContext.getBean(AuditService.class);
auditService.track(AuditableAction.User_Persist, Map.ofEntries(
new AbstractMap.SimpleEntry<String, Object>("model", event)
));
transaction.commit();
} catch (Exception e) {
transaction.rollback();
throw e;
} finally {
currentPrincipalResolver.pop();
}
} catch (OptimisticLockException ex) {
// we get this if/when someone else already modified the notifications. We want to essentially ignore this, and keep working
logger.debug("Concurrency exception getting queue outbox. Skipping: {} ", ex.getMessage());
if (transaction != null)
transaction.rollback();
} catch (Exception ex) {
logger.error("Problem getting list of queue outbox. Skipping: {}", ex.getMessage(), ex);
if (transaction != null)
transaction.rollback();
} finally {
if (entityManager != null)
entityManager.close();
}
} catch (Exception ex) {
logger.error("Problem getting list of queue outbox. Skipping: {}", ex.getMessage(), ex);
}
return EventProcessingStatus.Success;
}
}

View File

@ -1,4 +1,4 @@
package gr.cite.annotation.integrationevent.inbox.tenanttouched; package gr.cite.annotation.integrationevent.inbox.tenanttouch;
import gr.cite.annotation.integrationevent.TrackedEvent; import gr.cite.annotation.integrationevent.TrackedEvent;

View File

@ -1,4 +1,4 @@
package gr.cite.annotation.integrationevent.inbox.tenanttouched; package gr.cite.annotation.integrationevent.inbox.tenanttouch;
import gr.cite.annotation.integrationevent.inbox.IntegrationEventHandler; import gr.cite.annotation.integrationevent.inbox.IntegrationEventHandler;

View File

@ -1,4 +1,4 @@
package gr.cite.annotation.integrationevent.inbox.tenanttouched; package gr.cite.annotation.integrationevent.inbox.tenanttouch;
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;

View File

@ -1,4 +1,4 @@
package gr.cite.annotation.integrationevent.inbox.usertouched; package gr.cite.annotation.integrationevent.inbox.usertouch;
import gr.cite.annotation.common.enums.ContactInfoType; import gr.cite.annotation.common.enums.ContactInfoType;
import gr.cite.annotation.common.validation.BaseValidator; import gr.cite.annotation.common.validation.BaseValidator;

View File

@ -1,4 +1,4 @@
package gr.cite.annotation.integrationevent.inbox.usertouched; package gr.cite.annotation.integrationevent.inbox.usertouch;
import gr.cite.annotation.integrationevent.inbox.IntegrationEventHandler; import gr.cite.annotation.integrationevent.inbox.IntegrationEventHandler;

View File

@ -1,4 +1,4 @@
package gr.cite.annotation.integrationevent.inbox.usertouched; package gr.cite.annotation.integrationevent.inbox.usertouch;
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;

View File

@ -3,7 +3,7 @@ package gr.cite.annotation.model.persist;
import gr.cite.annotation.common.validation.BaseValidator; import gr.cite.annotation.common.validation.BaseValidator;
import gr.cite.annotation.convention.ConventionService; import gr.cite.annotation.convention.ConventionService;
import gr.cite.annotation.errorcode.ErrorThesaurusProperties; import gr.cite.annotation.errorcode.ErrorThesaurusProperties;
import gr.cite.annotation.integrationevent.inbox.usertouched.UserTouchedIntegrationEvent; import gr.cite.annotation.integrationevent.inbox.usertouch.UserTouchedIntegrationEvent;
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;

View File

@ -0,0 +1,146 @@
package gr.cite.annotation.query;
import gr.cite.annotation.authorization.AuthorizationFlags;
import gr.cite.annotation.common.enums.IsActive;
import gr.cite.annotation.data.EntityUserEntity;
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.stereotype.Component;
import org.springframework.web.context.annotation.RequestScope;
import java.util.*;
@Component
@RequestScope
public class EntityUserQuery extends QueryBase<EntityUserEntity> {
private Collection<UUID> ids, entityIds, userIds;
private Collection<IsActive> isActives;
private EnumSet<AuthorizationFlags> authorize = EnumSet.of(AuthorizationFlags.None);
public EntityUserQuery ids(UUID value) {
this.ids = List.of(value);
return this;
}
public EntityUserQuery ids(UUID... value) {
this.ids = Arrays.asList(value);
return this;
}
public EntityUserQuery ids(Collection<UUID> values) {
this.ids = values;
return this;
}
public EntityUserQuery entityIds(UUID value) {
this.entityIds = List.of(value);
return this;
}
public EntityUserQuery entityIds(UUID... value) {
this.entityIds = Arrays.asList(value);
return this;
}
public EntityUserQuery entityIds(Collection<UUID> values) {
this.entityIds = values;
return this;
}
public EntityUserQuery userIds(UUID value) {
this.userIds = List.of(value);
return this;
}
public EntityUserQuery userIds(UUID... value) {
this.userIds = Arrays.asList(value);
return this;
}
public EntityUserQuery userIds(Collection<UUID> values) {
this.userIds = values;
return this;
}
public EntityUserQuery isActive(IsActive value) {
this.isActives = List.of(value);
return this;
}
public EntityUserQuery isActive(IsActive... value) {
this.isActives = Arrays.asList(value);
return this;
}
public EntityUserQuery isActive(Collection<IsActive> values) {
this.isActives = values;
return this;
}
public EntityUserQuery authorize(EnumSet<AuthorizationFlags> values) {
this.authorize = values;
return this;
}
@Override
protected Boolean isFalseQuery() {
return false;
}
@Override
protected Class<EntityUserEntity> entityClass() {
return EntityUserEntity.class;
}
@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(EntityUserEntity._id));
for (UUID item : this.ids)
inClause.value(item);
predicates.add(inClause);
}
if (this.entityIds != null) {
CriteriaBuilder.In<UUID> inClause = queryContext.CriteriaBuilder.in(queryContext.Root.get(EntityUserEntity._entityId));
for (UUID item : this.entityIds)
inClause.value(item);
predicates.add(inClause);
}
if (this.userIds != null) {
CriteriaBuilder.In<UUID> inClause = queryContext.CriteriaBuilder.in(queryContext.Root.get(EntityUserEntity._userId));
for (UUID item : this.userIds)
inClause.value(item);
predicates.add(inClause);
}
if (this.isActives != null) {
CriteriaBuilder.In<IsActive> inClause = queryContext.CriteriaBuilder.in(queryContext.Root.get(EntityUserEntity._isActive));
for (IsActive item : this.isActives)
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) {
return null;
}
@Override
protected EntityUserEntity convert(Tuple tuple, Set<String> columns) {
return null;
}
}

View File

@ -1,6 +1,5 @@
package gr.cite.annotation.query; package gr.cite.annotation.query;
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.enums.IsActive; import gr.cite.annotation.common.enums.IsActive;
@ -8,6 +7,7 @@ import gr.cite.annotation.common.scope.user.UserScope;
import gr.cite.annotation.data.UserEntity; import gr.cite.annotation.data.UserEntity;
import gr.cite.annotation.model.User; import gr.cite.annotation.model.User;
import gr.cite.annotation.model.user.PublicUser; import gr.cite.annotation.model.user.PublicUser;
import gr.cite.commons.web.authz.service.AuthorizationService;
import gr.cite.tools.data.query.FieldResolver; import gr.cite.tools.data.query.FieldResolver;
import gr.cite.tools.data.query.QueryBase; import gr.cite.tools.data.query.QueryBase;
import gr.cite.tools.data.query.QueryContext; import gr.cite.tools.data.query.QueryContext;
@ -24,136 +24,151 @@ import java.util.*;
@RequestScope @RequestScope
public class UserQuery extends QueryBase<UserEntity> { public class UserQuery extends QueryBase<UserEntity> {
private String like; private String like;
private Collection<UUID> ids;
private Collection<IsActive> isActives;
private EnumSet<AuthorizationFlags> authorize = EnumSet.of(AuthorizationFlags.None); private Collection<UUID> ids;
private final UserScope userScope; private Collection<IsActive> isActives;
private final AuthorizationService authService;
public UserQuery( private EnumSet<AuthorizationFlags> authorize = EnumSet.of(AuthorizationFlags.None);
UserScope userScope,
AuthorizationService authService
) {
this.userScope = userScope;
this.authService = authService;
}
public UserQuery like(String value) { private final UserScope userScope;
this.like = value;
return this;
}
public UserQuery ids(UUID value) { private final AuthorizationService authService;
this.ids = List.of(value);
return this;
}
public UserQuery ids(UUID... value) { public UserQuery(
this.ids = Arrays.asList(value); UserScope userScope,
return this; AuthorizationService authService
} ) {
this.userScope = userScope;
this.authService = authService;
}
public UserQuery ids(Collection<UUID> values) { public UserQuery like(String value) {
this.ids = values; this.like = value;
return this; return this;
} }
public UserQuery isActive(IsActive value) { public UserQuery ids(UUID value) {
this.isActives = List.of(value); this.ids = List.of(value);
return this; return this;
} }
public UserQuery isActive(IsActive... value) { public UserQuery ids(UUID... value) {
this.isActives = Arrays.asList(value); this.ids = Arrays.asList(value);
return this; return this;
} }
public UserQuery isActive(Collection<IsActive> values) { public UserQuery ids(Collection<UUID> values) {
this.isActives = values; this.ids = values;
return this; return this;
} }
public UserQuery authorize(EnumSet<AuthorizationFlags> values) { public UserQuery isActive(IsActive value) {
this.authorize = values; this.isActives = List.of(value);
return this; return this;
} }
@Override public UserQuery isActive(IsActive... value) {
protected Class<UserEntity> entityClass() { this.isActives = Arrays.asList(value);
return UserEntity.class; return this;
} }
@Override public UserQuery isActive(Collection<IsActive> values) {
protected Boolean isFalseQuery() { this.isActives = values;
return this.isEmpty(this.ids) || this.isEmpty(this.isActives); return this;
} }
@Override public UserQuery authorize(EnumSet<AuthorizationFlags> values) {
protected <X, Y> Predicate applyAuthZ(QueryContext<X, Y> queryContext) { this.authorize = values;
if (this.authorize.contains(AuthorizationFlags.None)) return null; return this;
if (this.authorize.contains(AuthorizationFlags.Permission) && this.authService.authorize(Permission.BrowseUser)) return null; }
UUID ownerId = null;
if (this.authorize.contains(AuthorizationFlags.Owner)) ownerId = this.userScope.getUserIdSafe();
List<Predicate> predicates = new ArrayList<>(); @Override
if (ownerId != null) { protected Class<UserEntity> entityClass() {
predicates.add(queryContext.CriteriaBuilder.equal(queryContext.Root.get(User._id), ownerId)); return UserEntity.class;
} }
if (predicates.size() > 0) {
Predicate[] predicatesArray = predicates.toArray(new Predicate[0]);
return queryContext.CriteriaBuilder.and(predicatesArray);
} else {
return queryContext.CriteriaBuilder.or(); //Creates a false query
}
}
@Override @Override
protected <X, Y> Predicate applyFilters(QueryContext<X, Y> queryContext) { protected Boolean isFalseQuery() {
List<Predicate> predicates = new ArrayList<>(); return this.isEmpty(this.ids) || this.isEmpty(this.isActives);
if (this.ids != null) { }
CriteriaBuilder.In<UUID> inClause = queryContext.CriteriaBuilder.in(queryContext.Root.get(UserEntity._id));
for (UUID item : this.ids) inClause.value(item);
predicates.add(inClause);
}
if (this.like != null && !this.like.isEmpty()) {
predicates.add(queryContext.CriteriaBuilder.like(queryContext.Root.get(UserEntity._name), this.like));
}
if (this.isActives != null) {
CriteriaBuilder.In<IsActive> inClause = queryContext.CriteriaBuilder.in(queryContext.Root.get(UserEntity._isActive));
for (IsActive item : this.isActives) inClause.value(item);
predicates.add(inClause);
}
if (predicates.size() > 0) {
Predicate[] predicatesArray = predicates.toArray(new Predicate[0]);
return queryContext.CriteriaBuilder.and(predicatesArray);
} else {
return null;
}
}
@Override @Override
protected UserEntity convert(Tuple tuple, Set<String> columns) { protected <X, Y> Predicate applyAuthZ(QueryContext<X, Y> queryContext) {
UserEntity item = new UserEntity(); if (this.authorize.contains(AuthorizationFlags.None))
item.setId(QueryBase.convertSafe(tuple, columns, UserEntity._id, UUID.class)); return null;
item.setName(QueryBase.convertSafe(tuple, columns, UserEntity._name, String.class)); if (this.authorize.contains(AuthorizationFlags.Permission) && this.authService.authorize(Permission.BrowseUser))
item.setAdditionalInfo(QueryBase.convertSafe(tuple, columns, UserEntity._additionalInfo, String.class)); return null;
item.setCreatedAt(QueryBase.convertSafe(tuple, columns, UserEntity._createdAt, Instant.class)); UUID ownerId = null;
item.setUpdatedAt(QueryBase.convertSafe(tuple, columns, UserEntity._updatedAt, Instant.class)); if (this.authorize.contains(AuthorizationFlags.Owner))
item.setIsActive(QueryBase.convertSafe(tuple, columns, UserEntity._isActive, IsActive.class)); ownerId = this.userScope.getUserIdSafe();
return item;
}
@Override List<Predicate> predicates = new ArrayList<>();
protected String fieldNameOf(FieldResolver item) { if (ownerId != null) {
if (item.match(User._id) || item.match(PublicUser._id)) return UserEntity._id; predicates.add(queryContext.CriteriaBuilder.equal(queryContext.Root.get(User._id), ownerId));
else if (item.match(User._name) || item.match(PublicUser._name)) return UserEntity._name; }
else if (item.match(User._createdAt) ) return UserEntity._createdAt; if (!predicates.isEmpty()) {
else if (item.match(User._updatedAt)) return UserEntity._updatedAt; Predicate[] predicatesArray = predicates.toArray(new Predicate[0]);
else if (item.match(User._hash)) return UserEntity._updatedAt; return queryContext.CriteriaBuilder.and(predicatesArray);
else if (item.match(User._isActive)) return UserEntity._isActive; } else {
else return null; 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(UserEntity._id));
for (UUID item : this.ids)
inClause.value(item);
predicates.add(inClause);
}
if (this.like != null && !this.like.isEmpty()) {
predicates.add(queryContext.CriteriaBuilder.like(queryContext.Root.get(UserEntity._name), this.like));
}
if (this.isActives != null) {
CriteriaBuilder.In<IsActive> inClause = queryContext.CriteriaBuilder.in(queryContext.Root.get(UserEntity._isActive));
for (IsActive item : this.isActives)
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 UserEntity convert(Tuple tuple, Set<String> columns) {
UserEntity item = new UserEntity();
item.setId(QueryBase.convertSafe(tuple, columns, UserEntity._id, UUID.class));
item.setName(QueryBase.convertSafe(tuple, columns, UserEntity._name, String.class));
item.setAdditionalInfo(QueryBase.convertSafe(tuple, columns, UserEntity._additionalInfo, String.class));
item.setCreatedAt(QueryBase.convertSafe(tuple, columns, UserEntity._createdAt, Instant.class));
item.setUpdatedAt(QueryBase.convertSafe(tuple, columns, UserEntity._updatedAt, Instant.class));
item.setIsActive(QueryBase.convertSafe(tuple, columns, UserEntity._isActive, IsActive.class));
return item;
}
@Override
protected String fieldNameOf(FieldResolver item) {
if (item.match(User._id) || item.match(PublicUser._id))
return UserEntity._id;
else if (item.match(User._name) || item.match(PublicUser._name))
return UserEntity._name;
else if (item.match(User._createdAt))
return UserEntity._createdAt;
else if (item.match(User._updatedAt))
return UserEntity._updatedAt;
else if (item.match(User._hash))
return UserEntity._updatedAt;
else if (item.match(User._isActive))
return UserEntity._isActive;
else
return null;
}
} }

View File

@ -1,7 +1,7 @@
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.annotation.integrationevent.inbox.usertouched.UserTouchedIntegrationEvent; import gr.cite.annotation.integrationevent.inbox.usertouch.UserTouchedIntegrationEvent;
import gr.cite.annotation.model.User; import gr.cite.annotation.model.User;
import gr.cite.tools.exception.MyApplicationException; import gr.cite.tools.exception.MyApplicationException;
import gr.cite.tools.exception.MyForbiddenException; import gr.cite.tools.exception.MyForbiddenException;

View File

@ -10,7 +10,7 @@ import gr.cite.annotation.convention.ConventionService;
import gr.cite.annotation.data.UserContactInfoEntity; import gr.cite.annotation.data.UserContactInfoEntity;
import gr.cite.annotation.data.UserCredentialEntity; import gr.cite.annotation.data.UserCredentialEntity;
import gr.cite.annotation.data.UserEntity; import gr.cite.annotation.data.UserEntity;
import gr.cite.annotation.integrationevent.inbox.usertouched.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.UserDeleter; import gr.cite.annotation.model.deleter.UserDeleter;

View File

@ -27,6 +27,8 @@ public class OutboxIntegrationEvent extends IntegrationEvent {
public static final String DESCRIPTION_TOUCH = "DESCRIPTION_TOUCH"; public static final String DESCRIPTION_TOUCH = "DESCRIPTION_TOUCH";
public static final String ANNOTATION_ENTITY_TOUCH = "ANNOTATION_ENTITY_TOUCH";
public static final String WHAT_YOU_KNOW_ABOUT_ME_COMPLETED = "WHAT_YOU_KNOW_ABOUT_ME_COMPLETED"; public static final String WHAT_YOU_KNOW_ABOUT_ME_COMPLETED = "WHAT_YOU_KNOW_ABOUT_ME_COMPLETED";
public static final String GENERATE_FILE = "GENERATE_FILE"; public static final String GENERATE_FILE = "GENERATE_FILE";

View File

@ -23,6 +23,8 @@ public class OutboxProperties {
private final String descriptionTouchTopic; private final String descriptionTouchTopic;
private final String annotationEntityTouchTopic;
private final String notifyTopic; private final String notifyTopic;
private final String forgetMeCompletedTopic; private final String forgetMeCompletedTopic;
@ -37,7 +39,10 @@ public class OutboxProperties {
String tenantReactivationTopic, String tenantReactivationTopic,
String tenantUserInviteTopic, String tenantUserInviteTopic,
String userRemovalTopic, String userRemovalTopic,
String userTouchTopic, String dmpTouchTopic, String descriptionTouchTopic, String userTouchTopic,
String dmpTouchTopic,
String descriptionTouchTopic,
String annotationEntityTouchTopic,
String notifyTopic, String notifyTopic,
String forgetMeCompletedTopic, String forgetMeCompletedTopic,
String whatYouKnowAboutMeCompletedTopic, String whatYouKnowAboutMeCompletedTopic,
@ -52,6 +57,7 @@ public class OutboxProperties {
this.userTouchTopic = userTouchTopic; this.userTouchTopic = userTouchTopic;
this.dmpTouchTopic = dmpTouchTopic; this.dmpTouchTopic = dmpTouchTopic;
this.descriptionTouchTopic = descriptionTouchTopic; this.descriptionTouchTopic = descriptionTouchTopic;
this.annotationEntityTouchTopic = annotationEntityTouchTopic;
this.notifyTopic = notifyTopic; this.notifyTopic = notifyTopic;
this.forgetMeCompletedTopic = forgetMeCompletedTopic; this.forgetMeCompletedTopic = forgetMeCompletedTopic;
this.whatYouKnowAboutMeCompletedTopic = whatYouKnowAboutMeCompletedTopic; this.whatYouKnowAboutMeCompletedTopic = whatYouKnowAboutMeCompletedTopic;
@ -94,6 +100,10 @@ public class OutboxProperties {
return descriptionTouchTopic; return descriptionTouchTopic;
} }
public String getAnnotationEntityTouchTopic() {
return annotationEntityTouchTopic;
}
public String getNotifyTopic() { public String getNotifyTopic() {
return notifyTopic; return notifyTopic;
} }

View File

@ -415,6 +415,10 @@ public class OutboxRepositoryImpl implements OutboxRepository {
routingKey = this.outboxProperties.getDescriptionTouchTopic(); routingKey = this.outboxProperties.getDescriptionTouchTopic();
break; break;
} }
case OutboxIntegrationEvent.ANNOTATION_ENTITY_TOUCH: {
routingKey = this.outboxProperties.getAnnotationEntityTouchTopic();
break;
}
case OutboxIntegrationEvent.FORGET_ME_COMPLETED: { case OutboxIntegrationEvent.FORGET_ME_COMPLETED: {
routingKey = this.outboxProperties.getForgetMeCompletedTopic(); routingKey = this.outboxProperties.getForgetMeCompletedTopic();
break; break;

View File

@ -0,0 +1,30 @@
package eu.eudat.integrationevent.outbox.annotationentitytouch;
import eu.eudat.integrationevent.TrackedEvent;
import java.util.List;
import java.util.UUID;
public class AnnotationEntityTouchedIntegrationEvent extends TrackedEvent {
private UUID entityId;
private List<UUID> userIds;
public UUID getEntityId() {
return entityId;
}
public void setEntityId(UUID entityId) {
this.entityId = entityId;
}
public List<UUID> getUserIds() {
return userIds;
}
public void setUserIds(List<UUID> userIds) {
this.userIds = userIds;
}
}

View File

@ -0,0 +1,25 @@
package eu.eudat.integrationevent.outbox.annotationentitytouch;
import eu.eudat.integrationevent.outbox.dmptouched.DmpTouchedIntegrationEvent;
import eu.eudat.model.persist.DmpPersist;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
public interface AnnotationEntityTouchedIntegrationEventHandler {
void handle(AnnotationEntityTouchedIntegrationEvent event);
static AnnotationEntityTouchedIntegrationEvent buildEventFromPersistModel(DmpPersist persist) {
AnnotationEntityTouchedIntegrationEvent event = new AnnotationEntityTouchedIntegrationEvent();
event.setEntityId(persist.getId());
List<UUID> users = new ArrayList<>();
persist.getUsers().forEach(dmpUserPersist -> {
users.add(dmpUserPersist.getUser());
});
event.setUserIds(users);
return event;
}
}

View File

@ -0,0 +1,34 @@
package eu.eudat.integrationevent.outbox.annotationentitytouch;
import eu.eudat.integrationevent.outbox.OutboxIntegrationEvent;
import eu.eudat.integrationevent.outbox.OutboxService;
import gr.cite.tools.logging.LoggerService;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
import java.util.UUID;
@Component
@Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public class AnnotationEntityTouchedIntegrationEventHandlerImpl implements AnnotationEntityTouchedIntegrationEventHandler {
private static final LoggerService logger = new LoggerService(LoggerFactory.getLogger(AnnotationEntityTouchedIntegrationEventHandlerImpl.class));
private final OutboxService outboxService;
public AnnotationEntityTouchedIntegrationEventHandlerImpl(OutboxService outboxService) {
this.outboxService = outboxService;
}
@Override
public void handle(AnnotationEntityTouchedIntegrationEvent event) {
OutboxIntegrationEvent message = new OutboxIntegrationEvent();
message.setMessageId(UUID.randomUUID());
message.setType(OutboxIntegrationEvent.ANNOTATION_ENTITY_TOUCH);
message.setEvent(event);
this.outboxService.publish(message);
}
}

View File

@ -35,6 +35,7 @@ queue:
user-removal-topic: user.remove user-removal-topic: user.remove
dmp-touch-topic: dmp.touch dmp-touch-topic: dmp.touch
description-touch-topic: description.touch description-touch-topic: description.touch
annotation-entity-touch-topic: annotation.entity.touch
what-you-know-about-me-completed-topic: whatyouknowaboutme.completed what-you-know-about-me-completed-topic: whatyouknowaboutme.completed
generate-file-topic: generate.file generate-file-topic: generate.file
rabbitmq: rabbitmq: