UNPKG

@tuanltntu/n8n-nodes-bitrix24

Version:

Comprehensive n8n community node for Bitrix24 API integration with CRM, Tasks, Chat, Telephony, and more

251 lines 11.2 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.ResourceHandlerBase = void 0; const n8n_workflow_1 = require("n8n-workflow"); const GenericFunctions_1 = require("../GenericFunctions"); /** * Base class for all Bitrix24 resource handlers * Defines the common structure and methods for handling different Bitrix24 resources */ class ResourceHandlerBase { constructor(executeFunctions, returnData, options = {}) { this.executeFunctions = executeFunctions; this.returnData = returnData; this.items = executeFunctions.getInputData(); this.options = options; this.isDebugMode = false; // Disable debug logging for performance if (this.isDebugMode) { console.log(`ResourceHandlerBase: Initialized with options:`, JSON.stringify(this.options)); } } /** * Make a standardized API call to Bitrix24 * This encapsulates the standard way to call Bitrix24 API */ async makeApiCall(endpoint, body = {}, queryParams = {}, itemIndex = 0, getAllItems = false) { // Add this log to always show when the function is called console.log(`=== RESOURCE HANDLER MAKE API CALL: ${endpoint} ===`); try { console.log(`ResourceHandlerBase.makeApiCall: Calling endpoint ${endpoint}`); // Check if we need to add an accessToken from options const options = this.getOptionsWithAccessToken(itemIndex, {}); options.debug = true; // Always enable debug mode for troubleshooting if (options.accessToken) { // Log that we found an access token in options console.log(`ResourceHandlerBase.makeApiCall: Found access_token in options`); } // Get authentication type from node parameters let authType = "unknown"; try { authType = this.getNodeParameter("authentication", itemIndex, "oAuth2"); console.log(`ResourceHandlerBase.makeApiCall: Using authentication type: ${authType}`); } catch (error) { console.log(`ResourceHandlerBase.makeApiCall: Could not get authentication parameter, using default`); } // Add auth type to options options.authType = authType.toLowerCase(); // Use the appropriate authentication method if (this.options.forceWebhook === true) { if (this.isDebugMode) { console.log(`ResourceHandlerBase: Using webhook for API call to ${endpoint} (forced)`); } // Make the API call using webhook authentication, passing the accessToken through options return await GenericFunctions_1.bitrix24Request.call(this.executeFunctions, endpoint, body, queryParams, { debug: true, authType: "webhook", accessToken: options.accessToken, }); } else { console.log(`ResourceHandlerBase.makeApiCall: Making standard call with auth ${authType}`); // Add debug info for OAuth2 if (authType.toLowerCase() === "oauth2") { try { const credentials = await this.executeFunctions.getCredentials("bitrix24OAuth"); console.log(`ResourceHandlerBase.makeApiCall: OAuth2 credentials have portal URL: ${credentials.portalUrl}`); } catch (credError) { console.error(`ResourceHandlerBase.makeApiCall: Failed to get OAuth2 credentials: ${credError.message}`); } } // Create API call options with the accessToken const apiCallOptions = { debug: true, authType: authType.toLowerCase(), }; // Add accessToken to options if it exists if (options.accessToken) { apiCallOptions.accessToken = options.accessToken; } // Use the standard call method which will auto-detect authentication type return await GenericFunctions_1.makeStandardBitrix24Call.call(this.executeFunctions, endpoint, body, queryParams, itemIndex, getAllItems, apiCallOptions); } } catch (error) { console.error(`ResourceHandlerBase.makeApiCall: API call to ${endpoint} failed:`, error); // Add more debug info for OAuth2 errors if (error.statusCode) { console.error(`ResourceHandlerBase.makeApiCall: Error status code: ${error.statusCode}`); } if (error.response) { console.error(`ResourceHandlerBase.makeApiCall: Error response:`, JSON.stringify(error.response, null, 2)); } // Instead of throwing a NodeOperationError, return the error response // to allow handlers to process the error and display it properly let bitrixErrorResponse; if (error.response) { // If there's a response object containing Bitrix error info bitrixErrorResponse = error.response; } else if (error.error) { // If the error is directly from Bitrix bitrixErrorResponse = { error: error.error || "UNKNOWN_ERROR", error_description: error.error_description || error.message || "Unknown error occurred", }; } else { // Fallback with just error message bitrixErrorResponse = { error: "API_ERROR", error_description: error.message || "Unknown error occurred", endpoint: endpoint, }; } // Log the error details for debugging console.error(`Bitrix24 API error response for ${endpoint}:`, bitrixErrorResponse); // Return error response instead of throwing return bitrixErrorResponse; } } /** * Auto-detect and extract array data from nested Bitrix24 response structures */ extractResultsFromResponse(response, endpoint) { if (!response || !response.result) { return []; } let results; // Check if result has nested properties (common in Bitrix24) if (typeof response.result === "object" && !Array.isArray(response.result)) { // Get all properties of result object const resultKeys = Object.keys(response.result); // Look for array properties that might contain the actual data const arrayProperty = resultKeys.find((key) => Array.isArray(response.result[key]) && response.result[key].length >= 0); if (arrayProperty) { // Found nested array property (like types, categories, etc.) results = response.result[arrayProperty]; if (endpoint) { console.log(`Auto-detected nested property '${arrayProperty}' for ${endpoint}`); } } else { // No array property found, treat as single object results = [response.result]; } } else if (Array.isArray(response.result)) { // Direct array response (like crm.deal.list) results = response.result; } else { // Single object response results = [response.result]; } return Array.isArray(results) ? results : [results]; } /** * Process and add API response to the return data */ addResponseToReturnData(responseData, itemIndex) { if (responseData) { const executionData = GenericFunctions_1.returnFullBitrix24Response.call(this.executeFunctions, responseData, this.executeFunctions.helpers, itemIndex); this.returnData.push(...executionData); } } /** * Add error details to return data for failed items */ addErrorToReturnData(error, itemIndex) { this.returnData.push({ json: { error: error.message, item: this.items[itemIndex].json, }, }); } /** * Check if execution should continue on error */ continueOnFail() { return this.executeFunctions.getNode().continueOnFail === true; } /** * Get a parameter value for the current operation */ getNodeParameter(parameterName, itemIndex, fallback) { return this.executeFunctions.getNodeParameter(parameterName, itemIndex, fallback); } /** * Get options with access token handling * This provides a consistent way to get options that might include an accessToken * Handles multiple option fields (options, taskOptions, instanceOptions, etc.) */ getOptionsWithAccessToken(itemIndex, defaultOptions = {}) { let options = { ...defaultOptions }; // List of possible option parameter names const optionParameterNames = [ "options", "taskOptions", "instanceOptions", "additionalOptions", "advancedOptions", ]; try { // Try to get options from all possible option parameters for (const paramName of optionParameterNames) { try { const paramOptions = this.getNodeParameter(paramName, itemIndex, null); // If options exist, merge them with existing options if (paramOptions !== null) { options = { ...options, ...paramOptions }; } } catch (error) { // Ignore errors for parameters that don't exist } } // Make sure accessToken is a string if it exists if (options.accessToken !== undefined) { options.accessToken = String(options.accessToken).trim(); // If accessToken is empty string, delete it to avoid sending empty tokens if (options.accessToken === "") { delete options.accessToken; } } return options; } catch (error) { // If all option parameters don't exist or there's an error, return default options return options; } } /** * Parse JSON parameters safely */ parseJsonParameter(json, errorMessage, itemIndex) { try { return JSON.parse(json); } catch (error) { throw new n8n_workflow_1.NodeOperationError(this.executeFunctions.getNode(), errorMessage, { itemIndex }); } } } exports.ResourceHandlerBase = ResourceHandlerBase; //# sourceMappingURL=ResourceHandlerBase.js.map