Skip to content

Commit

Permalink
fix: (strf-8745) move common headers inside sendApiRequest and refact…
Browse files Browse the repository at this point in the history
…or NetworkUtils
  • Loading branch information
MaxGenash committed Dec 7, 2020
1 parent 5ee6138 commit 21a3522
Show file tree
Hide file tree
Showing 9 changed files with 336 additions and 104 deletions.
6 changes: 4 additions & 2 deletions lib/stencil-download.utils.js
Original file line number Diff line number Diff line change
@@ -1,15 +1,17 @@
const tmp = require('tmp-promise');
const { extractZipFiles } = require('./archiveManager');
const { fetchFile } = require('./utils/networkUtils');
const NetworkUtils = require('./utils/NetworkUtils');
const themeApiClient = require('./theme-api-client');

const networkUtils = new NetworkUtils();

const utils = {};

utils.downloadThemeFiles = async (options) => {
const { path: tempThemePath, cleanup } = await tmp.file();

try {
await fetchFile(options.downloadUrl, tempThemePath);
await networkUtils.fetchFile(options.downloadUrl, tempThemePath);
} catch (err) {
throw new Error(
`Unable to download theme files from ${options.downloadUrl}: ${err.message}`,
Expand Down
5 changes: 3 additions & 2 deletions lib/stencil-push.utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,9 @@ const Bundle = require('./stencil-bundle');
const themeApiClient = require('./theme-api-client');
const ThemeConfig = require('./theme-config');
const StencilConfigManager = require('./StencilConfigManager');
const { sendApiRequest } = require('./utils/networkUtils');
const NetworkUtils = require('./utils/NetworkUtils');

const networkUtils = new NetworkUtils();
const themeConfigManager = ThemeConfig.getInstance(THEME_PATH);
const stencilConfigManager = new StencilConfigManager();
const utils = {};
Expand Down Expand Up @@ -47,7 +48,7 @@ utils.getStoreHash = async (options) => {

try {
const url = `https://${storeUrlObj.host}/admin/oauth/info`;
const response = await sendApiRequest({ url });
const response = await networkUtils.sendApiRequest({ url });
if (!response.data || !response.data.store_hash) {
throw new Error('Received empty store_hash value in the server response');
}
Expand Down
8 changes: 3 additions & 5 deletions lib/stencil-start.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,12 @@ const ThemeConfig = require('./theme-config');
const BuildConfigManager = require('./BuildConfigManager');
const fsUtilsModule = require('./utils/fsUtils');
const cliCommonModule = require('./cliCommon');
const networkUtilsModule = require('./utils/networkUtils');
const NetworkUtils = require('./utils/NetworkUtils');

class StencilStart {
constructor({
browserSync = BrowserSync.create(),
networkUtils = networkUtilsModule,
networkUtils = new NetworkUtils(),
fs = fsModule,
fsUtils = fsUtilsModule,
cliCommon = cliCommonModule,
Expand Down Expand Up @@ -99,9 +99,7 @@ class StencilStart {
const url = new URL(`/stencil-version-check?v=${currentCliVersion}`, staplerUrl).toString();
let payload;

const headers = {
'stencil-cli': currentCliVersion,
};
const headers = {};
if (stencilConfig.staplerUrl) {
headers['stencil-store-url'] = stencilConfig.normalStoreUrl;
}
Expand Down
6 changes: 3 additions & 3 deletions lib/stencil-start.spec.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
const axios = require('axios');
const MockAdapter = require('axios-mock-adapter');
const path = require('path');

const StencilStart = require('./stencil-start');
Expand All @@ -11,7 +9,9 @@ describe('StencilStart unit tests', () => {
watch: jest.fn(),
init: jest.fn(),
});
const getNetworkUtilsStub = () => new MockAdapter(axios);
const getNetworkUtilsStub = () => ({
sendApiRequest: jest.fn(),
});
const getFsStub = () => ({
existsSync: jest.fn(),
});
Expand Down
59 changes: 21 additions & 38 deletions lib/theme-api-client.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@ require('colors');
const fs = require('fs');
const path = require('path');
const FormData = require('form-data');
const { sendApiRequest } = require('./utils/networkUtils');
const NetworkUtils = require('./utils/NetworkUtils');

const networkUtils = new NetworkUtils();

/**
* @param {object} options
Expand All @@ -14,14 +16,13 @@ const { sendApiRequest } = require('./utils/networkUtils');
*/
async function activateThemeByVariationId({ variationId, apiHost, storeHash, accessToken }) {
try {
return await sendApiRequest({
return await networkUtils.sendApiRequest({
url: `${apiHost}/stores/${storeHash}/v3/themes/actions/activate`,
headers: {
'x-auth-client': 'stencil-cli',
'x-auth-token': accessToken,
'content-type': 'application/json',
},
method: 'POST',
accessToken,
data: {
variation_id: variationId,
which: 'original',
Expand All @@ -45,12 +46,9 @@ async function activateThemeByVariationId({ variationId, apiHost, storeHash, acc
* @returns {Promise<void>}
*/
async function deleteThemeById({ themeId, accessToken, apiHost, storeHash }) {
return sendApiRequest({
return networkUtils.sendApiRequest({
url: `${apiHost}/stores/${storeHash}/v3/themes/${themeId}`,
headers: {
'x-auth-client': 'stencil-cli',
'x-auth-token': accessToken,
},
accessToken,
method: 'DELETE',
});
}
Expand All @@ -68,13 +66,12 @@ async function getJob({ accessToken, apiHost, storeHash, jobId, resultFilter })
let response;
let payload;
try {
response = await sendApiRequest({
response = await networkUtils.sendApiRequest({
url: `${apiHost}/stores/${storeHash}/v3/themes/jobs/${jobId}`,
headers: {
'cache-control': 'no-cache',
'x-auth-client': 'stencil-cli',
'x-auth-token': accessToken,
},
accessToken,
validateStatus: () => true, // Wanna handle the statuses manually later
});
payload = response.data;
Expand Down Expand Up @@ -106,12 +103,9 @@ async function getJob({ accessToken, apiHost, storeHash, jobId, resultFilter })
* @returns {Promise<object[]>}
*/
async function getThemes({ accessToken, apiHost, storeHash }) {
const response = await sendApiRequest({
const response = await networkUtils.sendApiRequest({
url: `${apiHost}/stores/${storeHash}/v3/themes`,
headers: {
'x-auth-client': 'stencil-cli',
'x-auth-token': accessToken,
},
accessToken,
});
return response.data.data;
}
Expand All @@ -126,12 +120,9 @@ async function getThemes({ accessToken, apiHost, storeHash }) {
*/
async function getChannelActiveTheme({ accessToken, apiHost, storeHash, channelId }) {
try {
const response = await sendApiRequest({
const response = await networkUtils.sendApiRequest({
url: `${apiHost}/stores/${storeHash}/v3/channels/${channelId}/active-theme`,
headers: {
'x-auth-client': 'stencil-cli',
'x-auth-token': accessToken,
},
accessToken,
});
return response.data.data;
} catch (err) {
Expand All @@ -158,12 +149,9 @@ async function getThemeConfiguration({
configurationId,
}) {
try {
const response = await sendApiRequest({
const response = await networkUtils.sendApiRequest({
url: `${apiHost}/stores/${storeHash}/v3/themes/${themeId}/configurations?uuid:in=${configurationId}`,
headers: {
'x-auth-client': 'stencil-cli',
'x-auth-token': accessToken,
},
accessToken,
});
// If configurations array is empty, the theme ID was valid but the configuration ID was not
if (!response.data || !response.data.data.length) {
Expand All @@ -187,12 +175,9 @@ async function getThemeConfiguration({
*/
async function getVariationsByThemeId({ accessToken, apiHost, storeHash, themeId }) {
try {
const response = await sendApiRequest({
const response = await networkUtils.sendApiRequest({
url: `${apiHost}/stores/${storeHash}/v3/themes/${themeId}`,
headers: {
'x-auth-client': 'stencil-cli',
'x-auth-token': accessToken,
},
accessToken,
});
return response.data.data.variations;
} catch (err) {
Expand All @@ -215,16 +200,15 @@ async function postTheme({ bundleZipPath, accessToken, apiHost, storeHash }) {
filename: path.basename(bundleZipPath),
});

const response = await sendApiRequest({
const response = await networkUtils.sendApiRequest({
url: `${apiHost}/stores/${storeHash}/v3/themes`,
method: 'POST',
data: formData,
headers: {
...formData.getHeaders(),
'cache-control': 'no-cache',
'x-auth-token': accessToken,
'x-auth-client': 'stencil-cli',
},
accessToken,
validateStatus: () => true, // Wanna handle the statuses manually later
});
const payload = response.data;
Expand Down Expand Up @@ -265,14 +249,13 @@ async function postTheme({ bundleZipPath, accessToken, apiHost, storeHash }) {
*/
async function downloadTheme({ accessToken, apiHost, storeHash, themeId }) {
try {
const response = await sendApiRequest({
const response = await networkUtils.sendApiRequest({
url: `${apiHost}/stores/${storeHash}/v3/themes/${themeId}/actions/download`,
headers: {
'cache-control': 'no-cache',
'x-auth-token': accessToken,
'x-auth-client': 'stencil-cli',
'content-type': 'application/json',
},
accessToken,
method: 'POST',
data: {
which: 'last_activated',
Expand Down
74 changes: 74 additions & 0 deletions lib/utils/NetworkUtils.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
/**
* @module Contains helpers functions for working with network requests
*/

const https = require('https');
const fsModule = require('fs');
const axios = require('axios');

const { PACKAGE_INFO } = require('../../constants');

const defaultHttpsAgent = new https.Agent({ rejectUnauthorized: false });

class NetworkUtils {
constructor({
fs = fsModule,
httpsAgent = defaultHttpsAgent,
reqLibrary = axios,
packageInfo = PACKAGE_INFO,
} = {}) {
this._fs = fs;
this._httpsAgent = httpsAgent;
this._reqLibrary = reqLibrary;
this._packageInfo = packageInfo;
}

/** Used to send request to our (Bigcommerce) servers only.
* Shouldn't be used to send requests to third party servers because we disable https checks
*
* @param {object} options
* @param {string} options.url
* @param {object} [options.headers]
* @param {string} [options.accessToken]
* @returns {Promise<object>}
*/
async sendApiRequest(options) {
const { accessToken, ...restOpts } = options;
const reqConfig = {
httpsAgent: this._httpsAgent,
...restOpts,
headers: {
'x-auth-client': 'stencil-cli',
'stencil-cli': this._packageInfo.version,
'stencil-version': this._packageInfo.config.stencil_version,
...(restOpts.headers || {}),
},
};
if (accessToken) {
reqConfig.headers['x-auth-token'] = accessToken;
}

return this._reqLibrary(reqConfig);
}

/**
* @param {string} url
* @param {string} outputPath
* @returns {Promise<any>}
*/
async fetchFile(url, outputPath) {
const response = await this.sendApiRequest({
url,
responseType: 'stream',
});

return new Promise((resolve, reject) => {
response.data
.pipe(this._fs.createWriteStream(outputPath))
.on('finish', resolve)
.on('error', reject);
});
}
}

module.exports = NetworkUtils;
Loading

0 comments on commit 21a3522

Please sign in to comment.