mirror of
https://github.com/n8n-io/n8n.git
synced 2024-12-28 05:59:42 -08:00
e77fd5d286
Ensure all errors in `nodes-base` are `ApplicationError` or children of it and contain no variables in the message, to continue normalizing all the backend errors we report to Sentry. Also, skip reporting to Sentry errors from user input and from external APIs. In future we should refine `ApplicationError` to more specific errors. Follow-up to: [#7877](https://github.com/n8n-io/n8n/pull/7877) - [x] Test workflows: https://github.com/n8n-io/n8n/actions/runs/7084627970 - [x] e2e: https://github.com/n8n-io/n8n/actions/runs/7084936861 --------- Co-authored-by: Michael Kret <michael.k@radency.com>
128 lines
3.6 KiB
TypeScript
128 lines
3.6 KiB
TypeScript
import type { OptionsWithUrl } from 'request';
|
|
|
|
import type {
|
|
IDataObject,
|
|
IExecuteFunctions,
|
|
IHookFunctions,
|
|
ILoadOptionsFunctions,
|
|
INodeParameterResourceLocator,
|
|
JsonObject,
|
|
} from 'n8n-workflow';
|
|
import { ApplicationError, NodeApiError, NodeOperationError } from 'n8n-workflow';
|
|
|
|
export async function twitterApiRequest(
|
|
this: IExecuteFunctions | ILoadOptionsFunctions | IHookFunctions,
|
|
method: string,
|
|
resource: string,
|
|
body: IDataObject = {},
|
|
qs: IDataObject = {},
|
|
fullOutput?: boolean,
|
|
uri?: string,
|
|
option: IDataObject = {},
|
|
) {
|
|
let options: OptionsWithUrl = {
|
|
method,
|
|
body,
|
|
qs,
|
|
url: uri || `https://api.twitter.com/2${resource}`,
|
|
json: true,
|
|
};
|
|
try {
|
|
if (Object.keys(option).length !== 0) {
|
|
options = Object.assign({}, options, option);
|
|
}
|
|
if (Object.keys(body).length === 0) {
|
|
delete options.body;
|
|
}
|
|
if (Object.keys(qs).length === 0) {
|
|
delete options.qs;
|
|
}
|
|
if (fullOutput) {
|
|
return await this.helpers.requestOAuth2.call(this, 'twitterOAuth2Api', options);
|
|
} else {
|
|
const { data } = await this.helpers.requestOAuth2.call(this, 'twitterOAuth2Api', options);
|
|
return data;
|
|
}
|
|
} catch (error) {
|
|
if (error.error?.required_enrollment === 'Appropriate Level of API Access') {
|
|
throw new NodeOperationError(
|
|
this.getNode(),
|
|
'The operation requires Twitter Api to be either Basic or Pro.',
|
|
);
|
|
} else if (error.errors && error.error?.errors[0].message.includes('must be ')) {
|
|
throw new NodeOperationError(this.getNode(), error.error.errors[0].message as string);
|
|
}
|
|
throw new NodeApiError(this.getNode(), error as JsonObject);
|
|
}
|
|
}
|
|
|
|
export async function twitterApiRequestAllItems(
|
|
this: IExecuteFunctions | ILoadOptionsFunctions,
|
|
propertyName: string,
|
|
method: string,
|
|
endpoint: string,
|
|
body: IDataObject = {},
|
|
query: IDataObject = {},
|
|
) {
|
|
const returnData: IDataObject[] = [];
|
|
|
|
let responseData;
|
|
|
|
query.max_results = 10;
|
|
|
|
do {
|
|
responseData = await twitterApiRequest.call(this, method, endpoint, body, query, true);
|
|
query.next_token = responseData.meta.next_token as string;
|
|
returnData.push.apply(returnData, responseData[propertyName] as IDataObject[]);
|
|
} while (responseData.meta.next_token);
|
|
|
|
return returnData;
|
|
}
|
|
|
|
export function returnId(tweetId: INodeParameterResourceLocator) {
|
|
if (tweetId.mode === 'id') {
|
|
return tweetId.value as string;
|
|
} else if (tweetId.mode === 'url') {
|
|
const value = tweetId.value as string;
|
|
const tweetIdMatch = value.includes('lists')
|
|
? value.match(/^https?:\/\/twitter\.com\/(?:#!\/)?(\w+)\/list(s)?\/(\d+)$/)
|
|
: value.match(/^https?:\/\/twitter\.com\/(?:#!\/)?(\w+)\/status(es)?\/(\d+)$/);
|
|
|
|
return tweetIdMatch?.[3] as string;
|
|
} else {
|
|
throw new ApplicationError(`The mode ${tweetId.mode} is not valid!`, { level: 'warning' });
|
|
}
|
|
}
|
|
|
|
export async function returnIdFromUsername(
|
|
this: IExecuteFunctions,
|
|
usernameRlc: INodeParameterResourceLocator,
|
|
) {
|
|
usernameRlc.value = (usernameRlc.value as string).includes('@')
|
|
? (usernameRlc.value as string).replace('@', '')
|
|
: usernameRlc.value;
|
|
if (
|
|
usernameRlc.mode === 'username' ||
|
|
(usernameRlc.mode === 'name' && this.getNode().parameters.list !== undefined)
|
|
) {
|
|
const user = (await twitterApiRequest.call(
|
|
this,
|
|
'GET',
|
|
`/users/by/username/${usernameRlc.value}`,
|
|
{},
|
|
)) as { id: string };
|
|
return user.id;
|
|
} else if (this.getNode().parameters.list === undefined) {
|
|
const list = (await twitterApiRequest.call(
|
|
this,
|
|
'GET',
|
|
`/list/by/name/${usernameRlc.value}`,
|
|
{},
|
|
)) as { id: string };
|
|
return list.id;
|
|
} else
|
|
throw new ApplicationError(`The username mode ${usernameRlc.mode} is not valid!`, {
|
|
level: 'warning',
|
|
});
|
|
}
|