From 77566229653c2890005bdda2f9fe7d7ba1029d09 Mon Sep 17 00:00:00 2001
From: Marlon Keating
Date: Wed, 6 Dec 2023 20:59:28 +0000
Subject: [PATCH] feat: Persist SSO Config 'authorized' checkbox state
---
.../SettingsSSOTab/SSOFormWorkflowConfig.tsx | 37 +++++++++++--------
.../steps/NewSSOConfigAuthorizeStep.tsx | 10 ++---
.../tests/NewSSOConfigForm.test.jsx | 6 ++-
3 files changed, 29 insertions(+), 24 deletions(-)
diff --git a/src/components/settings/SettingsSSOTab/SSOFormWorkflowConfig.tsx b/src/components/settings/SettingsSSOTab/SSOFormWorkflowConfig.tsx
index ca7dd08e07..218811ac3e 100644
--- a/src/components/settings/SettingsSSOTab/SSOFormWorkflowConfig.tsx
+++ b/src/components/settings/SettingsSSOTab/SSOFormWorkflowConfig.tsx
@@ -1,5 +1,6 @@
import omit from 'lodash/omit';
+import { AxiosError } from 'axios';
import type { FormWorkflowHandlerArgs, FormWorkflowStep } from '../../forms/FormWorkflow';
import SSOConfigConnectStep, { validations as SSOConfigConnectStepValidations } from './steps/NewSSOConfigConnectStep';
import SSOConfigConfigureStep, { validations as SSOConfigConfigureStepValidations } from './steps/NewSSOConfigConfigureStep';
@@ -8,7 +9,6 @@ import SSOConfigConfirmStep from './steps/NewSSOConfigConfirmStep';
import LmsApiService from '../../../data/services/LmsApiService';
import handleErrors from '../utils';
import { snakeCaseDict } from '../../../utils';
-import { AxiosError } from 'axios';
import { INVALID_IDP_METADATA_ERROR, RECORD_UNDER_CONFIGURATIONS_ERROR } from '../data/constants';
type SSOConfigSnakeCase = {
@@ -40,6 +40,7 @@ type SSOConfigSnakeCase = {
oauth_user_id: string,
sp_metadata_url?: string,
record?: object,
+ marked_authorized: boolean
};
export type SSOConfigCamelCase = {
@@ -70,7 +71,8 @@ export type SSOConfigCamelCase = {
sapsfPrivateKey: string,
odataClientId: string,
oauthUserId: string,
- spMetadataUrl?: string
+ spMetadataUrl?: string,
+ markedAuthorized: boolean
};
type SSOConfigFormControlVariables = {
@@ -81,13 +83,6 @@ type SSOConfigFormControlVariables = {
type SSOConfigFormContextData = SSOConfigCamelCase & SSOConfigFormControlVariables;
export const SSOFormWorkflowConfig = ({ enterpriseId, setConfigureError }) => {
- const placeHolderButton = (buttonName?: string) => () => ({
- buttonText: buttonName || 'Next',
- opensNewWindow: false,
- onClick: () => { },
- preventDefaultErrorModal: false,
- });
-
const advanceConnectStep = async ({
formFields,
errHandler,
@@ -98,7 +93,7 @@ export const SSOFormWorkflowConfig = ({ enterpriseId, setConfigureError }) => {
const sanitizeAndCopyFormFields = (formFields: SSOConfigSnakeCase) => {
const copiedFormFields = { ...formFields };
- return omit(copiedFormFields, ['record', 'sp_metadata_url', 'submitted_at', 'configured_at','validated_at']);
+ return omit(copiedFormFields, ['record', 'sp_metadata_url', 'submitted_at', 'configured_at', 'validated_at']);
};
const saveChanges = async ({
@@ -117,7 +112,7 @@ export const SSOFormWorkflowConfig = ({ enterpriseId, setConfigureError }) => {
let updatedFormFields: SSOConfigCamelCase = omit(formFields, ['idpConnectOption', 'spMetadataUrl', 'isPendingConfiguration']);
updatedFormFields.enterpriseCustomer = enterpriseId;
const submittedFormFields: SSOConfigSnakeCase = snakeCaseDict(updatedFormFields) as SSOConfigSnakeCase;
- let copiedFormFields = sanitizeAndCopyFormFields(submittedFormFields);
+ const copiedFormFields = sanitizeAndCopyFormFields(submittedFormFields);
if (copiedFormFields?.uuid) {
try {
const updateResponse = await LmsApiService.updateEnterpriseSsoOrchestrationRecord(
@@ -127,9 +122,9 @@ export const SSOFormWorkflowConfig = ({ enterpriseId, setConfigureError }) => {
updatedFormFields = updateResponse.data;
} catch (error: AxiosError | any) {
err = handleErrors(error);
- if (error.message?.includes("Must provide valid IDP metadata url")) {
+ if (error.message?.includes('Must provide valid IDP metadata url')) {
errHandler?.(INVALID_IDP_METADATA_ERROR);
- } else if (error.message?.includes("Record has already been submitted for configuration.")) {
+ } else if (error.message?.includes('Record has already been submitted for configuration.')) {
errHandler?.(RECORD_UNDER_CONFIGURATIONS_ERROR);
} else {
setConfigureError(error);
@@ -142,7 +137,7 @@ export const SSOFormWorkflowConfig = ({ enterpriseId, setConfigureError }) => {
updatedFormFields.spMetadataUrl = createResponse.data.sp_metadata_url;
} catch (error: AxiosError | any) {
err = handleErrors(error);
- if (error.message?.includes("Must provide valid IDP metadata url")) {
+ if (error.message?.includes('Must provide valid IDP metadata url')) {
errHandler?.(INVALID_IDP_METADATA_ERROR);
} else {
setConfigureError(error);
@@ -184,7 +179,12 @@ export const SSOFormWorkflowConfig = ({ enterpriseId, setConfigureError }) => {
formComponent: SSOConfigAuthorizeStep,
validations: SSOConfigAuthorizeStepValidations,
stepName: 'Authorize',
- nextButtonConfig: placeHolderButton(),
+ nextButtonConfig: () => ({
+ buttonText: 'Next',
+ opensNewWindow: false,
+ onClick: saveChanges,
+ preventDefaultErrorModal: false,
+ }),
showBackButton: true,
showCancelButton: false,
}, {
@@ -192,7 +192,12 @@ export const SSOFormWorkflowConfig = ({ enterpriseId, setConfigureError }) => {
formComponent: SSOConfigConfirmStep,
validations: [],
stepName: 'Confirm and Test',
- nextButtonConfig: placeHolderButton('Finish'),
+ nextButtonConfig: () => ({
+ buttonText: 'Finish',
+ opensNewWindow: false,
+ onClick: () => {},
+ preventDefaultErrorModal: false,
+ }),
showBackButton: true,
showCancelButton: false,
},
diff --git a/src/components/settings/SettingsSSOTab/steps/NewSSOConfigAuthorizeStep.tsx b/src/components/settings/SettingsSSOTab/steps/NewSSOConfigAuthorizeStep.tsx
index dd640f2450..88d280c983 100644
--- a/src/components/settings/SettingsSSOTab/steps/NewSSOConfigAuthorizeStep.tsx
+++ b/src/components/settings/SettingsSSOTab/steps/NewSSOConfigAuthorizeStep.tsx
@@ -1,21 +1,20 @@
import React, { useContext } from 'react';
import { useParams } from 'react-router-dom';
import {
- Alert, Form, Hyperlink, Button, Row,
+ Alert, Hyperlink, Button, Row,
} from '@edx/paragon';
import { Info, Download } from '@edx/paragon/icons';
import { getConfig } from '@edx/frontend-platform/config';
import { createSAMLURLs } from '../utils';
import { SSOConfigContext } from '../SSOConfigContext';
-import { setFormFieldAction } from '../../../forms/data/actions';
import { FormFieldValidation, useFormContext } from '../../../forms/FormContext';
import ValidatedFormCheckbox from '../../../forms/ValidatedFormCheckbox';
export const validations: FormFieldValidation[] = [
{
- formFieldId: 'confirmAuthorizedEdxServiceProvider',
+ formFieldId: 'markedAuthorized',
validator: (fields) => {
- const ret = !fields.confirmAuthorizedEdxServiceProvider && 'Please verify authorization of edX as a Service Provider.';
+ const ret = !fields.markedAuthorized && 'Please verify authorization of edX as a Service Provider.';
return ret;
},
},
@@ -40,7 +39,6 @@ const SSOConfigAuthorizeStep = () => {
ssoState,
} = useContext(SSOConfigContext);
const {
- dispatch,
formFields,
} = useFormContext();
const { enterpriseSlug } = useParams();
@@ -80,7 +78,7 @@ const SSOConfigAuthorizeStep = () => {
Return to this window and check the box once complete
-
+
I have authorized edX as a Service Provider
>
diff --git a/src/components/settings/SettingsSSOTab/tests/NewSSOConfigForm.test.jsx b/src/components/settings/SettingsSSOTab/tests/NewSSOConfigForm.test.jsx
index 084157a67b..3f08d7cbe5 100644
--- a/src/components/settings/SettingsSSOTab/tests/NewSSOConfigForm.test.jsx
+++ b/src/components/settings/SettingsSSOTab/tests/NewSSOConfigForm.test.jsx
@@ -421,7 +421,10 @@ describe('SAML Config Tab', () => {
test('navigate through new non-SAP sso workflow', async () => {
setupNewSSOStepper();
const mockCreateEnterpriseSsoOrchestrationRecord = jest.spyOn(LmsApiService, 'createEnterpriseSsoOrchestrationRecord');
- mockCreateEnterpriseSsoOrchestrationRecord.mockResolvedValue({ data: { record: 'fakeuuid', sp_metadata_url: 'https://fake.url' } });
+ const mockUpdateEnterpriseSsoOrchestrationRecord = jest.spyOn(LmsApiService, 'updateEnterpriseSsoOrchestrationRecord');
+ const mockReturnData = { data: { record: 'fakeuuid', sp_metadata_url: 'https://fake.url' } };
+ mockCreateEnterpriseSsoOrchestrationRecord.mockResolvedValue(mockReturnData);
+ mockUpdateEnterpriseSsoOrchestrationRecord.mockResolvedValue(mockReturnData);
jest.spyOn(Router, 'useParams').mockReturnValue({ enterpriseSlug: 'testslug' });
// Connect Step
await waitFor(() => {
@@ -504,7 +507,6 @@ describe('SAML Config Tab', () => {
}, []);
screen.queryByText(testMetadataUrl);
});
- // TODO: Test case where we go SAP route
test('navigate through new SAP sso workflow', async () => {
setupNewSSOStepper();
const mockCreateEnterpriseSsoOrchestrationRecord = jest.spyOn(LmsApiService, 'createEnterpriseSsoOrchestrationRecord');