From: andre.schmid Date: Tue, 21 Jun 2022 14:06:12 +0000 (+0100) Subject: Block interface operation edit in checkedin VFC X-Git-Tag: 1.11.5~8 X-Git-Url: https://gerrit.onap.org/r/gitweb?a=commitdiff_plain;h=fbab79aeaccf74385c9a55b697a1055a86bdf171;p=sdc.git Block interface operation edit in checkedin VFC VFC interface operation could be edited even when checked in, due to an incorrect viewOnly input passed to the modal component. Blocks edition also in the backend, by verifying if the component can be edited. Change-Id: I816e28897273aaa677237ca55794bb3dc8460975 Issue-ID: SDC-4058 Signed-off-by: andre.schmid Signed-off-by: JvD_Ericsson --- diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ComponentInterfaceOperationBusinessLogic.java b/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ComponentInterfaceOperationBusinessLogic.java index 461edd11dc..eb8b35ec60 100644 --- a/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ComponentInterfaceOperationBusinessLogic.java +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ComponentInterfaceOperationBusinessLogic.java @@ -166,11 +166,13 @@ public class ComponentInterfaceOperationBusinessLogic extends BaseBusinessLogic } public Optional updateResourceInterfaceOperation(final String componentId, + final String user, final InterfaceDefinition interfaceDefinition, final ComponentTypeEnum componentTypeEnum, final Wrapper errorWrapper, final boolean shouldLock) throws BusinessLogicException { final var component = getComponent(componentId); + validateCanWorkOnComponent(component, user); ResponseFormat responseFormat; Map componentInterfaceMap = component.getInterfaces(); diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/ComponentInterfaceOperationServlet.java b/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/ComponentInterfaceOperationServlet.java index 3b8bfe5bd7..64b8500979 100644 --- a/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/ComponentInterfaceOperationServlet.java +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/ComponentInterfaceOperationServlet.java @@ -50,6 +50,7 @@ import org.openecomp.sdc.be.components.impl.ComponentInterfaceOperationBusinessL import org.openecomp.sdc.be.components.impl.ResourceImportManager; import org.openecomp.sdc.be.components.impl.aaf.AafPermission; import org.openecomp.sdc.be.components.impl.aaf.PermissionAllowed; +import org.openecomp.sdc.be.components.impl.exceptions.ComponentException; import org.openecomp.sdc.be.config.BeEcompErrorManager; import org.openecomp.sdc.be.dao.api.ActionStatus; import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum; @@ -171,14 +172,14 @@ public class ComponentInterfaceOperationServlet extends AbstractValidationsServl LOGGER.debug(START_HANDLE_REQUEST_OF, request.getMethod(), request.getRequestURI()); LOGGER.debug(MODIFIER_ID_IS, userId); final User userModifier = componentInterfaceOperationBusinessLogic.validateUser(userId); - final ComponentTypeEnum componentTypeEnum = RESOURCE; final byte[] bytes = IOUtils.toByteArray(request.getInputStream()); if (bytes == null || bytes.length == 0) { LOGGER.error(INTERFACE_OPERATION_CONTENT_INVALID); return buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.INVALID_CONTENT)); } + final ComponentTypeEnum componentType = RESOURCE; final String data = new String(bytes); - final Optional mappedInterfaceOperationData = getMappedInterfaceData(data, userModifier, componentTypeEnum); + final Optional mappedInterfaceOperationData = getMappedInterfaceData(data, userModifier, componentType); if (mappedInterfaceOperationData.isEmpty()) { LOGGER.error(INTERFACE_OPERATION_CONTENT_INVALID, data); return buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.INVALID_CONTENT)); @@ -186,7 +187,7 @@ public class ComponentInterfaceOperationServlet extends AbstractValidationsServl final Wrapper errorWrapper = new Wrapper<>(); try { final Optional actionResponse = componentInterfaceOperationBusinessLogic - .updateResourceInterfaceOperation(componentId, mappedInterfaceOperationData.get(), componentTypeEnum, + .updateResourceInterfaceOperation(componentId, userId, mappedInterfaceOperationData.get(), componentType, errorWrapper, true); if (actionResponse.isEmpty()) { LOGGER.error(FAILED_TO_UPDATE_INTERFACE_OPERATION, componentId); @@ -195,6 +196,9 @@ public class ComponentInterfaceOperationServlet extends AbstractValidationsServl LOGGER.debug(INTERFACE_OPERATION_SUCCESSFULLY_UPDATED, componentId); return buildOkResponse(getComponentsUtils().getResponseFormat(ActionStatus.CREATED), actionResponse.get()); } + } catch (final ComponentException e) { + //let it be handled by org.openecomp.sdc.be.servlets.exception.ComponentExceptionMapper + throw e; } catch (final Exception e) { BeEcompErrorManager.getInstance().logBeRestApiGeneralError(UPDATE_INTERFACE_OPERATION); LOGGER.error(FAILED_TO_UPDATE_INTERFACE_OPERATION_WITH_ERROR, e); diff --git a/catalog-ui/src/app/ng2/pages/interface-definition/interface-definition.page.component.ts b/catalog-ui/src/app/ng2/pages/interface-definition/interface-definition.page.component.ts index 2a25ad90df..eab8b18f44 100644 --- a/catalog-ui/src/app/ng2/pages/interface-definition/interface-definition.page.component.ts +++ b/catalog-ui/src/app/ng2/pages/interface-definition/interface-definition.page.component.ts @@ -42,17 +42,11 @@ import { import {ComponentServiceNg2} from 'app/ng2/services/component-services/component.service'; import {TopologyTemplateService} from "../../services/component-services/topology-template.service"; import {InterfaceOperationModel} from "../../../models/interfaceOperation"; -import { - InterfaceOperationHandlerComponent -} from "../composition/interface-operatons/operation-creator/interface-operation-handler.component"; -import { - DropdownValue -} from "../../components/ui/form-components/dropdown/ui-element-dropdown.component"; +import {InterfaceOperationHandlerComponent} from "../composition/interface-operatons/operation-creator/interface-operation-handler.component"; +import {DropdownValue} from "../../components/ui/form-components/dropdown/ui-element-dropdown.component"; import {ToscaArtifactModel} from "../../../models/toscaArtifact"; import {ToscaArtifactService} from "../../services/tosca-artifact.service"; -import { - InterfaceOperationComponent -} from "../interface-operation/interface-operation.page.component"; +import {InterfaceOperationComponent} from "../interface-operation/interface-operation.page.component"; import {Observable} from "rxjs/Observable"; import {PluginsService} from 'app/ng2/services/plugins.service'; @@ -87,7 +81,6 @@ export class UIOperationModel extends OperationModel { } } -// tslint:disable-next-line:max-classes-per-file class ModalTranslation { CREATE_TITLE: string; EDIT_TITLE: string; @@ -127,7 +120,6 @@ export class UIInterfaceModel extends InterfaceModel { } } -// tslint:disable-next-line:max-classes-per-file @Component({ selector: 'interface-definition', templateUrl: './interface-definition.page.component.html', @@ -151,7 +143,6 @@ export class InterfaceDefinitionComponent { modalTranslation: ModalTranslation; workflows: any[]; capabilities: CapabilitiesGroup; - isViewOnly: boolean; openOperation: OperationModel; enableWorkflowAssociation: boolean; @@ -226,7 +217,7 @@ export class InterfaceDefinitionComponent { } private disableSaveButton = (): boolean => { - return this.isViewOnly || + return this.readonly || (this.isEnableAddArtifactImplementation() && (!this.modalInstance.instance.dynamicContent.toscaArtifactTypeSelected || !this.modalInstance.instance.dynamicContent.artifactName) @@ -235,13 +226,17 @@ export class InterfaceDefinitionComponent { onSelectInterfaceOperation(interfaceModel: UIInterfaceModel, operation: InterfaceOperationModel) { const isEdit = operation !== undefined; - const cancelButton: ButtonModel = new ButtonModel(this.modalTranslation.CANCEL_BUTTON, 'outline white', this.cancelAndCloseModal); - const saveButton: ButtonModel = new ButtonModel(this.modalTranslation.SAVE_BUTTON, 'blue', - () => isEdit ? this.updateOperation() : this.createOperationCallback(), - this.disableSaveButton - ); + const modalButtons = []; + if (!this.readonly) { + const saveButton: ButtonModel = new ButtonModel(this.modalTranslation.SAVE_BUTTON, 'blue', + () => isEdit ? this.updateOperation() : this.createOperationCallback(), + this.disableSaveButton + ); + modalButtons.push(saveButton); + } + modalButtons.push(new ButtonModel(this.modalTranslation.CANCEL_BUTTON, 'outline white', this.cancelAndCloseModal)); const interfaceDataModal: ModalModel = - new ModalModel('l', this.modalTranslation.EDIT_TITLE, '', [saveButton, cancelButton], 'custom'); + new ModalModel('l', this.modalTranslation.EDIT_TITLE, '', modalButtons, 'custom'); this.modalInstance = this.modalServiceNg2.createCustomModal(interfaceDataModal); this.modalServiceNg2.addDynamicContentToModal( @@ -253,8 +248,8 @@ export class InterfaceDefinitionComponent { selectedInterface: interfaceModel ? interfaceModel : new UIInterfaceModel(), selectedInterfaceOperation: operation ? operation : new InterfaceOperationModel(), validityChangedCallback: this.disableSaveButton, - isViewOnly: this.isViewOnly, - isEdit: isEdit, + isViewOnly: this.readonly, + 'isEdit': isEdit, interfaceTypesMap: this.interfaceTypesMap, modelName: this.component.model } diff --git a/integration-tests/src/test/java/org/onap/sdc/frontend/ci/tests/execute/sanity/ImportVfcUiTest.java b/integration-tests/src/test/java/org/onap/sdc/frontend/ci/tests/execute/sanity/ImportVfcUiTest.java index e1705a2255..ba4b6d77fe 100644 --- a/integration-tests/src/test/java/org/onap/sdc/frontend/ci/tests/execute/sanity/ImportVfcUiTest.java +++ b/integration-tests/src/test/java/org/onap/sdc/frontend/ci/tests/execute/sanity/ImportVfcUiTest.java @@ -48,7 +48,7 @@ import org.onap.sdc.frontend.ci.tests.flow.AddNodeToCompositionFlow; import org.onap.sdc.frontend.ci.tests.flow.CreateVfFlow; import org.onap.sdc.frontend.ci.tests.flow.CreateVfcFlow; import org.onap.sdc.frontend.ci.tests.flow.DownloadCsarArtifactFlow; -import org.onap.sdc.frontend.ci.tests.flow.InterfaceDefinitionFlow; +import org.onap.sdc.frontend.ci.tests.flow.GoToInterfaceDefinitionPageFlow; import org.onap.sdc.frontend.ci.tests.flow.exception.UiTestFlowRuntimeException; import org.onap.sdc.frontend.ci.tests.pages.AttributeModal; import org.onap.sdc.frontend.ci.tests.pages.AttributesPage; @@ -144,14 +144,14 @@ public class ImportVfcUiTest extends SetupCDTest { } private ComponentPage viewInterfaceDefinitionFromVFC(final ComponentPage componentPage) { - final InterfaceDefinitionFlow interfaceDefinitionFlow = new InterfaceDefinitionFlow(webDriver); - interfaceDefinitionFlow.run(componentPage); - final InterfaceDefinitionPage interfaceDefinitionPage = interfaceDefinitionFlow.getLandedPage() + final GoToInterfaceDefinitionPageFlow goToInterfaceDefinitionPageFlow = new GoToInterfaceDefinitionPageFlow(webDriver); + goToInterfaceDefinitionPageFlow.run(componentPage); + final InterfaceDefinitionPage interfaceDefinitionPage = goToInterfaceDefinitionPageFlow.getLandedPage() .orElseThrow(() -> new UiTestFlowRuntimeException("Missing expected return InterfaceDefinitionPage")); - final var OPERATION_NAME = "create"; - assertTrue(interfaceDefinitionPage.isInterfaceDefinitionOperationPresent(OPERATION_NAME)); - final InterfaceDefinitionOperationsModal interfaceDefinitionOperationsModal = interfaceDefinitionPage.clickOnInterfaceDefinitionOperation( - OPERATION_NAME); + final var operationName = "create"; + assertTrue(interfaceDefinitionPage.isInterfaceDefinitionOperationPresent(operationName)); + final InterfaceDefinitionOperationsModal interfaceDefinitionOperationsModal = + interfaceDefinitionPage.clickOnInterfaceDefinitionOperation(operationName); interfaceDefinitionOperationsModal.isLoaded(true); ExtentTestActions .takeScreenshot(Status.INFO, "clickOnOInterfaceOperation", "Interface Definition Operation Modal opened"); diff --git a/integration-tests/src/test/java/org/onap/sdc/frontend/ci/tests/flow/InterfaceDefinitionFlow.java b/integration-tests/src/test/java/org/onap/sdc/frontend/ci/tests/flow/GoToInterfaceDefinitionPageFlow.java similarity index 86% rename from integration-tests/src/test/java/org/onap/sdc/frontend/ci/tests/flow/InterfaceDefinitionFlow.java rename to integration-tests/src/test/java/org/onap/sdc/frontend/ci/tests/flow/GoToInterfaceDefinitionPageFlow.java index a0955ff800..72ae269b4e 100644 --- a/integration-tests/src/test/java/org/onap/sdc/frontend/ci/tests/flow/InterfaceDefinitionFlow.java +++ b/integration-tests/src/test/java/org/onap/sdc/frontend/ci/tests/flow/GoToInterfaceDefinitionPageFlow.java @@ -28,19 +28,19 @@ import org.onap.sdc.frontend.ci.tests.pages.component.workspace.InterfaceDefinit import org.openqa.selenium.WebDriver; /** - * UI Flow for managing an Interface Definition from a component + * UI Flow to go to the interfaces page of a VFC from the VFC Workspace */ -public class InterfaceDefinitionFlow extends AbstractUiTestFlow { +public class GoToInterfaceDefinitionPageFlow extends AbstractUiTestFlow { private InterfaceDefinitionPage interfaceDefinitionPage; - public InterfaceDefinitionFlow(final WebDriver webDriver) { + public GoToInterfaceDefinitionPageFlow(final WebDriver webDriver) { super(webDriver); } @Override public Optional run(final PageObject... pageObjects) { - extendTest.log(Status.INFO, "Downloading Tosca CSAR generated"); + extendTest.log(Status.INFO, "Going to access the Interfaces page from the resource Workspace"); final ComponentPage componentPage = findParameter(pageObjects, ComponentPage.class); componentPage.isLoaded(); interfaceDefinitionPage = componentPage.goToInterfaceDefinition(); diff --git a/integration-tests/src/test/java/org/onap/sdc/frontend/ci/tests/pages/component/workspace/InterfaceDefinitionOperationsModal.java b/integration-tests/src/test/java/org/onap/sdc/frontend/ci/tests/pages/component/workspace/InterfaceDefinitionOperationsModal.java index 78828d7bbe..160c314665 100644 --- a/integration-tests/src/test/java/org/onap/sdc/frontend/ci/tests/pages/component/workspace/InterfaceDefinitionOperationsModal.java +++ b/integration-tests/src/test/java/org/onap/sdc/frontend/ci/tests/pages/component/workspace/InterfaceDefinitionOperationsModal.java @@ -19,8 +19,9 @@ package org.onap.sdc.frontend.ci.tests.pages.component.workspace; +import static org.onap.sdc.frontend.ci.tests.utilities.GeneralUIUtils.waitForLoader; + import com.aventstack.extentreports.Status; -import java.time.Duration; import java.util.List; import lombok.AllArgsConstructor; import lombok.Getter; @@ -30,9 +31,6 @@ import org.onap.sdc.frontend.ci.tests.pages.component.workspace.InterfaceDefinit import org.openqa.selenium.By; import org.openqa.selenium.WebDriver; import org.openqa.selenium.WebElement; -import org.openqa.selenium.interactions.Actions; - -import static org.onap.sdc.frontend.ci.tests.utilities.GeneralUIUtils.waitForLoader; /** * Represents the Composition Interface Operations Modal. @@ -55,7 +53,9 @@ public class InterfaceDefinitionOperationsModal extends AbstractPageObject { waitForElementVisibility(By.xpath(XpathSelector.TITLE_SPAN.getXPath())); waitForElementVisibility(By.xpath(XpathSelector.INTERFACE_NAME_LABEL.getXPath())); waitForElementVisibility(By.xpath(XpathSelector.OPERATION_NAME_LABEL.getXPath())); - waitForElementVisibility(By.xpath(XpathSelector.SAVE_BTN.getXPath())); + if (!isInViewMode) { + waitForElementVisibility(By.xpath(XpathSelector.SAVE_BTN.getXPath())); + } waitToBeClickable(By.xpath(XpathSelector.CANCEL_BTN.getXPath())); this.inputListComponent = new InterfaceOperationInputListComponent(webDriver); this.inputListComponent.isLoaded();