argos/dmp-backend/core/src/main/java/eu/eudat/service/descriptiontemplate/DescriptionTemplateServiceI...

488 lines
24 KiB
Java

package eu.eudat.service.descriptiontemplate;
import com.fasterxml.jackson.core.JsonProcessingException;
import eu.eudat.authorization.AuthorizationFlags;
import eu.eudat.authorization.Permission;
import eu.eudat.commons.XmlHandlingService;
import eu.eudat.commons.enums.DescriptionTemplateStatus;
import eu.eudat.commons.enums.IsActive;
import eu.eudat.commons.enums.UserDescriptionTemplateRole;
import eu.eudat.commons.scope.user.UserScope;
import eu.eudat.commons.types.descriptiontemplate.*;
import eu.eudat.commons.types.descriptiontemplate.fielddata.BaseFieldDataEntity;
import eu.eudat.commons.types.descriptiontemplate.importmodel.DescriptionTemplateImportXml;
import eu.eudat.convention.ConventionService;
import eu.eudat.data.DescriptionTemplateEntity;
import eu.eudat.data.UserDescriptionTemplateEntity;
import eu.eudat.data.old.UserInfo;
import eu.eudat.errorcode.ErrorThesaurusProperties;
import eu.eudat.model.DescriptionTemplate;
import eu.eudat.model.builder.DescriptionTemplateBuilder;
import eu.eudat.model.deleter.DescriptionTemplateDeleter;
import eu.eudat.model.deleter.UserDescriptionTemplateDeleter;
import eu.eudat.model.descriptiontemplatedefinition.Definition;
import eu.eudat.model.descriptiontemplatedefinition.Field;
import eu.eudat.model.descriptiontemplatedefinition.Page;
import eu.eudat.model.descriptiontemplatedefinition.Section;
import eu.eudat.model.persist.DescriptionTemplatePersist;
import eu.eudat.model.persist.NewVersionDescriptionTemplatePersist;
import eu.eudat.model.persist.descriptiontemplatedefinition.*;
import eu.eudat.model.persist.descriptiontemplatedefinition.fielddata.BaseFieldDataPersist;
import eu.eudat.query.DescriptionTemplateQuery;
import eu.eudat.query.UserDescriptionTemplateQuery;
import eu.eudat.service.fielddatahelper.FieldDataHelperServiceProvider;
import eu.eudat.service.mail.MailService;
import eu.eudat.service.mail.SimpleMail;
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.data.query.Ordering;
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.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 gr.cite.tools.validation.ValidationService;
import jakarta.persistence.EntityManager;
import jakarta.xml.bind.JAXBException;
import org.jetbrains.annotations.NotNull;
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.core.env.Environment;
import org.springframework.stereotype.Service;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.xml.sax.SAXException;
import javax.management.InvalidApplicationException;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.TransformerException;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.time.Instant;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import java.util.stream.Collectors;
@Service
public class DescriptionTemplateServiceImpl implements DescriptionTemplateService {
private static final LoggerService logger = new LoggerService(LoggerFactory.getLogger(DescriptionTemplateServiceImpl.class));
private final EntityManager entityManager;
private final UserScope userScope;
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 FieldDataHelperServiceProvider fieldDataHelperServiceProvider;
private final QueryFactory queryFactory;
private final ErrorThesaurusProperties errors;
private final ValidationService validationService;
private final MailService mailService;
private final Environment environment;
@Autowired
public DescriptionTemplateServiceImpl(
EntityManager entityManager,
UserScope userScope, AuthorizationService authorizationService,
DeleterFactory deleterFactory,
BuilderFactory builderFactory,
ConventionService conventionService,
MessageSource messageSource,
XmlHandlingService xmlHandlingService,
FieldDataHelperServiceProvider fieldDataHelperServiceProvider, QueryFactory queryFactory, ErrorThesaurusProperties errors, ValidationService validationService, MailService mailService, Environment environment) {
this.entityManager = entityManager;
this.userScope = userScope;
this.authorizationService = authorizationService;
this.deleterFactory = deleterFactory;
this.builderFactory = builderFactory;
this.conventionService = conventionService;
this.messageSource = messageSource;
this.xmlHandlingService = xmlHandlingService;
this.fieldDataHelperServiceProvider = fieldDataHelperServiceProvider;
this.queryFactory = queryFactory;
this.errors = errors;
this.validationService = validationService;
this.mailService = mailService;
this.environment = environment;
}
public DescriptionTemplate persist(DescriptionTemplatePersist model, FieldSet fields) throws MyForbiddenException, MyValidationException, MyApplicationException, MyNotFoundException, InvalidApplicationException, JAXBException, ParserConfigurationException, JsonProcessingException, TransformerException {
logger.debug(new MapLogEntry("persisting data descriptionTemplate").And("model", model).And("fields", fields));
this.authorizationService.authorizeForce(Permission.EditDescriptionTemplate);
Boolean isUpdate = this.conventionService.isValidGuid(model.getId());
DescriptionTemplateEntity data;
if (isUpdate) {
data = this.entityManager.find(DescriptionTemplateEntity.class, model.getId());
if (data == null) throw new MyNotFoundException(messageSource.getMessage("General_ItemNotFound", new Object[]{model.getId(), DescriptionTemplate.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 DescriptionTemplateEntity();
data.setId(UUID.randomUUID());
data.setIsActive(IsActive.Active);
data.setCreatedAt(Instant.now());
data.setGroupId(UUID.randomUUID());
data.setVersion((short)1);
}
data.setDescription(model.getDescription());
data.setLabel(model.getLabel());
data.setType(model.getType());
data.setLanguage(model.getLanguage());
data.setStatus(model.getStatus());
data.setUpdatedAt(Instant.now());
data.setDefinition(this.xmlHandlingService.toXml(this.buildDefinitionEntity(model.getDefinition())));
if (isUpdate)
this.entityManager.merge(data);
else
this.entityManager.persist(data);
this.persistUsers(data.getId(), model.getUsers());
if (!isUpdate) this.addOwner(data);
this.entityManager.flush();
return this.builderFactory.builder(DescriptionTemplateBuilder.class).authorize(AuthorizationFlags.OwnerOrPermission).build(BaseFieldSet.build(fields, DescriptionTemplate._id), data);
}
private void persistUsers(UUID id, List<UUID> users) throws InvalidApplicationException {
if (users == null) users = new ArrayList<>();
List<UserDescriptionTemplateEntity> items = this.queryFactory.query(UserDescriptionTemplateQuery.class).isActive(IsActive.Active).descriptionTemplateIds(id).collect();
for (UUID userId : users) {
UserDescriptionTemplateEntity data = items.stream().filter(x -> x.getUser() == userId).findFirst().orElse(null);
if (data == null){
data = new UserDescriptionTemplateEntity();
data.setId(UUID.randomUUID());
data.setIsActive(IsActive.Active);
data.setCreatedAt(Instant.now());
data.setDescriptionTemplate(id);
data.setUser(userId);
data.setUser(userId);
data.setRole(UserDescriptionTemplateRole.Member);
this.entityManager.persist(data);
this.sendJoinMail(data);
}
}
List<UUID> finalUsers = users;
List<UserDescriptionTemplateEntity> toDelete = items.stream().filter(x-> finalUsers.stream().noneMatch(y-> y.equals(x.getUser()))).collect(Collectors.toList());
this.deleterFactory.deleter(UserDescriptionTemplateDeleter.class).delete(toDelete);
}
private void sendJoinMail(UserDescriptionTemplateEntity userDatasetProfile) {
SimpleMail mail = new SimpleMail();
UserInfo user = this.entityManager.find(UserInfo.class, userDatasetProfile.getUser());
DescriptionTemplateEntity descriptionTemplate = this.queryFactory.query(DescriptionTemplateQuery.class).isActive(IsActive.Active).ids(userDatasetProfile.getDescriptionTemplate()).first();
mail.setSubject(environment.getProperty("admin.mail.subject").replace( "{templateName}", descriptionTemplate.getLabel()));
String content = this.mailService.getMailTemplateContent(environment.getProperty("email.dataset.template"));
content = content.replace("{recipient}", user.getName());
content = content.replace("{templateName}", descriptionTemplate.getLabel());
content = content.replace("{host}", this.environment.getProperty("dmp.domain"));
content = content.replace("{templateID}", descriptionTemplate.getId().toString());
mail.setContent(content);
mail.setTo(user.getEmail());
try {
this.mailService.sendSimpleMail(mail);
} catch (Exception ex) {
logger.error(ex.getMessage(), ex);
}
}
private void addOwner(DescriptionTemplateEntity descriptionTemplateEntity) throws InvalidApplicationException {
UserDescriptionTemplateEntity data = new UserDescriptionTemplateEntity();
data.setId(UUID.randomUUID());
data.setIsActive(IsActive.Active);
data.setCreatedAt(Instant.now());
data.setRole(UserDescriptionTemplateRole.Owner);
data.setUser(userScope.getUserId());
data.setDescriptionTemplate(descriptionTemplateEntity.getId());
this.entityManager.persist(data);
}
private @NotNull DefinitionEntity buildDefinitionEntity(DefinitionPersist persist){
DefinitionEntity data = new DefinitionEntity();
if (persist == null) return data;
if (!this.conventionService.isListNullOrEmpty(persist.getSections())){
data.setSections(new ArrayList<>());
for (SectionPersist sectionPersist: persist.getSections()) {
data.getSections().add(this.buildSectionEntity(sectionPersist));
}
}
if (!this.conventionService.isListNullOrEmpty(persist.getPages())){
data.setPages(new ArrayList<>());
for (PagePersist pagePersist: persist.getPages()) {
data.getPages().add(this.buildPageEntity(pagePersist));
}
}
return data;
}
private @NotNull SectionEntity buildSectionEntity(SectionPersist persist){
SectionEntity data = new SectionEntity();
if (persist == null) return data;
data.setId(persist.getId());
data.setDescription(persist.getDescription());
data.setOrdinal(persist.getOrdinal());
data.setDefaultVisibility(persist.getDefaultVisibility());
data.setMultiplicity(persist.getMultiplicity());
data.setPage(persist.getPage());
data.setTitle(persist.getTitle());
if (!this.conventionService.isListNullOrEmpty(persist.getSections())){
data.setSections(new ArrayList<>());
for (SectionPersist sectionPersist: persist.getSections()) {
data.getSections().add(this.buildSectionEntity(sectionPersist));
}
}
if (!this.conventionService.isListNullOrEmpty(persist.getFieldSets())){
data.setFieldSets(new ArrayList<>());
for (FieldSetPersist fieldSetPersist: persist.getFieldSets()) {
data.getFieldSets().add(this.buildFieldSetEntity(fieldSetPersist));
}
}
return data;
}
private @NotNull FieldSetEntity buildFieldSetEntity(FieldSetPersist persist){
FieldSetEntity data = new FieldSetEntity();
if (persist == null) return data;
data.setId(persist.getId());
data.setDescription(persist.getDescription());
data.setOrdinal(persist.getOrdinal());
data.setTitle(persist.getTitle());
data.setNumbering(persist.getNumbering());
data.setAdditionalInformation(persist.getAdditionalInformation());
data.setTitle(persist.getTitle());
if (persist.getMultiplicity() != null) data.setMultiplicity(this.buildMultiplicityEntity(persist.getMultiplicity()));
data.setHasCommentField(persist.getHasCommentField());
data.setTitle(persist.getTitle());
if (!this.conventionService.isListNullOrEmpty(persist.getFields())){
data.setFields(new ArrayList<>());
for (FieldPersist fieldPersist: persist.getFields()) {
data.getFields().add(this.buildFieldEntity(fieldPersist));
}
}
return data;
}
private @NotNull FieldEntity buildFieldEntity(FieldPersist persist){
FieldEntity data = new FieldEntity();
if (persist == null) return data;
data.setId(persist.getId());
data.setOrdinal(persist.getOrdinal());
data.setSchematics(persist.getSchematics());
//data.setNumbering(persist.get()); //TODO
data.setDefaultValue(persist.getDefaultValue());
data.setValidations(persist.getValidations());
data.setIncludeInExport(persist.getIncludeInExport());
if (persist.getData() != null) data.setData(this.buildFieldDataEntity(persist.getData()));
if (!this.conventionService.isListNullOrEmpty(persist.getVisibilityRules())){
data.setVisibilityRules(new ArrayList<>());
for (RulePersist fieldPersist: persist.getVisibilityRules()) {
data.getVisibilityRules().add(this.buildRuleEntity(fieldPersist));
}
}
return data;
}
private BaseFieldDataEntity<?> buildFieldDataEntity(BaseFieldDataPersist persist){
if (persist == null) return null;
return this.fieldDataHelperServiceProvider.get(persist.getFieldType()).applyPersist(persist);
}
private @NotNull RuleEntity buildRuleEntity(RulePersist persist){
RuleEntity data = new RuleEntity();
if (persist == null) return data;
data.setTarget(persist.getTarget());
data.setValue(persist.getValue());
return data;
}
private @NotNull MultiplicityEntity buildMultiplicityEntity(MultiplicityPersist persist){
MultiplicityEntity data = new MultiplicityEntity();
if (persist == null) return data;
data.setMax(persist.getMax());
data.setMin(persist.getMin());
data.setPlaceholder(persist.getPlaceholder());
data.setTableView(persist.getTableView());
return data;
}
private @NotNull PageEntity buildPageEntity(PagePersist persist){
PageEntity data = new PageEntity();
if (persist == null) return data;
data.setId(persist.getId());
data.setOrdinal(persist.getOrdinal());
data.setTitle(persist.getTitle());
return data;
}
public void deleteAndSave(UUID id) throws MyForbiddenException, InvalidApplicationException {
logger.debug("deleting dataset: {}", id);
this.authorizationService.authorizeForce(Permission.DeleteDescriptionTemplate);
this.deleterFactory.deleter(DescriptionTemplateDeleter.class).deleteAndSaveByIds(List.of(id));
}
public DescriptionTemplate buildClone(UUID id, FieldSet fields) throws MyForbiddenException, MyValidationException, MyApplicationException, MyNotFoundException {
logger.debug(new MapLogEntry("persisting data").And("id", id).And("fields", fields));
this.authorizationService.authorizeForce(Permission.CloneDescriptionTemplate);
DescriptionTemplateQuery query = this.queryFactory.query(DescriptionTemplateQuery.class).authorize(AuthorizationFlags.OwnerOrPermission).ids(id);
DescriptionTemplate model = this.builderFactory.builder(DescriptionTemplateBuilder.class).authorize(AuthorizationFlags.OwnerOrPermission).build(fields, query.firstAs(fields));
if (model == null) throw new MyNotFoundException(messageSource.getMessage("General_ItemNotFound", new Object[]{id, DescriptionTemplate.class.getSimpleName()}, LocaleContextHolder.getLocale()));
model.setLabel(model.getLabel() + " new ");
model.setId(null);
model.setHash(null);
model.setStatus(DescriptionTemplateStatus.Draft);
this.reassignDefinition(model.getDefinition());
return model;
}
private void reassignDefinition(Definition model){
if (model == null) return;
if (model.getSections() != null){
for (Section section : model.getSections()) {
this.reassignSection(section);
}
}
if (model.getPages() != null){
for (Page page : model.getPages()) {
this.reassignPage(page);
}
}
}
private void reassignPage(Page model){
if (model == null) return;
model.setId(UUID.randomUUID().toString());
}
private void reassignSection(Section model){
if (model == null) return;
model.setId(UUID.randomUUID().toString());
if (model.getSections() != null){
for (Section section : model.getSections()) {
this.reassignSection(section);
}
}
if (model.getFieldSets() != null){
for (eu.eudat.model.descriptiontemplatedefinition.FieldSet fieldSet : model.getFieldSets()) {
this.reassignFieldSet(fieldSet);
}
}
}
private void reassignFieldSet(eu.eudat.model.descriptiontemplatedefinition.FieldSet model){
if (model == null) return;
model.setId(UUID.randomUUID().toString());
if (model.getFields() != null){
for (Field field : model.getFields()) {
this.reassignField(field);
}
}
}
private void reassignField(Field model){
if (model == null) return;
model.setId(UUID.randomUUID().toString());
}
public DescriptionTemplate createNewVersion(NewVersionDescriptionTemplatePersist model, FieldSet fields) throws MyForbiddenException, MyValidationException, MyApplicationException, MyNotFoundException, InvalidApplicationException, JAXBException, ParserConfigurationException, JsonProcessingException, TransformerException {
logger.debug(new MapLogEntry("persisting data descriptionTemplateType").And("model", model).And("fields", fields));
this.authorizationService.authorizeForce(Permission.CreateNewVersionDescriptionTemplate);
DescriptionTemplateEntity oldDescriptionTemplateEntity = this.entityManager.find(DescriptionTemplateEntity.class, model.getId());
if (oldDescriptionTemplateEntity == null) throw new MyNotFoundException(messageSource.getMessage("General_ItemNotFound", new Object[]{model.getId(), DescriptionTemplate.class.getSimpleName()}, LocaleContextHolder.getLocale()));
if (!this.conventionService.hashValue(oldDescriptionTemplateEntity.getUpdatedAt()).equals(model.getHash())) throw new MyValidationException(this.errors.getHashConflict().getCode(), this.errors.getHashConflict().getMessage());
DescriptionTemplateQuery latestVersionDescriptionTemplateEntityQuery = this.queryFactory.query(DescriptionTemplateQuery.class).groupIds(oldDescriptionTemplateEntity.getGroupId());
latestVersionDescriptionTemplateEntityQuery.setOrder(new Ordering().addDescending(DescriptionTemplateEntity._version));
DescriptionTemplateEntity latestVersionDescriptionTemplateEntity = latestVersionDescriptionTemplateEntityQuery.first();
if (!latestVersionDescriptionTemplateEntity.getVersion().equals(oldDescriptionTemplateEntity.getVersion())){
throw new MyValidationException(this.errors.getDescriptionTemplateNewVersionConflict().getCode(), this.errors.getDescriptionTemplateNewVersionConflict().getMessage());
}
DescriptionTemplateEntity data = new DescriptionTemplateEntity();
data.setId(UUID.randomUUID());
data.setIsActive(IsActive.Active);
data.setCreatedAt(Instant.now());
data.setUpdatedAt(Instant.now());
data.setGroupId(oldDescriptionTemplateEntity.getGroupId());
data.setVersion((short)(oldDescriptionTemplateEntity.getVersion() + 1));
data.setDescription(model.getDescription());
data.setLabel(model.getLabel());
data.setType(model.getType());
data.setLanguage(model.getLanguage());
data.setStatus(model.getStatus());
data.setDefinition(this.xmlHandlingService.toXml(this.buildDefinitionEntity(model.getDefinition())));
this.entityManager.persist(data);
this.persistUsers(data.getId(), model.getUsers());
//this.addOwner(data);
this.entityManager.flush();
return this.builderFactory.builder(DescriptionTemplateBuilder.class).authorize(AuthorizationFlags.OwnerOrPermission).build(BaseFieldSet.build(fields, DescriptionTemplate._id), data);
}
public DescriptionTemplate importXml(byte[] bytes, UUID id, String label, FieldSet fields) throws MyForbiddenException, MyNotFoundException, JAXBException, ParserConfigurationException, TransformerException, InvalidApplicationException, IOException, InstantiationException, IllegalAccessException, SAXException {
logger.debug(new MapLogEntry("import data").And("bytes", bytes).And("fields", fields));
this.authorizationService.authorizeForce(Permission.ImportDescriptionTemplate);
if (id != null) {
DescriptionTemplateImportXml importXml = this.xmlHandlingService.fromXml(DescriptionTemplateImportXml.class, new String(bytes, StandardCharsets.UTF_8));
DescriptionTemplatePersist persist = importXml.toPersistModel(label, this.fieldDataHelperServiceProvider);
this.validationService.validateForce(persist);
return this.persist(persist, fields);
} else {
DescriptionTemplateImportXml importXml = this.xmlHandlingService.fromXml(DescriptionTemplateImportXml.class, new String(bytes, StandardCharsets.UTF_8));
NewVersionDescriptionTemplatePersist persist = importXml.toNewVersionPersistModel(id, label, this.fieldDataHelperServiceProvider);
DescriptionTemplateEntity oldDescriptionTemplateEntity = this.entityManager.find(DescriptionTemplateEntity.class, id);
if (oldDescriptionTemplateEntity == null) throw new MyNotFoundException(messageSource.getMessage("General_ItemNotFound", new Object[]{id, DescriptionTemplate.class.getSimpleName()}, LocaleContextHolder.getLocale()));
persist.setHash(this.conventionService.hashValue(oldDescriptionTemplateEntity.getUpdatedAt()));
this.validationService.validateForce(persist);
return this.createNewVersion(persist, fields);
}
}
}