diff --git a/packages/nodes-base/nodes/Aws/Cognito/GenericFunctions.ts b/packages/nodes-base/nodes/Aws/Cognito/GenericFunctions.ts index 5d70f513b5..b0ae8353fb 100644 --- a/packages/nodes-base/nodes/Aws/Cognito/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Aws/Cognito/GenericFunctions.ts @@ -116,7 +116,7 @@ export async function processAttributes( return requestOptions; } -/* Helper function to process Group Response */ +/* Helper function to process Group/User Response */ export async function processGroupsResponse( this: IExecuteSingleFunctions, items: INodeExecutionData[], @@ -135,8 +135,26 @@ export async function processGroupsResponse( return executionData; } +export async function processUsersResponse( + this: IExecuteSingleFunctions, + items: INodeExecutionData[], + response: IN8nHttpFullResponse, +): Promise { + const responseBody = response.body as { Users: IDataObject[] }; + + if (!responseBody || !Array.isArray(responseBody.Users)) { + throw new ApplicationError('Unexpected response format: No users found.'); + } + + const executionData: INodeExecutionData[] = responseBody.Users.map((user) => ({ + json: user, + })); + + return executionData; +} + /* Helper function to handle pagination */ -const possibleRootProperties = ['Users']; // Root properties that can be returned by the list operations of the API +const possibleRootProperties = ['Attributes']; // ToDo: Test if pagination works export async function handlePagination( this: IExecutePaginationFunctions, @@ -146,6 +164,8 @@ export async function handlePagination( let nextPageToken: string | undefined; const returnAll = this.getNodeParameter('returnAll') as boolean; let limit = 60; + + // Update limit if 'returnAll' is not selected if (!returnAll) { limit = this.getNodeParameter('limit') as number; resultOptions.maxResults = limit; @@ -154,147 +174,229 @@ export async function handlePagination( do { if (nextPageToken) { - // For different responses the pagination token might differ. ToDo: Ensure this code works for all endpoints. + // Append PaginationToken to the request body + const body = + typeof resultOptions.options.body === 'object' && resultOptions.options.body !== null + ? resultOptions.options.body + : {}; resultOptions.options.body = { - ...(resultOptions.options.body as IDataObject), + ...body, PaginationToken: nextPageToken, } as IDataObject; + console.log('Updated request body with PaginationToken:', resultOptions.options.body); } + // Make the request + console.log('Sending request with options:', resultOptions); const responseData = await this.makeRoutingRequest(resultOptions); + // Process response data for (const page of responseData) { + console.log('Processing page:', page.json); + + // Iterate over possible root properties (e.g., "Users") for (const prop of possibleRootProperties) { if (page.json[prop]) { const currentData = page.json[prop] as IDataObject[]; + console.log(`Extracted data from property "${prop}":`, currentData); aggregatedResult.push(...currentData); } } + // Check if the limit has been reached if (!returnAll && aggregatedResult.length >= limit) { + console.log('Limit reached. Returning results.'); return aggregatedResult.slice(0, limit).map((item) => ({ json: item })); } - // For different responses the pagination token might differ. ToDo: Ensure this code works for all endpoints. + // Update the nextPageToken for the next request nextPageToken = page.json.PaginationToken as string | undefined; + console.log('Next Page Token:', nextPageToken); } } while (nextPageToken); + console.log('Final Aggregated Results:', aggregatedResult); return aggregatedResult.map((item) => ({ json: item })); } /* Helper functions to handle errors */ - -// ToDo: Handle errors when something is not found. Answer the questions "what happened?" and "how to fix it?". export async function handleErrorPostReceive( this: IExecuteSingleFunctions, data: INodeExecutionData[], response: IN8nHttpFullResponse, ): Promise { if (String(response.statusCode).startsWith('4') || String(response.statusCode).startsWith('5')) { - const { resource, operation } = this.getNode().parameters as { - resource: string; - operation: string; - }; - const { - code: errorCode, - message: errorMessage, - details: errorDetails, - } = (response.body as IDataObject)?.error as { - code: string; - message: string; - innerError?: { - code: string; - 'request-id'?: string; - date?: string; - }; - details?: Array<{ - code: string; - message: string; - }>; - }; + const resource = this.getNodeParameter('resource') as string; + const operation = this.getNodeParameter('operation') as string; + const responseBody = response.body as IDataObject; + const errorType = responseBody.__type ?? response.headers?.['x-amzn-errortype']; + const errorMessage = responseBody.message ?? response.headers?.['x-amzn-errormessage']; - if (errorCode === 'Request_BadRequest' && errorMessage === 'Invalid object identifier') { + // Resource/Operation specific errors + if (resource === 'group') { + if (operation === 'delete') { + if (errorType === 'ResourceNotFoundException' || errorType === 'NoSuchEntity') { + throw new NodeApiError(this.getNode(), response as unknown as JsonObject, { + message: "The required group doesn't match any existing one", + description: "Double-check the value in the parameter 'Group' and try again", + }); + } + } else if (operation === 'get') { + if (errorType === 'ResourceNotFoundException' || errorType === 'NoSuchEntity') { + throw new NodeApiError(this.getNode(), response as unknown as JsonObject, { + message: "The required group doesn't match any existing one", + description: "Double-check the value in the parameter 'Group' and try again", + }); + } + } else if (operation === 'update') { + if (errorType === 'ResourceNotFoundException' || errorType === 'NoSuchEntity') { + throw new NodeApiError(this.getNode(), response as unknown as JsonObject, { + message: "The required group doesn't match any existing one", + description: "Double-check the value in the parameter 'Group' and try again", + }); + } + } else if (operation === 'create') { + if (errorType === 'EntityAlreadyExists' || errorType === 'GroupExistsException') { + throw new NodeApiError(this.getNode(), response as unknown as JsonObject, { + message: 'The group is already created', + description: "Double-check the value in the parameter 'Group Name' and try again", + }); + } + } + } else if (resource === 'user') { + if (operation === 'create') { + if ( + errorType === 'UsernameExistsException' && + errorMessage === 'User account already exists' + ) { + throw new NodeApiError(this.getNode(), response as unknown as JsonObject, { + message: 'The user is already created', + description: "Double-check the value in the parameter 'User Name' and try again", + }); + } + } else if (operation === 'addToGroup') { + // Group or user doesn't exist + if (errorType === 'UserNotFoundException') { + const user = this.getNodeParameter('user.value', '') as string; + + if (typeof errorMessage === 'string' && errorMessage.includes(user)) { + throw new NodeApiError(this.getNode(), response as unknown as JsonObject, { + message: "The required user doesn't match any existing one", + description: "Double-check the value in the parameter 'User' and try again.", + }); + } + } else if (errorType === 'ResourceNotFoundException') { + const group = this.getNodeParameter('group.value', '') as string; + + if (typeof errorMessage === 'string' && errorMessage.includes(group)) { + throw new NodeApiError(this.getNode(), response as unknown as JsonObject, { + message: "The required group doesn't match any existing one", + description: "Double-check the value in the parameter 'Group' and try again.", + }); + } + } + } else if (operation === 'delete') { + if (errorType === 'UserNotFoundException') { + throw new NodeApiError(this.getNode(), response as unknown as JsonObject, { + message: "The required user doesn't match any existing one", + description: "Double-check the value in the parameter 'User' and try again", + }); + } + } else if (operation === 'get') { + if (errorType === 'UserNotFoundException') { + throw new NodeApiError(this.getNode(), response as unknown as JsonObject, { + message: "The required user doesn't match any existing one", + description: "Double-check the value in the parameter 'User' and try again", + }); + } + } else if (operation === 'removeFromGroup') { + // Group or user doesn't exist + if (errorType === 'UserNotFoundException') { + const user = this.getNodeParameter('user.value', '') as string; + + if (typeof errorMessage === 'string' && errorMessage.includes(user)) { + throw new NodeApiError(this.getNode(), response as unknown as JsonObject, { + message: "The required user doesn't match any existing one", + description: "Double-check the value in the parameter 'User' and try again.", + }); + } + } else if (errorType === 'ResourceNotFoundException') { + const group = this.getNodeParameter('group.value', '') as string; + + if (typeof errorMessage === 'string' && errorMessage.includes(group)) { + throw new NodeApiError(this.getNode(), response as unknown as JsonObject, { + message: "The required group doesn't match any existing one", + description: "Double-check the value in the parameter 'Group' and try again.", + }); + } + } + } else if (operation === 'update') { + if (errorType === 'UserNotFoundException') { + throw new NodeApiError(this.getNode(), response as unknown as JsonObject, { + message: "The required user doesn't match any existing one", + description: "Double-check the value in the parameter 'User' and try again", + }); + } + } + } + + // Generic Error Handling + if (errorType === 'InvalidParameterException') { const group = this.getNodeParameter('group.value', '') as string; const parameterResource = - resource === 'group' || errorMessage.includes(group) ? 'group' : 'user'; + resource === 'group' || (typeof errorMessage === 'string' && errorMessage.includes(group)) + ? 'group' + : 'user'; throw new NodeApiError(this.getNode(), response as unknown as JsonObject, { message: `The ${parameterResource} ID is invalid`, description: 'The ID should be in the format e.g. 02bd9fd6-8f93-4758-87c3-1fb73740a315', }); } - if (errorCode === 'Request_ResourceNotFound') { - const group = this.getNodeParameter('group.value', '') as string; - const parameterResource = - resource === 'group' || errorMessage.includes(group) ? 'group' : 'user'; - let parameterDisplayName = undefined; - if (parameterResource === 'group' && operation === 'delete') { - parameterDisplayName = 'Group to Delete'; - } else if (parameterResource === 'group' && operation === 'get') { - parameterDisplayName = 'Group to Get'; - } else if (parameterResource === 'group' && operation === 'update') { - parameterDisplayName = 'Group to Update'; - } else if (parameterResource === 'user' && operation === 'delete') { - parameterDisplayName = 'User to Delete'; - } else if (parameterResource === 'user' && operation === 'get') { - parameterDisplayName = 'User to Get'; - } else if (parameterResource === 'user' && operation === 'update') { - parameterDisplayName = 'User to Update'; - } else if (parameterResource === 'group' && operation === 'addGroup') { - parameterDisplayName = 'Group'; - } else if (parameterResource === 'user' && operation === 'addGroup') { - parameterDisplayName = 'User to Add'; - } else if (parameterResource === 'group' && operation === 'removeGroup') { - parameterDisplayName = 'Group'; - } else if (parameterResource === 'user' && operation === 'removeGroup') { - parameterDisplayName = 'User to Remove'; - } - if (parameterDisplayName) { - throw new NodeApiError(this.getNode(), response as unknown as JsonObject, { - message: `The required ${parameterResource} doesn't match any existing one`, - description: `Double-check the value in the parameter '${parameterDisplayName}' and try again`, - }); - } - } - if (errorDetails?.some((x) => x.code === 'ObjectConflict' || x.code === 'ConflictingObjects')) { + if (errorType === 'InternalErrorException') { throw new NodeApiError(this.getNode(), response as unknown as JsonObject, { - message: `The ${resource} already exists`, - description: errorMessage, + message: 'Internal Server Error', + description: 'Amazon Cognito encountered an internal error. Try again later.', }); } + if (errorType === 'TooManyRequestsException') { + throw new NodeApiError(this.getNode(), response as unknown as JsonObject, { + message: 'Too Many Requests', + description: 'You have exceeded the allowed number of requests. Try again later.', + }); + } + + if (errorType === 'NotAuthorizedException') { + throw new NodeApiError(this.getNode(), response as unknown as JsonObject, { + message: 'Unauthorized Access', + description: + 'You are not authorized to perform this operation. Check your permissions and try again.', + }); + } + + if (errorType === 'ServiceFailure') { + throw new NodeApiError(this.getNode(), response as unknown as JsonObject, { + message: 'Service Failure', + description: + 'The request processing has failed because of an unknown error, exception, or failure. Try again later.', + }); + } + + if (errorType === 'LimitExceeded') { + throw new NodeApiError(this.getNode(), response as unknown as JsonObject, { + message: 'Limit Exceeded', + description: + 'The request was rejected because it attempted to create resources beyond the current AWS account limits. Check your AWS limits and try again.', + }); + } throw new NodeApiError(this.getNode(), response as unknown as JsonObject); } return data; } -export async function handleErrorsDeleteUser( - this: IExecuteSingleFunctions, - data: INodeExecutionData[], - response: IN8nHttpFullResponse, -): Promise { - if (response.statusCode < 200 || response.statusCode >= 300) { - const post = this.getNodeParameter('user', undefined) as IDataObject; - - // Provide a user-friendly error message - if (post && response.statusCode === 404) { - throw new NodeOperationError( - this.getNode(), - 'The user you are deleting could not be found. Adjust the "user" parameter setting to delete the post correctly.', - ); - } - - throw new NodeApiError(this.getNode(), response.body as JsonObject, { - message: response.statusMessage, - httpCode: response.statusCode.toString(), - }); - } - return data; -} - /* Helper function used in listSearch methods */ export async function awsRequest( this: ILoadOptionsFunctions | IPollFunctions, diff --git a/packages/nodes-base/nodes/Aws/Cognito/descriptions/GroupDescription.ts b/packages/nodes-base/nodes/Aws/Cognito/descriptions/GroupDescription.ts index efdd57fd46..e504654645 100644 --- a/packages/nodes-base/nodes/Aws/Cognito/descriptions/GroupDescription.ts +++ b/packages/nodes-base/nodes/Aws/Cognito/descriptions/GroupDescription.ts @@ -26,12 +26,7 @@ export const groupOperations: INodeProperties[] = [ headers: { 'X-Amz-Target': 'AWSCognitoIdentityProviderService.CreateGroup', }, - // preSend: [ - // async function (this: IExecuteSingleFunctions, requestOptions: IHttpRequestOptions) { - // // Call the function you created in GenericFunctions - // return await getUserIdForGroup.call(this, requestOptions); - // }, - // ], + ignoreHttpStatusErrors: true, }, output: { postReceive: [handleErrorPostReceive], @@ -49,6 +44,7 @@ export const groupOperations: INodeProperties[] = [ headers: { 'X-Amz-Target': 'AWSCognitoIdentityProviderService.DeleteGroup', }, + ignoreHttpStatusErrors: true, }, output: { postReceive: [ @@ -74,6 +70,7 @@ export const groupOperations: INodeProperties[] = [ headers: { 'X-Amz-Target': 'AWSCognitoIdentityProviderService.GetGroup', }, + ignoreHttpStatusErrors: true, }, output: { postReceive: [handleErrorPostReceive], @@ -98,6 +95,7 @@ export const groupOperations: INodeProperties[] = [ pageSize: '={{ $parameter["limit"] ? ($parameter["limit"] < 60 ? $parameter["limit"] : 60) : 60 }}', // The API allows maximum 60 results per page }, + ignoreHttpStatusErrors: true, }, output: { postReceive: [handleErrorPostReceive, processGroupsResponse], @@ -115,6 +113,7 @@ export const groupOperations: INodeProperties[] = [ headers: { 'X-Amz-Target': 'AWSCognitoIdentityProviderService.UpdateGroup', }, + ignoreHttpStatusErrors: true, }, output: { postReceive: [ @@ -186,7 +185,7 @@ const createFields: INodeProperties[] = [ ], }, { - displayName: 'Name', + displayName: 'Group Name', name: 'GroupName', default: '', placeholder: 'e.g. My New Group', diff --git a/packages/nodes-base/nodes/Aws/Cognito/descriptions/UserDescription.ts b/packages/nodes-base/nodes/Aws/Cognito/descriptions/UserDescription.ts index b7e4404357..3b9dc7b063 100644 --- a/packages/nodes-base/nodes/Aws/Cognito/descriptions/UserDescription.ts +++ b/packages/nodes-base/nodes/Aws/Cognito/descriptions/UserDescription.ts @@ -2,9 +2,10 @@ import type { INodeProperties } from 'n8n-workflow'; import { handleErrorPostReceive, + handlePagination, presendFilter, - presendTest, processAttributes, + processUsersResponse, } from '../GenericFunctions'; export const userOperations: INodeProperties[] = [ @@ -31,6 +32,7 @@ export const userOperations: INodeProperties[] = [ headers: { 'X-Amz-Target': 'AWSCognitoIdentityProviderService.AdminAddUserToGroup', }, + ignoreHttpStatusErrors: true, }, output: { postReceive: [handleErrorPostReceive], @@ -48,6 +50,7 @@ export const userOperations: INodeProperties[] = [ headers: { 'X-Amz-Target': 'AWSCognitoIdentityProviderService.AdminCreateUser', }, + ignoreHttpStatusErrors: true, }, output: { postReceive: [handleErrorPostReceive], @@ -65,9 +68,18 @@ export const userOperations: INodeProperties[] = [ headers: { 'X-Amz-Target': 'AWSCognitoIdentityProviderService.AdminDeleteUser', }, + ignoreHttpStatusErrors: true, }, output: { - postReceive: [handleErrorPostReceive], + postReceive: [ + handleErrorPostReceive, + { + type: 'set', + properties: { + value: '={{ { "deleted": true } }}', + }, + }, + ], }, }, }, @@ -82,6 +94,7 @@ export const userOperations: INodeProperties[] = [ headers: { 'X-Amz-Target': 'AWSCognitoIdentityProviderService.AdminGetUser', }, + ignoreHttpStatusErrors: true, }, output: { postReceive: [handleErrorPostReceive], @@ -91,13 +104,11 @@ export const userOperations: INodeProperties[] = [ { name: 'Get Many', value: 'getAll', - action: 'Get many users', + description: 'Retrieve a list of users', routing: { send: { paginate: true, }, - // ToDo: Test with pagination (ideally we need 4+ users in the user pool) - // operations: { pagination: handlePagination }, // Responsible for pagination and number of results returned request: { method: 'POST', headers: { @@ -107,11 +118,13 @@ export const userOperations: INodeProperties[] = [ pageSize: '={{ $parameter["limit"] ? ($parameter["limit"] < 60 ? $parameter["limit"] : 60) : 60 }}', // The API allows maximum 60 results per page }, + ignoreHttpStatusErrors: true, }, output: { - postReceive: [handleErrorPostReceive], + postReceive: [handleErrorPostReceive, processUsersResponse], }, }, + action: 'Get many users', }, { name: 'Remove From Group', @@ -124,6 +137,7 @@ export const userOperations: INodeProperties[] = [ headers: { 'X-Amz-Target': 'AWSCognitoIdentityProviderService.AdminRemoveUserFromGroup', }, + ignoreHttpStatusErrors: true, }, output: { postReceive: [handleErrorPostReceive], @@ -141,9 +155,18 @@ export const userOperations: INodeProperties[] = [ headers: { 'X-Amz-Target': 'AWSCognitoIdentityProviderService.AdminUpdateUserAttributes', }, + ignoreHttpStatusErrors: true, }, output: { - postReceive: [handleErrorPostReceive], + postReceive: [ + handleErrorPostReceive, + { + type: 'set', + properties: { + value: '={{ { "updated": true } }}', + }, + }, + ], }, }, }, @@ -176,7 +199,7 @@ const createFields: INodeProperties[] = [ }, modes: [ { - displayName: 'From list', // ToDo: Fix error when selecting this option + displayName: 'From list', name: 'list', type: 'list', typeOptions: { @@ -194,8 +217,8 @@ const createFields: INodeProperties[] = [ { type: 'regex', properties: { - regex: '^[\\w-]+_[0-9a-zA-Z]+$', - errorMessage: 'The ID must follow the pattern "xxxxxx_xxxxxxxxxxx"', + regex: '^[a-zA-Z0-9-]+_[0-9a-zA-Z]+$', + errorMessage: 'The ID must follow the pattern "xx-xx-xx_xxxxxx"', }, }, ], @@ -219,7 +242,6 @@ const createFields: INodeProperties[] = [ send: { property: 'Username', type: 'body', - preSend: [presendTest], }, }, type: 'string', @@ -288,7 +310,6 @@ const createFields: INodeProperties[] = [ send: { property: 'TemporaryPassword', type: 'body', - preSend: [presendTest], }, }, type: 'string', @@ -315,7 +336,6 @@ const createFields: INodeProperties[] = [ send: { property: 'MessageAction', type: 'body', - preSend: [presendTest], }, }, }, @@ -355,7 +375,6 @@ const createFields: INodeProperties[] = [ send: { property: 'DesiredDeliveryMediums', type: 'body', - preSend: [presendTest], }, }, }, @@ -470,12 +489,11 @@ const getFields: INodeProperties[] = [ send: { type: 'body', property: 'UserPoolId', - preSend: [presendTest], }, }, modes: [ { - displayName: 'From list', // ToDo: Fix error when selecting this option + displayName: 'From list', name: 'list', type: 'list', typeOptions: { @@ -492,8 +510,8 @@ const getFields: INodeProperties[] = [ { type: 'regex', properties: { - regex: '^[\\w-]+_[0-9a-zA-Z]+$', - errorMessage: 'The ID must follow the pattern "xxxxxx_xxxxxxxxxxx"', + regex: '^[a-zA-Z0-9-]+_[0-9a-zA-Z]+$', + errorMessage: 'The ID must follow the pattern "xx-xx-xx_xxxxxx"', }, }, ], @@ -502,7 +520,7 @@ const getFields: INodeProperties[] = [ ], }, { - displayName: 'User Name', + displayName: 'User', name: 'Username', default: { mode: 'list', @@ -535,8 +553,8 @@ const getFields: INodeProperties[] = [ { type: 'regex', properties: { - regex: '^[\\w-]+_[0-9a-zA-Z]+$', - errorMessage: 'The ID must follow the pattern "xxxxxx_xxxxxxxxxxx"', + regex: '^[\\w-]+-[0-9a-zA-Z]+$', + errorMessage: 'The ID must follow the pattern "xxxxxx-xxxxxxxxxxx"', }, }, ], @@ -546,7 +564,6 @@ const getFields: INodeProperties[] = [ send: { type: 'body', property: 'Username', - preSend: [presendTest], }, }, required: true, @@ -564,7 +581,7 @@ const getAllFields: INodeProperties[] = [ mode: 'list', value: '', }, - description: 'The user pool ID that the users are in', // ToDo: Improve description + description: 'The user pool ID where the users are managed', displayOptions: { show: { resource: ['user'], @@ -579,7 +596,7 @@ const getAllFields: INodeProperties[] = [ }, modes: [ { - displayName: 'From list', // ToDo: Fix error when selecting this option + displayName: 'From list', name: 'list', type: 'list', typeOptions: { @@ -597,8 +614,8 @@ const getAllFields: INodeProperties[] = [ { type: 'regex', properties: { - regex: '^[\\w-]+_[0-9a-zA-Z]+$', - errorMessage: 'The ID must follow the pattern "xxxxxx_xxxxxxxxxxx"', + regex: '^[a-zA-Z0-9-]+_[0-9a-zA-Z]+$', + errorMessage: 'The ID must follow the pattern "xx-xx-xx_xxxxxx"', }, }, ], @@ -621,21 +638,7 @@ const getAllFields: INodeProperties[] = [ paginate: '={{ $value }}', }, operations: { - pagination: { - type: 'generic', - properties: { - continue: '={{ !!$response.body?.["@odata.nextLink"] }}', - request: { - url: '={{ $response.body?.["@odata.nextLink"] ?? $request.url }}', - qs: { - $filter: - '={{ !!$response.body?.["@odata.nextLink"] ? undefined : $request.qs?.$filter }}', - $select: - '={{ !!$response.body?.["@odata.nextLink"] ? undefined : $request.qs?.$select }}', - }, - }, - }, - }, + pagination: handlePagination, }, }, type: 'boolean', @@ -654,8 +657,8 @@ const getAllFields: INodeProperties[] = [ }, routing: { send: { - property: '$top', - type: 'query', + property: 'limit', + type: 'body', value: '={{ $value }}', }, }, @@ -775,12 +778,11 @@ const deleteFields: INodeProperties[] = [ send: { type: 'body', property: 'UserPoolId', - preSend: [presendTest], }, }, modes: [ { - displayName: 'From list', // ToDo: Fix error when selecting this option + displayName: 'From list', name: 'list', type: 'list', typeOptions: { @@ -797,8 +799,8 @@ const deleteFields: INodeProperties[] = [ { type: 'regex', properties: { - regex: '^[\\w-]+_[0-9a-zA-Z]+$', - errorMessage: 'The ID must follow the pattern "xxxxxx_xxxxxxxxxxx"', + regex: '^[a-zA-Z0-9-]+_[0-9a-zA-Z]+$', + errorMessage: 'The ID must follow the pattern "xx-xx-xx_xxxxxx"', }, }, ], @@ -807,7 +809,7 @@ const deleteFields: INodeProperties[] = [ ], }, { - displayName: 'User Name', + displayName: 'User', name: 'Username', default: { mode: 'list', @@ -840,8 +842,8 @@ const deleteFields: INodeProperties[] = [ { type: 'regex', properties: { - regex: '^[\\w-]+_[0-9a-zA-Z]+$', - errorMessage: 'The ID must follow the pattern "xxxxxx_xxxxxxxxxxx"', + regex: '^[\\w-]+-[0-9a-zA-Z]+$', + errorMessage: 'The ID must follow the pattern "xxxxxx-xxxxxxxxxxx"', }, }, ], @@ -851,7 +853,6 @@ const deleteFields: INodeProperties[] = [ send: { type: 'body', property: 'Username', - preSend: [presendTest], }, }, required: true, @@ -880,12 +881,11 @@ const updateFields: INodeProperties[] = [ send: { type: 'body', property: 'UserPoolId', - preSend: [presendTest], }, }, modes: [ { - displayName: 'From list', // ToDo: Fix error when selecting this option + displayName: 'From list', name: 'list', type: 'list', typeOptions: { @@ -902,8 +902,8 @@ const updateFields: INodeProperties[] = [ { type: 'regex', properties: { - regex: '^[\\w-]+_[0-9a-zA-Z]+$', - errorMessage: 'The ID must follow the pattern "xxxxxx_xxxxxxxxxxx"', + regex: '^[a-zA-Z0-9-]+_[0-9a-zA-Z]+$', + errorMessage: 'The ID must follow the pattern "xx-xx-xx_xxxxxx"', }, }, ], @@ -912,7 +912,7 @@ const updateFields: INodeProperties[] = [ ], }, { - displayName: 'User Name', + displayName: 'User', name: 'Username', default: { mode: 'list', @@ -945,8 +945,8 @@ const updateFields: INodeProperties[] = [ { type: 'regex', properties: { - regex: '^[\\w-]+_[0-9a-zA-Z]+$', - errorMessage: 'The ID must follow the pattern "xxxxxx_xxxxxxxxxxx"', + regex: '^[\\w-]+-[0-9a-zA-Z]+$', + errorMessage: 'The ID must follow the pattern "xxxxxx-xxxxxxxxxxx"', }, }, ], @@ -956,7 +956,6 @@ const updateFields: INodeProperties[] = [ send: { type: 'body', property: 'Username', - preSend: [presendTest], }, }, required: true, @@ -1095,7 +1094,7 @@ const addToGroupFields: INodeProperties[] = [ }, modes: [ { - displayName: 'From list', // ToDo: Fix error when selecting this option + displayName: 'From list', name: 'list', type: 'list', typeOptions: { @@ -1112,8 +1111,8 @@ const addToGroupFields: INodeProperties[] = [ { type: 'regex', properties: { - regex: '^[\\w-]+_[0-9a-zA-Z]+$', - errorMessage: 'The ID must follow the pattern "xxxxxx_xxxxxxxxxxx"', + regex: '^[a-zA-Z0-9-]+_[0-9a-zA-Z]+$', + errorMessage: 'The ID must follow the pattern "xx-xx-xx_xxxxxx"', }, }, ], @@ -1122,7 +1121,7 @@ const addToGroupFields: INodeProperties[] = [ ], }, { - displayName: 'User Name', + displayName: 'User', name: 'Username', default: { mode: 'list', @@ -1155,8 +1154,8 @@ const addToGroupFields: INodeProperties[] = [ { type: 'regex', properties: { - regex: '^[\\w-]+_[0-9a-zA-Z]+$', - errorMessage: 'The ID must follow the pattern "xxxxxx_xxxxxxxxxxx"', + regex: '^[\\w-]+-[0-9a-zA-Z]+$', + errorMessage: 'The ID must follow the pattern "xxxxxx-xxxxxxxxxxx"', }, }, ], @@ -1172,7 +1171,7 @@ const addToGroupFields: INodeProperties[] = [ type: 'resourceLocator', }, { - displayName: 'Group Name', + displayName: 'Group', name: 'GroupName', default: { mode: 'list', @@ -1215,7 +1214,6 @@ const addToGroupFields: INodeProperties[] = [ required: true, routing: { send: { - preSend: [presendTest], // ToDo: Remove this line before completing the pull request type: 'body', property: 'GroupName', }, @@ -1249,7 +1247,7 @@ const removeFromGroupFields: INodeProperties[] = [ }, modes: [ { - displayName: 'From list', // ToDo: Fix error when selecting this option + displayName: 'From list', name: 'list', type: 'list', typeOptions: { @@ -1266,8 +1264,8 @@ const removeFromGroupFields: INodeProperties[] = [ { type: 'regex', properties: { - regex: '^[\\w-]+_[0-9a-zA-Z]+$', - errorMessage: 'The ID must follow the pattern "xxxxxx_xxxxxxxxxxx"', + regex: '^[a-zA-Z0-9-]+_[0-9a-zA-Z]+$', + errorMessage: 'The ID must follow the pattern "xx-xx-xx_xxxxxx"', }, }, ], @@ -1276,7 +1274,7 @@ const removeFromGroupFields: INodeProperties[] = [ ], }, { - displayName: 'User Name', + displayName: 'User', name: 'Username', default: { mode: 'list', @@ -1309,8 +1307,8 @@ const removeFromGroupFields: INodeProperties[] = [ { type: 'regex', properties: { - regex: '^[\\w-]+_[0-9a-zA-Z]+$', - errorMessage: 'The ID must follow the pattern "xxxxxx_xxxxxxxxxxx"', + regex: '^[\\w-]+-[0-9a-zA-Z]+$', + errorMessage: 'The ID must follow the pattern "xxxxxx-xxxxxxxxxxx"', }, }, ], @@ -1318,7 +1316,6 @@ const removeFromGroupFields: INodeProperties[] = [ ], routing: { send: { - preSend: [presendTest], // ToDo: Remove this line before completing the pull request type: 'body', property: 'Username', }, @@ -1327,7 +1324,7 @@ const removeFromGroupFields: INodeProperties[] = [ type: 'resourceLocator', }, { - displayName: 'Group Name', + displayName: 'Group', name: 'GroupName', default: { mode: 'list', @@ -1370,7 +1367,6 @@ const removeFromGroupFields: INodeProperties[] = [ required: true, routing: { send: { - preSend: [presendTest], // ToDo: Remove this line before completing the pull request type: 'body', property: 'GroupName', },