fix update_notification script

This commit is contained in:
amentis 2023-12-06 13:08:49 +02:00
parent 2dac2326ee
commit bee0e9f152
19 changed files with 1102 additions and 3 deletions

View File

@ -154,6 +154,12 @@ public final class Permission {
public static String BrowseTenant = "BrowseTenant";
public static String EditTenant= "EditTenant";
public static String DeleteTenant = "DeleteTenant";
public static String AllowNoTenant = "AllowNoTenant";
//TenantUser
public static String BrowseTenantUser = "BrowseTenantUser";
public static String EditTenantUser = "EditTenantUser";
public static String DeleteTenantUser = "DeleteTenantUser";
}

View File

@ -0,0 +1,9 @@
package eu.eudat.commons.scope.tenant;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Configuration;
@Configuration
@EnableConfigurationProperties(MultitenancyProperties.class)
public class MultitenancyConfiguration {
}

View File

@ -0,0 +1,16 @@
package eu.eudat.commons.scope.tenant;
import org.springframework.boot.context.properties.ConfigurationProperties;
@ConfigurationProperties(prefix = "tenant.multitenancy")
public class MultitenancyProperties {
private boolean isMultitenant;
public boolean isMultitenant() {
return isMultitenant;
}
public void setIsMultitenant(boolean multitenant) {
isMultitenant = multitenant;
}
}

View File

@ -0,0 +1,91 @@
package eu.eudat.commons.scope.tenant;
import eu.eudat.data.tenant.TenantScopedBaseEntity;
import gr.cite.tools.logging.LoggerService;
import jakarta.persistence.EntityManager;
import org.hibernate.Session;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.context.annotation.RequestScope;
import javax.management.InvalidApplicationException;
import java.util.UUID;
import java.util.concurrent.atomic.AtomicReference;
@Component
//@RequestScope
public class TenantScope {
public static final String TenantReplaceParameter = "::TenantCode::";
public static final String TenantCodesClaimName = "TenantCodes";
public static final String TenantClaimName = "x-tenant";
private final MultitenancyProperties multitenancy;
private static final LoggerService logger = new LoggerService(LoggerFactory.getLogger(TenantScope.class));
private final AtomicReference<UUID> tenant = new AtomicReference<>();
private final AtomicReference<String> tenantCode = new AtomicReference<>();
private final AtomicReference<UUID> initialTenant = new AtomicReference<>();
private final AtomicReference<String> initialTenantCode = new AtomicReference<>();
@Autowired
public TenantScope(MultitenancyProperties multitenancy) {
this.multitenancy = multitenancy;
}
public Boolean isMultitenant() {
return multitenancy.isMultitenant();
}
public Boolean isSet() {
if (!this.isMultitenant())
return Boolean.TRUE;
return this.tenant.get() != null;
}
public UUID getTenant() throws InvalidApplicationException {
if (!this.isMultitenant())
return null;
if (this.tenant.get() == null)
throw new InvalidApplicationException("tenant not set");
return this.tenant.get();
}
public String getTenantCode() throws InvalidApplicationException {
if (!this.isMultitenant())
return null;
if (this.tenant.get() == null)
throw new InvalidApplicationException("tenant not set");
return this.tenantCode.get();
}
public void setTempTenant(EntityManager entityManager, UUID tenant) {
this.tenant.set(tenant);
if (this.tenant.get() != null) {
entityManager
.unwrap(Session.class)
.enableFilter(TenantScopedBaseEntity.tenantFilter).setParameter(TenantScopedBaseEntity.tenantFilterTenantParam, this.tenant.get().toString());
}
}
public void removeTempTenant(EntityManager entityManager) {
this.tenant.set(this.initialTenant.get());
this.tenantCode.set(this.initialTenantCode.get());
if (this.initialTenant.get() != null) {
entityManager
.unwrap(Session.class)
.enableFilter(TenantScopedBaseEntity.tenantFilter).setParameter(TenantScopedBaseEntity.tenantFilterTenantParam, this.initialTenant.get().toString());
}
}
public void setTenant(UUID tenant, String tenantCode) {
if (this.isMultitenant()) {
this.tenant.set(tenant);
this.initialTenant.set(tenant);
this.tenantCode.set(tenantCode);
this.initialTenantCode.set(tenantCode);
}
}
}

View File

@ -0,0 +1,8 @@
package eu.eudat.commons.scope.tenant;
import java.util.UUID;
public interface TenantScoped {
void setTenantId(UUID tenantId);
UUID getTenantId();
}

View File

@ -0,0 +1,93 @@
package eu.eudat.data;
import eu.eudat.authorization.Permission;
import eu.eudat.commons.scope.tenant.TenantScope;
import eu.eudat.commons.scope.tenant.TenantScoped;
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 jakarta.persistence.*;
import org.springframework.stereotype.Service;
import org.springframework.web.context.annotation.RequestScope;
import javax.management.InvalidApplicationException;
import java.util.UUID;
@Service
@RequestScope
public class TenantEntityManager {
@PersistenceContext
private EntityManager entityManager;
private final CurrentPrincipalResolver currentPrincipalResolver;
private final ClaimExtractor claimExtractor;
private final AuthorizationService authorizationService;
private final TenantScope tenantScope;
public TenantEntityManager(CurrentPrincipalResolver currentPrincipalResolver, ClaimExtractor claimExtractor, AuthorizationService authorizationService, TenantScope tenantScope) {
this.currentPrincipalResolver = currentPrincipalResolver;
this.claimExtractor = claimExtractor;
this.authorizationService = authorizationService;
this.tenantScope = tenantScope;
}
public void persist(Object entity) {
this.entityManager.persist(entity);
}
public <T> T merge(T entity) throws InvalidApplicationException {
if (tenantScope.isMultitenant() && (entity instanceof TenantScoped)) {
this.currentPrincipalResolver.currentPrincipal().isAuthenticated();
this.claimExtractor.subjectUUID(this.currentPrincipalResolver.currentPrincipal());
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)) {
this.currentPrincipalResolver.currentPrincipal().isAuthenticated();
this.claimExtractor.subjectUUID(this.currentPrincipalResolver.currentPrincipal());
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

@ -0,0 +1,85 @@
package eu.eudat.data;
import eu.eudat.commons.enums.IsActive;
import eu.eudat.data.converters.enums.IsActiveConverter;
import jakarta.persistence.*;
import java.time.Instant;
import java.util.UUID;
@Entity
@Table(name = "\"TenantUser\"")
public class TenantUserEntity {
@Id
@Column(name = "id", columnDefinition = "uuid", updatable = false, nullable = false)
private UUID id;
public final static String _id = "id";
@Column(name = "user", columnDefinition = "uuid", updatable = false, nullable = false)
private UUID userId;
public final static String _userId = "userId";
@Column(name = "tenant", columnDefinition = "uuid", updatable = false, nullable = false)
private UUID tenantId;
public final static String _tenantId = "tenantId";
@Column(name = "is_active", length = 20, nullable = false)
@Convert(converter = IsActiveConverter.class)
private IsActive isActive;
public final static String _isActive = "isActive";
@Column(name = "created_at", nullable = false)
private Instant createdAt;
public final static String _createdAt = "createdAt";
@Column(name = "updated_at", nullable = false)
private Instant updatedAt;
public final static String _updatedAt = "updatedAt";
public UUID getId() {
return id;
}
public void setId(UUID id) {
this.id = id;
}
public UUID getUserId() {
return userId;
}
public void setUserId(UUID userId) {
this.userId = userId;
}
public UUID getTenantId() {
return tenantId;
}
public void setTenantId(UUID tenantId) {
this.tenantId = tenantId;
}
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;
}
}

View File

@ -13,7 +13,7 @@ import java.util.List;
import java.util.UUID;
@Entity
@Table(name = "\"Notification\"")
@Table(name = "\"NotificationLegacy\"")
public class Notification implements DataEntity<Notification, UUID> {
@Id

View File

@ -0,0 +1,40 @@
package eu.eudat.data.tenant;
import eu.eudat.commons.scope.tenant.TenantScope;
import jakarta.persistence.EntityManager;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.hibernate.Session;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.management.InvalidApplicationException;
//@Aspect
@Component
public class TenantFilterAspect {
private final TenantScope tenantScope;
@Autowired
public TenantFilterAspect(
TenantScope tenantScope
) {
this.tenantScope = tenantScope;
}
@AfterReturning(
pointcut = "bean(entityManagerFactory) && execution(* createEntityManager(..))",
returning = "retVal")
public void getSessionAfter(JoinPoint joinPoint, Object retVal) throws InvalidApplicationException {
if (retVal != null && retVal instanceof EntityManager && tenantScope.isSet()) {
Session session = ((EntityManager) retVal).unwrap(Session.class);
session
.enableFilter(TenantScopedBaseEntity.tenantFilter)
.setParameter(TenantScopedBaseEntity.tenantFilterTenantParam, tenantScope.getTenant().toString());
}
}
}

View File

@ -0,0 +1,61 @@
package eu.eudat.data.tenant;
import eu.eudat.commons.scope.tenant.TenantScope;
import eu.eudat.commons.scope.tenant.TenantScoped;
import gr.cite.tools.exception.MyForbiddenException;
import gr.cite.tools.logging.LoggerService;
import jakarta.persistence.PrePersist;
import jakarta.persistence.PreRemove;
import jakarta.persistence.PreUpdate;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import javax.management.InvalidApplicationException;
import java.util.UUID;
public class TenantListener {
private static final LoggerService logger = new LoggerService(LoggerFactory.getLogger(TenantListener.class));
private final TenantScope tenantScope;
@Autowired
public TenantListener(
TenantScope tenantScope
) {
this.tenantScope = tenantScope;
}
@PrePersist
public void setTenantOnCreate(TenantScoped entity) throws InvalidApplicationException {
if (tenantScope.isMultitenant()) {
final UUID tenantId = tenantScope.getTenant();
entity.setTenantId(tenantId);
} else {
entity.setTenantId(null);
}
}
@PreUpdate
@PreRemove
public void setTenantOnUpdate(TenantScoped entity) throws InvalidApplicationException {
if (tenantScope.isMultitenant()) {
if (entity.getTenantId() == null) {
logger.error("somebody tried to set null tenant");
throw new MyForbiddenException("tenant tampering");
}
if (entity.getTenantId().compareTo(tenantScope.getTenant()) != 0) {
logger.error("somebody tried to change an entries tenant");
throw new MyForbiddenException("tenant tampering");
}
final UUID tenantId = tenantScope.getTenant();
entity.setTenantId(tenantId);
} else {
if (entity.getTenantId() != null) {
logger.error("somebody tried to set non null tenant");
throw new MyForbiddenException("tenant tampering");
}
}
}
}

View File

@ -0,0 +1,36 @@
package eu.eudat.data.tenant;
import eu.eudat.commons.scope.tenant.TenantScoped;
import jakarta.persistence.*;
import org.hibernate.annotations.Filter;
import org.hibernate.annotations.FilterDef;
import org.hibernate.annotations.ParamDef;
import java.io.Serializable;
import java.util.UUID;
@MappedSuperclass
//@Getter
//@Setter
//@NoArgsConstructor
@FilterDef(name = TenantScopedBaseEntity.tenantFilter, parameters = {@ParamDef(name = TenantScopedBaseEntity.tenantFilterTenantParam, type = String.class)})
@Filter(name = "tenantFilter", condition = "tenant = (cast(:tenantId as uuid))")
@EntityListeners(TenantListener.class)
public abstract class TenantScopedBaseEntity implements TenantScoped, Serializable {
private static final long serialVersionUID = 1L;
public static final String tenantFilter = "tenantFilter";
public static final String tenantFilterTenantParam = "tenantId";
@Column(name = "tenant", columnDefinition = "uuid", nullable = false)
private UUID tenantId;
public static final String _tenantId = "tenantId";
public UUID getTenantId() {
return tenantId;
}
@Override
public void setTenantId(UUID tenantId) {
this.tenantId = tenantId;
}
}

View File

@ -0,0 +1,86 @@
package eu.eudat.model;
import eu.eudat.commons.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";
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;
}
}

View File

@ -0,0 +1,138 @@
package eu.eudat.model.builder;
import eu.eudat.authorization.AuthorizationFlags;
import eu.eudat.convention.ConventionService;
import eu.eudat.data.TenantUserEntity;
import eu.eudat.model.Tenant;
import eu.eudat.model.TenantUser;
import eu.eudat.model.User;
import eu.eudat.query.TenantQuery;
import eu.eudat.query.UserQuery;
import gr.cite.tools.data.builder.BuilderFactory;
import gr.cite.tools.data.query.QueryFactory;
import gr.cite.tools.exception.MyApplicationException;
import gr.cite.tools.fieldset.BaseFieldSet;
import gr.cite.tools.fieldset.FieldSet;
import gr.cite.tools.logging.DataLogEntry;
import gr.cite.tools.logging.LoggerService;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
import java.util.*;
import java.util.stream.Collectors;
@Component
@Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public class TenantUserBuilder extends BaseBuilder<TenantUser, TenantUserEntity> {
private final BuilderFactory builderFactory;
private final QueryFactory queryFactory;
private EnumSet<AuthorizationFlags> authorize = EnumSet.of(AuthorizationFlags.None);
@Autowired
public TenantUserBuilder(
ConventionService conventionService,
BuilderFactory builderFactory,
QueryFactory queryFactory
) {
super(conventionService, new LoggerService(LoggerFactory.getLogger(TenantUserBuilder.class)));
this.builderFactory = builderFactory;
this.queryFactory = queryFactory;
}
public TenantUserBuilder authorize(EnumSet<AuthorizationFlags> values) {
this.authorize = values;
return this;
}
@Override
public List<TenantUser> build(FieldSet fields, List<TenantUserEntity> datas) throws MyApplicationException {
this.logger.debug("building for {} items requesting {} fields", Optional.ofNullable(datas).map(e -> e.size()).orElse(0), Optional.ofNullable(fields).map(e -> e.getFields()).map(e -> e.size()).orElse(0));
this.logger.trace(new DataLogEntry("requested fields", fields));
if (fields == null || fields.isEmpty()) return new ArrayList<>();
FieldSet userFields = fields.extractPrefixed(this.asPrefix(TenantUser._user));
Map<UUID, User> userMap = this.collectUsers(userFields, datas);
FieldSet tenantFields = fields.extractPrefixed(this.asPrefix(TenantUser._tenant));
Map<UUID, Tenant> tenantMap = this.collectTenants(tenantFields, datas);
List<TenantUser> models = new ArrayList<>();
for (TenantUserEntity d : datas) {
TenantUser m = new TenantUser();
if (fields.hasField(this.asIndexer(TenantUser._id))) m.setId(d.getId());
if (fields.hasField(this.asIndexer(TenantUser._hash))) m.setHash(this.hashValue(d.getUpdatedAt()));
if (fields.hasField(this.asIndexer(TenantUser._createdAt))) m.setCreatedAt(d.getCreatedAt());
if (fields.hasField(this.asIndexer(TenantUser._updatedAt))) m.setUpdatedAt(d.getUpdatedAt());
if (fields.hasField(this.asIndexer(TenantUser._isActive))) m.setIsActive(d.getIsActive());
if (!userFields.isEmpty() && userMap != null && userMap.containsKey(d.getUserId())) m.setUser(userMap.get(d.getUserId()));
if (!tenantFields.isEmpty() && tenantMap != null && tenantMap.containsKey(d.getTenantId())) m.setTenant(tenantMap.get(d.getTenantId()));
models.add(m);
}
this.logger.debug("build {} items", Optional.ofNullable(models).map(e -> e.size()).orElse(0));
return models;
}
private Map<UUID, User> collectUsers(FieldSet fields, List<TenantUserEntity> datas) throws MyApplicationException {
if (fields.isEmpty() || datas.isEmpty()) return null;
this.logger.debug("checking related - {}", User.class.getSimpleName());
Map<UUID, User> itemMap = null;
if (!fields.hasOtherField(this.asIndexer(User._id))) {
itemMap = this.asEmpty(
datas.stream().map(x -> x.getUserId()).distinct().collect(Collectors.toList()),
x -> {
User item = new User();
item.setId(x);
return item;
},
x -> x.getId());
} else {
FieldSet clone = new BaseFieldSet(fields.getFields()).ensure(User._id);
UserQuery q = this.queryFactory.query(UserQuery.class).authorize(this.authorize).ids(datas.stream().map(x -> x.getUserId()).distinct().collect(Collectors.toList()));
itemMap = this.builderFactory.builder(UserBuilder.class).authorize(this.authorize).asForeignKey(q, clone, x -> x.getId());
}
if (!fields.hasField(User._id)) {
itemMap.values().stream().filter(x -> x != null).map(x -> {
x.setId(null);
return x;
}).collect(Collectors.toList());
}
return itemMap;
}
private Map<UUID, Tenant> collectTenants(FieldSet fields, List<TenantUserEntity> datas) throws MyApplicationException {
if (fields.isEmpty() || datas.isEmpty()) return null;
this.logger.debug("checking related - {}", Tenant.class.getSimpleName());
Map<UUID, Tenant> itemMap = null;
if (!fields.hasOtherField(this.asIndexer(Tenant._id))) {
itemMap = this.asEmpty(
datas.stream().map(x -> x.getTenantId()).distinct().collect(Collectors.toList()),
x -> {
Tenant item = new Tenant();
item.setId(x);
return item;
},
x -> x.getId());
} else {
FieldSet clone = new BaseFieldSet(fields.getFields()).ensure(Tenant._id);
TenantQuery q = this.queryFactory.query(TenantQuery.class).authorize(this.authorize).ids(datas.stream().map(x -> x.getTenantId()).distinct().collect(Collectors.toList()));
itemMap = this.builderFactory.builder(TenantBuilder.class).authorize(this.authorize).asForeignKey(q, clone, x -> x.getId());
}
if (!fields.hasField(Tenant._id)) {
itemMap.values().stream().filter(x -> x != null).map(x -> {
x.setId(null);
return x;
}).collect(Collectors.toList());
}
return itemMap;
}
}

View File

@ -0,0 +1,51 @@
package eu.eudat.model.censorship;
import eu.eudat.authorization.OwnedResource;
import eu.eudat.authorization.Permission;
import eu.eudat.convention.ConventionService;
import eu.eudat.model.TenantUser;
import gr.cite.commons.web.authz.service.AuthorizationService;
import gr.cite.tools.data.censor.CensorFactory;
import gr.cite.tools.exception.MyForbiddenException;
import gr.cite.tools.fieldset.FieldSet;
import gr.cite.tools.logging.DataLogEntry;
import gr.cite.tools.logging.LoggerService;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
import java.util.List;
import java.util.UUID;
@Component
@Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public class TenantUserCensor extends BaseCensor {
private static final LoggerService logger = new LoggerService(LoggerFactory.getLogger(TenantUserCensor.class));
protected final AuthorizationService authService;
protected final CensorFactory censorFactory;
@Autowired
public TenantUserCensor(
ConventionService conventionService,
AuthorizationService authService,
CensorFactory censorFactory
) {
super(conventionService);
this.authService = authService;
this.censorFactory = censorFactory;
}
public void censor(FieldSet fields, UUID userId) throws MyForbiddenException {
logger.debug(new DataLogEntry("censoring fields", fields));
if (this.isEmpty(fields)) return;
this.authService.authorizeAtLeastOneForce(userId != null ? List.of(new OwnedResource(userId)) : null, Permission.BrowseTenantUser);
FieldSet tenantFields = fields.extractPrefixed(this.asIndexerPrefix(TenantUser._tenant));
this.censorFactory.censor(TenantCensor.class).censor(tenantFields, null);
FieldSet userFields = fields.extractPrefixed(this.asIndexerPrefix(TenantUser._user));
this.censorFactory.censor(UserCensor.class).censor(userFields, userId);
}
}

View File

@ -0,0 +1,74 @@
package eu.eudat.model.deleter;
import eu.eudat.commons.enums.IsActive;
import eu.eudat.data.TenantEntityManager;
import eu.eudat.data.TenantUserEntity;
import eu.eudat.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,208 @@
package eu.eudat.query;
import eu.eudat.authorization.AuthorizationFlags;
import eu.eudat.authorization.Permission;
import eu.eudat.commons.enums.IsActive;
import eu.eudat.commons.scope.user.UserScope;
import eu.eudat.data.TenantUserEntity;
import eu.eudat.data.UserEntity;
import eu.eudat.model.Tenant;
import eu.eudat.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.criteria.CriteriaBuilder;
import jakarta.persistence.criteria.Predicate;
import jakarta.persistence.criteria.Subquery;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
import jakarta.persistence.*;
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.BrowseTenantUser)) 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.size() > 0) {
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) {
Subquery<UserEntity> subQuery = queryContext.Query.subquery(this.userQuery.entityClass());
this.applySubQuery(this.userQuery, queryContext.CriteriaBuilder, subQuery);
predicates.add(queryContext.CriteriaBuilder.in(queryContext.Root.get(TenantUserEntity._userId)).value(subQuery));
}
if (predicates.size() > 0) {
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.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 return null;
}
}

View File

@ -0,0 +1,68 @@
package eu.eudat.query.lookup;
import eu.eudat.commons.enums.IsActive;
import eu.eudat.query.TenantUserQuery;
import gr.cite.tools.data.query.Lookup;
import gr.cite.tools.data.query.QueryFactory;
import java.util.List;
import java.util.UUID;
public class TenantUserLookup extends Lookup {
private List<IsActive> isActive;
private List<UUID> ids;
private List<UUID> userIds;
private List<UUID> tenantIds;
private UserLookup userSubQuery;
public List<IsActive> getIsActive() {
return isActive;
}
public void setIsActive(List<IsActive> isActive) {
this.isActive = isActive;
}
public List<UUID> getIds() {
return ids;
}
public void setIds(List<UUID> ids) {
this.ids = ids;
}
public List<UUID> getUserIds() { return userIds; }
public void setUserIds(List<UUID> userIds) { this.userIds = userIds; }
public List<UUID> getTenantIds() {
return tenantIds;
}
public void setTenantIds(List<UUID> tenantIds) {
this.tenantIds = tenantIds;
}
public UserLookup getUserSubQuery() {
return userSubQuery;
}
public void setUserSubQuery(UserLookup userSubQuery) {
this.userSubQuery = userSubQuery;
}
public TenantUserQuery enrich(QueryFactory queryFactory) {
TenantUserQuery query = queryFactory.query(TenantUserQuery.class);
if (this.isActive != null) query.isActive(this.isActive);
if (this.ids != null) query.ids(this.ids);
if (this.userIds != null) query.userIds(this.userIds);
if (this.tenantIds != null) query.tenantIds(this.tenantIds);
if (this.userSubQuery != null) query.userSubQuery(this.userSubQuery.enrich(queryFactory));
this.enrichCommon(query);
return query;
}
}

View File

@ -523,7 +523,7 @@ permissions:
allowAnonymous: false
allowAuthenticated: false
# ReferenceType Permissions
# Tenant Permissions
BrowseTenant:
roles:
- Admin
@ -543,7 +543,34 @@ permissions:
clients: [ ]
allowAnonymous: false
allowAuthenticated: false
AllowNoTenant:
roles:
- Admin
claims: [ ]
clients: [ ]
allowAnonymous: false
allowAuthenticated: false
# TenantUser Permissions
BrowseTenantUser:
roles:
- Admin
clients: [ ]
allowAnonymous: false
allowAuthenticated: false
EditTenantUser:
roles:
- Admin
clients: [ ]
allowAnonymous: false
allowAuthenticated: false
DeleteTenantUser:
roles:
- Admin
claims: [ ]
clients: [ ]
allowAnonymous: false
allowAuthenticated: false
# DmpDescriptionTemplate Permissions
BrowseDmpDescriptionTemplate:

View File

@ -1,3 +1,5 @@
tenant:
configEncryptionAesKey: rmpTvZnRWzyisUtFADBcZCn0q7Z75Xdz
configEncryptionAesIv: ec05d521a23f80ad
multitenancy:
is-multitenant: false