diff --git a/dmp-backend/core/src/main/java/eu/eudat/audit/AuditableAction.java b/dmp-backend/core/src/main/java/eu/eudat/audit/AuditableAction.java index aa262ad0e..7e747ebe4 100644 --- a/dmp-backend/core/src/main/java/eu/eudat/audit/AuditableAction.java +++ b/dmp-backend/core/src/main/java/eu/eudat/audit/AuditableAction.java @@ -145,5 +145,10 @@ public class AuditableAction { public static final EventId GetSemantics = new EventId(250000, "GetSemantics"); + public static final EventId PrefillingSource_Query = new EventId(260000, "PrefillingSource_Query"); + public static final EventId PrefillingSource_Lookup = new EventId(260001, "PrefillingSource_Lookup"); + public static final EventId PrefillingSource_Persist = new EventId(260002, "PrefillingSource_Persist"); + public static final EventId PrefillingSource_Delete = new EventId(260003, "PrefillingSource_Delete"); + } diff --git a/dmp-backend/core/src/main/java/eu/eudat/authorization/Permission.java b/dmp-backend/core/src/main/java/eu/eudat/authorization/Permission.java index 35d331bb7..322326452 100644 --- a/dmp-backend/core/src/main/java/eu/eudat/authorization/Permission.java +++ b/dmp-backend/core/src/main/java/eu/eudat/authorization/Permission.java @@ -184,5 +184,10 @@ public final class Permission { public static String EditActionConfirmation = "EditActionConfirmation"; public static String DeleteActionConfirmation = "DeleteActionConfirmation"; + //PrefillingSource + public static String BrowsePrefillingSource = "BrowsePrefillingSource"; + public static String EditPrefillingSource= "EditPrefillingSource"; + public static String DeletePrefillingSource = "DeletePrefillingSource"; + } diff --git a/dmp-backend/core/src/main/java/eu/eudat/data/PrefillingSourceEntity.java b/dmp-backend/core/src/main/java/eu/eudat/data/PrefillingSourceEntity.java new file mode 100644 index 000000000..72d0e7235 --- /dev/null +++ b/dmp-backend/core/src/main/java/eu/eudat/data/PrefillingSourceEntity.java @@ -0,0 +1,89 @@ +package eu.eudat.data; + +import eu.eudat.commons.enums.IsActive; +import eu.eudat.data.converters.enums.IsActiveConverter; +import eu.eudat.data.tenant.TenantScopedBaseEntity; +import jakarta.persistence.*; + +import java.time.Instant; +import java.util.UUID; + +@Entity +@Table(name = "\"PrefillingSource\"") +public class PrefillingSourceEntity extends TenantScopedBaseEntity { + + @Id + @Column(name = "id", columnDefinition = "uuid", updatable = false, nullable = false) + private UUID id; + public static final String _id = "id"; + + @Column(name = "label", length = _labelLength, nullable = false) + private String label; + public static final String _label = "label"; + public static final int _labelLength = 250; + + @Column(name = "definition") + private String definition; + public static final String _definition = "definition"; + + @Column(name = "is_active", nullable = false) + @Convert(converter = IsActiveConverter.class) + private IsActive isActive; + public static final String _isActive = "isActive"; + + @Column(name = "created_at", nullable = false) + private Instant createdAt; + public static final String _createdAt = "createdAt"; + + @Column(name = "updated_at", nullable = false) + private Instant updatedAt; + public static final String _updatedAt = "updatedAt"; + + public UUID getId() { + return id; + } + + public void setId(UUID id) { + this.id = id; + } + + public String getLabel() { + return label; + } + + public void setLabel(String label) { + this.label = label; + } + + public String getDefinition() { + return definition; + } + + public void setDefinition(String definition) { + this.definition = definition; + } + + 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; + } +} diff --git a/dmp-backend/core/src/main/java/eu/eudat/model/PrefillingSource.java b/dmp-backend/core/src/main/java/eu/eudat/model/PrefillingSource.java new file mode 100644 index 000000000..6531866b2 --- /dev/null +++ b/dmp-backend/core/src/main/java/eu/eudat/model/PrefillingSource.java @@ -0,0 +1,87 @@ +package eu.eudat.model; + +import eu.eudat.commons.enums.IsActive; +import eu.eudat.model.referencetypedefinition.ReferenceTypeDefinition; + +import java.time.Instant; +import java.util.UUID; + +public class PrefillingSource { + + private UUID id; + public static final String _id = "id"; + + private String label; + public static final String _label = "label"; + + private String definition; + public static final String _definition = "definition"; + + private IsActive isActive; + public static final String _isActive = "isActive"; + + private Instant createdAt; + public static final String _createdAt = "createdAt"; + + private Instant updatedAt; + public static final String _updatedAt = "updatedAt"; + + public final static String _hash = "hash"; + private String hash; + + public UUID getId() { + return id; + } + + public void setId(UUID id) { + this.id = id; + } + + public String getLabel() { + return label; + } + + public void setLabel(String label) { + this.label = label; + } + + public String getDefinition() { + return definition; + } + + public void setDefinition(String definition) { + this.definition = definition; + } + + 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; + } +} diff --git a/dmp-backend/core/src/main/java/eu/eudat/model/builder/PrefillingSourceBuilder.java b/dmp-backend/core/src/main/java/eu/eudat/model/builder/PrefillingSourceBuilder.java new file mode 100644 index 000000000..932dd0bb4 --- /dev/null +++ b/dmp-backend/core/src/main/java/eu/eudat/model/builder/PrefillingSourceBuilder.java @@ -0,0 +1,71 @@ +package eu.eudat.model.builder; + +import eu.eudat.authorization.AuthorizationFlags; +import eu.eudat.commons.XmlHandlingService; +import eu.eudat.convention.ConventionService; +import eu.eudat.data.PrefillingSourceEntity; +import eu.eudat.model.PrefillingSource; +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.FieldSet; +import gr.cite.tools.logging.DataLogEntry; +import gr.cite.tools.logging.LoggerService; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.config.ConfigurableBeanFactory; +import org.springframework.context.annotation.Scope; +import org.springframework.stereotype.Component; + +import java.util.*; + +@Component +@Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE) +public class PrefillingSourceBuilder extends BaseBuilder{ + + private final BuilderFactory builderFactory; + private final QueryFactory queryFactory; + private final XmlHandlingService xmlHandlingService; + private EnumSet authorize = EnumSet.of(AuthorizationFlags.None); + + @Autowired + public PrefillingSourceBuilder( + ConventionService conventionService, + BuilderFactory builderFactory, QueryFactory queryFactory, XmlHandlingService xmlHandlingService) { + super(conventionService, new LoggerService(LoggerFactory.getLogger(PrefillingSourceBuilder.class))); + this.builderFactory = builderFactory; + this.queryFactory = queryFactory; + this.xmlHandlingService = xmlHandlingService; + } + + public PrefillingSourceBuilder 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<>(); + + FieldSet definitionFields = fields.extractPrefixed(this.asPrefix(PrefillingSource._definition)); + + List models = new ArrayList<>(); + for (PrefillingSourceEntity d : data) { + PrefillingSource m = new PrefillingSource(); + if (fields.hasField(this.asIndexer(PrefillingSource._id))) m.setId(d.getId()); + if (fields.hasField(this.asIndexer(PrefillingSource._label))) m.setLabel(d.getLabel()); + if (fields.hasField(this.asIndexer(PrefillingSource._definition))) m.setDefinition(d.getDefinition()); + if (fields.hasField(this.asIndexer(PrefillingSource._createdAt))) m.setCreatedAt(d.getCreatedAt()); + if (fields.hasField(this.asIndexer(PrefillingSource._updatedAt))) m.setUpdatedAt(d.getUpdatedAt()); + if (fields.hasField(this.asIndexer(PrefillingSource._isActive))) m.setIsActive(d.getIsActive()); + if (fields.hasField(this.asIndexer(PrefillingSource._hash))) m.setHash(this.hashValue(d.getUpdatedAt())); + + models.add(m); + } + this.logger.debug("build {} items", Optional.of(models).map(List::size).orElse(0)); + return models; + } +} diff --git a/dmp-backend/core/src/main/java/eu/eudat/model/censorship/PrefillingSourceCensor.java b/dmp-backend/core/src/main/java/eu/eudat/model/censorship/PrefillingSourceCensor.java new file mode 100644 index 000000000..7690e4083 --- /dev/null +++ b/dmp-backend/core/src/main/java/eu/eudat/model/censorship/PrefillingSourceCensor.java @@ -0,0 +1,46 @@ +package eu.eudat.model.censorship; + +import eu.eudat.authorization.Permission; +import eu.eudat.convention.ConventionService; +import eu.eudat.model.PrefillingSource; +import eu.eudat.model.censorship.referencetypedefinition.ReferenceTypeDefinitionCensor; +import gr.cite.commons.web.authz.service.AuthorizationService; +import gr.cite.tools.data.censor.CensorFactory; +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.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 PrefillingSourceCensor extends BaseCensor { + + private static final LoggerService logger = new LoggerService(LoggerFactory.getLogger(PrefillingSourceCensor.class)); + + protected final AuthorizationService authService; + protected final CensorFactory censorFactory; + + public PrefillingSourceCensor(ConventionService conventionService, + AuthorizationService authService, + CensorFactory censorFactory) { + super(conventionService); + this.authService = authService; + this.censorFactory = censorFactory; + } + + public void censor(FieldSet fields, UUID userId) { + logger.debug(new DataLogEntry("censoring fields", fields)); + if (fields == null || fields.isEmpty()) + return; + + this.authService.authorizeForce(Permission.BrowsePrefillingSource); + FieldSet definitionFields = fields.extractPrefixed(this.asIndexerPrefix(PrefillingSource._definition)); + this.censorFactory.censor(ReferenceTypeDefinitionCensor.class).censor(definitionFields, userId); + } + +} diff --git a/dmp-backend/core/src/main/java/eu/eudat/model/deleter/PrefillingSourceDeleter.java b/dmp-backend/core/src/main/java/eu/eudat/model/deleter/PrefillingSourceDeleter.java new file mode 100644 index 000000000..4e952f10b --- /dev/null +++ b/dmp-backend/core/src/main/java/eu/eudat/model/deleter/PrefillingSourceDeleter.java @@ -0,0 +1,78 @@ +package eu.eudat.model.deleter; + +import eu.eudat.commons.enums.IsActive; +import eu.eudat.data.PrefillingSourceEntity; +import eu.eudat.query.PrefillingSourceQuery; +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 jakarta.persistence.EntityManager; +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 PrefillingSourceDeleter implements Deleter { + + private static final LoggerService logger = new LoggerService(LoggerFactory.getLogger(PrefillingSourceDeleter.class)); + private final EntityManager entityManager; + + protected final QueryFactory queryFactory; + + protected final DeleterFactory deleterFactory; + + @Autowired + public PrefillingSourceDeleter( + EntityManager entityManager, + QueryFactory queryFactory, + DeleterFactory deleterFactory + ) { + this.entityManager = entityManager; + this.queryFactory = queryFactory; + this.deleterFactory = deleterFactory; + } + + public void deleteAndSaveByIds(List ids) throws InvalidApplicationException { + logger.debug(new MapLogEntry("collecting to delete").And("count", Optional.ofNullable(ids).map(List::size).orElse(0)).And("ids", ids)); + List data = this.queryFactory.query(PrefillingSourceQuery.class).ids(ids).collect(); + logger.trace("retrieved {} items", Optional.ofNullable(data).map(List::size).orElse(0)); + this.deleteAndSave(data); + } + + public void deleteAndSave(List 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 data) throws InvalidApplicationException { + logger.debug("will delete {} items", Optional.ofNullable(data).map(List::size).orElse(0)); + if (data == null || data.isEmpty()) + return; + + Instant now = Instant.now(); + + for (PrefillingSourceEntity item : data) { + 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"); + } + } + +} diff --git a/dmp-backend/core/src/main/java/eu/eudat/model/persist/PrefillingSourcePersist.java b/dmp-backend/core/src/main/java/eu/eudat/model/persist/PrefillingSourcePersist.java new file mode 100644 index 000000000..aa78ead46 --- /dev/null +++ b/dmp-backend/core/src/main/java/eu/eudat/model/persist/PrefillingSourcePersist.java @@ -0,0 +1,105 @@ +package eu.eudat.model.persist; + +import eu.eudat.commons.validation.BaseValidator; +import eu.eudat.convention.ConventionService; +import eu.eudat.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 PrefillingSourcePersist { + + private UUID id; + + private String label; + + public static final String _label = "label"; + + private String definition; + + public static final String _definition = "definition"; + + private String hash; + + public static final String _hash = "hash"; + + public UUID getId() { + return id; + } + + public void setId(UUID id) { + this.id = id; + } + + public String getLabel() { + return label; + } + + public void setLabel(String label) { + this.label = label; + } + + public String getDefinition() { + return definition; + } + + public void setDefinition(String definition) { + this.definition = definition; + } + + public String getHash() { + return hash; + } + + public void setHash(String hash) { + this.hash = hash; + } + + @Component(PrefillingSourcePersistValidator.ValidatorName) + @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE) + public static class PrefillingSourcePersistValidator extends BaseValidator { + + public static final String ValidatorName = "PrefillingSourcePersistValidator"; + + private final MessageSource messageSource; + + private final ValidatorFactory validatorFactory; + + protected PrefillingSourcePersistValidator(ConventionService conventionService, ErrorThesaurusProperties errors, MessageSource messageSource, ValidatorFactory validatorFactory) { + super(conventionService, errors); + this.messageSource = messageSource; + this.validatorFactory = validatorFactory; + } + + @Override + protected Class modelClass() { + return PrefillingSourcePersist.class; + } + + @Override + protected List specifications(PrefillingSourcePersist item) { + return Arrays.asList( + this.spec() + .iff(() -> this.isValidGuid(item.getId())) + .must(() -> this.isValidHash(item.getHash())) + .failOn(PrefillingSourcePersist._hash).failWith(messageSource.getMessage("Validation_Required", new Object[]{PrefillingSourcePersist._hash}, LocaleContextHolder.getLocale())), + this.spec() + .iff(() -> !this.isValidGuid(item.getId())) + .must(() -> !this.isValidHash(item.getHash())) + .failOn(PrefillingSourcePersist._hash).failWith(messageSource.getMessage("Validation_OverPosting", new Object[]{}, LocaleContextHolder.getLocale())), + this.spec() + .must(() -> !this.isEmpty(item.getLabel())) + .failOn(PrefillingSourcePersist._label).failWith(messageSource.getMessage("Validation_Required", new Object[]{PrefillingSourcePersist._label}, LocaleContextHolder.getLocale())) + ); + } + } + +} diff --git a/dmp-backend/core/src/main/java/eu/eudat/query/PrefillingSourceQuery.java b/dmp-backend/core/src/main/java/eu/eudat/query/PrefillingSourceQuery.java new file mode 100644 index 000000000..c876558e6 --- /dev/null +++ b/dmp-backend/core/src/main/java/eu/eudat/query/PrefillingSourceQuery.java @@ -0,0 +1,160 @@ +package eu.eudat.query; + +import eu.eudat.authorization.AuthorizationFlags; +import eu.eudat.commons.enums.IsActive; +import eu.eudat.data.PrefillingSourceEntity; +import eu.eudat.model.PrefillingSource; +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 PrefillingSourceQuery extends QueryBase { + + private String like; + + private Collection ids; + + private Collection isActives; + + private Collection excludedIds; + + private EnumSet authorize = EnumSet.of(AuthorizationFlags.None); + + public PrefillingSourceQuery like(String value) { + this.like = value; + return this; + } + + public PrefillingSourceQuery ids(UUID value) { + this.ids = List.of(value); + return this; + } + + public PrefillingSourceQuery ids(UUID... value) { + this.ids = Arrays.asList(value); + return this; + } + + public PrefillingSourceQuery ids(Collection values) { + this.ids = values; + return this; + } + + public PrefillingSourceQuery isActive(IsActive value) { + this.isActives = List.of(value); + return this; + } + + public PrefillingSourceQuery isActive(IsActive... value) { + this.isActives = Arrays.asList(value); + return this; + } + + public PrefillingSourceQuery isActive(Collection values) { + this.isActives = values; + return this; + } + + public PrefillingSourceQuery excludedIds(Collection values) { + this.excludedIds = values; + return this; + } + + public PrefillingSourceQuery excludedIds(UUID value) { + this.excludedIds = List.of(value); + return this; + } + + public PrefillingSourceQuery excludedIds(UUID... value) { + this.excludedIds = Arrays.asList(value); + return this; + } + + public PrefillingSourceQuery authorize(EnumSet values) { + this.authorize = values; + return this; + } + + + public PrefillingSourceQuery( + ) { + } + + @Override + protected Class entityClass() { + return PrefillingSourceEntity.class; + } + + @Override + protected Boolean isFalseQuery() { + return this.isEmpty(this.ids) || this.isEmpty(this.isActives) || this.isEmpty(this.excludedIds); + } + + @Override + protected Predicate applyFilters(QueryContext queryContext) { + List predicates = new ArrayList<>(); + if (this.ids != null) { + CriteriaBuilder.In inClause = queryContext.CriteriaBuilder.in(queryContext.Root.get(PrefillingSourceEntity._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(PrefillingSourceEntity._label), this.like)); + } + if (this.isActives != null) { + CriteriaBuilder.In inClause = queryContext.CriteriaBuilder.in(queryContext.Root.get(PrefillingSourceEntity._isActive)); + for (IsActive item : this.isActives) + inClause.value(item); + predicates.add(inClause); + } + if (this.excludedIds != null) { + CriteriaBuilder.In notInClause = queryContext.CriteriaBuilder.in(queryContext.Root.get(PrefillingSourceEntity._id)); + for (UUID item : this.excludedIds) + notInClause.value(item); + predicates.add(notInClause.not()); + } + if (!predicates.isEmpty()) { + Predicate[] predicatesArray = predicates.toArray(new Predicate[0]); + return queryContext.CriteriaBuilder.and(predicatesArray); + } else { + return null; + } + } + + @Override + protected PrefillingSourceEntity convert(Tuple tuple, Set columns) { + PrefillingSourceEntity item = new PrefillingSourceEntity(); + item.setId(QueryBase.convertSafe(tuple, columns, PrefillingSourceEntity._id, UUID.class)); + item.setLabel(QueryBase.convertSafe(tuple, columns, PrefillingSourceEntity._label, String.class)); + item.setDefinition(QueryBase.convertSafe(tuple, columns, PrefillingSourceEntity._definition, String.class)); + item.setCreatedAt(QueryBase.convertSafe(tuple, columns, PrefillingSourceEntity._createdAt, Instant.class)); + item.setUpdatedAt(QueryBase.convertSafe(tuple, columns, PrefillingSourceEntity._updatedAt, Instant.class)); + item.setIsActive(QueryBase.convertSafe(tuple, columns, PrefillingSourceEntity._isActive, IsActive.class)); + return item; + } + + @Override + protected String fieldNameOf(FieldResolver item) { + if (item.match(PrefillingSource._id)) return PrefillingSourceEntity._id; + else if (item.match(PrefillingSource._label)) return PrefillingSourceEntity._label; + else if (item.prefix(PrefillingSource._definition)) return PrefillingSourceEntity._definition; + else if (item.match(PrefillingSource._createdAt)) return PrefillingSourceEntity._createdAt; + else if (item.match(PrefillingSource._updatedAt)) return PrefillingSourceEntity._updatedAt; + else if (item.match(PrefillingSource._hash)) return PrefillingSourceEntity._updatedAt; + else if (item.match(PrefillingSource._isActive)) return PrefillingSourceEntity._isActive; + else return null; + } + +} diff --git a/dmp-backend/core/src/main/java/eu/eudat/query/lookup/PrefillingSourceLookup.java b/dmp-backend/core/src/main/java/eu/eudat/query/lookup/PrefillingSourceLookup.java new file mode 100644 index 000000000..ba47ddb1c --- /dev/null +++ b/dmp-backend/core/src/main/java/eu/eudat/query/lookup/PrefillingSourceLookup.java @@ -0,0 +1,66 @@ +package eu.eudat.query.lookup; + +import eu.eudat.commons.enums.IsActive; +import eu.eudat.query.PrefillingSourceQuery; +import gr.cite.tools.data.query.Lookup; +import gr.cite.tools.data.query.QueryFactory; + +import java.util.List; +import java.util.UUID; + +public class PrefillingSourceLookup extends Lookup { + + private String like; + + private List isActive; + + private List ids; + + private List excludedIds; + + public String getLike() { + return like; + } + + public void setLike(String like) { + this.like = like; + } + + public List getIsActive() { + return isActive; + } + + public void setIsActive(List isActive) { + this.isActive = isActive; + } + + public List getIds() { + return ids; + } + + public void setIds(List ids) { + this.ids = ids; + } + + public List getExcludedIds() { + return excludedIds; + } + + public void setExcludedIds(List excludeIds) { + this.excludedIds = excludeIds; + } + + + public PrefillingSourceQuery enrich(QueryFactory queryFactory) { + PrefillingSourceQuery query = queryFactory.query(PrefillingSourceQuery.class); + if (this.like != null) query.like(this.like); + if (this.isActive != null) query.isActive(this.isActive); + if (this.ids != null) query.ids(this.ids); + if (this.excludedIds != null) query.excludedIds(this.excludedIds); + + this.enrichCommon(query); + + return query; + } + +} diff --git a/dmp-backend/core/src/main/java/eu/eudat/service/prefillingsource/PrefillingSourceService.java b/dmp-backend/core/src/main/java/eu/eudat/service/prefillingsource/PrefillingSourceService.java new file mode 100644 index 000000000..f612b604e --- /dev/null +++ b/dmp-backend/core/src/main/java/eu/eudat/service/prefillingsource/PrefillingSourceService.java @@ -0,0 +1,19 @@ +package eu.eudat.service.prefillingsource; + +import eu.eudat.model.PrefillingSource; +import eu.eudat.model.persist.PrefillingSourcePersist; +import gr.cite.tools.exception.MyApplicationException; +import gr.cite.tools.exception.MyForbiddenException; +import gr.cite.tools.exception.MyNotFoundException; +import gr.cite.tools.exception.MyValidationException; +import gr.cite.tools.fieldset.FieldSet; + +import javax.management.InvalidApplicationException; +import java.util.UUID; + +public interface PrefillingSourceService { + + PrefillingSource persist(PrefillingSourcePersist model, FieldSet fields) throws MyForbiddenException, MyValidationException, MyApplicationException, MyNotFoundException, InvalidApplicationException; + + void deleteAndSave(UUID id) throws MyForbiddenException, InvalidApplicationException; +} diff --git a/dmp-backend/core/src/main/java/eu/eudat/service/prefillingsource/PrefillingSourceServiceImpl.java b/dmp-backend/core/src/main/java/eu/eudat/service/prefillingsource/PrefillingSourceServiceImpl.java new file mode 100644 index 000000000..1409eda3e --- /dev/null +++ b/dmp-backend/core/src/main/java/eu/eudat/service/prefillingsource/PrefillingSourceServiceImpl.java @@ -0,0 +1,105 @@ +package eu.eudat.service.prefillingsource; + +import eu.eudat.authorization.AuthorizationFlags; +import eu.eudat.authorization.Permission; +import eu.eudat.commons.XmlHandlingService; +import eu.eudat.commons.enums.IsActive; +import eu.eudat.convention.ConventionService; +import eu.eudat.data.PrefillingSourceEntity; +import eu.eudat.errorcode.ErrorThesaurusProperties; +import eu.eudat.model.PrefillingSource; +import eu.eudat.model.builder.PrefillingSourceBuilder; +import eu.eudat.model.deleter.PrefillingSourceDeleter; +import eu.eudat.model.persist.PrefillingSourcePersist; +import gr.cite.commons.web.authz.service.AuthorizationService; +import gr.cite.tools.data.builder.BuilderFactory; +import gr.cite.tools.data.deleter.DeleterFactory; +import gr.cite.tools.exception.MyApplicationException; +import gr.cite.tools.exception.MyForbiddenException; +import gr.cite.tools.exception.MyNotFoundException; +import gr.cite.tools.exception.MyValidationException; +import gr.cite.tools.fieldset.BaseFieldSet; +import gr.cite.tools.fieldset.FieldSet; +import gr.cite.tools.logging.LoggerService; +import gr.cite.tools.logging.MapLogEntry; +import jakarta.persistence.EntityManager; +import org.slf4j.LoggerFactory; +import org.springframework.context.MessageSource; +import org.springframework.context.i18n.LocaleContextHolder; +import org.springframework.stereotype.Service; + +import javax.management.InvalidApplicationException; +import java.time.Instant; +import java.util.List; +import java.util.UUID; + +@Service +public class PrefillingSourceServiceImpl implements PrefillingSourceService { + + private static final LoggerService logger = new LoggerService(LoggerFactory.getLogger(PrefillingSourceServiceImpl.class)); + private final EntityManager entityManager; + private final AuthorizationService authorizationService; + private final DeleterFactory deleterFactory; + private final BuilderFactory builderFactory; + private final ConventionService conventionService; + private final MessageSource messageSource; + private final XmlHandlingService xmlHandlingService; + private final ErrorThesaurusProperties errors; + + + public PrefillingSourceServiceImpl( + EntityManager entityManager, AuthorizationService authorizationService, DeleterFactory deleterFactory, BuilderFactory builderFactory, + ConventionService conventionService, MessageSource messageSource, + XmlHandlingService xmlHandlingService, ErrorThesaurusProperties errors) { + this.entityManager = entityManager; + this.authorizationService = authorizationService; + this.deleterFactory = deleterFactory; + this.builderFactory = builderFactory; + this.conventionService = conventionService; + this.messageSource = messageSource; + this.xmlHandlingService = xmlHandlingService; + this.errors = errors; + } + + + public PrefillingSource persist(PrefillingSourcePersist model, FieldSet fields) throws MyForbiddenException, MyValidationException, MyApplicationException, MyNotFoundException, InvalidApplicationException{ + logger.debug(new MapLogEntry("persisting data").And("model", model).And("fields", fields)); + + this.authorizationService.authorizeForce(Permission.EditPrefillingSource); + + Boolean isUpdate = this.conventionService.isValidGuid(model.getId()); + + PrefillingSourceEntity data; + if (isUpdate) { + data = this.entityManager.find(PrefillingSourceEntity.class, model.getId()); + if (data == null) + throw new MyNotFoundException(messageSource.getMessage("General_ItemNotFound", new Object[]{model.getId(), PrefillingSource.class.getSimpleName()}, LocaleContextHolder.getLocale())); + if (!this.conventionService.hashValue(data.getUpdatedAt()).equals(model.getHash())) throw new MyValidationException(this.errors.getHashConflict().getCode(), this.errors.getHashConflict().getMessage()); + } else { + + data = new PrefillingSourceEntity(); + data.setId(UUID.randomUUID()); + data.setIsActive(IsActive.Active); + data.setCreatedAt(Instant.now()); + } + + data.setLabel(model.getLabel()); + data.setDefinition(model.getDefinition()); + data.setUpdatedAt(Instant.now()); + + if (isUpdate) this.entityManager.merge(data); + else this.entityManager.persist(data); + + this.entityManager.flush(); + + return this.builderFactory.builder(PrefillingSourceBuilder.class).authorize(AuthorizationFlags.OwnerOrDmpAssociatedOrPermissionOrPublic).build(BaseFieldSet.build(fields, PrefillingSource._id), data); + } + + public void deleteAndSave(UUID id) throws MyForbiddenException, InvalidApplicationException { + logger.debug("deleting : {}", id); + + this.authorizationService.authorizeForce(Permission.DeletePrefillingSource); + + this.deleterFactory.deleter(PrefillingSourceDeleter.class).deleteAndSaveByIds(List.of(id)); + } +} diff --git a/dmp-backend/core/src/main/java/eu/eudat/service/referencetype/ReferenceTypeServiceImpl.java b/dmp-backend/core/src/main/java/eu/eudat/service/referencetype/ReferenceTypeServiceImpl.java index 88533773c..8c663c878 100644 --- a/dmp-backend/core/src/main/java/eu/eudat/service/referencetype/ReferenceTypeServiceImpl.java +++ b/dmp-backend/core/src/main/java/eu/eudat/service/referencetype/ReferenceTypeServiceImpl.java @@ -14,7 +14,6 @@ import eu.eudat.model.builder.ReferenceTypeBuilder; import eu.eudat.model.deleter.ReferenceTypeDeleter; import eu.eudat.model.persist.ReferenceTypePersist; import eu.eudat.model.persist.referencetypedefinition.*; -import eu.eudat.service.dmpblueprint.DmpBlueprintServiceImpl; import gr.cite.commons.web.authz.service.AuthorizationService; import gr.cite.tools.data.builder.BuilderFactory; import gr.cite.tools.data.deleter.DeleterFactory; @@ -44,7 +43,7 @@ import java.util.UUID; @Service public class ReferenceTypeServiceImpl implements ReferenceTypeService { - private static final LoggerService logger = new LoggerService(LoggerFactory.getLogger(DmpBlueprintServiceImpl.class)); + private static final LoggerService logger = new LoggerService(LoggerFactory.getLogger(ReferenceTypeServiceImpl.class)); private final EntityManager entityManager; private final AuthorizationService authorizationService; private final DeleterFactory deleterFactory; diff --git a/dmp-backend/web/src/main/java/eu/eudat/controllers/PrefillingSourceController.java b/dmp-backend/web/src/main/java/eu/eudat/controllers/PrefillingSourceController.java new file mode 100644 index 000000000..7137398b0 --- /dev/null +++ b/dmp-backend/web/src/main/java/eu/eudat/controllers/PrefillingSourceController.java @@ -0,0 +1,139 @@ +package eu.eudat.controllers; + +import com.fasterxml.jackson.core.JsonProcessingException; +import eu.eudat.audit.AuditableAction; +import eu.eudat.authorization.AuthorizationFlags; +import eu.eudat.data.PrefillingSourceEntity; +import eu.eudat.model.PrefillingSource; +import eu.eudat.model.builder.PrefillingSourceBuilder; +import eu.eudat.model.censorship.PrefillingSourceCensor; +import eu.eudat.model.persist.PrefillingSourcePersist; +import eu.eudat.model.result.QueryResult; +import eu.eudat.query.PrefillingSourceQuery; +import eu.eudat.query.lookup.PrefillingSourceLookup; +import eu.eudat.service.prefillingsource.PrefillingSourceService; +import gr.cite.commons.web.authz.service.AuthorizationService; +import gr.cite.tools.auditing.AuditService; +import gr.cite.tools.data.builder.BuilderFactory; +import gr.cite.tools.data.censor.CensorFactory; +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.FieldSet; +import gr.cite.tools.logging.LoggerService; +import gr.cite.tools.logging.MapLogEntry; +import gr.cite.tools.validation.ValidationFilterAnnotation; +import jakarta.transaction.Transactional; +import jakarta.xml.bind.JAXBException; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.MessageSource; +import org.springframework.context.i18n.LocaleContextHolder; +import org.springframework.web.bind.annotation.*; + +import javax.management.InvalidApplicationException; +import java.util.AbstractMap; +import java.util.List; +import java.util.Map; +import java.util.UUID; + +@RestController +@RequestMapping(path = {"api/prefilling-source"}) +public class PrefillingSourceController { + + private static final LoggerService logger = new LoggerService(LoggerFactory.getLogger(PrefillingSourceController.class)); + + private final BuilderFactory builderFactory; + + private final AuditService auditService; + + private final CensorFactory censorFactory; + + private final QueryFactory queryFactory; + + private final MessageSource messageSource; + + private final AuthorizationService authorizationService; + + private final PrefillingSourceService prefillingSourceService; + + @Autowired + public PrefillingSourceController( + BuilderFactory builderFactory, + AuditService auditService, + CensorFactory censorFactory, + QueryFactory queryFactory, + MessageSource messageSource, AuthorizationService authorizationService, PrefillingSourceService prefillingSourceService) { + this.builderFactory = builderFactory; + this.auditService = auditService; + this.censorFactory = censorFactory; + this.queryFactory = queryFactory; + this.messageSource = messageSource; + this.authorizationService = authorizationService; + this.prefillingSourceService = prefillingSourceService; + } + + @PostMapping("query") + public QueryResult query(@RequestBody PrefillingSourceLookup lookup) throws MyApplicationException, MyForbiddenException { + logger.debug("querying {}", PrefillingSource.class.getSimpleName()); + + this.censorFactory.censor(PrefillingSourceCensor.class).censor(lookup.getProject(), null); + + PrefillingSourceQuery query = lookup.enrich(this.queryFactory).authorize(AuthorizationFlags.OwnerOrDmpAssociatedOrPermissionOrPublic); + List data = query.collectAs(lookup.getProject()); + List models = this.builderFactory.builder(PrefillingSourceBuilder.class).authorize(AuthorizationFlags.OwnerOrDmpAssociatedOrPermissionOrPublic).build(lookup.getProject(), data); + long count = (lookup.getMetadata() != null && lookup.getMetadata().getCountAll()) ? query.count() : models.size(); + + this.auditService.track(AuditableAction.PrefillingSource_Query, "lookup", lookup); + + return new QueryResult<>(models, count); + } + + @GetMapping("{id}") + public PrefillingSource get(@PathVariable("id") UUID id, FieldSet fieldSet) throws MyApplicationException, MyForbiddenException, MyNotFoundException { + logger.debug(new MapLogEntry("retrieving" + PrefillingSource.class.getSimpleName()).And("id", id).And("fields", fieldSet)); + + this.censorFactory.censor(PrefillingSourceCensor.class).censor(fieldSet, null); + + PrefillingSourceQuery query = this.queryFactory.query(PrefillingSourceQuery.class).authorize(AuthorizationFlags.OwnerOrDmpAssociatedOrPermissionOrPublic).ids(id); + PrefillingSource model = this.builderFactory.builder(PrefillingSourceBuilder.class).authorize(AuthorizationFlags.OwnerOrDmpAssociatedOrPermissionOrPublic).build(fieldSet, query.firstAs(fieldSet)); + if (model == null) + throw new MyNotFoundException(messageSource.getMessage("General_ItemNotFound", new Object[]{id, PrefillingSource.class.getSimpleName()}, LocaleContextHolder.getLocale())); + + this.auditService.track(AuditableAction.PrefillingSource_Lookup, Map.ofEntries( + new AbstractMap.SimpleEntry("id", id), + new AbstractMap.SimpleEntry("fields", fieldSet) + )); + + return model; + } + + @PostMapping("persist") + @Transactional + @ValidationFilterAnnotation(validator = PrefillingSourcePersist.PrefillingSourcePersistValidator.ValidatorName, argumentName = "model") + public PrefillingSource persist(@RequestBody PrefillingSourcePersist model, FieldSet fieldSet) throws MyApplicationException, MyForbiddenException, MyNotFoundException, InvalidApplicationException, JAXBException, JsonProcessingException, InvalidApplicationException { + logger.debug(new MapLogEntry("persisting" + PrefillingSource.class.getSimpleName()).And("model", model).And("fieldSet", fieldSet)); + this.censorFactory.censor(PrefillingSourceCensor.class).censor(fieldSet, null); + + PrefillingSource persisted = this.prefillingSourceService.persist(model, fieldSet); + + this.auditService.track(AuditableAction.PrefillingSource_Persist, Map.ofEntries( + new AbstractMap.SimpleEntry("model", model), + new AbstractMap.SimpleEntry("fields", fieldSet) + )); + + return persisted; + } + + @DeleteMapping("{id}") + @Transactional + public void delete(@PathVariable("id") UUID id) throws MyForbiddenException, InvalidApplicationException { + logger.debug(new MapLogEntry("retrieving" + PrefillingSource.class.getSimpleName()).And("id", id)); + + this.prefillingSourceService.deleteAndSave(id); + + this.auditService.track(AuditableAction.PrefillingSource_Delete, "id", id); + } + +} diff --git a/dmp-backend/web/src/main/java/eu/eudat/controllers/ReferenceTypeController.java b/dmp-backend/web/src/main/java/eu/eudat/controllers/ReferenceTypeController.java index bde464354..40a56d931 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/controllers/ReferenceTypeController.java +++ b/dmp-backend/web/src/main/java/eu/eudat/controllers/ReferenceTypeController.java @@ -100,7 +100,7 @@ public class ReferenceTypeController{ ReferenceTypeQuery query = this.queryFactory.query(ReferenceTypeQuery.class).authorize(AuthorizationFlags.OwnerOrDmpAssociatedOrPermissionOrPublic).ids(id); ReferenceType model = this.builderFactory.builder(ReferenceTypeBuilder.class).authorize(AuthorizationFlags.OwnerOrDmpAssociatedOrPermissionOrPublic).build(fieldSet, query.firstAs(fieldSet)); if (model == null) - throw new MyNotFoundException(messageSource.getMessage("General_ItemNotFound", new Object[]{id, Reference.class.getSimpleName()}, LocaleContextHolder.getLocale())); + throw new MyNotFoundException(messageSource.getMessage("General_ItemNotFound", new Object[]{id, ReferenceType.class.getSimpleName()}, LocaleContextHolder.getLocale())); this.auditService.track(AuditableAction.ReferenceType_Lookup, Map.ofEntries( new AbstractMap.SimpleEntry("id", id), @@ -119,7 +119,7 @@ public class ReferenceTypeController{ ReferenceTypeQuery query = this.queryFactory.query(ReferenceTypeQuery.class).authorize(AuthorizationFlags.OwnerOrDmpAssociatedOrPermissionOrPublic).codes(code); ReferenceType model = this.builderFactory.builder(ReferenceTypeBuilder.class).authorize(AuthorizationFlags.OwnerOrDmpAssociatedOrPermissionOrPublic).build(fieldSet, query.firstAs(fieldSet)); if (model == null) - throw new MyNotFoundException(messageSource.getMessage("General_ItemNotFound", new Object[]{code, Reference.class.getSimpleName()}, LocaleContextHolder.getLocale())); + throw new MyNotFoundException(messageSource.getMessage("General_ItemNotFound", new Object[]{code, ReferenceType.class.getSimpleName()}, LocaleContextHolder.getLocale())); this.auditService.track(AuditableAction.ReferenceType_Lookup, Map.ofEntries( new AbstractMap.SimpleEntry("code", code), diff --git a/dmp-backend/web/src/main/resources/config/permissions.yml b/dmp-backend/web/src/main/resources/config/permissions.yml index d4ebb62a7..0623855fa 100644 --- a/dmp-backend/web/src/main/resources/config/permissions.yml +++ b/dmp-backend/web/src/main/resources/config/permissions.yml @@ -740,3 +740,24 @@ permissions: clients: [ ] allowAnonymous: false allowAuthenticated: false + + # PrefillingSource Permissions + BrowsePrefillingSource: + roles: + - Admin + clients: [ ] + allowAnonymous: false + allowAuthenticated: false + EditPrefillingSource: + roles: + - Admin + clients: [ ] + allowAnonymous: false + allowAuthenticated: false + DeletePrefillingSource: + roles: + - Admin + claims: [ ] + clients: [ ] + allowAnonymous: false + allowAuthenticated: false diff --git a/dmp-db-scema/updates/00.01.057_Add_PrefillingSource_table.sql b/dmp-db-scema/updates/00.01.057_Add_PrefillingSource_table.sql new file mode 100644 index 000000000..f65d6eb01 --- /dev/null +++ b/dmp-db-scema/updates/00.01.057_Add_PrefillingSource_table.sql @@ -0,0 +1,26 @@ +DO $$DECLARE + this_version CONSTANT varchar := '00.01.057'; +BEGIN + PERFORM * FROM "DBVersion" WHERE version = this_version; + IF FOUND THEN RETURN; END IF; + + CREATE TABLE public."PrefillingSource" + ( + id uuid NOT NULL, + label character varying(250) NOT NULL, + definition xml NOT NULL, + is_active smallint NOT NULL, + created_at timestamp without time zone NOT NULL, + updated_at timestamp without time zone NOT NULL, + tenant uuid, + CONSTRAINT "PrefillingSource_pkey" PRIMARY KEY (id), + CONSTRAINT "PrefillingSource_tenant_fkey" FOREIGN KEY (tenant) + REFERENCES public."Tenant" (id) MATCH SIMPLE + ON UPDATE NO ACTION + ON DELETE NO ACTION + NOT VALID + ); + + INSERT INTO public."DBVersion" VALUES ('DMPDB', '00.01.057', '2024-02-22 12:00:00.000000+02', now(), 'Add PrefillingSource table.'); + +END$$; \ No newline at end of file