From 5aead27ae50780ea19deb1748b85f009a3d24786 Mon Sep 17 00:00:00 2001 From: nicdavidson Date: Fri, 20 Jun 2025 12:17:09 -0600 Subject: [PATCH 1/4] resolved camelcase and null SOAP issues --- .../df-api-docs/df-api-docs.component.ts | 12 +- .../df-service-details.component.ts | 110 +++++++++++++----- src/app/shared/utilities/case.ts | 54 +++++++-- 3 files changed, 132 insertions(+), 44 deletions(-) diff --git a/src/app/adf-api-docs/df-api-docs/df-api-docs.component.ts b/src/app/adf-api-docs/df-api-docs/df-api-docs.component.ts index 8d805e37..49f64271 100644 --- a/src/app/adf-api-docs/df-api-docs/df-api-docs.component.ts +++ b/src/app/adf-api-docs/df-api-docs/df-api-docs.component.ts @@ -115,13 +115,13 @@ export class DfApiDocsComponent implements OnInit, AfterContentInit, OnDestroy { this.subscriptions.push( this.activatedRoute.data.subscribe(({ data }) => { if (data) { - if ( - data.paths['/']?.get && - data.paths['/']?.get.operationId && - data.paths['/']?.get.operationId === 'getSoapResources' - ) { - this.apiDocJson = { ...data, paths: mapSnakeToCamel(data.paths) }; + // Check if this is a SOAP service + const isSoapService = data.paths['/']?.get?.operationId === 'getSoapResources'; + if (isSoapService) { + // For SOAP services, preserve the original paths without case transformation + this.apiDocJson = { ...data }; } else { + // For non-SOAP services, apply the normal case transformation this.apiDocJson = { ...data, paths: mapCamelToSnake(data.paths) }; } } diff --git a/src/app/adf-services/df-service-details/df-service-details.component.ts b/src/app/adf-services/df-service-details/df-service-details.component.ts index 9ab190fd..30001bef 100644 --- a/src/app/adf-services/df-service-details/df-service-details.component.ts +++ b/src/app/adf-services/df-service-details/df-service-details.component.ts @@ -116,6 +116,18 @@ interface CategorizedField { advanced: ConfigSchema[]; } +interface ServicePayload { + id?: number | null; + type: string; + name: string; + label: string; + description: string; + isActive?: boolean; + config: any; + service_doc_by_service_id: any; + [key: string]: any; // Allow additional properties for SAML and other service types +} + @UntilDestroy({ checkProperties: true }) @Component({ selector: 'df-service-details', @@ -566,14 +578,15 @@ export class DfServiceDetailsComponent implements OnInit { fields: '*', related: 'service_doc_by_service_id', }; - // if (!data.config.serviceDefinition) { - // data.service_doc_by_service_id = null; - // } else { - data.service_doc_by_service_id.content = data.config.content; - data.service_doc_by_service_id.format = Number( - this.serviceDefinitionType - ); - // } + // Skip service_doc_by_service_id handling for SOAP services + if (data.type.toLowerCase() === 'soap') { + data.service_doc_by_service_id = null; + } else { + data.service_doc_by_service_id.content = data.config.content; + data.service_doc_by_service_id.format = Number( + this.serviceDefinitionType + ); + } } else if (this.isScriptService) { params = { ...params, @@ -598,8 +611,27 @@ export class DfServiceDetailsComponent implements OnInit { } else { delete data.service_doc_by_service_id; } - let payload; - if (data.type.toLowerCase().includes('saml')) { + let payload: ServicePayload; + if (data.type.toLowerCase() === 'soap') { + // For SOAP services, we only need basic fields and wsdl config + payload = { + type: data.type, + name: data.name, + label: data.label, + description: data.description, + isActive: data.isActive, + config: { + wsdl: data.config.wsdl, + options: null, + headers: null, + wsse_username_token: null, + cache_enabled: false, + cache_ttl: 0, + content: "" + }, + service_doc_by_service_id: null + }; + } else if (data.type.toLowerCase().includes('saml')) { params = { ...params, fields: '*', @@ -608,7 +640,7 @@ export class DfServiceDetailsComponent implements OnInit { // data.service_doc_by_service_id = null; payload = { ...data, - is_active: data.isActive, + isActive: data.isActive, id: this.edit ? this.serviceData.id : null, config: { sp_nameIDFormat: data.config.spNameIDFormat, @@ -642,26 +674,48 @@ export class DfServiceDetailsComponent implements OnInit { ...data, id: this.edit ? this.serviceData.id : null, }; - payload = { ...data }; } if (this.edit) { - const payload = { - ...this.serviceData, - ...data, - config: { - ...(this.serviceData.config || {}), - ...data.config, - }, - service_doc_by_service_id: data.service_doc_by_service_id - ? { - ...(this.serviceData.serviceDocByServiceId || {}), - ...data.service_doc_by_service_id, - } - : null, - }; - delete payload.config.serviceDefinition; + let editPayload; + if (data.type.toLowerCase() === 'soap') { + // For SOAP services in edit mode, preserve only necessary fields + editPayload = { + id: this.serviceData.id, + type: data.type, + name: data.name, + label: data.label, + description: data.description, + isActive: data.isActive, + config: { + wsdl: data.config.wsdl, + options: null, + headers: null, + wsse_username_token: null, + cache_enabled: false, + cache_ttl: 0, + content: "" + }, + service_doc_by_service_id: null + }; + } else { + editPayload = { + ...this.serviceData, + ...data, + config: { + ...(this.serviceData.config || {}), + ...data.config, + }, + service_doc_by_service_id: data.service_doc_by_service_id + ? { + ...(this.serviceData.serviceDocByServiceId || {}), + ...data.service_doc_by_service_id, + } + : null, + }; + } + delete editPayload.config.serviceDefinition; this.servicesService - .update(this.serviceData.id, payload, { + .update(this.serviceData.id, editPayload, { snackbarError: 'server', snackbarSuccess: 'services.updateSuccessMsg', }) diff --git a/src/app/shared/utilities/case.ts b/src/app/shared/utilities/case.ts index 6ff9d58c..9312333f 100644 --- a/src/app/shared/utilities/case.ts +++ b/src/app/shared/utilities/case.ts @@ -1,5 +1,10 @@ -export const snakeToCamelString = (str: string) => - str.replace(/([-_]\w)/g, g => g[1].toUpperCase()); +export const snakeToCamelString = (str: string) => { + // For SOAP method paths, preserve the original case + if (str.startsWith('_') || str.startsWith('/')) { + return str; + } + return str.replace(/([-_]\w)/g, g => g[1].toUpperCase()); +}; export function mapSnakeToCamel(obj: T): T { if (Array.isArray(obj)) { @@ -8,12 +13,25 @@ export function mapSnakeToCamel(obj: T): T { const newObj: Record = {}; for (const key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { - newObj[snakeToCamelString(key)] = mapSnakeToCamel( - (obj as Record)[key] - ); + const value = (obj as Record)[key]; + // For paths object, preserve the path keys but transform the contents + if (key === 'paths') { + const pathsObj = value as Record; + const newPathsObj: Record = {}; + for (const pathKey in pathsObj) { + // Preserve the original path key + newPathsObj[pathKey] = mapSnakeToCamel(pathsObj[pathKey]); + } + newObj[key] = newPathsObj; + } else { + newObj[snakeToCamelString(key)] = mapSnakeToCamel(value); + } } } return newObj as unknown as T; + } else if (typeof obj === 'string' && (obj.startsWith('_') || obj.startsWith('/'))) { + // Preserve SOAP method paths in string values + return obj as unknown as T; } else { return obj; } @@ -41,6 +59,7 @@ export function mapSnakeToCamel(obj: T): T { // } export const camelToSnakeString = (str: string) => { + // Special cases for SAML fields if ( str === 'idpSingleSignOnServiceUrl' || str === 'idp_singleSignOnService_url' @@ -56,6 +75,10 @@ export const camelToSnakeString = (str: string) => { if (str === 'spPrivateKey' || str === 'sp_privateKey') { return 'sp_privateKey'; } + // For SOAP method paths, preserve the original case + if (str.startsWith('_') || str.startsWith('/')) { + return str; + } return str.replace(/([a-z0-9]|(?=[A-Z]))([A-Z])/g, '$1_$2').toLowerCase(); }; @@ -66,16 +89,27 @@ export function mapCamelToSnake(obj: T): T { const newObj: Record = {}; for (const key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { - if (key === 'requestBody') { - newObj[key] = (obj as Record)[key]; + const value = (obj as Record)[key]; + // For paths object, preserve the path keys but transform the contents + if (key === 'paths') { + const pathsObj = value as Record; + const newPathsObj: Record = {}; + for (const pathKey in pathsObj) { + // Preserve the original path key + newPathsObj[pathKey] = mapCamelToSnake(pathsObj[pathKey]); + } + newObj[key] = newPathsObj; + } else if (key === 'requestBody') { + newObj[key] = value; } else { - newObj[camelToSnakeString(key)] = mapCamelToSnake( - (obj as Record)[key] - ); + newObj[camelToSnakeString(key)] = mapCamelToSnake(value); } } } return newObj as unknown as T; + } else if (typeof obj === 'string' && (obj.startsWith('_') || obj.startsWith('/'))) { + // Preserve SOAP method paths in string values + return obj as unknown as T; } else { return obj; } From 4c320731a6106db3a298dca16cdbf9e0d25d671f Mon Sep 17 00:00:00 2001 From: nicdavidson Date: Fri, 20 Jun 2025 12:22:17 -0600 Subject: [PATCH 2/4] resolved camelcase and null SOAP issues --- .../adf-api-docs/df-api-docs/df-api-docs.component.ts | 3 ++- .../df-cors/df-cors-config-details.component.html | 2 +- .../df-welcome-page/df-welcome-page.component.html | 2 +- .../df-limit-details/df-limit-details.component.html | 2 +- .../df-roles-access/df-roles-access.component.html | 4 ++-- .../df-roles-access/df-roles-access.component.ts | 5 +++-- .../df-scheduler-details.component.html | 2 +- .../df-service-details.component.html | 8 ++++---- .../df-service-details/df-service-details.component.ts | 8 ++++---- .../df-login/df-login.component.html | 4 ++-- .../df-password-reset/df-password-reset.component.html | 4 ++-- .../services/df-password.service.ts | 8 +++----- .../df-dynamic-field/df-dynamic-field.component.html | 6 +++--- .../df-manage-table/df-manage-table.component.html | 2 +- .../df-script-editor/df-script-editor.component.ts | 8 +++++--- .../df-user-app-roles/df-user-app-roles.component.html | 2 +- .../df-user-details-base.component.html | 2 +- .../df-verb-picker/df-verb-picker.component.ts | 9 +++++---- src/app/shared/services/df-base-crud.service.ts | 4 ++-- src/app/shared/utilities/case.ts | 10 ++++++++-- 20 files changed, 52 insertions(+), 43 deletions(-) diff --git a/src/app/adf-api-docs/df-api-docs/df-api-docs.component.ts b/src/app/adf-api-docs/df-api-docs/df-api-docs.component.ts index 49f64271..79835864 100644 --- a/src/app/adf-api-docs/df-api-docs/df-api-docs.component.ts +++ b/src/app/adf-api-docs/df-api-docs/df-api-docs.component.ts @@ -116,7 +116,8 @@ export class DfApiDocsComponent implements OnInit, AfterContentInit, OnDestroy { this.activatedRoute.data.subscribe(({ data }) => { if (data) { // Check if this is a SOAP service - const isSoapService = data.paths['/']?.get?.operationId === 'getSoapResources'; + const isSoapService = + data.paths['/']?.get?.operationId === 'getSoapResources'; if (isSoapService) { // For SOAP services, preserve the original paths without case transformation this.apiDocJson = { ...data }; diff --git a/src/app/adf-config/df-cors/df-cors-config-details.component.html b/src/app/adf-config/df-cors/df-cors-config-details.component.html index 246af75c..39f0faf8 100644 --- a/src/app/adf-config/df-cors/df-cors-config-details.component.html +++ b/src/app/adf-config/df-cors/df-cors-config-details.component.html @@ -61,7 +61,7 @@

{{ 'cors.pageSubtitle' | transloco }}

class="dynamic-width" formControlName="methods" [schema]="{ - label: 'cors.formControls.methods' | transloco + label: 'cors.formControls.methods' | transloco, }" type="verb_multiple">
diff --git a/src/app/adf-roles/df-roles-access/df-roles-access.component.ts b/src/app/adf-roles/df-roles-access/df-roles-access.component.ts index 64c7eeea..ff698948 100644 --- a/src/app/adf-roles/df-roles-access/df-roles-access.component.ts +++ b/src/app/adf-roles/df-roles-access/df-roles-access.component.ts @@ -245,8 +245,9 @@ export class DfRolesAccessComponent implements OnInit { } getExtendOperator(index: number) { - const serviceId = this.serviceAccess.at(index).get('extend-operator') - ?.value; + const serviceId = this.serviceAccess + .at(index) + .get('extend-operator')?.value; const operators = this.componentOptions.find( option => option.serviceId === serviceId )?.components; diff --git a/src/app/adf-scheduler/df-scheduler-details/df-scheduler-details.component.html b/src/app/adf-scheduler/df-scheduler-details/df-scheduler-details.component.html index 1605b74e..92cbcfd0 100644 --- a/src/app/adf-scheduler/df-scheduler-details/df-scheduler-details.component.html +++ b/src/app/adf-scheduler/df-scheduler-details/df-scheduler-details.component.html @@ -93,7 +93,7 @@

{{ 'scheduler.taskOverviewSubtitle' | transloco }}

class="dynamic-width" formControlName="method" [schema]="{ - label: 'scheduler.form.label.method' | transloco + label: 'scheduler.form.label.method' | transloco, }">