mirror of
https://github.com/Abdulazizzn/n8n-enterprise-unlocked.git
synced 2025-12-17 10:02:05 +00:00
✨ Add Reddit Node (#1345)
* Set up initial scaffolding and auth * Add grant type to credentials * Add Account operations and OAuth2 request * Add post submission functionality * Refactor resources into resource descriptions * Refactor request for no auth URL * Refactor submission description for consistency * Add listing resource * Refactor My Account resource into details * Add request for all items * Add listings for specific subreddits * Fix minor linting details * Add subreddit resource * Add All-Reddit and Subreddit resource descriptions * Adjust display options for credentials * Add subreddit search functionality * Clean up auth parameter * Add user resource with GET endpoint * Add user description * Add submission search and commenting functionality * Clean up logging and comments * Fix minor details * Fix casing in properties * Add dividers to execute() method * Refactor per feedback * Remove unused description * Add punctuation to property descriptions * Fix resources indentation * Add resource dividers * Remove deprecated sidebar option * Make subreddit:get responses consistent * Remove returnAll and limit from subreddit:get * Flatten user:get response for about * Rename comment target property * Remove best property from post:getAll * Enrich subreddit search by keyword operation * Remove unneeded scopes * Add endpoint documentation * Add scaffolding for post comment * Add all operations for postComment resource * Add all operations for post resource * Refactor subreddit:getAll * Fix postComment:getAll * Flatten responses for profile:get * ⚡ Improvements * Fix response traversal for postComment:add * Flatten response for postComment:reply * Fix subreddit:getAll with keyword search * Fix pagination to enforce limit * Wrap unauthenticated API call in try-catch block * Add 404 error for empty array responses * Revert "Fix pagination to enforce limit" This reverts commit 72548d952378a2f899517522b5ba4950a940c6e4. * Turn user:get (gilded) into listing * ⚡ Small improvement * ⚡ Improve Reddit-Node Co-authored-by: ricardo <ricardoespinoza105@gmail.com> Co-authored-by: Jan Oberhauser <jan.oberhauser@gmail.com>
This commit is contained in:
145
packages/nodes-base/nodes/Reddit/GenericFunctions.ts
Normal file
145
packages/nodes-base/nodes/Reddit/GenericFunctions.ts
Normal file
@@ -0,0 +1,145 @@
|
||||
import {
|
||||
IExecuteFunctions,
|
||||
IHookFunctions,
|
||||
} from 'n8n-core';
|
||||
|
||||
import {
|
||||
IDataObject,
|
||||
} from 'n8n-workflow';
|
||||
|
||||
import {
|
||||
OptionsWithUri,
|
||||
} from 'request';
|
||||
|
||||
/**
|
||||
* Make an authenticated or unauthenticated API request to Reddit.
|
||||
*/
|
||||
export async function redditApiRequest(
|
||||
this: IHookFunctions | IExecuteFunctions,
|
||||
method: string,
|
||||
endpoint: string,
|
||||
qs: IDataObject,
|
||||
): Promise<any> { // tslint:disable-line:no-any
|
||||
|
||||
const resource = this.getNodeParameter('resource', 0) as string;
|
||||
|
||||
const authRequired = ['profile', 'post', 'postComment'].includes(resource);
|
||||
|
||||
qs.api_type = 'json';
|
||||
|
||||
const options: OptionsWithUri = {
|
||||
headers: {
|
||||
'user-agent': 'n8n',
|
||||
},
|
||||
method,
|
||||
uri: authRequired ? `https://oauth.reddit.com/${endpoint}` : `https://www.reddit.com/${endpoint}`,
|
||||
qs,
|
||||
json: true,
|
||||
};
|
||||
|
||||
if (!Object.keys(qs).length) {
|
||||
delete options.qs;
|
||||
}
|
||||
|
||||
if (authRequired) {
|
||||
let response;
|
||||
|
||||
try {
|
||||
response = await this.helpers.requestOAuth2.call(this, 'redditOAuth2Api', options);
|
||||
} catch (error) {
|
||||
if (error.response.body && error.response.body.message) {
|
||||
const message = error.response.body.message;
|
||||
throw new Error(`Reddit error response [${error.statusCode}]: ${message}`);
|
||||
}
|
||||
}
|
||||
|
||||
if ((response.errors && response.errors.length !== 0) || (response.json && response.json.errors && response.json.errors.length !== 0)) {
|
||||
const errors = response?.errors || response?.json?.errors;
|
||||
const errorMessage = errors.map((error: []) => error.join('-'));
|
||||
|
||||
throw new Error(`Reddit error response [400]: ${errorMessage.join('|')}`);
|
||||
}
|
||||
|
||||
return response;
|
||||
|
||||
} else {
|
||||
|
||||
try {
|
||||
return await this.helpers.request.call(this, options);
|
||||
} catch (error) {
|
||||
const errorMessage = error?.response?.body?.message;
|
||||
if (errorMessage) {
|
||||
throw new Error(`Reddit error response [${error.statusCode}]: ${errorMessage}`);
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Make an unauthenticated API request to Reddit and return all results.
|
||||
*/
|
||||
export async function redditApiRequestAllItems(
|
||||
this: IHookFunctions | IExecuteFunctions,
|
||||
method: string,
|
||||
endpoint: string,
|
||||
qs: IDataObject,
|
||||
): Promise<any> { // tslint:disable-line:no-any
|
||||
|
||||
let responseData;
|
||||
const returnData: IDataObject[] = [];
|
||||
|
||||
const resource = this.getNodeParameter('resource', 0) as string;
|
||||
const operation = this.getNodeParameter('operation', 0) as string;
|
||||
const returnAll = this.getNodeParameter('returnAll', 0, false) as boolean;
|
||||
|
||||
qs.limit = 100;
|
||||
|
||||
do {
|
||||
responseData = await redditApiRequest.call(this, method, endpoint, qs);
|
||||
if (!Array.isArray(responseData)) {
|
||||
qs.after = responseData.data.after;
|
||||
}
|
||||
|
||||
if (endpoint === 'api/search_subreddits.json') {
|
||||
responseData.subreddits.forEach((child: any) => returnData.push(child)); // tslint:disable-line:no-any
|
||||
} else if (resource === 'postComment' && operation === 'getAll') {
|
||||
responseData[1].data.children.forEach((child: any) => returnData.push(child.data)); // tslint:disable-line:no-any
|
||||
} else {
|
||||
responseData.data.children.forEach((child: any) => returnData.push(child.data)); // tslint:disable-line:no-any
|
||||
}
|
||||
if (qs.limit && returnData.length >= qs.limit && returnAll === false) {
|
||||
return returnData;
|
||||
}
|
||||
|
||||
} while (responseData.data && responseData.data.after);
|
||||
|
||||
return returnData;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles a large Reddit listing by returning all items or up to a limit.
|
||||
*/
|
||||
export async function handleListing(
|
||||
this: IExecuteFunctions,
|
||||
i: number,
|
||||
endpoint: string,
|
||||
qs: IDataObject = {},
|
||||
requestMethod: 'GET' | 'POST' = 'GET',
|
||||
): Promise<any> { // tslint:disable-line:no-any
|
||||
|
||||
let responseData;
|
||||
|
||||
const returnAll = this.getNodeParameter('returnAll', i);
|
||||
|
||||
if (returnAll) {
|
||||
responseData = await redditApiRequestAllItems.call(this, requestMethod, endpoint, qs);
|
||||
} else {
|
||||
const limit = this.getNodeParameter('limit', i);
|
||||
qs.limit = limit;
|
||||
responseData = await redditApiRequestAllItems.call(this, requestMethod, endpoint, qs);
|
||||
responseData = responseData.slice(0, limit);
|
||||
}
|
||||
|
||||
return responseData;
|
||||
}
|
||||
Reference in New Issue
Block a user