@kadam-net/n8n-nodes-kadam
Version:
Kadam node for n8n to manage campaigns, creatives, and more.
509 lines • 26.5 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.createCampaign = createCampaign;
exports.updateCampaign = updateCampaign;
exports.deleteCampaign = deleteCampaign;
exports.getCampaigns = getCampaigns;
exports.getCampaignCategories = getCampaignCategories;
exports.getAdFormats = getAdFormats;
exports.updatePlacementMultiplier = updatePlacementMultiplier;
const n8n_workflow_1 = require("n8n-workflow");
const utils_1 = require("./utils");
async function createCampaign() {
var _a;
this.logger.debug('Entered createCampaign function.');
const items = this.getInputData();
const returnData = [];
const length = items.length;
const credentials = await this.getCredentials('kadam');
const token = credentials.apiToken;
const appId = credentials.appId;
const baseUrl = 'https://api.kadam.net';
const headers = {
'Content-Type': 'application/json',
Authorization: `Bearer ${token}`,
};
for (let i = 0; i < length; i++) {
try {
this.logger.debug(`Attempting to get parameter: campaignName for item ${i}`);
const campaignName = this.getNodeParameter('campaignName', i);
this.logger.debug(`Got campaignName: ${campaignName}`);
if (!campaignName)
throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Missing required parameter 'campaignName' for item ${i}`);
this.logger.debug(`Attempting to get parameter: adFormatId for item ${i}`);
const adFormatId = this.getNodeParameter('adFormatId', i);
this.logger.debug(`Got adFormatId: ${adFormatId}`);
if (adFormatId === undefined || adFormatId === null)
throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Missing required parameter 'adFormatId' for item ${i}`);
this.logger.debug(`Attempting to get parameter: priceModel for item ${i}`);
const priceModel = this.getNodeParameter('priceModel', i);
this.logger.debug(`Got priceModel: ${priceModel}`);
if (!priceModel)
throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Missing required parameter 'priceModel' for item ${i}`);
const costTypeMap = { cpc: 0, cpm: 2, cpa: 1 };
const costType = costTypeMap[priceModel.toLowerCase()];
this.logger.debug(`Derived costType: ${costType}`);
if (costType === undefined)
throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Invalid 'priceModel' value '${priceModel}' for item ${i}. Expected 'cpc', 'cpm', or 'cpa'.`);
this.logger.debug(`Attempting to get parameter: targetUrl for item ${i}`);
const targetUrl = this.getNodeParameter('targetUrl', i);
this.logger.debug(`Got targetUrl: ${targetUrl}`);
if (!targetUrl)
throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Missing required parameter 'targetUrl' for item ${i}`);
this.logger.debug(`Attempting to get parameter: countryTargetCollection for item ${i}`);
const countryTargetCollection = this.getNodeParameter('countryTargetCollection', i, { countryTargetValues: [] });
this.logger.debug(`Got countryTargetCollection: ${JSON.stringify(countryTargetCollection)}`);
const countryTarget = {};
for (const item of countryTargetCollection.countryTargetValues || []) {
countryTarget[item.countryId] = { bid: item.bid };
}
this.logger.debug(`Converted to countryTarget format: ${JSON.stringify(countryTarget)}`);
this.logger.debug(`Attempting to get parameter: categories for item ${i}`);
const categories = this.getNodeParameter('categories', i);
this.logger.debug(`Got categories: ${JSON.stringify(categories)}`);
if (!categories || !Array.isArray(categories) || categories.length === 0)
throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Missing or invalid required parameter 'categories' for item ${i}. Expected a non-empty array of IDs.`);
this.logger.debug(`Attempting to get parameter: status for item ${i}`);
const statusInput = this.getNodeParameter('status', i, '');
this.logger.debug(`Got status input: ${statusInput}`);
this.logger.debug(`Attempting to get parameter: additionalOptions for item ${i}`);
const additionalOptions = this.getNodeParameter('additionalOptions', i, {});
this.logger.debug(`Got additionalOptions object: ${JSON.stringify(additionalOptions)}`);
this.logger.debug(`Validating parameters for item ${i}`);
if (!campaignName)
throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Missing required parameter 'campaignName' for item ${i}.`);
if (adFormatId === undefined || adFormatId === null)
throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Missing required parameter 'adFormatId' for item ${i}.`);
if (!priceModel)
throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Missing required parameter 'priceModel' for item ${i}.`);
if (!targetUrl)
throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Missing required parameter 'targetUrl' for item ${i}.`);
if (!countryTarget || typeof countryTarget !== 'object' || Object.keys(countryTarget).length === 0) {
this.logger.error(`Validation failed: countryTarget is not a non-empty object. Type: ${typeof countryTarget}, Value: ${JSON.stringify(countryTarget)}`);
throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Missing or invalid required parameter 'countryTarget' for item ${i}. Expected a non-empty JSON object.`);
}
if (!categories || categories.length === 0)
throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Missing required parameter 'categories' for item ${i}.`);
const data = {
client_id: appId,
ad_format: adFormatId,
cost_type: costType,
name: campaignName,
link_url: targetUrl,
sex: 3,
age: '0',
real_url: targetUrl,
categories: categories,
countryTarget: countryTarget,
status: statusInput === 0 ? 0 : 1,
};
if (additionalOptions.dayLimit !== undefined && additionalOptions.dayLimit !== null)
data.day_limit = additionalOptions.dayLimit;
if (additionalOptions.allLimit !== undefined && additionalOptions.allLimit !== null)
data.all_limit = additionalOptions.allLimit;
if (additionalOptions.clickLimit !== undefined && additionalOptions.clickLimit !== null)
data.click_limit = additionalOptions.clickLimit;
if (additionalOptions.langTarget)
data.langTarget = additionalOptions.langTarget;
if (additionalOptions.deviceTarget)
data.deviceTarget = additionalOptions.deviceTarget;
const optionalApiFields = [
'pushType',
'regionTarget',
'cityTarget',
'cpa_mode',
'tags',
'conversion_limit',
'adult_content',
'adult_site',
'time_show',
'platforms',
'browsers',
'black_list',
'white_list',
'black_list_ip',
'unique_day_count',
'unique_days',
];
for (const fieldName of optionalApiFields) {
if (additionalOptions[fieldName] !== undefined && additionalOptions[fieldName] !== null && additionalOptions[fieldName] !== '') {
data[fieldName] = additionalOptions[fieldName];
}
}
const requestUrl = `${baseUrl}/ads.campaigns.put`;
const campaignDataArrayString = JSON.stringify([data]);
const queryParams = {
app_id: appId,
data: campaignDataArrayString,
};
this.logger.debug(`Making GET request to ${requestUrl} with query params: ${JSON.stringify(queryParams)}`);
const response = await utils_1.makeApiRequest.call(this, 'get', requestUrl, headers, queryParams);
this.logger.debug(`API Response received for campaign create.`);
if (Array.isArray(response) && ((_a = response[0]) === null || _a === void 0 ? void 0 : _a.error_code)) {
const apiError = response[0];
this.logger.debug(`Kadam API Error Response: ${JSON.stringify(apiError)}`);
const errorMessage = `Kadam API error (${apiError.error_code}): ${apiError.error_desc || 'Unknown error'}`;
const error = new Error(errorMessage);
error.kadamError = apiError;
throw new n8n_workflow_1.NodeApiError(this.getNode(), { error: apiError }, error);
}
else {
this.logger.debug(`Kadam API Success Response structure: ${JSON.stringify(response).substring(0, 100)}...`);
}
if ((0, utils_1.isContinueOnFailError)(response)) {
returnData.push({ json: response });
}
else {
returnData.push({ json: response });
}
}
catch (error) {
if (this.continueOnFail()) {
const errorItem = {
json: { error: error.message },
};
returnData.push(errorItem);
continue;
}
throw error;
}
}
return returnData;
}
async function updateCampaign() {
const items = this.getInputData();
const returnData = [];
const length = items.length;
const credentials = await this.getCredentials('kadam');
const token = credentials.apiToken;
const appId = credentials.appId;
const baseUrl = 'https://api.kadam.net';
const headers = {
'Content-Type': 'application/json',
Authorization: `Bearer ${token}`,
};
for (let i = 0; i < length; i++) {
try {
const campaignId = this.getNodeParameter('campaignId', i);
if (!campaignId) {
throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'Campaign ID is required for update operation.', { itemIndex: i });
}
const additionalOptions = this.getNodeParameter('additionalOptions', i, {});
this.logger.info(`Reading additionalOptions for update: ${JSON.stringify(additionalOptions)}`);
const allParams = this.getNode().parameters;
this.logger.info(`Node parameters configuration: ${JSON.stringify(allParams)}`);
const name = additionalOptions.name || '';
const targetUrl = additionalOptions.targetUrl || '';
const categories = additionalOptions.categories || [];
const status = additionalOptions.status !== undefined ? additionalOptions.status : '';
this.logger.debug(`Getting countryTargetCollection for campaign update ${campaignId} (item ${i})`);
const countryTargetCollection = additionalOptions.countryTargetCollection || { countryTargetValues: [] };
const countryTarget = {};
if (countryTargetCollection.countryTargetValues) {
for (const item of countryTargetCollection.countryTargetValues) {
countryTarget[item.countryId] = { bid: item.bid };
}
}
this.logger.debug(`Converted country targeting for update: ${JSON.stringify(countryTarget)}`);
const data = {
client_id: appId,
campaign_id: campaignId,
};
if (name)
data.name = name;
if (targetUrl)
data.link_url = targetUrl;
if (Object.keys(countryTarget).length > 0) {
data.countryTarget = countryTarget;
}
if (categories && categories.length > 0)
data.categories = categories;
if (status !== '' && status !== undefined)
data.status = status;
if (additionalOptions.dayLimit)
data.day_limit = additionalOptions.dayLimit;
if (additionalOptions.allLimit)
data.all_limit = additionalOptions.allLimit;
if (additionalOptions.clickLimit)
data.click_limit = additionalOptions.clickLimit;
if (additionalOptions.conversionLimit)
data.conversion_limit = additionalOptions.conversionLimit;
if (additionalOptions.adult_content !== undefined)
data.adult_content = additionalOptions.adult_content;
if (additionalOptions.adult_site !== undefined)
data.adult_site = additionalOptions.adult_site;
if (additionalOptions.realUrl)
data.real_url = additionalOptions.realUrl;
if (additionalOptions.sex)
data.sex = additionalOptions.sex;
if (additionalOptions.age)
data.age = additionalOptions.age;
if (additionalOptions.regionTarget)
data.regionTarget = additionalOptions.regionTarget.toString().split(',').map(Number);
if (additionalOptions.cityTarget)
data.cityTarget = additionalOptions.cityTarget.toString().split(',').map(Number);
if (additionalOptions.deviceTarget)
data.deviceTarget = additionalOptions.deviceTarget.toString().split(',').map(Number);
if (additionalOptions.langTarget)
data.langTarget = additionalOptions.langTarget.toString().split(',').map(Number);
if (additionalOptions.platforms)
data.platforms = additionalOptions.platforms.toString().split(',').map(Number);
if (additionalOptions.browsers)
data.browsers = additionalOptions.browsers.toString().split(',').map(Number);
if (additionalOptions.tags)
data.tags = additionalOptions.tags;
if (additionalOptions.blackList)
data.blackList = additionalOptions.blackList.toString().split(',').map(Number);
if (additionalOptions.whiteList)
data.whiteList = additionalOptions.whiteList.toString().split(',').map(Number);
if (additionalOptions.blackListIp)
data.blackListIp = additionalOptions.blackListIp.split(',').map((item) => item.trim());
if (Object.keys(data).length <= 2) {
returnData.push({ json: { warning: 'No parameters provided to update.', campaignId: campaignId } });
continue;
}
this.logger.info(`Updating campaign ${campaignId} with data: ${JSON.stringify(data)}`);
this.logger.info(`additionalOptions content: ${JSON.stringify(additionalOptions)}`);
const requestUrl = `${baseUrl}/ads.campaigns.update`;
const dataString = JSON.stringify(data);
const queryParams = {
app_id: appId,
data: dataString,
};
this.logger.info(`⚠️ DEBUG: Making GET request to ${requestUrl}`);
this.logger.info(`⚠️ DEBUG: Query params: ${JSON.stringify(queryParams)}`);
this.logger.info(`⚠️ DEBUG: Raw dataString: ${dataString}`);
const response = await utils_1.makeApiRequest.call(this, 'get', requestUrl, headers, queryParams);
if ((0, utils_1.isContinueOnFailError)(response)) {
returnData.push({ json: response });
}
else {
returnData.push({ json: response });
}
}
catch (error) {
if (this.continueOnFail()) {
const errorItem = {
json: { error: error.message },
};
returnData.push(errorItem);
continue;
}
throw error;
}
}
return returnData;
}
async function deleteCampaign() {
const items = this.getInputData();
const returnData = [];
const length = items.length;
const credentials = await this.getCredentials('kadam');
const token = credentials.apiToken;
const appId = credentials.appId;
const baseUrl = 'https://api.kadam.net';
const headers = {
'Content-Type': 'application/json',
Authorization: `Bearer ${token}`,
};
for (let i = 0; i < length; i++) {
const campaignIds = this.getNodeParameter('ids', i);
if (!campaignIds || campaignIds.length === 0) {
if (this.continueOnFail()) {
const errorItem = {
json: { error: 'Campaign IDs are required for delete operation.' },
};
returnData.push(errorItem);
continue;
}
else {
throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'Campaign IDs are required for delete operation.', { itemIndex: i });
}
}
const queryParams = {
app_id: appId,
ids: campaignIds.join(','),
};
try {
const response = await utils_1.makeApiRequest.call(this, 'get', `${baseUrl}/ads.campaigns.delete`, headers, queryParams);
if ((0, utils_1.isContinueOnFailError)(response)) {
returnData.push({ json: response });
}
else {
returnData.push({ json: response || { success: true } });
}
}
catch (error) {
if (this.continueOnFail()) {
const errorItem = {
json: { error: error.message },
};
returnData.push(errorItem);
continue;
}
throw error;
}
}
return returnData;
}
async function getCampaigns(i, baseUrl, headers, appId) {
var _a, _b, _c, _d, _e, _f;
const params = {
app_id: appId,
client_id: appId,
campaign_ids: this.getNodeParameter('campaignIds', i, null),
};
const includeDataOptions = this.getNodeParameter('includeDataOptions', i, []);
const outputFieldsRaw = this.getNodeParameter('outputFields', i, '');
params.include_archive = includeDataOptions.includes('includeArchive');
params.with_bwlist = includeDataOptions.includes('withBwlist');
params.with_materials = includeDataOptions.includes('withCreatives');
const fullResponseArray = await utils_1.fetchAll.call(this, `${baseUrl}/ads.campaigns.get`, headers, params);
console.log('--- Kadam GetCampaigns Debug ---');
console.log('Keys of fullResponseArray:', Object.keys(fullResponseArray || {}));
if (fullResponseArray === null || fullResponseArray === void 0 ? void 0 : fullResponseArray.response) {
console.log('Keys of fullResponseArray.response:', Object.keys(fullResponseArray.response));
if (fullResponseArray.response.items) {
console.log('First item in fullResponseArray.response.items:', JSON.stringify((_b = (_a = fullResponseArray.response.items) === null || _a === void 0 ? void 0 : _a[0]) !== null && _b !== void 0 ? _b : 'items missing or empty', null, 2));
}
else {
console.log('fullResponseArray.response.items does not exist.');
}
}
else {
console.log('fullResponseArray.response does not exist.');
}
const campaignItems = (_d = (_c = fullResponseArray === null || fullResponseArray === void 0 ? void 0 : fullResponseArray.response) === null || _c === void 0 ? void 0 : _c.items) !== null && _d !== void 0 ? _d : [];
const fieldsToKeep = outputFieldsRaw
.split(',')
.map((f) => f.trim())
.filter((f) => f);
console.log('--- Kadam GetCampaigns Debug ---');
console.log('Output Fields Raw:', outputFieldsRaw);
console.log('Fields to Keep:', fieldsToKeep);
console.log('Applying filter:', fieldsToKeep.length > 0);
console.log('Number of extracted campaignItems:', campaignItems.length);
console.log('------------------------------');
if (campaignItems.length > 0) {
if (fieldsToKeep.length > 0) {
const filteredCampaigns = campaignItems.map((item) => {
const filteredCampaign = {};
for (const path of fieldsToKeep) {
const value = getValueByPath(item, path);
if (value !== undefined) {
setValueByPath(filteredCampaign, path, value);
}
}
return filteredCampaign;
});
console.log('--- Final Check Before Return (Filtering Applied) ---');
console.log('Returning filteredCampaigns (first item):', JSON.stringify((_e = filteredCampaigns === null || filteredCampaigns === void 0 ? void 0 : filteredCampaigns[0]) !== null && _e !== void 0 ? _e : 'Empty or undefined'));
console.log('Total items in filteredCampaigns:', filteredCampaigns === null || filteredCampaigns === void 0 ? void 0 : filteredCampaigns.length);
const executionData = filteredCampaigns.map((item) => ({ json: item }));
return executionData;
}
}
console.log('--- Final Check Before Return (No Filtering Applied or No Items) ---');
console.log('Returning campaignItems (first item):', JSON.stringify((_f = campaignItems === null || campaignItems === void 0 ? void 0 : campaignItems[0]) !== null && _f !== void 0 ? _f : 'Empty or undefined'));
console.log('Total items in campaignItems:', campaignItems === null || campaignItems === void 0 ? void 0 : campaignItems.length);
const executionData = campaignItems.map((item) => ({ json: item }));
return executionData;
}
function getValueByPath(obj, path) {
const keys = path.split('.');
let current = obj;
for (const key of keys) {
if (current === null || typeof current !== 'object' || !Object.prototype.hasOwnProperty.call(current, key)) {
return undefined;
}
current = current[key];
}
return current;
}
function setValueByPath(obj, path, value) {
const keys = path.split('.');
let current = obj;
for (let i = 0; i < keys.length - 1; i++) {
const key = keys[i];
if (current[key] === undefined || typeof current[key] !== 'object' || current[key] === null) {
current[key] = {};
}
current = current[key];
}
const finalKey = keys[keys.length - 1];
current[finalKey] = value;
}
async function getCampaignCategories(i, baseUrl, headers, appId) {
const params = {
app_id: appId,
ad_format: this.getNodeParameter('adFormat', i),
category_id: this.getNodeParameter('categoryId', i, null),
};
const response = await utils_1.makeApiRequest.call(this, 'get', `${baseUrl}/ads.campaigns.categories.get`, headers, params);
if ((0, utils_1.isContinueOnFailError)(response)) {
return { json: response };
}
else {
return { json: response };
}
}
async function getAdFormats(i, baseUrl, headers, appId) {
this.logger.debug(`Getting ad formats with app_id: ${appId}`);
const response = await utils_1.makeApiRequest.call(this, 'get', `${baseUrl}/ads.campaigns.formats.get`, headers, { app_id: appId });
if ((0, utils_1.isContinueOnFailError)(response)) {
return [{ json: response }];
}
let responseData;
if (response && typeof response === 'object' && 'response' in response &&
response.response && typeof response.response === 'object') {
if ('items' in response.response) {
responseData = response.response.items;
}
else if ('formats' in response.response) {
responseData = response.response.formats;
}
else {
responseData = response.response;
}
}
else {
responseData = response;
}
return [{ json: responseData }];
}
async function updatePlacementMultiplier(i, baseUrl, headers, appId) {
const campaignId = this.getNodeParameter('campaignId', i);
const multiplier = this.getNodeParameter('multiplier', i, 1);
const placement = this.getNodeParameter('placement', i);
if (!campaignId || campaignId.trim() === '') {
throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'Campaign ID parameter cannot be empty for Update Placement Multiplier.', { itemIndex: i });
}
if (!placement || placement.trim() === '') {
throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'Placement ID parameter cannot be empty for Update Placement Multiplier.', { itemIndex: i });
}
const formattedMultiplier = `x${multiplier}`;
const params = {
app_id: appId,
campaign_id: campaignId.trim(),
multiplier: formattedMultiplier,
placement: placement.trim(),
};
const endpoint = `${baseUrl}/ads.stats.campaign.placement.put`;
const urlWithParams = `${endpoint}?app_id=${encodeURIComponent(params.app_id)}&campaign_id=${encodeURIComponent(params.campaign_id)}&multiplier=${encodeURIComponent(params.multiplier)}&placement=${encodeURIComponent(params.placement)}`;
this.logger.debug(`Calling makeApiRequest (GET) for updatePlacementMultiplier with URL: ${urlWithParams}`);
this.logger.debug(`Headers being sent: ${JSON.stringify(headers)}`);
const response = await utils_1.makeApiRequest.call(this, 'get', urlWithParams, headers, undefined);
let requestData;
if (response && typeof response === 'object' && 'response' in response &&
response.response && typeof response.response === 'object' && 'request' in response.response) {
requestData = response.response.request;
}
else if (response && typeof response === 'object' && 'request' in response) {
requestData = response.request;
}
else {
requestData = response;
}
return [{ json: requestData }];
}
//# sourceMappingURL=campaigns.js.map