mirror of
https://github.com/n8n-io/n8n.git
synced 2025-03-05 20:50:17 -08:00
Changes after feedback
This commit is contained in:
parent
477bbbc7d8
commit
3615cd9021
|
@ -14,16 +14,6 @@ import type {
|
||||||
} from 'n8n-workflow';
|
} from 'n8n-workflow';
|
||||||
import { ApplicationError, jsonParse, NodeApiError, NodeOperationError } from 'n8n-workflow';
|
import { ApplicationError, jsonParse, NodeApiError, NodeOperationError } from 'n8n-workflow';
|
||||||
|
|
||||||
/* Function which helps while developing the node */
|
|
||||||
// ToDo: Remove before completing the pull request
|
|
||||||
export async function presendTest(
|
|
||||||
this: IExecuteSingleFunctions,
|
|
||||||
requestOptions: IHttpRequestOptions,
|
|
||||||
): Promise<IHttpRequestOptions> {
|
|
||||||
console.log('requestOptions', requestOptions);
|
|
||||||
return requestOptions;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Helper function which stringifies the body before sending the request.
|
* Helper function which stringifies the body before sending the request.
|
||||||
* It is added to the routing property in the "resource" parameter thus for all requests.
|
* It is added to the routing property in the "resource" parameter thus for all requests.
|
||||||
|
@ -47,15 +37,21 @@ export async function presendFilter(
|
||||||
let filterType = additionalFields.filterType as string;
|
let filterType = additionalFields.filterType as string;
|
||||||
const filterValue = additionalFields.filterValue as string;
|
const filterValue = additionalFields.filterValue as string;
|
||||||
|
|
||||||
if (filterAttribute && filterType && filterValue) {
|
console.log('Attribute', filterAttribute, 'Type', filterType, 'Value', filterValue);
|
||||||
// Convert the filterType to the format the API expects
|
|
||||||
|
if (!filterAttribute || !filterType || !filterValue) {
|
||||||
|
throw new NodeOperationError(
|
||||||
|
this.getNode(),
|
||||||
|
'Please provide Filter Attribute, Filter Type, and Filter Value to use filtering.',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
const filterTypeMapping: { [key: string]: string } = {
|
const filterTypeMapping: { [key: string]: string } = {
|
||||||
exactMatch: '=',
|
exactMatch: '=',
|
||||||
startsWith: '^=',
|
startsWith: '^=',
|
||||||
};
|
};
|
||||||
filterType = filterTypeMapping[filterType] || filterType;
|
filterType = filterTypeMapping[filterType] || filterType;
|
||||||
|
|
||||||
// Parse the body if it's a string to add the new property
|
|
||||||
let body: IDataObject;
|
let body: IDataObject;
|
||||||
if (typeof requestOptions.body === 'string') {
|
if (typeof requestOptions.body === 'string') {
|
||||||
try {
|
try {
|
||||||
|
@ -71,7 +67,43 @@ export async function presendFilter(
|
||||||
...body,
|
...body,
|
||||||
Filter: `${filterAttribute} ${filterType} "${filterValue}"`,
|
Filter: `${filterAttribute} ${filterType} "${filterValue}"`,
|
||||||
});
|
});
|
||||||
} else {
|
|
||||||
|
return requestOptions;
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function presendOptions(
|
||||||
|
this: IExecuteSingleFunctions,
|
||||||
|
requestOptions: IHttpRequestOptions,
|
||||||
|
): Promise<IHttpRequestOptions> {
|
||||||
|
const options = this.getNodeParameter('options', {}) as IDataObject;
|
||||||
|
|
||||||
|
const hasOptions = options.Description || options.Precedence || options.Path || options.RoleArn;
|
||||||
|
|
||||||
|
if (!hasOptions) {
|
||||||
|
throw new NodeOperationError(
|
||||||
|
this.getNode(),
|
||||||
|
'At least one of the options (Description, Precedence, Path, or RoleArn) must be provided to update the group.',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return requestOptions;
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function presendPath(
|
||||||
|
this: IExecuteSingleFunctions,
|
||||||
|
requestOptions: IHttpRequestOptions,
|
||||||
|
): Promise<IHttpRequestOptions> {
|
||||||
|
const path = this.getNodeParameter('path', '/') as string;
|
||||||
|
|
||||||
|
if (path.length < 1 || path.length > 512) {
|
||||||
|
throw new NodeOperationError(this.getNode(), 'Path must be between 1 and 512 characters.');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!/^\/$|^\/[\u0021-\u007E]+\/$/.test(path)) {
|
||||||
|
throw new NodeOperationError(
|
||||||
|
this.getNode(),
|
||||||
|
'Path must begin and end with a forward slash and contain valid ASCII characters.',
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return requestOptions;
|
return requestOptions;
|
||||||
|
@ -176,34 +208,33 @@ export async function handleErrorPostReceive(
|
||||||
const errorType = responseBody.__type ?? response.headers?.['x-amzn-errortype'];
|
const errorType = responseBody.__type ?? response.headers?.['x-amzn-errortype'];
|
||||||
const errorMessage = responseBody.message ?? response.headers?.['x-amzn-errormessage'];
|
const errorMessage = responseBody.message ?? response.headers?.['x-amzn-errormessage'];
|
||||||
|
|
||||||
// Resource/Operation specific errors
|
|
||||||
if (resource === 'group') {
|
if (resource === 'group') {
|
||||||
if (operation === 'delete') {
|
if (operation === 'delete') {
|
||||||
if (errorType === 'ResourceNotFoundException' || errorType === 'NoSuchEntity') {
|
if (errorType === 'ResourceNotFoundException' || errorType === 'NoSuchEntity') {
|
||||||
throw new NodeApiError(this.getNode(), response as unknown as JsonObject, {
|
throw new NodeApiError(this.getNode(), response as unknown as JsonObject, {
|
||||||
message: "The required group doesn't match any existing one",
|
message: 'The group you are deleting could not be found.',
|
||||||
description: "Double-check the value in the parameter 'Group' and try again",
|
description: 'Adjust the "Group" parameter setting to delete the group correctly.',
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
} else if (operation === 'get') {
|
} else if (operation === 'get') {
|
||||||
if (errorType === 'ResourceNotFoundException' || errorType === 'NoSuchEntity') {
|
if (errorType === 'ResourceNotFoundException' || errorType === 'NoSuchEntity') {
|
||||||
throw new NodeApiError(this.getNode(), response as unknown as JsonObject, {
|
throw new NodeApiError(this.getNode(), response as unknown as JsonObject, {
|
||||||
message: "The required group doesn't match any existing one",
|
message: 'The group you are requesting could not be found.',
|
||||||
description: "Double-check the value in the parameter 'Group' and try again",
|
description: 'Adjust the "Group" parameter setting to retrieve the group correctly.',
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
} else if (operation === 'update') {
|
} else if (operation === 'update') {
|
||||||
if (errorType === 'ResourceNotFoundException' || errorType === 'NoSuchEntity') {
|
if (errorType === 'ResourceNotFoundException' || errorType === 'NoSuchEntity') {
|
||||||
throw new NodeApiError(this.getNode(), response as unknown as JsonObject, {
|
throw new NodeApiError(this.getNode(), response as unknown as JsonObject, {
|
||||||
message: "The required group doesn't match any existing one",
|
message: 'The group you are updating could not be found.',
|
||||||
description: "Double-check the value in the parameter 'Group' and try again",
|
description: 'Adjust the "Group" parameter setting to update the group correctly.',
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
} else if (operation === 'create') {
|
} else if (operation === 'create') {
|
||||||
if (errorType === 'EntityAlreadyExists' || errorType === 'GroupExistsException') {
|
if (errorType === 'EntityAlreadyExists' || errorType === 'GroupExistsException') {
|
||||||
throw new NodeApiError(this.getNode(), response as unknown as JsonObject, {
|
throw new NodeApiError(this.getNode(), response as unknown as JsonObject, {
|
||||||
message: 'The group is already created',
|
message: 'The group you are trying to create already exists',
|
||||||
description: "Double-check the value in the parameter 'Group Name' and try again",
|
description: 'Adjust the "Group Name" parameter setting to create the group correctly.',
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -214,19 +245,18 @@ export async function handleErrorPostReceive(
|
||||||
errorMessage === 'User account already exists'
|
errorMessage === 'User account already exists'
|
||||||
) {
|
) {
|
||||||
throw new NodeApiError(this.getNode(), response as unknown as JsonObject, {
|
throw new NodeApiError(this.getNode(), response as unknown as JsonObject, {
|
||||||
message: 'The user is already created',
|
message: 'The user you are trying to create already exists',
|
||||||
description: "Double-check the value in the parameter 'User Name' and try again",
|
description: 'Adjust the "User Name" parameter setting to create the user correctly.',
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
} else if (operation === 'addToGroup') {
|
} else if (operation === 'addToGroup') {
|
||||||
// Group or user doesn't exist
|
|
||||||
if (errorType === 'UserNotFoundException') {
|
if (errorType === 'UserNotFoundException') {
|
||||||
const user = this.getNodeParameter('user.value', '') as string;
|
const user = this.getNodeParameter('user.value', '') as string;
|
||||||
|
|
||||||
if (typeof errorMessage === 'string' && errorMessage.includes(user)) {
|
if (typeof errorMessage === 'string' && errorMessage.includes(user)) {
|
||||||
throw new NodeApiError(this.getNode(), response as unknown as JsonObject, {
|
throw new NodeApiError(this.getNode(), response as unknown as JsonObject, {
|
||||||
message: "The required user doesn't match any existing one",
|
message: 'The user you are requesting could not be found.',
|
||||||
description: "Double-check the value in the parameter 'User' and try again.",
|
description: 'Adjust the "User" parameter setting to retrieve the post correctly.',
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
} else if (errorType === 'ResourceNotFoundException') {
|
} else if (errorType === 'ResourceNotFoundException') {
|
||||||
|
@ -234,34 +264,33 @@ export async function handleErrorPostReceive(
|
||||||
|
|
||||||
if (typeof errorMessage === 'string' && errorMessage.includes(group)) {
|
if (typeof errorMessage === 'string' && errorMessage.includes(group)) {
|
||||||
throw new NodeApiError(this.getNode(), response as unknown as JsonObject, {
|
throw new NodeApiError(this.getNode(), response as unknown as JsonObject, {
|
||||||
message: "The required group doesn't match any existing one",
|
message: 'The group you are requesting could not be found.',
|
||||||
description: "Double-check the value in the parameter 'Group' and try again.",
|
description: 'Adjust the "Group" parameter setting to retrieve the post correctly.',
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (operation === 'delete') {
|
} else if (operation === 'delete') {
|
||||||
if (errorType === 'UserNotFoundException') {
|
if (errorType === 'UserNotFoundException') {
|
||||||
throw new NodeApiError(this.getNode(), response as unknown as JsonObject, {
|
throw new NodeApiError(this.getNode(), response as unknown as JsonObject, {
|
||||||
message: "The required user doesn't match any existing one",
|
message: 'The user you are requesting could not be found.',
|
||||||
description: "Double-check the value in the parameter 'User' and try again",
|
description: 'Adjust the "User" parameter setting to retrieve the post correctly.',
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
} else if (operation === 'get') {
|
} else if (operation === 'get') {
|
||||||
if (errorType === 'UserNotFoundException') {
|
if (errorType === 'UserNotFoundException') {
|
||||||
throw new NodeApiError(this.getNode(), response as unknown as JsonObject, {
|
throw new NodeApiError(this.getNode(), response as unknown as JsonObject, {
|
||||||
message: "The required user doesn't match any existing one",
|
message: 'The user you are requesting could not be found.',
|
||||||
description: "Double-check the value in the parameter 'User' and try again",
|
description: 'Adjust the "User" parameter setting to retrieve the post correctly.',
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
} else if (operation === 'removeFromGroup') {
|
} else if (operation === 'removeFromGroup') {
|
||||||
// Group or user doesn't exist
|
|
||||||
if (errorType === 'UserNotFoundException') {
|
if (errorType === 'UserNotFoundException') {
|
||||||
const user = this.getNodeParameter('user.value', '') as string;
|
const user = this.getNodeParameter('user.value', '') as string;
|
||||||
|
|
||||||
if (typeof errorMessage === 'string' && errorMessage.includes(user)) {
|
if (typeof errorMessage === 'string' && errorMessage.includes(user)) {
|
||||||
throw new NodeApiError(this.getNode(), response as unknown as JsonObject, {
|
throw new NodeApiError(this.getNode(), response as unknown as JsonObject, {
|
||||||
message: "The required user doesn't match any existing one",
|
message: 'The user you are deleting could not be found.',
|
||||||
description: "Double-check the value in the parameter 'User' and try again.",
|
description: 'Adjust the "User" parameter setting to delete the user correctly.',
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
} else if (errorType === 'ResourceNotFoundException') {
|
} else if (errorType === 'ResourceNotFoundException') {
|
||||||
|
@ -269,72 +298,21 @@ export async function handleErrorPostReceive(
|
||||||
|
|
||||||
if (typeof errorMessage === 'string' && errorMessage.includes(group)) {
|
if (typeof errorMessage === 'string' && errorMessage.includes(group)) {
|
||||||
throw new NodeApiError(this.getNode(), response as unknown as JsonObject, {
|
throw new NodeApiError(this.getNode(), response as unknown as JsonObject, {
|
||||||
message: "The required group doesn't match any existing one",
|
message: 'The group you are requesting could not be found.',
|
||||||
description: "Double-check the value in the parameter 'Group' and try again.",
|
description: 'Adjust the "Group" parameter setting to delete the user correctly.',
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (operation === 'update') {
|
} else if (operation === 'update') {
|
||||||
if (errorType === 'UserNotFoundException') {
|
if (errorType === 'UserNotFoundException') {
|
||||||
throw new NodeApiError(this.getNode(), response as unknown as JsonObject, {
|
throw new NodeApiError(this.getNode(), response as unknown as JsonObject, {
|
||||||
message: "The required user doesn't match any existing one",
|
message: 'The user you are updating could not be found.',
|
||||||
description: "Double-check the value in the parameter 'User' and try again",
|
description: 'Adjust the "User" parameter setting to update the user correctly.',
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generic Error Handling
|
|
||||||
if (errorType === 'InvalidParameterException') {
|
|
||||||
const group = this.getNodeParameter('group.value', '') as string;
|
|
||||||
const parameterResource =
|
|
||||||
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 (errorType === 'InternalErrorException') {
|
|
||||||
throw new NodeApiError(this.getNode(), response as unknown as JsonObject, {
|
|
||||||
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);
|
throw new NodeApiError(this.getNode(), response as unknown as JsonObject);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -401,13 +379,13 @@ export async function searchUserPools(
|
||||||
paginationToken?: string,
|
paginationToken?: string,
|
||||||
): Promise<INodeListSearchResult> {
|
): Promise<INodeListSearchResult> {
|
||||||
const opts: IHttpRequestOptions = {
|
const opts: IHttpRequestOptions = {
|
||||||
url: '', // the base url is set in "awsRequest"
|
url: '',
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: {
|
headers: {
|
||||||
'X-Amz-Target': 'AWSCognitoIdentityProviderService.ListUserPools',
|
'X-Amz-Target': 'AWSCognitoIdentityProviderService.ListUserPools',
|
||||||
},
|
},
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
MaxResults: 60, // the maximum number by documentation is 60
|
MaxResults: 60,
|
||||||
NextToken: paginationToken ?? undefined,
|
NextToken: paginationToken ?? undefined,
|
||||||
}),
|
}),
|
||||||
};
|
};
|
||||||
|
@ -432,7 +410,7 @@ export async function searchUserPools(
|
||||||
return 0;
|
return 0;
|
||||||
});
|
});
|
||||||
|
|
||||||
return { results, paginationToken: responseData.NextToken }; // ToDo: Test if pagination for the search methods works
|
return { results, paginationToken: responseData.NextToken };
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function searchUsers(
|
export async function searchUsers(
|
||||||
|
@ -440,20 +418,16 @@ export async function searchUsers(
|
||||||
filter?: string,
|
filter?: string,
|
||||||
paginationToken?: string,
|
paginationToken?: string,
|
||||||
): Promise<INodeListSearchResult> {
|
): Promise<INodeListSearchResult> {
|
||||||
// Get the userPoolId from the input
|
|
||||||
const userPoolIdRaw = this.getNodeParameter('userPoolId', '') as IDataObject;
|
const userPoolIdRaw = this.getNodeParameter('userPoolId', '') as IDataObject;
|
||||||
|
|
||||||
// Extract the actual value
|
|
||||||
const userPoolId = userPoolIdRaw.value as string;
|
const userPoolId = userPoolIdRaw.value as string;
|
||||||
|
|
||||||
// Ensure that userPoolId is provided
|
|
||||||
if (!userPoolId) {
|
if (!userPoolId) {
|
||||||
throw new ApplicationError('User Pool ID is required to search users');
|
throw new ApplicationError('User Pool ID is required to search users');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Setup the options for the AWS request
|
|
||||||
const opts: IHttpRequestOptions = {
|
const opts: IHttpRequestOptions = {
|
||||||
url: '', // the base URL is set in "awsRequest"
|
url: '',
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: {
|
headers: {
|
||||||
'X-Amz-Target': 'AWSCognitoIdentityProviderService.ListUsers',
|
'X-Amz-Target': 'AWSCognitoIdentityProviderService.ListUsers',
|
||||||
|
@ -465,30 +439,23 @@ export async function searchUsers(
|
||||||
}),
|
}),
|
||||||
};
|
};
|
||||||
|
|
||||||
// Make the AWS request
|
|
||||||
const responseData: IDataObject = await awsRequest.call(this, opts);
|
const responseData: IDataObject = await awsRequest.call(this, opts);
|
||||||
|
|
||||||
// Extract users from the response
|
|
||||||
const users = responseData.Users as IDataObject[] | undefined;
|
const users = responseData.Users as IDataObject[] | undefined;
|
||||||
|
|
||||||
// Handle cases where no users are returned
|
|
||||||
if (!users) {
|
if (!users) {
|
||||||
console.warn('No users found in the response');
|
console.warn('No users found in the response');
|
||||||
return { results: [] };
|
return { results: [] };
|
||||||
}
|
}
|
||||||
|
|
||||||
// Map and filter the response data to create results
|
|
||||||
const results: INodeListSearchItems[] = users
|
const results: INodeListSearchItems[] = users
|
||||||
.map((user) => {
|
.map((user) => {
|
||||||
// Extract user attributes, if any
|
|
||||||
const attributes = user.Attributes as Array<{ Name: string; Value: string }> | undefined;
|
const attributes = user.Attributes as Array<{ Name: string; Value: string }> | undefined;
|
||||||
|
|
||||||
// Find the `email` or `sub` attribute, fallback to `Username`
|
|
||||||
const email = attributes?.find((attr) => attr.Name === 'email')?.Value;
|
const email = attributes?.find((attr) => attr.Name === 'email')?.Value;
|
||||||
const sub = attributes?.find((attr) => attr.Name === 'sub')?.Value;
|
const sub = attributes?.find((attr) => attr.Name === 'sub')?.Value;
|
||||||
const username = user.Username as string;
|
const username = user.Username as string;
|
||||||
|
|
||||||
// Use email, sub, or Username as the user name and value
|
|
||||||
const name = email || sub || username;
|
const name = email || sub || username;
|
||||||
const value = username;
|
const value = username;
|
||||||
|
|
||||||
|
@ -504,7 +471,6 @@ export async function searchUsers(
|
||||||
return a.name.toLowerCase().localeCompare(b.name.toLowerCase());
|
return a.name.toLowerCase().localeCompare(b.name.toLowerCase());
|
||||||
});
|
});
|
||||||
|
|
||||||
// Return the results and the pagination token
|
|
||||||
return { results, paginationToken: responseData.NextToken as string | undefined };
|
return { results, paginationToken: responseData.NextToken as string | undefined };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -513,17 +479,13 @@ export async function searchGroups(
|
||||||
filter?: string,
|
filter?: string,
|
||||||
paginationToken?: string,
|
paginationToken?: string,
|
||||||
): Promise<INodeListSearchResult> {
|
): Promise<INodeListSearchResult> {
|
||||||
// Get the userPoolId from the input
|
|
||||||
const userPoolIdRaw = this.getNodeParameter('userPoolId', '') as IDataObject;
|
const userPoolIdRaw = this.getNodeParameter('userPoolId', '') as IDataObject;
|
||||||
|
|
||||||
// Extract the actual value
|
|
||||||
const userPoolId = userPoolIdRaw.value as string;
|
const userPoolId = userPoolIdRaw.value as string;
|
||||||
|
|
||||||
// Ensure that userPoolId is provided
|
|
||||||
if (!userPoolId) {
|
if (!userPoolId) {
|
||||||
throw new ApplicationError('User Pool ID is required to search groups');
|
throw new ApplicationError('User Pool ID is required to search groups');
|
||||||
}
|
}
|
||||||
// Setup the options for the AWS request
|
|
||||||
const opts: IHttpRequestOptions = {
|
const opts: IHttpRequestOptions = {
|
||||||
url: '',
|
url: '',
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
|
@ -541,12 +503,10 @@ export async function searchGroups(
|
||||||
|
|
||||||
const groups = responseData.Groups as Array<{ GroupName?: string }> | undefined;
|
const groups = responseData.Groups as Array<{ GroupName?: string }> | undefined;
|
||||||
|
|
||||||
// If no groups exist, return an empty list
|
|
||||||
if (!groups) {
|
if (!groups) {
|
||||||
return { results: [] };
|
return { results: [] };
|
||||||
}
|
}
|
||||||
|
|
||||||
// Map and filter the response
|
|
||||||
const results: INodeListSearchItems[] = groups
|
const results: INodeListSearchItems[] = groups
|
||||||
.filter((group) => group.GroupName)
|
.filter((group) => group.GroupName)
|
||||||
.map((group) => ({
|
.map((group) => ({
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
import type { IExecuteSingleFunctions, IHttpRequestOptions, INodeProperties } from 'n8n-workflow';
|
import type { INodeProperties } from 'n8n-workflow';
|
||||||
import { NodeOperationError } from 'n8n-workflow';
|
|
||||||
|
|
||||||
import { handleErrorPostReceive, handlePagination } from '../GenericFunctions';
|
import { handleErrorPostReceive, handlePagination, presendPath } from '../GenericFunctions';
|
||||||
|
|
||||||
export const groupOperations: INodeProperties[] = [
|
export const groupOperations: INodeProperties[] = [
|
||||||
{
|
{
|
||||||
|
@ -92,7 +91,7 @@ export const groupOperations: INodeProperties[] = [
|
||||||
},
|
},
|
||||||
qs: {
|
qs: {
|
||||||
pageSize:
|
pageSize:
|
||||||
'={{ $parameter["limit"] ? ($parameter["limit"] < 60 ? $parameter["limit"] : 60) : 60 }}', // The API allows maximum 60 results per page
|
'={{ $parameter["limit"] ? ($parameter["limit"] < 60 ? $parameter["limit"] : 60) : 60 }}',
|
||||||
},
|
},
|
||||||
ignoreHttpStatusErrors: true,
|
ignoreHttpStatusErrors: true,
|
||||||
},
|
},
|
||||||
|
@ -257,38 +256,13 @@ const createFields: INodeProperties[] = [
|
||||||
send: {
|
send: {
|
||||||
property: 'Path',
|
property: 'Path',
|
||||||
type: 'body',
|
type: 'body',
|
||||||
preSend: [
|
preSend: [presendPath],
|
||||||
async function (
|
|
||||||
this: IExecuteSingleFunctions,
|
|
||||||
requestOptions: IHttpRequestOptions,
|
|
||||||
): Promise<IHttpRequestOptions> {
|
|
||||||
const path = this.getNodeParameter('path', '/') as string;
|
|
||||||
|
|
||||||
// Length validation
|
|
||||||
if (path.length < 1 || path.length > 512) {
|
|
||||||
throw new NodeOperationError(
|
|
||||||
this.getNode(),
|
|
||||||
'Path must be between 1 and 512 characters.',
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Regex validation
|
|
||||||
if (!/^\/$|^\/[\u0021-\u007E]+\/$/.test(path)) {
|
|
||||||
throw new NodeOperationError(
|
|
||||||
this.getNode(),
|
|
||||||
'Path must begin and end with a forward slash and contain valid ASCII characters.',
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return requestOptions;
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
displayName: 'Role ARN',
|
displayName: 'Role ARN',
|
||||||
name: 'RoleArn',
|
name: 'Arn',
|
||||||
default: '',
|
default: '',
|
||||||
placeholder: 'e.g. arn:aws:iam::123456789012:role/GroupRole',
|
placeholder: 'e.g. arn:aws:iam::123456789012:role/GroupRole',
|
||||||
description: 'The role ARN for the group, used for setting claims in tokens',
|
description: 'The role ARN for the group, used for setting claims in tokens',
|
||||||
|
@ -296,7 +270,7 @@ const createFields: INodeProperties[] = [
|
||||||
routing: {
|
routing: {
|
||||||
send: {
|
send: {
|
||||||
type: 'body',
|
type: 'body',
|
||||||
property: 'RoleArn',
|
property: 'Arn',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -510,91 +484,9 @@ const getFields: INodeProperties[] = [
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
|
||||||
displayName: 'Include Members',
|
|
||||||
name: 'includeMembers',
|
|
||||||
type: 'boolean',
|
|
||||||
default: false,
|
|
||||||
description: 'Whether include members of the group in the result',
|
|
||||||
displayOptions: {
|
|
||||||
show: {
|
|
||||||
resource: ['group'],
|
|
||||||
operation: ['get'],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
routing: {
|
|
||||||
send: {
|
|
||||||
property: '$expand',
|
|
||||||
type: 'query',
|
|
||||||
value:
|
|
||||||
'={{ $value ? "members($select=CreatedDate,Description,GroupName,LastModifiedDate,Precedence,UserPoolId)" : undefined }}',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
displayName: 'Include Group Policy',
|
|
||||||
name: 'includeGroupPolicy',
|
|
||||||
type: 'boolean',
|
|
||||||
default: false,
|
|
||||||
description: 'Whether include group policy details in the result',
|
|
||||||
displayOptions: {
|
|
||||||
show: {
|
|
||||||
resource: ['group'],
|
|
||||||
operation: ['get'],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
routing: {
|
|
||||||
send: {
|
|
||||||
property: '$expand',
|
|
||||||
type: 'query',
|
|
||||||
value: '={{ $value ? "groupPolicy($select=policyName,policyType)" : undefined }}',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
displayName: 'Simplified',
|
|
||||||
name: 'simplified',
|
|
||||||
type: 'boolean',
|
|
||||||
default: false,
|
|
||||||
description: 'Whether simplify the response if there are more than 10 fields',
|
|
||||||
displayOptions: {
|
|
||||||
show: {
|
|
||||||
resource: ['group'],
|
|
||||||
operation: ['get'],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
routing: {
|
|
||||||
send: {
|
|
||||||
property: '$select',
|
|
||||||
type: 'query',
|
|
||||||
value: 'CreatedDate,Description,GroupName,LastModifiedDate,Precedence,UserPoolId',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
];
|
];
|
||||||
|
|
||||||
const getAllFields: INodeProperties[] = [
|
const getAllFields: INodeProperties[] = [
|
||||||
{
|
|
||||||
displayName: 'Return All',
|
|
||||||
name: 'returnAll',
|
|
||||||
default: false,
|
|
||||||
description: 'Whether to return all results or only up to a given limit',
|
|
||||||
displayOptions: { show: { resource: ['group'], operation: ['getAll'] } },
|
|
||||||
type: 'boolean',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
displayName: 'Limit',
|
|
||||||
name: 'limit',
|
|
||||||
required: true,
|
|
||||||
type: 'number',
|
|
||||||
typeOptions: {
|
|
||||||
minValue: 1,
|
|
||||||
},
|
|
||||||
default: 20,
|
|
||||||
description: 'Max number of results to return',
|
|
||||||
displayOptions: { show: { resource: ['group'], operation: ['getAll'], returnAll: [false] } },
|
|
||||||
routing: { send: { type: 'body', property: 'Limit' } },
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
displayName: 'User Pool ID',
|
displayName: 'User Pool ID',
|
||||||
name: 'userPoolId',
|
name: 'userPoolId',
|
||||||
|
@ -633,65 +525,25 @@ const getAllFields: INodeProperties[] = [
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
displayName: 'Include Members',
|
displayName: 'Return All',
|
||||||
name: 'includeMembers',
|
name: 'returnAll',
|
||||||
type: 'boolean',
|
|
||||||
default: false,
|
default: false,
|
||||||
description: 'Whether include members of the group in the result',
|
description: 'Whether to return all results or only up to a given limit',
|
||||||
displayOptions: {
|
displayOptions: { show: { resource: ['group'], operation: ['getAll'] } },
|
||||||
show: {
|
type: 'boolean',
|
||||||
resource: ['group'],
|
|
||||||
operation: ['getAll'],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
routing: {
|
|
||||||
send: {
|
|
||||||
property: '$expand',
|
|
||||||
type: 'query',
|
|
||||||
value:
|
|
||||||
'={{ $value ? "members($select=CreatedDate,Description,GroupName,LastModifiedDate,Precedence,UserPoolId)" : undefined }}',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
displayName: 'Include Group Policy',
|
displayName: 'Limit',
|
||||||
name: 'includeGroupPolicy',
|
name: 'limit',
|
||||||
type: 'boolean',
|
required: true,
|
||||||
default: false,
|
type: 'number',
|
||||||
description: 'Whether include group policy details in the result',
|
typeOptions: {
|
||||||
displayOptions: {
|
minValue: 1,
|
||||||
show: {
|
|
||||||
resource: ['group'],
|
|
||||||
operation: ['getAll'],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
routing: {
|
|
||||||
send: {
|
|
||||||
property: '$expand',
|
|
||||||
type: 'query',
|
|
||||||
value: '={{ $value ? "groupPolicy($select=policyName,policyType)" : undefined }}',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
displayName: 'Simplified',
|
|
||||||
name: 'simplified',
|
|
||||||
type: 'boolean',
|
|
||||||
default: false,
|
|
||||||
description: 'Whether simplify the response if there are more than 10 fields',
|
|
||||||
displayOptions: {
|
|
||||||
show: {
|
|
||||||
resource: ['group'],
|
|
||||||
operation: ['getAll'],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
routing: {
|
|
||||||
send: {
|
|
||||||
property: '$select',
|
|
||||||
type: 'query',
|
|
||||||
value: 'CreatedDate,Description,GroupName,LastModifiedDate,Precedence,UserPoolId',
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
|
default: 20,
|
||||||
|
description: 'Max number of results to return',
|
||||||
|
displayOptions: { show: { resource: ['group'], operation: ['getAll'], returnAll: [false] } },
|
||||||
|
routing: { send: { type: 'body', property: 'Limit' } },
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
@ -848,38 +700,13 @@ const updateFields: INodeProperties[] = [
|
||||||
send: {
|
send: {
|
||||||
property: 'Path',
|
property: 'Path',
|
||||||
type: 'body',
|
type: 'body',
|
||||||
preSend: [
|
preSend: [presendPath],
|
||||||
async function (
|
|
||||||
this: IExecuteSingleFunctions,
|
|
||||||
requestOptions: IHttpRequestOptions,
|
|
||||||
): Promise<IHttpRequestOptions> {
|
|
||||||
const path = this.getNodeParameter('path', '/') as string;
|
|
||||||
|
|
||||||
// Length validation
|
|
||||||
if (path.length < 1 || path.length > 512) {
|
|
||||||
throw new NodeOperationError(
|
|
||||||
this.getNode(),
|
|
||||||
'Path must be between 1 and 512 characters.',
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Regex validation
|
|
||||||
if (!/^\/$|^\/[\u0021-\u007E]+\/$/.test(path)) {
|
|
||||||
throw new NodeOperationError(
|
|
||||||
this.getNode(),
|
|
||||||
'Path must begin and end with a forward slash and contain valid ASCII characters.',
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return requestOptions;
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
displayName: 'Role ARN',
|
displayName: 'Role ARN',
|
||||||
name: 'RoleArn',
|
name: 'Arn',
|
||||||
default: '',
|
default: '',
|
||||||
placeholder: 'e.g. arn:aws:iam::123456789012:role/GroupRole',
|
placeholder: 'e.g. arn:aws:iam::123456789012:role/GroupRole',
|
||||||
description:
|
description:
|
||||||
|
@ -888,7 +715,7 @@ const updateFields: INodeProperties[] = [
|
||||||
routing: {
|
routing: {
|
||||||
send: {
|
send: {
|
||||||
type: 'body',
|
type: 'body',
|
||||||
property: 'RoleArn',
|
property: 'Arn',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
|
@ -34,7 +34,15 @@ export const userOperations: INodeProperties[] = [
|
||||||
ignoreHttpStatusErrors: true,
|
ignoreHttpStatusErrors: true,
|
||||||
},
|
},
|
||||||
output: {
|
output: {
|
||||||
postReceive: [handleErrorPostReceive],
|
postReceive: [
|
||||||
|
handleErrorPostReceive,
|
||||||
|
{
|
||||||
|
type: 'set',
|
||||||
|
properties: {
|
||||||
|
value: '={{ { "added": true } }}',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -114,7 +122,7 @@ export const userOperations: INodeProperties[] = [
|
||||||
},
|
},
|
||||||
qs: {
|
qs: {
|
||||||
pageSize:
|
pageSize:
|
||||||
'={{ $parameter["limit"] ? ($parameter["limit"] < 60 ? $parameter["limit"] : 60) : 60 }}', // The API allows maximum 60 results per page
|
'={{ $parameter["limit"] ? ($parameter["limit"] < 60 ? $parameter["limit"] : 60) : 60 }}',
|
||||||
},
|
},
|
||||||
ignoreHttpStatusErrors: true,
|
ignoreHttpStatusErrors: true,
|
||||||
},
|
},
|
||||||
|
@ -138,7 +146,15 @@ export const userOperations: INodeProperties[] = [
|
||||||
ignoreHttpStatusErrors: true,
|
ignoreHttpStatusErrors: true,
|
||||||
},
|
},
|
||||||
output: {
|
output: {
|
||||||
postReceive: [handleErrorPostReceive],
|
postReceive: [
|
||||||
|
handleErrorPostReceive,
|
||||||
|
{
|
||||||
|
type: 'set',
|
||||||
|
properties: {
|
||||||
|
value: '={{ { "removed": true } }}',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -262,7 +278,7 @@ const createFields: INodeProperties[] = [
|
||||||
displayName: 'Client Metadata',
|
displayName: 'Client Metadata',
|
||||||
name: 'clientMetadata',
|
name: 'clientMetadata',
|
||||||
type: 'fixedCollection',
|
type: 'fixedCollection',
|
||||||
placeholder: 'Add Metadata Pair',
|
placeholder: 'Add Metadata',
|
||||||
default: { metadata: [] },
|
default: { metadata: [] },
|
||||||
description: 'A map of custom key-value pairs for workflows triggered by this action',
|
description: 'A map of custom key-value pairs for workflows triggered by this action',
|
||||||
typeOptions: {
|
typeOptions: {
|
||||||
|
@ -318,7 +334,7 @@ const createFields: INodeProperties[] = [
|
||||||
name: 'MessageAction',
|
name: 'MessageAction',
|
||||||
default: 'RESEND',
|
default: 'RESEND',
|
||||||
description:
|
description:
|
||||||
"Set to RESEND to resend the invitation message to a user that already exists and reset the expiration limit on the user's account. Set to SUPPRESS to suppress sending the message. You can specify only one value.",
|
"Set to RESEND to resend the invitation message to a user that already exists and reset the expiration limit on the user's account. Set to SUPPRESS to suppress sending the message.",
|
||||||
type: 'options',
|
type: 'options',
|
||||||
options: [
|
options: [
|
||||||
{
|
{
|
||||||
|
@ -685,7 +701,13 @@ const getAllFields: INodeProperties[] = [
|
||||||
name: 'filterAttribute',
|
name: 'filterAttribute',
|
||||||
type: 'options',
|
type: 'options',
|
||||||
default: 'username',
|
default: 'username',
|
||||||
|
hint: 'Make sure to select an attribute, type, and provide a value before submitting.',
|
||||||
description: 'The attribute to search for',
|
description: 'The attribute to search for',
|
||||||
|
routing: {
|
||||||
|
send: {
|
||||||
|
preSend: [presendFilter],
|
||||||
|
},
|
||||||
|
},
|
||||||
options: [
|
options: [
|
||||||
{ name: 'Cognito User Status', value: 'cognito:user_status' },
|
{ name: 'Cognito User Status', value: 'cognito:user_status' },
|
||||||
{ name: 'Email', value: 'email' },
|
{ name: 'Email', value: 'email' },
|
||||||
|
@ -716,11 +738,6 @@ const getAllFields: INodeProperties[] = [
|
||||||
type: 'string',
|
type: 'string',
|
||||||
default: '',
|
default: '',
|
||||||
description: 'The value of the attribute to search for',
|
description: 'The value of the attribute to search for',
|
||||||
routing: {
|
|
||||||
send: {
|
|
||||||
preSend: [presendFilter],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
|
Loading…
Reference in a new issue