diff --git a/packages/nodes-base/nodes/Aws/Cognito/GenericFunctions.ts b/packages/nodes-base/nodes/Aws/Cognito/GenericFunctions.ts index bc447cf911..64a9869952 100644 --- a/packages/nodes-base/nodes/Aws/Cognito/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Aws/Cognito/GenericFunctions.ts @@ -14,13 +14,27 @@ import type { } from 'n8n-workflow'; import { ApplicationError, jsonParse, NodeApiError, NodeOperationError } from 'n8n-workflow'; -export async function presendTest( - this: IExecuteSingleFunctions, - requestOptions: IHttpRequestOptions, -): Promise { - console.log('requestOptions', requestOptions); - return requestOptions; -} +type UserPool = { + Arn: string; + CreationDate: number; + DeletionProtection: string; + Domain: string; + EstimatedNumberOfUsers: number; + Id: string; + LastModifiedDate: number; + MfaConfiguration: string; + Name: string; +}; + +type User = { + Enabled: boolean; + UserAttributes?: Array<{ Name: string; Value: string }>; + Attributes?: Array<{ Name: string; Value: string }>; + UserCreateDate: number; + UserLastModifiedDate: number; + UserStatus: string; + Username: string; +}; /* * Helper function which stringifies the body before sending the request. @@ -36,33 +50,17 @@ export async function presendStringifyBody( return requestOptions; } -export async function presendFilter( +export async function presendFilters( this: IExecuteSingleFunctions, requestOptions: IHttpRequestOptions, ): Promise { - const additionalFields = this.getNodeParameter('additionalFields', {}) as IDataObject; - const filterAttribute = additionalFields.filters as string; - let filterType = additionalFields.filterType as string; - const filterValue = additionalFields.filterValue as string; + const filters = this.getNodeParameter('filters') as IDataObject; - const hasAnyFilter = filterAttribute || filterType || filterValue; + if (filters.length === 0) return requestOptions; - if (!hasAnyFilter) { - return requestOptions; - } - - if (hasAnyFilter && (!filterAttribute || !filterType || !filterValue)) { - throw new NodeOperationError( - this.getNode(), - 'If filtering is used, please provide Filter Attribute, Filter Type, and Filter Value.', - ); - } - - const filterTypeMapping: { [key: string]: string } = { - exactMatch: '=', - startsWith: '^=', - }; - filterType = filterTypeMapping[filterType] || filterType; + const filterToSend = filters.filter as IDataObject; + const filterAttribute = filterToSend?.attribute as string; + const filterValue = filterToSend?.value as string; let body: IDataObject; if (typeof requestOptions.body === 'string') { @@ -72,12 +70,17 @@ export async function presendFilter( throw new NodeOperationError(this.getNode(), 'Failed to parse requestOptions body'); } } else { - body = requestOptions.body as IDataObject; + body = (requestOptions.body as IDataObject) || {}; + } + + let filter = ''; + if (filterAttribute && filterValue) { + filter = `"${filterAttribute}"^="${filterValue}"`; } requestOptions.body = JSON.stringify({ ...body, - Filter: `${filterAttribute} ${filterType} "${filterValue}"`, + Filter: filter, }); return requestOptions; @@ -121,7 +124,6 @@ export async function presendVerifyPath( return requestOptions; } -/* Helper function to process attributes in UserAttributes */ export async function processAttributes( this: IExecuteSingleFunctions, requestOptions: IHttpRequestOptions, @@ -156,7 +158,6 @@ export async function processAttributes( return requestOptions; } -/* Helper function to handle pagination */ const possibleRootProperties = ['Users', 'Groups']; export async function handlePagination( this: IExecutePaginationFunctions, @@ -207,7 +208,6 @@ export async function handlePagination( return aggregatedResult.map((item) => ({ json: item })); } -/* Helper functions to handle errors */ export async function handleErrorPostReceive( this: IExecuteSingleFunctions, data: INodeExecutionData[], @@ -337,7 +337,6 @@ export async function handleErrorPostReceive( return data; } -/* Helper function used in listSearch methods */ export async function awsRequest( this: ILoadOptionsFunctions | IPollFunctions | IExecuteSingleFunctions, opts: IHttpRequestOptions, @@ -542,6 +541,20 @@ export async function searchGroups( return { results, paginationToken: responseData.NextToken }; } +export function mapUserAttributes(userAttributes: Array<{ Name: string; Value: string }>): { + [key: string]: string; +} { + return userAttributes?.reduce( + (acc, { Name, Value }) => { + if (Name !== 'sub') { + acc[Name] = Value; + } + return acc; + }, + {} as { [key: string]: string }, + ); +} + export async function simplifyData( this: IExecuteSingleFunctions, items: INodeExecutionData[], @@ -549,42 +562,6 @@ export async function simplifyData( ): Promise { const simple = this.getNodeParameter('simple') as boolean; - type UserPool = { - Arn: string; - CreationDate: number; - DeletionProtection: string; - Domain: string; - EstimatedNumberOfUsers: number; - Id: string; - LastModifiedDate: number; - MfaConfiguration: string; - Name: string; - }; - - type User = { - Enabled: boolean; - UserAttributes?: Array<{ Name: string; Value: string }>; - Attributes?: Array<{ Name: string; Value: string }>; - UserCreateDate: number; - UserLastModifiedDate: number; - UserStatus: string; - Username: string; - }; - - function mapUserAttributes(userAttributes: Array<{ Name: string; Value: string }>): { - [key: string]: string; - } { - return userAttributes?.reduce( - (acc, { Name, Value }) => { - if (Name !== 'sub') { - acc[Name] = Value; - } - return acc; - }, - {} as { [key: string]: string }, - ); - } - if (!simple) { return items; } @@ -643,12 +620,12 @@ export async function simplifyData( users.forEach((user) => { const userAttributes = user.Attributes ? mapUserAttributes(user.Attributes) : {}; processedUsers.push({ - Enabled: userData.Enabled, + Enabled: user.Enabled, ...Object.fromEntries(Object.entries(userAttributes).slice(0, 6)), - UserCreateDate: userData.UserCreateDate, - UserLastModifiedDate: userData.UserLastModifiedDate, - UserStatus: userData.UserStatus, - Username: userData.Username, + UserCreateDate: user.UserCreateDate, + UserLastModifiedDate: user.UserLastModifiedDate, + UserStatus: user.UserStatus, + Username: user.Username, }); }); return { @@ -793,31 +770,3 @@ export async function processUsersForGroups( json: { ...item.json, Groups: processedGroups }, })); } - -//Check if needed -export async function fetchUserPoolConfig( - this: IExecuteSingleFunctions, - requestOptions: IHttpRequestOptions, -): Promise { - const userPoolIdRaw = this.getNodeParameter('userPoolId') as IDataObject; - const userPoolId = userPoolIdRaw.value as string; - - if (!userPoolId) { - throw new ApplicationError('User Pool ID is required'); - } - - const opts: IHttpRequestOptions = { - url: '', - method: 'POST', - body: JSON.stringify({ - UserPoolId: userPoolId, - }), - headers: { - 'X-Amz-Target': 'AWSCognitoIdentityProviderService.DescribeUserPool', - }, - }; - - const responseData: IDataObject = await awsRequest.call(this, opts); - - return requestOptions; -} diff --git a/packages/nodes-base/nodes/Aws/Cognito/descriptions/GroupDescription.ts b/packages/nodes-base/nodes/Aws/Cognito/descriptions/GroupDescription.ts index c68cdb3369..39fe7ae444 100644 --- a/packages/nodes-base/nodes/Aws/Cognito/descriptions/GroupDescription.ts +++ b/packages/nodes-base/nodes/Aws/Cognito/descriptions/GroupDescription.ts @@ -34,7 +34,15 @@ export const groupOperations: INodeProperties[] = [ ignoreHttpStatusErrors: true, }, output: { - postReceive: [handleErrorPostReceive], + postReceive: [ + handleErrorPostReceive, + { + type: 'rootProperty', + properties: { + property: 'Group', + }, + }, + ], }, }, action: 'Create group', @@ -215,8 +223,8 @@ const createFields: INodeProperties[] = [ validateType: 'string', }, { - displayName: 'Options', - name: 'options', + displayName: 'Additional Fields', + name: 'additionalFields', default: {}, displayOptions: { show: { diff --git a/packages/nodes-base/nodes/Aws/Cognito/descriptions/UserDescription.ts b/packages/nodes-base/nodes/Aws/Cognito/descriptions/UserDescription.ts index f07e811381..61d49ea884 100644 --- a/packages/nodes-base/nodes/Aws/Cognito/descriptions/UserDescription.ts +++ b/packages/nodes-base/nodes/Aws/Cognito/descriptions/UserDescription.ts @@ -1,11 +1,9 @@ import type { INodeProperties } from 'n8n-workflow'; import { - fetchUserPoolConfig, handleErrorPostReceive, handlePagination, - presendFilter, - presendTest, + presendFilters, processAttributes, simplifyData, } from '../GenericFunctions'; @@ -55,9 +53,6 @@ export const userOperations: INodeProperties[] = [ description: 'Create a new user', action: 'Create user', routing: { - send: { - preSend: [presendTest, fetchUserPoolConfig], - }, request: { method: 'POST', headers: { @@ -121,7 +116,7 @@ export const userOperations: INodeProperties[] = [ routing: { send: { paginate: true, - preSend: [presendFilter], + preSend: [presendFilters], }, operations: { pagination: handlePagination }, request: { @@ -173,7 +168,6 @@ export const userOperations: INodeProperties[] = [ description: 'Update a user', action: 'Update user', routing: { - send: { preSend: [presendTest] }, request: { method: 'POST', headers: { @@ -395,39 +389,11 @@ const createFields: INodeProperties[] = [ { displayName: 'Temporary Password', name: 'temporaryPasswordOptions', - type: 'options', - default: 'generatePassword', - description: 'Choose to set a password manually or one will be automatically generated', - options: [ - { - name: 'Set a Password', - value: 'setPassword', - }, - { - name: 'Generate a Password', - value: 'generatePassword', - }, - ], - routing: { - send: { - property: 'TemporaryPassword', - type: 'body', - }, - }, - }, - { - displayName: 'Password', - name: 'password', type: 'string', typeOptions: { password: true }, default: '', - placeholder: 'Enter a temporary password', - description: "The user's temporary password", - displayOptions: { - show: { - temporaryPasswordOptions: ['setPassword'], - }, - }, + description: + "The user's temporary password that will be valid only once. If not set, Amazon Cognito will automatically generate one for you.", routing: { send: { property: 'TemporaryPassword', @@ -641,11 +607,11 @@ const getAllFields: INodeProperties[] = [ description: 'Whether to return a simplified version of the response instead of the raw data', }, { - displayName: 'Additional Fields', - name: 'additionalFields', - type: 'collection', - placeholder: 'Add Field', - default: {}, + displayName: 'Filters', + name: 'filters', + type: 'fixedCollection', + placeholder: 'Add Filter', + default: [], displayOptions: { show: { resource: ['user'], @@ -654,43 +620,37 @@ const getAllFields: INodeProperties[] = [ }, options: [ { - displayName: 'Filters', - name: 'filters', - type: 'options', - default: 'username', - hint: 'Make sure to select an attribute, type, and provide a value before submitting.', - description: 'The attribute to search for', - options: [ - { name: 'Cognito User Status', value: 'cognito:user_status' }, - { name: 'Email', value: 'email' }, - { name: 'Family Name', value: 'family_name' }, - { name: 'Given Name', value: 'given_name' }, - { name: 'Name', value: 'name' }, - { name: 'Phone Number', value: 'phone_number' }, - { name: 'Preferred Username', value: 'preferred_username' }, - { name: 'Status (Enabled)', value: 'status' }, - { name: 'Sub', value: 'sub' }, - { name: 'Username', value: 'username' }, + displayName: 'Filter', + name: 'filter', + values: [ + { + displayName: 'Attribute', + name: 'attribute', + type: 'options', + default: 'email', + description: 'The attribute to search for', + options: [ + { name: 'Cognito User Status', value: 'cognito:user_status' }, + { name: 'Email', value: 'email' }, + { name: 'Family Name', value: 'family_name' }, + { name: 'Given Name', value: 'given_name' }, + { name: 'Name', value: 'name' }, + { name: 'Phone Number', value: 'phone_number' }, + { name: 'Preferred Username', value: 'preferred_username' }, + { name: 'Status (Enabled)', value: 'status' }, + { name: 'Sub', value: 'sub' }, + { name: 'Username', value: 'username' }, + ], + }, + { + displayName: 'Value', + name: 'value', + type: 'string', + default: '', + description: 'The value of the attribute to search for', + }, ], }, - { - displayName: 'Filter Type', - name: 'filterType', - type: 'options', - default: 'exactMatch', - description: 'The matching strategy of the filter', - options: [ - { name: 'Exact Match', value: 'exactMatch' }, - { name: 'Starts With', value: 'startsWith' }, - ], - }, - { - displayName: 'Filter Value', - name: 'filterValue', - type: 'string', - default: '', - description: 'The value of the attribute to search for', - }, ], }, ]; diff --git a/packages/nodes-base/nodes/Aws/Cognito/descriptions/UserPoolDescription.ts b/packages/nodes-base/nodes/Aws/Cognito/descriptions/UserPoolDescription.ts index 0576612a0c..fa4ab5888e 100644 --- a/packages/nodes-base/nodes/Aws/Cognito/descriptions/UserPoolDescription.ts +++ b/packages/nodes-base/nodes/Aws/Cognito/descriptions/UserPoolDescription.ts @@ -1,5 +1,6 @@ import type { INodeProperties } from 'n8n-workflow'; -import { presendTest, simplifyData } from '../GenericFunctions'; + +import { simplifyData } from '../GenericFunctions'; export const userPoolOperations: INodeProperties[] = [ { @@ -14,9 +15,6 @@ export const userPoolOperations: INodeProperties[] = [ value: 'get', action: 'Describe the configuration of a user pool', routing: { - send: { - preSend: [presendTest], - }, request: { method: 'POST', headers: {