package eu.eudat.model.builder; import eu.eudat.authorization.AuthorizationFlags; import eu.eudat.authorization.AuthorizationProperties; import eu.eudat.commons.JsonHandlingService; import eu.eudat.commons.scope.tenant.TenantScope; import eu.eudat.commons.types.user.AdditionalInfoEntity; import eu.eudat.convention.ConventionService; import eu.eudat.data.TenantEntity; import eu.eudat.data.TenantEntityManager; import eu.eudat.data.UserEntity; import eu.eudat.model.*; import eu.eudat.query.*; import gr.cite.tools.data.builder.BuilderFactory; import gr.cite.tools.data.query.QueryFactory; import gr.cite.tools.exception.MyApplicationException; import gr.cite.tools.exception.MyForbiddenException; import gr.cite.tools.exception.MyNotFoundException; 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.MessageSource; import org.springframework.context.annotation.Scope; import org.springframework.context.i18n.LocaleContextHolder; import org.springframework.stereotype.Component; import javax.management.InvalidApplicationException; import java.util.*; import java.util.stream.Collectors; @Component @Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE) public class UserBuilder extends BaseBuilder { private final QueryFactory queryFactory; private final BuilderFactory builderFactory; private final JsonHandlingService jsonHandlingService; private final AuthorizationProperties authorizationProperties; private final TenantEntityManager tenantEntityManager; private final TenantScope tenantScope; private final MessageSource messageSource; private EnumSet authorize = EnumSet.of(AuthorizationFlags.None); @Autowired public UserBuilder(ConventionService conventionService, QueryFactory queryFactory, BuilderFactory builderFactory, JsonHandlingService jsonHandlingService, AuthorizationProperties authorizationProperties, TenantEntityManager tenantEntityManager, TenantScope tenantScope, MessageSource messageSource) { super(conventionService, new LoggerService(LoggerFactory.getLogger(UserBuilder.class))); this.queryFactory = queryFactory; this.builderFactory = builderFactory; this.jsonHandlingService = jsonHandlingService; this.authorizationProperties = authorizationProperties; this.tenantEntityManager = tenantEntityManager; this.tenantScope = tenantScope; this.messageSource = messageSource; } public UserBuilder authorize(EnumSet values) { this.authorize = values; return this; } @Override public List build(FieldSet fields, List data) throws MyApplicationException { this.logger.debug("building for {} items requesting {} fields", Optional.ofNullable(data).map(List::size).orElse(0), Optional.ofNullable(fields).map(FieldSet::getFields).map(Set::size).orElse(0)); this.logger.trace(new DataLogEntry("requested fields", fields)); if (fields == null || data == null || fields.isEmpty()) return new ArrayList<>(); List models = new ArrayList<>(); FieldSet contactsFields = fields.extractPrefixed(this.asPrefix(User._contacts)); Map> contactsMap = this.collectUserContactInfos(contactsFields, data); FieldSet globalRolesFields = fields.extractPrefixed(this.asPrefix(User._globalRoles)); Map> globalRolesMap = this.collectUserGlobalRoles(globalRolesFields, data); FieldSet tenantRolesFields = fields.extractPrefixed(this.asPrefix(User._tenantRoles)); Map> tenantRolesMap = this.collectUserTenantRoles(tenantRolesFields, data); FieldSet credentialsFields = fields.extractPrefixed(this.asPrefix(User._credentials)); Map> credentialsMap = this.collectUserCredentials(credentialsFields, data); FieldSet additionalInfoFields = fields.extractPrefixed(this.asPrefix(User._additionalInfo)); FieldSet tenantUsersFields = fields.extractPrefixed(this.asPrefix(User._tenantUsers)); Map> tenantUsersMap = this.collectTenantUsers(tenantUsersFields, data); for (UserEntity d : data) { User m = new User(); if (fields.hasField(this.asIndexer(User._id))) m.setId(d.getId()); if (fields.hasField(this.asIndexer(User._name))) m.setName(d.getName()); if (fields.hasField(this.asIndexer(User._createdAt))) m.setCreatedAt(d.getCreatedAt()); if (fields.hasField(this.asIndexer(User._updatedAt))) m.setUpdatedAt(d.getUpdatedAt()); if (fields.hasField(this.asIndexer(User._isActive))) m.setIsActive(d.getIsActive()); if (fields.hasField(this.asIndexer(User._hash))) m.setHash(this.hashValue(d.getUpdatedAt())); if (contactsMap != null && !contactsFields.isEmpty() && contactsMap.containsKey(d.getId())) m.setContacts(contactsMap.get(d.getId())); if (globalRolesMap != null && !globalRolesFields.isEmpty() && globalRolesMap.containsKey(d.getId())) m.setGlobalRoles(globalRolesMap.get(d.getId())); if (tenantRolesMap != null && !tenantRolesFields.isEmpty() && tenantRolesMap.containsKey(d.getId())) m.setTenantRoles(tenantRolesMap.get(d.getId())); if (credentialsMap != null && !credentialsFields.isEmpty() && credentialsMap.containsKey(d.getId())) m.setCredentials(credentialsMap.get(d.getId())); if (!additionalInfoFields.isEmpty() && d.getAdditionalInfo() != null){ AdditionalInfoEntity definition = this.jsonHandlingService.fromJsonSafe(AdditionalInfoEntity.class, d.getAdditionalInfo()); m.setAdditionalInfo(this.builderFactory.builder(UserAdditionalInfoBuilder.class).authorize(this.authorize).build(additionalInfoFields, definition)); } if (!tenantUsersFields.isEmpty() && tenantUsersMap != null && tenantUsersMap.containsKey(d.getId())) m.setTenantUsers(tenantUsersMap.get(d.getId())); models.add(m); } this.logger.debug("build {} items", Optional.of(models).map(List::size).orElse(0)); return models; } private Map> collectUserContactInfos(FieldSet fields, List data) throws MyApplicationException { if (fields.isEmpty() || data.isEmpty()) return null; this.logger.debug("checking related - {}", UserContactInfo.class.getSimpleName()); Map> itemMap; FieldSet clone = new BaseFieldSet(fields.getFields()).ensure(this.asIndexer(UserContactInfo._user, User._id)); UserContactInfoQuery query = this.queryFactory.query(UserContactInfoQuery.class).authorize(this.authorize).userIds(data.stream().map(UserEntity::getId).distinct().collect(Collectors.toList())); itemMap = this.builderFactory.builder(UserContactInfoBuilder.class).authorize(this.authorize).asMasterKey(query, clone, x -> x.getUser().getId()); if (!fields.hasField(this.asIndexer(UserContactInfo._user, User._id))) { itemMap.values().stream().flatMap(List::stream).filter(x -> x != null && x.getUser() != null).peek(x -> { x.getUser().setId(null); }); } return itemMap; } private Map> collectUserGlobalRoles(FieldSet fields, List data) throws MyApplicationException { if (fields.isEmpty() || data.isEmpty()) return null; this.logger.debug("checking related - {}", UserRole.class.getSimpleName()); Map> itemMap; FieldSet clone = new BaseFieldSet(fields.getFields()).ensure(this.asIndexer(UserRole._user, User._id)); UserRoleQuery query = this.queryFactory.query(UserRoleQuery.class).authorize(this.authorize).tenantIsSet(false).roles(this.authorizationProperties.getAllowedGlobalRoles()).userIds(data.stream().map(UserEntity::getId).distinct().collect(Collectors.toList())); itemMap = this.builderFactory.builder(UserRoleBuilder.class).authorize(this.authorize).asMasterKey(query, clone, x -> x.getUser().getId()); if (!fields.hasField(this.asIndexer(UserRole._user, User._id))) { itemMap.values().stream().flatMap(List::stream).filter(x -> x != null && x.getUser() != null).peek(x -> { x.getUser().setId(null); }); } return itemMap; } private Map> collectUserTenantRoles(FieldSet fields, List data) throws MyApplicationException { if (fields.isEmpty() || data.isEmpty()) return null; this.logger.debug("checking related - {}", UserRole.class.getSimpleName()); Map> itemMap; FieldSet clone = new BaseFieldSet(fields.getFields()).ensure(this.asIndexer(UserRole._user, User._id)); if (!tenantScope.isSet()) throw new MyForbiddenException("tenant scope required"); UserRoleQuery query = this.queryFactory.query(UserRoleQuery.class).authorize(this.authorize).roles(this.authorizationProperties.getAllowedTenantRoles()).userIds(data.stream().map(UserEntity::getId).distinct().collect(Collectors.toList())); if (tenantScope.isDefaultTenant()) query.tenantIsSet(false); else { try { query.tenantIsSet(true).tenantIds(this.tenantScope.getTenant()); } catch (InvalidApplicationException e) { throw new RuntimeException(e); } } itemMap = this.builderFactory.builder(UserRoleBuilder.class).authorize(this.authorize).asMasterKey(query, clone, x -> x.getUser().getId()); if (!fields.hasField(this.asIndexer(UserRole._user, User._id))) { itemMap.values().stream().flatMap(List::stream).filter(x -> x != null && x.getUser() != null).peek(x -> { x.getUser().setId(null); }); } return itemMap; } private Map> collectUserCredentials(FieldSet fields, List data) throws MyApplicationException { if (fields.isEmpty() || data.isEmpty()) return null; this.logger.debug("checking related - {}", UserCredential.class.getSimpleName()); Map> itemMap; FieldSet clone = new BaseFieldSet(fields.getFields()).ensure(this.asIndexer(UserCredential._user, User._id)); UserCredentialQuery query = this.queryFactory.query(UserCredentialQuery.class).authorize(this.authorize).userIds(data.stream().map(UserEntity::getId).distinct().collect(Collectors.toList())); itemMap = this.builderFactory.builder(UserCredentialBuilder.class).authorize(this.authorize).asMasterKey(query, clone, x -> x.getUser().getId()); if (!fields.hasField(this.asIndexer(UserCredential._user, User._id))) { itemMap.values().stream().flatMap(List::stream).filter(x -> x != null && x.getUser() != null).peek(x -> { x.getUser().setId(null); }); } return itemMap; } private Map> collectTenantUsers(FieldSet fields, List datas) throws MyApplicationException { if (fields.isEmpty() || datas.isEmpty()) return null; this.logger.debug("checking related - {}", TenantUser.class.getSimpleName()); Map> itemMap = null; FieldSet clone = new BaseFieldSet(fields.getFields()).ensure(this.asIndexer(TenantUser._user, User._id)); TenantUserQuery query = this.queryFactory.query(TenantUserQuery.class).authorize(this.authorize).userIds(datas.stream().map(x -> x.getId()).distinct().collect(Collectors.toList())); itemMap = this.builderFactory.builder(TenantUserBuilder.class).authorize(this.authorize).asMasterKey(query, clone, x -> x.getUser().getId()); if (!fields.hasField(this.asIndexer(TenantUser._user, User._id))) { itemMap.values().stream().flatMap(List::stream).filter(x -> x != null && x.getUser() != null).map(x -> { x.getUser().setId(null); return x; }).collect(Collectors.toList()); } return itemMap; } }