implement public clone plan, description
This commit is contained in:
parent
e843a2487f
commit
bed157b320
|
@ -49,6 +49,7 @@ public class AuditableAction {
|
||||||
public static final EventId Plan_Import = new EventId(5017, "Plan_Import");
|
public static final EventId Plan_Import = new EventId(5017, "Plan_Import");
|
||||||
public static final EventId Plan_GetPublicXml = new EventId(5017, "Plan_GetPublicXml");
|
public static final EventId Plan_GetPublicXml = new EventId(5017, "Plan_GetPublicXml");
|
||||||
public static final EventId Plan_ExportPublic = new EventId(5018, "Plan_ExportPublic");
|
public static final EventId Plan_ExportPublic = new EventId(5018, "Plan_ExportPublic");
|
||||||
|
public static final EventId Plan_PublicClone = new EventId(5019, "Plan_PublicClone");
|
||||||
|
|
||||||
|
|
||||||
public static final EventId Description_Query = new EventId(6000, "Description_Query");
|
public static final EventId Description_Query = new EventId(6000, "Description_Query");
|
||||||
|
|
|
@ -43,6 +43,7 @@ public interface PlanService {
|
||||||
Plan createNewVersion(NewVersionPlanPersist model, FieldSet fields) throws MyForbiddenException, MyValidationException, MyApplicationException, MyNotFoundException, InvalidApplicationException, JAXBException, ParserConfigurationException, IOException, TransformerException;
|
Plan createNewVersion(NewVersionPlanPersist model, FieldSet fields) throws MyForbiddenException, MyValidationException, MyApplicationException, MyNotFoundException, InvalidApplicationException, JAXBException, ParserConfigurationException, IOException, TransformerException;
|
||||||
|
|
||||||
Plan buildClone(ClonePlanPersist model, FieldSet fields) throws MyForbiddenException, MyValidationException, MyApplicationException, MyNotFoundException, IOException, InvalidApplicationException;
|
Plan buildClone(ClonePlanPersist model, FieldSet fields) throws MyForbiddenException, MyValidationException, MyApplicationException, MyNotFoundException, IOException, InvalidApplicationException;
|
||||||
|
Plan buildPublicClone(ClonePlanPersist model, FieldSet fields) throws MyForbiddenException, MyValidationException, MyApplicationException, MyNotFoundException, IOException, InvalidApplicationException;
|
||||||
|
|
||||||
List<PlanUser> assignUsers(UUID planId, List<PlanUserPersist> model, FieldSet fields, boolean disableDelete) throws InvalidApplicationException, IOException;
|
List<PlanUser> assignUsers(UUID planId, List<PlanUserPersist> model, FieldSet fields, boolean disableDelete) throws InvalidApplicationException, IOException;
|
||||||
Plan removeUser(PlanUserRemovePersist model, FieldSet fields) throws InvalidApplicationException, IOException;
|
Plan removeUser(PlanUserRemovePersist model, FieldSet fields) throws InvalidApplicationException, IOException;
|
||||||
|
|
|
@ -69,6 +69,7 @@ import org.opencdmp.integrationevent.outbox.annotationentityremoval.AnnotationEn
|
||||||
import org.opencdmp.integrationevent.outbox.annotationentitytouch.AnnotationEntityTouchedIntegrationEventHandler;
|
import org.opencdmp.integrationevent.outbox.annotationentitytouch.AnnotationEntityTouchedIntegrationEventHandler;
|
||||||
import org.opencdmp.integrationevent.outbox.notification.NotifyIntegrationEvent;
|
import org.opencdmp.integrationevent.outbox.notification.NotifyIntegrationEvent;
|
||||||
import org.opencdmp.integrationevent.outbox.notification.NotifyIntegrationEventHandler;
|
import org.opencdmp.integrationevent.outbox.notification.NotifyIntegrationEventHandler;
|
||||||
|
import org.opencdmp.model.PlanDescriptionTemplate;
|
||||||
import org.opencdmp.model.PlanUser;
|
import org.opencdmp.model.PlanUser;
|
||||||
import org.opencdmp.model.PlanValidationResult;
|
import org.opencdmp.model.PlanValidationResult;
|
||||||
import org.opencdmp.model.PublicPlan;
|
import org.opencdmp.model.PublicPlan;
|
||||||
|
@ -168,7 +169,7 @@ public class PlanServiceImpl implements PlanService {
|
||||||
|
|
||||||
private final ActionConfirmationService actionConfirmationService;
|
private final ActionConfirmationService actionConfirmationService;
|
||||||
|
|
||||||
private final gr.cite.tools.validation.ValidatorFactory validatorFactory;
|
private final ValidatorFactory validatorFactory;
|
||||||
|
|
||||||
private final ElasticService elasticService;
|
private final ElasticService elasticService;
|
||||||
private final DescriptionTemplateService descriptionTemplateService;
|
private final DescriptionTemplateService descriptionTemplateService;
|
||||||
|
@ -676,6 +677,173 @@ public class PlanServiceImpl implements PlanService {
|
||||||
this.accountingService.increase(UsageLimitTargetMetric.DESCRIPTION_COUNT.getValue());
|
this.accountingService.increase(UsageLimitTargetMetric.DESCRIPTION_COUNT.getValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void clonePublicDescription(UUID planId, Map<UUID, UUID> planDescriptionTemplateRemap, UUID descriptionId, org.opencdmp.commons.types.planblueprint.DefinitionEntity blueprintDefinition) throws InvalidApplicationException, IOException {
|
||||||
|
logger.debug("cloning public description: {} with description: {}", descriptionId, planId);
|
||||||
|
|
||||||
|
this.usageLimitService.checkIncrease(UsageLimitTargetMetric.DESCRIPTION_COUNT);
|
||||||
|
|
||||||
|
this.authorizationService.authorizeAtLeastOneForce(List.of(this.authorizationContentResolver.descriptionAffiliation(descriptionId)), Permission.PublicCloneDescription);
|
||||||
|
|
||||||
|
DescriptionEntity existing = null;
|
||||||
|
List<DescriptionReferenceEntity> descriptionReferences = new ArrayList<>();
|
||||||
|
List<ReferenceEntity> referenceEntities = new ArrayList<>();
|
||||||
|
|
||||||
|
List<DescriptionTagEntity> descriptionTags = new ArrayList<>();
|
||||||
|
List<TagEntity> tags = new ArrayList<>();
|
||||||
|
try {
|
||||||
|
this.entityManager.disableTenantFilters();
|
||||||
|
existing = this.queryFactory.query(DescriptionQuery.class).disableTracking().authorize(EnumSet.of(Public)).ids(descriptionId).planSubQuery(this.queryFactory.query(PlanQuery.class).isActive(IsActive.Active).statuses(PlanStatus.Finalized).accessTypes(PlanAccessType.Public)).first();
|
||||||
|
|
||||||
|
if (existing == null) throw new MyNotFoundException(this.messageSource.getMessage("General_ItemNotFound", new Object[]{descriptionId, Description.class.getSimpleName()}, LocaleContextHolder.getLocale()));
|
||||||
|
|
||||||
|
PlanDescriptionTemplateEntity planDescriptionTemplate = this.queryFactory.query(PlanDescriptionTemplateQuery.class).disableTracking().ids(existing.getPlanDescriptionTemplateId()).first();
|
||||||
|
if (planDescriptionTemplate == null) throw new MyNotFoundException(this.messageSource.getMessage("General_ItemNotFound", new Object[]{existing.getPlanDescriptionTemplateId(), PlanDescriptionTemplate.class.getSimpleName()}, LocaleContextHolder.getLocale()));
|
||||||
|
|
||||||
|
if (blueprintDefinition != null && planDescriptionTemplate.getSectionId() != null && !this.conventionService.isListNullOrEmpty(blueprintDefinition.getSections())) {
|
||||||
|
if (blueprintDefinition.getSections().stream().filter(x -> x.getId().equals(planDescriptionTemplate.getSectionId()) && x.getHasTemplates()).findFirst().orElse(null) == null) {
|
||||||
|
// ignore this description because don't exist templates in this section
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.entityManager.disableTenantFilters();
|
||||||
|
descriptionReferences = this.queryFactory.query(DescriptionReferenceQuery.class).disableTracking()
|
||||||
|
.descriptionIds(existing.getId())
|
||||||
|
.isActive(IsActive.Active)
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
if (!this.conventionService.isListNullOrEmpty(descriptionReferences)) {
|
||||||
|
this.entityManager.disableTenantFilters();
|
||||||
|
referenceEntities = this.queryFactory.query(ReferenceQuery.class).disableTracking()
|
||||||
|
.ids(descriptionReferences.stream().map(DescriptionReferenceEntity::getReferenceId).distinct().toList())
|
||||||
|
.collect();
|
||||||
|
}
|
||||||
|
|
||||||
|
this.entityManager.disableTenantFilters();
|
||||||
|
descriptionTags = this.queryFactory.query(DescriptionTagQuery.class).disableTracking()
|
||||||
|
.descriptionIds(existing.getId())
|
||||||
|
.isActive(IsActive.Active)
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
if (!this.conventionService.isListNullOrEmpty(descriptionTags)) {
|
||||||
|
this.entityManager.disableTenantFilters();
|
||||||
|
tags = this.queryFactory.query(TagQuery.class).disableTracking()
|
||||||
|
.ids(descriptionTags.stream().map(DescriptionTagEntity::getTagId).distinct().toList())
|
||||||
|
.collect();
|
||||||
|
}
|
||||||
|
|
||||||
|
this.entityManager.reloadTenantFilters();
|
||||||
|
} finally {
|
||||||
|
this.entityManager.reloadTenantFilters();
|
||||||
|
DescriptionEntity newDescription = new DescriptionEntity();
|
||||||
|
newDescription.setId(UUID.randomUUID());
|
||||||
|
newDescription.setLabel(existing.getLabel());
|
||||||
|
newDescription.setDescription(existing.getDescription());
|
||||||
|
newDescription.setStatus(DescriptionStatus.Draft);
|
||||||
|
newDescription.setProperties(existing.getProperties());
|
||||||
|
newDescription.setPlanId(planId);
|
||||||
|
if (planDescriptionTemplateRemap != null) newDescription.setPlanDescriptionTemplateId(planDescriptionTemplateRemap.get(existing.getPlanDescriptionTemplateId()));
|
||||||
|
newDescription.setDescriptionTemplateId(existing.getDescriptionTemplateId());
|
||||||
|
newDescription.setCreatedById(this.userScope.getUserId());
|
||||||
|
newDescription.setCreatedAt(Instant.now());
|
||||||
|
newDescription.setUpdatedAt(Instant.now());
|
||||||
|
newDescription.setIsActive(IsActive.Active);
|
||||||
|
|
||||||
|
this.entityManager.persist(newDescription);
|
||||||
|
if (newDescription.getId() != null){
|
||||||
|
|
||||||
|
for (DescriptionReferenceEntity descriptionReference : descriptionReferences) {
|
||||||
|
if (!this.conventionService.isListNullOrEmpty(referenceEntities)){
|
||||||
|
ReferenceEntity existingReference = referenceEntities.stream().filter(x -> x.getId().equals(descriptionReference.getReferenceId())).findFirst().orElse(null);
|
||||||
|
if (existingReference != null) {
|
||||||
|
// persist reference for selected tenant
|
||||||
|
ReferenceEntity existingTenantReference = this.queryFactory.query(ReferenceQuery.class).ids(existingReference.getId()).first(); //TODO: optimize
|
||||||
|
if (existingTenantReference == null) existingTenantReference = this.queryFactory.query(ReferenceQuery.class).references(existingReference.getReference()).typeIds(existingReference.getTypeId()).sources(existingReference.getSource()).first();
|
||||||
|
UUID referenceId;
|
||||||
|
if (existingTenantReference == null) {
|
||||||
|
ReferenceTypeEntity referenceTypeEntity = this.queryFactory.query(ReferenceTypeQuery.class).ids(existingReference.getTypeId()).firstAs(new BaseFieldSet().ensure(ReferenceType._id));//TODO: optimize
|
||||||
|
if (referenceTypeEntity == null) continue;
|
||||||
|
|
||||||
|
ReferenceEntity newReferenceEntity = new ReferenceEntity();
|
||||||
|
newReferenceEntity.setId(UUID.randomUUID());
|
||||||
|
newReferenceEntity.setLabel(existingReference.getLabel());
|
||||||
|
newReferenceEntity.setReference(existingReference.getReference());
|
||||||
|
newReferenceEntity.setTypeId(referenceTypeEntity.getId());
|
||||||
|
newReferenceEntity.setSource(existingReference.getSource());
|
||||||
|
newReferenceEntity.setSourceType(existingReference.getSourceType());
|
||||||
|
newReferenceEntity.setAbbreviation(existingReference.getAbbreviation());
|
||||||
|
newReferenceEntity.setDescription(existingReference.getDescription());
|
||||||
|
newReferenceEntity.setDefinition(existingReference.getDefinition());
|
||||||
|
this.entityManager.persist(newReferenceEntity);
|
||||||
|
|
||||||
|
referenceId = newReferenceEntity.getId();
|
||||||
|
} else {
|
||||||
|
referenceId = existingTenantReference.getId();
|
||||||
|
}
|
||||||
|
DescriptionReferenceEntity newDescriptionReference = new DescriptionReferenceEntity();
|
||||||
|
newDescriptionReference.setId(UUID.randomUUID());
|
||||||
|
newDescriptionReference.setDescriptionId(newDescription.getId());
|
||||||
|
newDescriptionReference.setReferenceId(referenceId);
|
||||||
|
newDescriptionReference.setData(descriptionReference.getData());
|
||||||
|
newDescriptionReference.setCreatedAt(Instant.now());
|
||||||
|
newDescriptionReference.setUpdatedAt(Instant.now());
|
||||||
|
newDescriptionReference.setIsActive(IsActive.Active);
|
||||||
|
|
||||||
|
this.entityManager.persist(newDescriptionReference);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (DescriptionTagEntity descriptionTag : descriptionTags) {
|
||||||
|
if (!this.conventionService.isListNullOrEmpty(tags)) {
|
||||||
|
TagEntity existingTag = tags.stream().filter(x -> x.getId().equals(descriptionTag.getTagId())).findFirst().orElse(null);
|
||||||
|
if (existingTag != null) {
|
||||||
|
UUID tagId;
|
||||||
|
// persist tag for selected tenant
|
||||||
|
TagEntity existingTenantTag = this.queryFactory.query(TagQuery.class).ids(existingTag.getId()).first(); //TODO: optimize
|
||||||
|
if (existingTenantTag == null) {
|
||||||
|
TagEntity tagEntity = new TagEntity();
|
||||||
|
tagEntity.setId(UUID.randomUUID());
|
||||||
|
tagEntity.setId(UUID.randomUUID());
|
||||||
|
tagEntity.setLabel(existingTag.getLabel());
|
||||||
|
tagEntity.setIsActive(IsActive.Active);
|
||||||
|
tagEntity.setCreatedAt(Instant.now());
|
||||||
|
tagEntity.setUpdatedAt(Instant.now());
|
||||||
|
this.entityManager.persist(tagEntity);
|
||||||
|
|
||||||
|
tagId = tagEntity.getId();
|
||||||
|
} else {
|
||||||
|
tagId = existingTenantTag.getId();
|
||||||
|
}
|
||||||
|
DescriptionTagEntity newTag = new DescriptionTagEntity();
|
||||||
|
newTag.setId(UUID.randomUUID());
|
||||||
|
newTag.setDescriptionId(newDescription.getId());
|
||||||
|
newTag.setTagId(tagId);
|
||||||
|
newTag.setCreatedAt(Instant.now());
|
||||||
|
newTag.setUpdatedAt(Instant.now());
|
||||||
|
newTag.setIsActive(IsActive.Active);
|
||||||
|
|
||||||
|
this.entityManager.persist(newTag);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
this.entityManager.flush();
|
||||||
|
|
||||||
|
this.elasticService.persistDescription(newDescription);
|
||||||
|
|
||||||
|
this.annotationEntityTouchedIntegrationEventHandler.handleDescription(newDescription.getId());
|
||||||
|
this.annotationEntityTouchedIntegrationEventHandler.handleDescription(existing.getId());
|
||||||
|
|
||||||
|
this.accountingService.increase(UsageLimitTargetMetric.DESCRIPTION_COUNT.getValue());
|
||||||
|
this.entityManager.reloadTenantFilters();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
private void updateVersionStatusAndSave(PlanEntity data, PlanStatus previousStatus, PlanStatus newStatus) throws InvalidApplicationException {
|
private void updateVersionStatusAndSave(PlanEntity data, PlanStatus previousStatus, PlanStatus newStatus) throws InvalidApplicationException {
|
||||||
|
@ -833,6 +1001,207 @@ public class PlanServiceImpl implements PlanService {
|
||||||
return this.builderFactory.builder(PlanBuilder.class).build(fields, resultingPlanEntity);
|
return this.builderFactory.builder(PlanBuilder.class).build(fields, resultingPlanEntity);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Plan buildPublicClone(ClonePlanPersist model, FieldSet fields) throws MyForbiddenException, MyValidationException, MyApplicationException, MyNotFoundException, IOException, InvalidApplicationException {
|
||||||
|
|
||||||
|
this.usageLimitService.checkIncrease(UsageLimitTargetMetric.PLAN_COUNT);
|
||||||
|
|
||||||
|
PlanEntity existingPlanEntity = null;
|
||||||
|
PlanEntity newPlan = new PlanEntity();
|
||||||
|
PlanBlueprintEntity existingBlueprintEntity = null;
|
||||||
|
org.opencdmp.commons.types.planblueprint.DefinitionEntity definition = null;
|
||||||
|
List<PlanReferenceEntity> planReferences = new ArrayList<>();
|
||||||
|
List<ReferenceEntity> referenceEntities = new ArrayList<>();
|
||||||
|
List<PlanDescriptionTemplateEntity> planDescriptionTemplates = new ArrayList<>();
|
||||||
|
List<org.opencdmp.data.DescriptionTemplateEntity> descriptionTemplates = new ArrayList<>();
|
||||||
|
List<DescriptionTemplateTypeEntity> descriptionTemplateTypes = new ArrayList<>();
|
||||||
|
|
||||||
|
try {
|
||||||
|
this.entityManager.disableTenantFilters();
|
||||||
|
// query for public plan
|
||||||
|
existingPlanEntity = this.queryFactory.query(PlanQuery.class).disableTracking().authorize(EnumSet.of(Public)).ids(model.getId()).isActive(IsActive.Active).statuses(PlanStatus.Finalized).accessTypes(PlanAccessType.Public).firstAs(fields);
|
||||||
|
|
||||||
|
if (existingPlanEntity == null) throw new MyNotFoundException(this.messageSource.getMessage("General_ItemNotFound", new Object[]{model.getId(), PublicPlan.class.getSimpleName()}, LocaleContextHolder.getLocale()));
|
||||||
|
|
||||||
|
this.authorizationService.authorizeAtLeastOneForce(List.of(this.authorizationContentResolver.planAffiliation( model.getId())), Permission.PublicClonePlan);
|
||||||
|
|
||||||
|
// find blueprint code to check if exist in current tenant
|
||||||
|
existingBlueprintEntity = this.queryFactory.query(PlanBlueprintQuery.class).disableTracking()
|
||||||
|
.ids(existingPlanEntity.getBlueprintId())
|
||||||
|
.first();
|
||||||
|
|
||||||
|
if (existingBlueprintEntity == null) throw new MyNotFoundException(this.messageSource.getMessage("General_ItemNotFound", new Object[]{existingPlanEntity.getBlueprintId(), PlanBlueprint.class.getSimpleName()}, LocaleContextHolder.getLocale()));
|
||||||
|
|
||||||
|
this.entityManager.disableTenantFilters();
|
||||||
|
planReferences = this.queryFactory.query(PlanReferenceQuery.class).disableTracking()
|
||||||
|
.planIds(model.getId())
|
||||||
|
.isActives(IsActive.Active)
|
||||||
|
.collect();
|
||||||
|
this.entityManager.disableTenantFilters();
|
||||||
|
planDescriptionTemplates = this.queryFactory.query(PlanDescriptionTemplateQuery.class).disableTracking()
|
||||||
|
.planIds(model.getId())
|
||||||
|
.isActive(IsActive.Active)
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
if (!this.conventionService.isListNullOrEmpty(planReferences)) {
|
||||||
|
this.entityManager.disableTenantFilters();
|
||||||
|
referenceEntities = this.queryFactory.query(ReferenceQuery.class).disableTracking()
|
||||||
|
.ids(planReferences.stream().map(PlanReferenceEntity::getReferenceId).distinct().toList())
|
||||||
|
.collect();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!this.conventionService.isListNullOrEmpty(planDescriptionTemplates)) {
|
||||||
|
this.entityManager.disableTenantFilters();
|
||||||
|
descriptionTemplates = this.queryFactory.query(DescriptionTemplateQuery.class).disableTracking()
|
||||||
|
.groupIds(planDescriptionTemplates.stream().map(PlanDescriptionTemplateEntity::getDescriptionTemplateGroupId).distinct().toList())
|
||||||
|
.versionStatuses(DescriptionTemplateVersionStatus.Current)
|
||||||
|
.collect();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!this.conventionService.isListNullOrEmpty(descriptionTemplates)){
|
||||||
|
this.entityManager.disableTenantFilters();
|
||||||
|
descriptionTemplateTypes = this.queryFactory.query(DescriptionTemplateTypeQuery.class).disableTracking()
|
||||||
|
.ids(descriptionTemplates.stream().map(org.opencdmp.data.DescriptionTemplateEntity::getTypeId).distinct().toList())
|
||||||
|
.collect();
|
||||||
|
}
|
||||||
|
|
||||||
|
this.entityManager.reloadTenantFilters();
|
||||||
|
} finally {
|
||||||
|
this.entityManager.reloadTenantFilters();
|
||||||
|
if (existingPlanEntity != null && existingBlueprintEntity != null) {
|
||||||
|
|
||||||
|
PlanBlueprintEntity blueprintEntityByTenant = this.queryFactory.query(PlanBlueprintQuery.class).disableTracking().ids(existingBlueprintEntity.getId()).first();
|
||||||
|
if (blueprintEntityByTenant == null){
|
||||||
|
blueprintEntityByTenant = this.queryFactory.query(PlanBlueprintQuery.class).disableTracking().groupIds(existingBlueprintEntity.getGroupId()).versionStatuses(PlanBlueprintVersionStatus.Current).isActive(IsActive.Active).statuses(PlanBlueprintStatus.Finalized).first();
|
||||||
|
if (blueprintEntityByTenant == null){
|
||||||
|
blueprintEntityByTenant = this.queryFactory.query(PlanBlueprintQuery.class).disableTracking().codes(existingBlueprintEntity.getCode()).first();
|
||||||
|
if (blueprintEntityByTenant == null) {
|
||||||
|
throw new MyValidationException(this.errors.getPlanBlueprintImportNotFound().getCode(), existingBlueprintEntity.getCode());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!blueprintEntityByTenant.getStatus().equals(PlanBlueprintStatus.Finalized)) throw new MyValidationException(this.errors.getPlanBlueprintImportDraft().getCode(), existingBlueprintEntity.getCode());
|
||||||
|
|
||||||
|
definition = this.xmlHandlingService.fromXmlSafe(org.opencdmp.commons.types.planblueprint.DefinitionEntity.class, blueprintEntityByTenant.getDefinition());
|
||||||
|
if (definition == null) throw new MyNotFoundException(this.messageSource.getMessage("General_ItemNotFound", new Object[]{blueprintEntityByTenant.getId(), org.opencdmp.commons.types.planblueprint.DefinitionEntity.class.getSimpleName()}, LocaleContextHolder.getLocale()));
|
||||||
|
|
||||||
|
newPlan.setId(UUID.randomUUID());
|
||||||
|
newPlan.setIsActive(IsActive.Active);
|
||||||
|
newPlan.setCreatedAt(Instant.now());
|
||||||
|
newPlan.setUpdatedAt(Instant.now());
|
||||||
|
newPlan.setGroupId(UUID.randomUUID());
|
||||||
|
newPlan.setVersion((short) 1);
|
||||||
|
newPlan.setVersionStatus(PlanVersionStatus.NotFinalized);
|
||||||
|
newPlan.setDescription(model.getDescription());
|
||||||
|
newPlan.setLabel(model.getLabel());
|
||||||
|
newPlan.setLanguage(existingPlanEntity.getLanguage());
|
||||||
|
newPlan.setStatus(PlanStatus.Draft);
|
||||||
|
newPlan.setProperties(existingPlanEntity.getProperties());
|
||||||
|
newPlan.setBlueprintId(blueprintEntityByTenant.getId());
|
||||||
|
newPlan.setAccessType(existingPlanEntity.getAccessType());
|
||||||
|
newPlan.setCreatorId(this.userScope.getUserId());
|
||||||
|
|
||||||
|
this.entityManager.persist(newPlan);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (newPlan.getId() != null) {
|
||||||
|
this.addOwner(newPlan);
|
||||||
|
|
||||||
|
for (PlanReferenceEntity planReference : planReferences) {
|
||||||
|
if (!this.conventionService.isListNullOrEmpty(referenceEntities)){
|
||||||
|
ReferenceEntity existingReference = referenceEntities.stream().filter(x -> x.getId().equals(planReference.getReferenceId())).findFirst().orElse(null);
|
||||||
|
if (existingReference != null) {
|
||||||
|
// persist reference for selected tenant
|
||||||
|
ReferenceEntity existingTenantReference = this.queryFactory.query(ReferenceQuery.class).ids(existingReference.getId()).first(); //TODO: optimize
|
||||||
|
if (existingTenantReference == null) existingTenantReference = this.queryFactory.query(ReferenceQuery.class).references(existingReference.getReference()).typeIds(existingReference.getTypeId()).sources(existingReference.getSource()).first();
|
||||||
|
UUID referenceId;
|
||||||
|
if (existingTenantReference == null) {
|
||||||
|
ReferenceTypeEntity referenceTypeEntity = this.queryFactory.query(ReferenceTypeQuery.class).ids(existingReference.getTypeId()).firstAs(new BaseFieldSet().ensure(ReferenceType._id));//TODO: optimize
|
||||||
|
if (referenceTypeEntity == null) continue;
|
||||||
|
|
||||||
|
ReferenceEntity newReferenceEntity = new ReferenceEntity();
|
||||||
|
newReferenceEntity.setId(UUID.randomUUID());
|
||||||
|
newReferenceEntity.setLabel(existingReference.getLabel());
|
||||||
|
newReferenceEntity.setReference(existingReference.getReference());
|
||||||
|
newReferenceEntity.setTypeId(referenceTypeEntity.getId());
|
||||||
|
newReferenceEntity.setSource(existingReference.getSource());
|
||||||
|
newReferenceEntity.setSourceType(existingReference.getSourceType());
|
||||||
|
newReferenceEntity.setAbbreviation(existingReference.getAbbreviation());
|
||||||
|
newReferenceEntity.setDescription(existingReference.getDescription());
|
||||||
|
newReferenceEntity.setDefinition(existingReference.getDefinition());
|
||||||
|
this.entityManager.persist(newReferenceEntity);
|
||||||
|
|
||||||
|
referenceId = newReferenceEntity.getId();
|
||||||
|
} else {
|
||||||
|
referenceId = existingTenantReference.getId();
|
||||||
|
}
|
||||||
|
PlanReferenceEntity newPlanReference = new PlanReferenceEntity();
|
||||||
|
newPlanReference.setId(UUID.randomUUID());
|
||||||
|
newPlanReference.setPlanId(newPlan.getId());
|
||||||
|
newPlanReference.setReferenceId(referenceId);
|
||||||
|
newPlanReference.setData(planReference.getData());
|
||||||
|
newPlanReference.setCreatedAt(Instant.now());
|
||||||
|
newPlanReference.setUpdatedAt(Instant.now());
|
||||||
|
newPlanReference.setIsActive(IsActive.Active);
|
||||||
|
|
||||||
|
this.entityManager.persist(newPlanReference);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<UUID, UUID> planDescriptionTemplateRemap = new HashMap<>();
|
||||||
|
for (PlanDescriptionTemplateEntity planDescriptionTemplate : planDescriptionTemplates) {
|
||||||
|
if (!this.conventionService.isListNullOrEmpty(descriptionTemplates)) {
|
||||||
|
org.opencdmp.data.DescriptionTemplateEntity existingDescriptionTemplate = descriptionTemplates.stream().filter(x -> x.getGroupId().equals(planDescriptionTemplate.getDescriptionTemplateGroupId())).findFirst().orElse(null);
|
||||||
|
if (existingDescriptionTemplate != null) {
|
||||||
|
DescriptionTemplateTypeEntity existingDescriptionTemplateType = descriptionTemplateTypes.stream().filter(x -> x.getId().equals(existingDescriptionTemplate.getTypeId())).findFirst().orElse(null);
|
||||||
|
if (existingDescriptionTemplateType != null) {
|
||||||
|
DescriptionTemplateTypeEntity existingTenantTemplateType = this.queryFactory.query(DescriptionTemplateTypeQuery.class).ids(existingDescriptionTemplateType.getId()).first();
|
||||||
|
if (existingTenantTemplateType == null) existingTenantTemplateType = this.queryFactory.query(DescriptionTemplateTypeQuery.class).codes(existingDescriptionTemplateType.getCode()).first();
|
||||||
|
if (existingTenantTemplateType == null) throw new MyValidationException(this.errors.getDescriptionTemplateTypeImportNotFound().getCode(), existingTenantTemplateType.getCode());
|
||||||
|
if (!existingTenantTemplateType.getStatus().equals(DescriptionTemplateTypeStatus.Finalized)) throw new MyValidationException(this.errors.getDescriptionTemplateTypeImportDraft().getCode(), existingTenantTemplateType.getCode());
|
||||||
|
}
|
||||||
|
|
||||||
|
org.opencdmp.data.DescriptionTemplateEntity existingTenantTemplate = this.queryFactory.query(DescriptionTemplateQuery.class).ids(existingDescriptionTemplate.getId()).first();
|
||||||
|
if (existingTenantTemplate == null) existingTenantTemplate = this.queryFactory.query(DescriptionTemplateQuery.class).groupIds(existingDescriptionTemplate.getId()).first();
|
||||||
|
if (existingTenantTemplate == null) existingTenantTemplate = this.queryFactory.query(DescriptionTemplateQuery.class).codes(existingDescriptionTemplate.getCode()).first();
|
||||||
|
if (existingTenantTemplate == null) throw new MyValidationException(this.errors.getDescriptionTemplateImportNotFound().getCode(), existingTenantTemplate.getCode());
|
||||||
|
if (!existingTenantTemplate.getStatus().equals(DescriptionTemplateStatus.Finalized)) throw new MyValidationException(this.errors.getPlanDescriptionTemplateImportDraft().getCode(), existingTenantTemplate.getCode());
|
||||||
|
|
||||||
|
PlanDescriptionTemplateEntity newTemplate = new PlanDescriptionTemplateEntity();
|
||||||
|
newTemplate.setId(UUID.randomUUID());
|
||||||
|
newTemplate.setPlanId(newPlan.getId());
|
||||||
|
newTemplate.setDescriptionTemplateGroupId(planDescriptionTemplate.getDescriptionTemplateGroupId());
|
||||||
|
newTemplate.setSectionId(planDescriptionTemplate.getSectionId());
|
||||||
|
newTemplate.setCreatedAt(Instant.now());
|
||||||
|
newTemplate.setUpdatedAt(Instant.now());
|
||||||
|
newTemplate.setIsActive(IsActive.Active);
|
||||||
|
planDescriptionTemplateRemap.put(planDescriptionTemplate.getId(), newTemplate.getId());
|
||||||
|
|
||||||
|
this.entityManager.persist(newTemplate);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.entityManager.flush();
|
||||||
|
|
||||||
|
this.elasticService.persistPlan(newPlan);
|
||||||
|
|
||||||
|
this.annotationEntityTouchedIntegrationEventHandler.handlePlan(newPlan.getId());
|
||||||
|
|
||||||
|
this.accountingService.increase(UsageLimitTargetMetric.PLAN_COUNT.getValue());
|
||||||
|
|
||||||
|
if (!this.conventionService.isListNullOrEmpty(model.getDescriptions())){
|
||||||
|
for (UUID description: model.getDescriptions()) {
|
||||||
|
this.clonePublicDescription(newPlan.getId(), planDescriptionTemplateRemap, description, definition);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.builderFactory.builder(PlanBuilder.class).build(fields, existingPlanEntity);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<PlanUser> assignUsers(UUID planId, List<PlanUserPersist> model, FieldSet fieldSet, boolean disableDelete) throws InvalidApplicationException, IOException {
|
public List<PlanUser> assignUsers(UUID planId, List<PlanUserPersist> model, FieldSet fieldSet, boolean disableDelete) throws InvalidApplicationException, IOException {
|
||||||
this.authorizationService.authorizeAtLeastOneForce(List.of(this.authorizationContentResolver.planAffiliation(planId)), Permission.AssignPlanUsers);
|
this.authorizationService.authorizeAtLeastOneForce(List.of(this.authorizationContentResolver.planAffiliation(planId)), Permission.AssignPlanUsers);
|
||||||
|
@ -1963,6 +2332,7 @@ public class PlanServiceImpl implements PlanService {
|
||||||
PlanBlueprintEntity planBlueprintEntity = planXml.getBlueprint().getId() != null ? this.queryFactory.query(PlanBlueprintQuery.class).disableTracking().ids(planXml.getBlueprint().getId()).first() : null;
|
PlanBlueprintEntity planBlueprintEntity = planXml.getBlueprint().getId() != null ? this.queryFactory.query(PlanBlueprintQuery.class).disableTracking().ids(planXml.getBlueprint().getId()).first() : null;
|
||||||
if (planBlueprintEntity == null) planBlueprintEntity = planXml.getBlueprint().getGroupId() != null ? this.queryFactory.query(PlanBlueprintQuery.class).disableTracking().groupIds(planXml.getBlueprint().getGroupId()).versionStatuses(PlanBlueprintVersionStatus.Current).isActive(IsActive.Active).statuses(PlanBlueprintStatus.Finalized).first() : null;
|
if (planBlueprintEntity == null) planBlueprintEntity = planXml.getBlueprint().getGroupId() != null ? this.queryFactory.query(PlanBlueprintQuery.class).disableTracking().groupIds(planXml.getBlueprint().getGroupId()).versionStatuses(PlanBlueprintVersionStatus.Current).isActive(IsActive.Active).statuses(PlanBlueprintStatus.Finalized).first() : null;
|
||||||
if (planBlueprintEntity != null){
|
if (planBlueprintEntity != null){
|
||||||
|
if (!planBlueprintEntity.getStatus().equals(PlanBlueprintStatus.Finalized)) throw new MyValidationException(this.errors.getPlanBlueprintImportDraft().getCode(), planBlueprintEntity.getCode());
|
||||||
return planBlueprintEntity.getId();
|
return planBlueprintEntity.getId();
|
||||||
} else {
|
} else {
|
||||||
planBlueprintEntity = !this.conventionService.isNullOrEmpty(planXml.getBlueprint().getCode()) ? this.queryFactory.query(PlanBlueprintQuery.class).disableTracking().codes(planXml.getBlueprint().getCode()).first() : null;
|
planBlueprintEntity = !this.conventionService.isNullOrEmpty(planXml.getBlueprint().getCode()) ? this.queryFactory.query(PlanBlueprintQuery.class).disableTracking().codes(planXml.getBlueprint().getCode()).first() : null;
|
||||||
|
|
|
@ -334,6 +334,35 @@ public class PlanController {
|
||||||
return clone;
|
return clone;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@PostMapping("public-clone")
|
||||||
|
@OperationWithTenantHeader(summary = "Create a clone of an existing public plan", description = "",
|
||||||
|
responses = @ApiResponse(description = "OK", responseCode = "200", content = @Content(
|
||||||
|
schema = @Schema(
|
||||||
|
implementation = Plan.class
|
||||||
|
))
|
||||||
|
))
|
||||||
|
@Swagger400
|
||||||
|
@Swagger404
|
||||||
|
@Transactional
|
||||||
|
@ValidationFilterAnnotation(validator = ClonePlanPersist.ClonePlanPersistValidator.ValidatorName, argumentName = "model")
|
||||||
|
public Plan buildPublicClone(
|
||||||
|
@RequestBody ClonePlanPersist model,
|
||||||
|
@Parameter(name = "fieldSet", description = SwaggerHelpers.Commons.fieldset_description, required = true) FieldSet fieldSet
|
||||||
|
) throws MyApplicationException, MyForbiddenException, MyNotFoundException, IOException, InvalidApplicationException {
|
||||||
|
logger.debug(new MapLogEntry("clone public" + PublicPlan.class.getSimpleName()).And("model", model).And("fields", fieldSet));
|
||||||
|
|
||||||
|
this.censorFactory.censor(PublicPlanCensor.class).censor(fieldSet);
|
||||||
|
|
||||||
|
Plan clone = this.planService.buildPublicClone(model, fieldSet);
|
||||||
|
|
||||||
|
this.auditService.track(AuditableAction.Plan_PublicClone, Map.ofEntries(
|
||||||
|
new AbstractMap.SimpleEntry<String, Object>("model", model),
|
||||||
|
new AbstractMap.SimpleEntry<String, Object>("fields", fieldSet)
|
||||||
|
));
|
||||||
|
|
||||||
|
return clone;
|
||||||
|
}
|
||||||
|
|
||||||
@PostMapping("new-version")
|
@PostMapping("new-version")
|
||||||
@OperationWithTenantHeader(summary = "Create a new version of an existing plan", description = "",
|
@OperationWithTenantHeader(summary = "Create a new version of an existing plan", description = "",
|
||||||
responses = @ApiResponse(description = "OK", responseCode = "200", content = @Content(
|
responses = @ApiResponse(description = "OK", responseCode = "200", content = @Content(
|
||||||
|
|
|
@ -129,6 +129,15 @@ export class PlanService {
|
||||||
catchError((error: any) => throwError(error)));
|
catchError((error: any) => throwError(error)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
publicClone(item: ClonePlanPersist, reqFields: string[] = []): Observable<Plan> {
|
||||||
|
const url = `${this.apiBase}/public-clone`;
|
||||||
|
const options = { params: { f: reqFields } };
|
||||||
|
|
||||||
|
return this.http
|
||||||
|
.post<Plan>(url, item, options).pipe(
|
||||||
|
catchError((error: any) => throwError(error)));
|
||||||
|
}
|
||||||
|
|
||||||
newVersion(item: NewVersionPlanPersist, reqFields: string[] = []): Observable<Plan> {
|
newVersion(item: NewVersionPlanPersist, reqFields: string[] = []): Observable<Plan> {
|
||||||
const url = `${this.apiBase}/new-version`;
|
const url = `${this.apiBase}/new-version`;
|
||||||
const options = { params: { f: reqFields } };
|
const options = { params: { f: reqFields } };
|
||||||
|
|
|
@ -22,6 +22,7 @@ export class ClonePlanDialogComponent extends BaseComponent {
|
||||||
plan: Plan;
|
plan: Plan;
|
||||||
editorModel: PlanCloneDialogEditorModel;
|
editorModel: PlanCloneDialogEditorModel;
|
||||||
formGroup: UntypedFormGroup;
|
formGroup: UntypedFormGroup;
|
||||||
|
isPublic: boolean = false;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
public dialogRef: MatDialogRef<ClonePlanDialogComponent>,
|
public dialogRef: MatDialogRef<ClonePlanDialogComponent>,
|
||||||
|
@ -33,6 +34,7 @@ export class ClonePlanDialogComponent extends BaseComponent {
|
||||||
) {
|
) {
|
||||||
super();
|
super();
|
||||||
this.plan = data.plan;
|
this.plan = data.plan;
|
||||||
|
this.isPublic = data.isPublic;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -72,11 +74,19 @@ export class ClonePlanDialogComponent extends BaseComponent {
|
||||||
confirm() {
|
confirm() {
|
||||||
if (!this.formGroup.valid) { return; }
|
if (!this.formGroup.valid) { return; }
|
||||||
const value: ClonePlanPersist = this.formGroup.value;
|
const value: ClonePlanPersist = this.formGroup.value;
|
||||||
|
|
||||||
|
if (this.isPublic) {
|
||||||
|
this.planService.publicClone(value, PlanEditorEntityResolver.lookupFields()).pipe(takeUntil(this._destroyed)).subscribe(
|
||||||
|
plan => this.dialogRef.close(plan),
|
||||||
|
error => this.onCallbackError(error)
|
||||||
|
);
|
||||||
|
} else {
|
||||||
this.planService.clone(value, PlanEditorEntityResolver.lookupFields()).pipe(takeUntil(this._destroyed)).subscribe(
|
this.planService.clone(value, PlanEditorEntityResolver.lookupFields()).pipe(takeUntil(this._destroyed)).subscribe(
|
||||||
plan => this.dialogRef.close(plan),
|
plan => this.dialogRef.close(plan),
|
||||||
error => this.onCallbackError(error)
|
error => this.onCallbackError(error)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
toggleAllDescriptions(event: any) {
|
toggleAllDescriptions(event: any) {
|
||||||
if (event === true) {
|
if (event === true) {
|
||||||
|
|
|
@ -131,7 +131,8 @@ export class PlanListingItemComponent extends BaseComponent implements OnInit {
|
||||||
maxWidth: '700px',
|
maxWidth: '700px',
|
||||||
maxHeight: '80vh',
|
maxHeight: '80vh',
|
||||||
data: {
|
data: {
|
||||||
plan: this.plan
|
plan: this.plan,
|
||||||
|
isPublic: this.isPublic ? this.isPublic : false
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
dialogRef.afterClosed().pipe(takeUntil(this._destroyed)).subscribe((result: Plan) => {
|
dialogRef.afterClosed().pipe(takeUntil(this._destroyed)).subscribe((result: Plan) => {
|
||||||
|
|
|
@ -288,7 +288,8 @@ export class PlanOverviewComponent extends BaseComponent implements OnInit {
|
||||||
maxWidth: '700px',
|
maxWidth: '700px',
|
||||||
maxHeight: '80vh',
|
maxHeight: '80vh',
|
||||||
data: {
|
data: {
|
||||||
plan: this.plan
|
plan: this.plan,
|
||||||
|
isPublic: this.isPublicView ? this.isPublicView : false
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
dialogRef.afterClosed().pipe(takeUntil(this._destroyed)).subscribe((result: Plan) => {
|
dialogRef.afterClosed().pipe(takeUntil(this._destroyed)).subscribe((result: Plan) => {
|
||||||
|
|
Loading…
Reference in New Issue