diff --git a/bin/paragon-scripts.js b/bin/paragon-scripts.js index dbc9329699..8b35a7c5a4 100755 --- a/bin/paragon-scripts.js +++ b/bin/paragon-scripts.js @@ -5,6 +5,7 @@ const helpCommand = require('../lib/help'); const buildTokensCommand = require('../lib/build-tokens'); const replaceVariablesCommand = require('../lib/replace-variables'); const buildScssCommand = require('../lib/build-scss'); +const { sendTrackInfo } = require('../utils'); const COMMANDS = { /** @@ -181,9 +182,11 @@ const COMMANDS = { try { await executor.executor(commandArgs); + sendTrackInfo('openedx.paragon.cli-command.used', { command, status: 'success' }); } catch (error) { // eslint-disable-next-line no-console console.error(chalk.red.bold('An error occurred:', error.message)); + sendTrackInfo('openedx.paragon.cli-command.used', { command, status: 'error', errorMsg: error.message }); process.exit(1); } })(); diff --git a/component-generator/index.js b/component-generator/index.js index f27712a22e..7f37f7bf9b 100644 --- a/component-generator/index.js +++ b/component-generator/index.js @@ -4,17 +4,17 @@ const path = require('path'); const { COMPONENT_FILES } = require('./constants'); const { validateComponentName, - sendTrackInfo, createFile, addComponentToExports, addComponentToGit, } = require('./utils'); +const { sendTrackInfo } = require('../utils'); program .argument('', 'Component must have a name', validateComponentName) .action((componentName) => { // send data to analytics - sendTrackInfo(componentName); + sendTrackInfo('openedx.paragon.functions.track-generate-component.created', { componentName }); const componentDir = path.resolve(__dirname, `../src/${componentName}`); // create directory for the component files fs.mkdirSync(componentDir); diff --git a/component-generator/utils.js b/component-generator/utils.js index 5d4b4c2585..f742c3bff5 100644 --- a/component-generator/utils.js +++ b/component-generator/utils.js @@ -1,7 +1,6 @@ const { InvalidOptionArgumentError } = require('commander'); const fs = require('fs'); const path = require('path'); -const axios = require('axios'); const { exec } = require('child_process'); require('dotenv').config(); @@ -32,25 +31,6 @@ function validateComponentName(value) { return value; } -/** - * Sends request to the Netlify function to inform about generate-component usage. - * @param {string} componentName - component name - */ -function sendTrackInfo(componentName) { - const { BASE_URL, TRACK_ANONYMOUS_ANALYTICS } = process.env; - if (TRACK_ANONYMOUS_ANALYTICS) { - const url = `${BASE_URL}/.netlify/functions/trackGenerateComponent`; - axios.post(url, { componentName }) - .then(result => { - // eslint-disable-next-line no-console - console.log(`Track info is successfully sent (status ${result.status})`); - }).catch(error => { - // eslint-disable-next-line no-console - console.log(`Track info request failed (${error})`); - }); - } -} - /** * Creates a file for the component based on the template. * Note that 'componentName' string is a reserved placeholder, @@ -97,7 +77,6 @@ function addComponentToGit(componentName) { } exports.validateComponentName = validateComponentName; -exports.sendTrackInfo = sendTrackInfo; exports.createFile = createFile; exports.addComponentToExports = addComponentToExports; exports.addComponentToGit = addComponentToGit; diff --git a/package-lock.json b/package-lock.json index 82e76fc866..3c1fc40fd0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -19,6 +19,7 @@ "@fortawesome/fontawesome-svg-core": "^6.1.1", "@fortawesome/react-fontawesome": "^0.1.18", "@popperjs/core": "^2.11.4", + "axios": "^0.27.2", "bootstrap": "^4.6.2", "chalk": "^4.1.2", "child_process": "^1.0.2", @@ -75,7 +76,6 @@ "@types/uuid": "^9.0.0", "@typescript-eslint/eslint-plugin": "^5.22.0", "@typescript-eslint/parser": "^5.22.0", - "axios": "^0.27.2", "axios-mock-adapter": "^1.21.1", "babel-jest": "^28.1.2", "babel-loader": "^8.2.4", @@ -9685,7 +9685,8 @@ }, "node_modules/axios": { "version": "0.27.2", - "license": "MIT", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.27.2.tgz", + "integrity": "sha512-t+yRIyySRTp/wua5xEr+z1q60QmLq8ABsS5O9Me1AsE5dfKqgnCFzwiCZZ/cGNd1lq4/7akDWMxdhVlucjmnOQ==", "dependencies": { "follow-redirects": "^1.14.9", "form-data": "^4.0.0" @@ -12809,42 +12810,6 @@ "node": "*" } }, - "node_modules/cheerio": { - "version": "1.0.0-rc.12", - "dev": true, - "license": "MIT", - "dependencies": { - "cheerio-select": "^2.1.0", - "dom-serializer": "^2.0.0", - "domhandler": "^5.0.3", - "domutils": "^3.0.1", - "htmlparser2": "^8.0.1", - "parse5": "^7.0.0", - "parse5-htmlparser2-tree-adapter": "^7.0.0" - }, - "engines": { - "node": ">= 6" - }, - "funding": { - "url": "https://github.com/cheeriojs/cheerio?sponsor=1" - } - }, - "node_modules/cheerio-select": { - "version": "2.1.0", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "boolbase": "^1.0.0", - "css-select": "^5.1.0", - "css-what": "^6.1.0", - "domelementtype": "^2.3.0", - "domhandler": "^5.0.3", - "domutils": "^3.0.1" - }, - "funding": { - "url": "https://github.com/sponsors/fb55" - } - }, "node_modules/child_process": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/child_process/-/child_process-1.0.2.tgz", diff --git a/package.json b/package.json index a72e74374e..7e8b280789 100644 --- a/package.json +++ b/package.json @@ -52,6 +52,7 @@ "@fortawesome/fontawesome-svg-core": "^6.1.1", "@fortawesome/react-fontawesome": "^0.1.18", "@popperjs/core": "^2.11.4", + "axios": "^0.27.2", "bootstrap": "^4.6.2", "chalk": "^4.1.2", "child_process": "^1.0.2", @@ -110,7 +111,6 @@ "@types/uuid": "^9.0.0", "@typescript-eslint/eslint-plugin": "^5.22.0", "@typescript-eslint/parser": "^5.22.0", - "axios": "^0.27.2", "axios-mock-adapter": "^1.21.1", "babel-jest": "^28.1.2", "babel-loader": "^8.2.4", diff --git a/utils.js b/utils.js new file mode 100644 index 0000000000..667932a4e8 --- /dev/null +++ b/utils.js @@ -0,0 +1,23 @@ +const axios = require('axios'); + +/** + * Sends request to the Netlify function to inform about specified event. + * @param {string} eventId - tracking event id + * @param {object} properties - tracking properties + */ +function sendTrackInfo(eventId, properties) { + const { BASE_URL, TRACK_ANONYMOUS_ANALYTICS } = process.env; + if (TRACK_ANONYMOUS_ANALYTICS) { + const url = `${BASE_URL}/.netlify/functions/sendTrackData`; + axios.post(url, { eventId, properties }) + .then(result => { + // eslint-disable-next-line no-console + console.log(`Track info is successfully sent (status ${result.status})`); + }).catch(error => { + // eslint-disable-next-line no-console + console.log(`Track info request failed (${error})`); + }); + } +} + +module.exports = { sendTrackInfo }; diff --git a/www/netlify/functions/sendAnalyticsData.js b/www/netlify/functions/sendAnalyticsData.js new file mode 100644 index 0000000000..964bf57869 --- /dev/null +++ b/www/netlify/functions/sendAnalyticsData.js @@ -0,0 +1,23 @@ +const { v4: uuidv4 } = require('uuid'); +const Analytics = require('analytics-node'); + +const analytics = new Analytics(process.env.SEGMENT_KEY); + +exports.handler = async function eventHandler(event) { + // Only allow POST + if (event.httpMethod !== 'POST') { + return { statusCode: 405, body: 'Method Not Allowed' }; + } + const { eventId, properties } = JSON.parse(event.body); + // dispatch event to Segment + analytics.track({ + anonymousId: uuidv4(), + event: eventId, + properties, + }); + + return { + statusCode: 200, + body: JSON.stringify({ success: true }), + }; +}; diff --git a/www/netlify/functions/trackGenerateComponent.js b/www/netlify/functions/trackGenerateComponent.js index b0b29ed3b3..8090e88369 100644 --- a/www/netlify/functions/trackGenerateComponent.js +++ b/www/netlify/functions/trackGenerateComponent.js @@ -1,23 +1,12 @@ -const { v4: uuidv4 } = require('uuid'); -const Analytics = require('analytics-node'); - -const analytics = new Analytics(process.env.SEGMENT_KEY); +const { handler: actualHandler } = require('./sendAnalyticsData'); exports.handler = async function eventHandler(event) { - // Only allow POST - if (event.httpMethod !== 'POST') { - return { statusCode: 405, body: 'Method Not Allowed' }; - } - const { componentName } = JSON.parse(event.body); - // dispatch event to Segment - analytics.track({ - anonymousId: uuidv4(), - event: 'openedx.paragon.functions.track-generate-component.created', - properties: { componentName }, + const body = JSON.parse(event.body); + event.body = JSON.stringify({ + ...body, + eventId: 'openedx.paragon.functions.track-generate-component.created', + properties: { componentName: body.componentName }, }); - return { - statusCode: 200, - body: JSON.stringify({ success: true }), - }; + return actualHandler(event); };