/* eslint-disable max-len */
/* eslint-disable camelcase, no-underscore-dangle, no-unneeded-ternary, brace-style */
const qs = require('qs');
const { AbortController } = require('node-abort-controller');
const helpers = require('../../utils/helpers');
// Create URL from supplied path and options
function createCampaignsUrl(path, options, additionalQueryParams = {}, apiVersion = 'v1') {
const {
apiKey,
serviceUrl,
version,
} = options;
let queryParams = {
c: version,
...additionalQueryParams,
};
// Validate path is provided
if (!path || typeof path !== 'string') {
throw new Error('path is a required parameter of type string');
}
queryParams.key = apiKey;
queryParams = helpers.cleanParams(queryParams);
const queryString = qs.stringify(queryParams, { indices: false });
const encodedPath = path.split('/').map(encodeURIComponent).join('/');
return `${serviceUrl}/${encodeURIComponent(apiVersion)}/${encodedPath}?${queryString}`;
}
/**
* Interface to searchandising campaign related API calls
*
* @module searchandising/campaigns
* @inner
* @returns {object}
*/
class Campaigns {
constructor(options) {
this.options = options || {};
}
/**
* Retrieve campaigns
*
* @function retrieveCampaigns
* @param {object} [parameters] - Additional parameters for retrieving campaigns
* @param {string} [parameters.section='Products'] - The section of the index to use
* @param {number|number[]} [parameters.id] - The ID(s) of campaigns to filter by
* @param {string[]} [parameters.refinedQueries] - A list of refined queries to filter by
* @param {object} [parameters.refinedFilters] - An object of refined filters to filter by
* @param {object} [parameters.refinedRecommendationContexts] - A filter for refined recommendation contexts
* @param {number} [parameters.numResultsPerPage=20] - The number of campaigns to return - maximum value 100
* @param {number} [parameters.page] - The page of results to return
* @param {number} [parameters.offset] - The number of results to skip from the beginning - cannot be used together with `page`
* @param {object} [networkParameters] - Parameters relevant to the network request
* @param {number} [networkParameters.timeout] - Request timeout (in milliseconds)
* @returns {Promise}
* @see https://docs.constructor.com/reference/v1-searchandising-retrieve-campaigns
* @example
* constructorio.searchandising.campaigns.retrieveCampaigns({
* section: 'Products',
* numResultsPerPage: 50,
* page: 1,
* });
*/
retrieveCampaigns(parameters = {}, networkParameters = {}) {
const queryParams = {};
let requestUrl;
const { fetch } = this.options;
const controller = new AbortController();
const { signal } = controller;
const headers = {
'Content-Type': 'application/json',
};
if (parameters) {
const {
section,
id,
refined_filters,
refinedFilters = refined_filters,
num_results_per_page,
numResultsPerPage = num_results_per_page,
page,
offset,
refined_recommendation_contexts,
refinedRecommendationContexts = refined_recommendation_contexts,
refined_queries,
refinedQueries = refined_queries,
} = parameters;
if (section) {
queryParams.section = section;
}
if (id) {
queryParams.id = id;
}
if (refinedFilters) {
queryParams.refined_filters = refinedFilters;
}
if (numResultsPerPage) {
queryParams.num_results_per_page = numResultsPerPage;
}
if (page) {
queryParams.page = page;
}
if (offset) {
queryParams.offset = offset;
}
if (refinedRecommendationContexts) {
queryParams.refined_recommendation_contexts = refinedRecommendationContexts;
}
if (refinedQueries) {
queryParams.refined_queries = refinedQueries;
}
}
try {
requestUrl = createCampaignsUrl('campaigns', this.options, queryParams);
} catch (e) {
return Promise.reject(e);
}
Object.assign(headers, helpers.combineCustomHeaders(this.options, networkParameters));
helpers.applyNetworkTimeout(this.options, networkParameters, controller);
return fetch(requestUrl, {
method: 'GET',
headers: {
...headers,
...helpers.createAuthHeader(this.options),
},
signal,
}).then((response) => {
if (response.ok) {
return response.json();
}
return helpers.throwHttpErrorFromResponse(new Error(), response);
}).then((json) => json);
}
/**
* Retrieve a campaign given a specific id
*
* @function retrieveCampaign
* @param {object} parameters - Additional parameters for retrieving a campaign
* @param {number} parameters.id - The ID of the campaign to be retrieved
* @param {string} [parameters.section='Products'] - The section of the index to use
* @param {object} [networkParameters] - Parameters relevant to the network request
* @param {number} [networkParameters.timeout] - Request timeout (in milliseconds)
* @returns {Promise}
* @see https://docs.constructor.com/reference/v1-searchandising-retrieve-campaign
* @example
* constructorio.searchandising.campaigns.retrieveCampaign({
* id: 42,
* section: 'Products',
* });
*/
retrieveCampaign(parameters = {}, networkParameters = {}) {
const queryParams = {};
let requestUrl;
const { fetch } = this.options;
const controller = new AbortController();
const { signal } = controller;
const headers = {
'Content-Type': 'application/json',
};
const { id, section } = parameters;
if (section) {
queryParams.section = section;
}
try {
requestUrl = createCampaignsUrl(`campaigns/${id}`, this.options, queryParams);
} catch (e) {
return Promise.reject(e);
}
Object.assign(headers, helpers.combineCustomHeaders(this.options, networkParameters));
helpers.applyNetworkTimeout(this.options, networkParameters, controller);
return fetch(requestUrl, {
method: 'GET',
headers: {
...headers,
...helpers.createAuthHeader(this.options),
},
signal,
}).then((response) => {
if (response.ok) {
return response.json();
}
return helpers.throwHttpErrorFromResponse(new Error(), response);
}).then((json) => json);
}
/**
* Create a campaign
*
* @function createCampaign
* @param {object} parameters - Additional parameters for the campaign to be created
* @param {string} parameters.name - The name of the campaign
* @param {string} [parameters.section='Products'] - The section of the index to use
* @param {string} [parameters.description] - The description of the campaign
* @param {string} [parameters.requestTagName] - Request tag name used to activate this campaign for, used only with `request_tag_value`
* @param {string} [parameters.requestTagValue] - Request tag value used to activate this campaign for, used only with `request_tag_name`
* @param {string} [parameters.startTime] - The start time of the campaign (ISO 8601 date-time)
* @param {string} [parameters.endTime] - The end time of the campaign (ISO 8601 date-time)
* @param {object[]} [parameters.refinedQueries] - A list of refined queries
* @param {object[]} [parameters.refinedFilters] - A list of refined filters
* @param {object[]} [parameters.refinedRecommendationContexts] - A list of refined recommendation contexts
* @param {object[]} [parameters.boostRules] - A list of boost rules
* @param {object[]} [parameters.blacklistRules] - A list of blacklist rules
* @param {object[]} [parameters.slotRules] - A list of slot rules
* @param {object[]} [parameters.contentRules] - A list of content rules
* @param {object[]} [parameters.filtersSlotRules] - A list of filters slot rules
* @param {object} [parameters.whitelistRule] - A whitelist rule
* @param {object} [parameters.variationSlicingRule] - A variation slicing rule
* @param {object} [parameters.metadataJson] - Metadata related to the campaign
* @param {object} [networkParameters] - Parameters relevant to the network request
* @param {number} [networkParameters.timeout] - Request timeout (in milliseconds)
* @returns {Promise}
* @see https://docs.constructor.com/reference/v1-searchandising-create-campaign
* @example
* constructorio.searchandising.campaigns.createCampaign({
* name: 'Spring Sale',
* section: 'Products',
* description: 'Seasonal promotion campaign',
* boostRules: [
* { rule_type: 'boost', rule: { boost: 5, filters: { brand: ['Nike'] } } },
* ],
* });
*/
createCampaign(parameters = {}, networkParameters = {}) {
const queryParams = {};
let requestUrl;
const { fetch } = this.options;
const controller = new AbortController();
const { signal } = controller;
const headers = {
'Content-Type': 'application/json',
};
const { section, ...body } = parameters;
if (section) {
queryParams.section = section;
}
try {
requestUrl = createCampaignsUrl('campaigns', this.options, queryParams);
} catch (e) {
return Promise.reject(e);
}
Object.assign(headers, helpers.combineCustomHeaders(this.options, networkParameters));
helpers.applyNetworkTimeout(this.options, networkParameters, controller);
return fetch(requestUrl, {
method: 'POST',
body: JSON.stringify(helpers.toSnakeCaseKeys(body, false)),
headers: {
...headers,
...helpers.createAuthHeader(this.options),
},
signal,
}).then((response) => {
if (response.ok) {
return response.json();
}
return helpers.throwHttpErrorFromResponse(new Error(), response);
}).then((json) => json);
}
/**
* Update a campaign - only the fields present in the request will be updated
*
* @function updateCampaign
* @param {object} parameters - Additional parameters for the campaign to be updated
* @param {number} parameters.id - The ID of the campaign to be updated
* @param {string} [parameters.section='Products'] - The section of the index to use
* @param {string} [parameters.name] - The name of the campaign
* @param {string} [parameters.description] - The description of the campaign
* @param {string} [parameters.requestTagName] - Request tag name used to activate this campaign for, used only with `request_tag_value`
* @param {string} [parameters.requestTagValue] - Request tag value used to activate this campaign for, used only with `request_tag_name`
* @param {string} [parameters.startTime] - The start time of the campaign (ISO 8601 date-time)
* @param {string} [parameters.endTime] - The end time of the campaign (ISO 8601 date-time)
* @param {object[]} [parameters.refinedQueries] - A list of refined queries
* @param {object[]} [parameters.refinedFilters] - A list of refined filters
* @param {object[]} [parameters.refinedRecommendationContexts] - A list of refined recommendation contexts
* @param {object[]} [parameters.boostRules] - A list of boost rules
* @param {object[]} [parameters.blacklistRules] - A list of blacklist rules
* @param {object[]} [parameters.slotRules] - A list of slot rules
* @param {object[]} [parameters.contentRules] - A list of content rules
* @param {object[]} [parameters.filtersSlotRules] - A list of filters slot rules
* @param {object} [parameters.whitelistRule] - A whitelist rule
* @param {object} [parameters.variationSlicingRule] - A variation slicing rule
* @param {object} [parameters.metadataJson] - Metadata related to the campaign
* @param {object} [networkParameters] - Parameters relevant to the network request
* @param {number} [networkParameters.timeout] - Request timeout (in milliseconds)
* @returns {Promise}
* @see https://docs.constructor.com/reference/v1-searchandising-update-campaign
* @example
* constructorio.searchandising.campaigns.updateCampaign({
* id: 42,
* name: 'Spring Sale - Updated',
* description: 'Updated seasonal promotion campaign',
* });
*/
updateCampaign(parameters = {}, networkParameters = {}) {
const queryParams = {};
let requestUrl;
const { fetch } = this.options;
const controller = new AbortController();
const { signal } = controller;
const headers = {
'Content-Type': 'application/json',
};
const { id, section, ...body } = parameters;
if (section) {
queryParams.section = section;
}
try {
requestUrl = createCampaignsUrl(`campaigns/${id}`, this.options, queryParams);
} catch (e) {
return Promise.reject(e);
}
Object.assign(headers, helpers.combineCustomHeaders(this.options, networkParameters));
helpers.applyNetworkTimeout(this.options, networkParameters, controller);
return fetch(requestUrl, {
method: 'PATCH',
body: JSON.stringify(helpers.toSnakeCaseKeys(body, false)),
headers: {
...headers,
...helpers.createAuthHeader(this.options),
},
signal,
}).then((response) => {
if (response.ok) {
return response.json();
}
return helpers.throwHttpErrorFromResponse(new Error(), response);
}).then((json) => json);
}
/**
* Delete a campaign given a specific id
*
* @function deleteCampaign
* @param {object} parameters - Additional parameters for the campaign to be deleted
* @param {number} parameters.id - The ID of the campaign to be deleted
* @param {string} [parameters.section='Products'] - The section of the index to use
* @param {object} [networkParameters] - Parameters relevant to the network request
* @param {number} [networkParameters.timeout] - Request timeout (in milliseconds)
* @returns {Promise}
* @see https://docs.constructor.com/reference/v1-searchandising-delete-campaign
* @example
* constructorio.searchandising.campaigns.deleteCampaign({
* id: 42,
* section: 'Products',
* });
*/
deleteCampaign(parameters = {}, networkParameters = {}) {
const queryParams = {};
let requestUrl;
const { fetch } = this.options;
const controller = new AbortController();
const { signal } = controller;
const headers = {
'Content-Type': 'application/json',
};
const { id, section } = parameters;
if (section) {
queryParams.section = section;
}
try {
requestUrl = createCampaignsUrl(`campaigns/${id}`, this.options, queryParams);
} catch (e) {
return Promise.reject(e);
}
Object.assign(headers, helpers.combineCustomHeaders(this.options, networkParameters));
helpers.applyNetworkTimeout(this.options, networkParameters, controller);
return fetch(requestUrl, {
method: 'DELETE',
headers: {
...headers,
...helpers.createAuthHeader(this.options),
},
signal,
}).then((response) => {
if (response.ok) {
return Promise.resolve();
}
return helpers.throwHttpErrorFromResponse(new Error(), response);
});
}
}
module.exports = Campaigns;