diff --git a/components/main.ts b/components/main.ts index 75da538..38b6a80 100644 --- a/components/main.ts +++ b/components/main.ts @@ -1,5 +1,5 @@ -import { Command, CommandDescriptor, CommandList } from "interfaces/main"; -import { Component, IConfigReader, IInjector } from "merapi"; +import { Command, CommandDescriptor, CommandList, IHelper } from "interfaces/main"; +import { Component, IConfigReader, IInjector, Json, JsonObject } from "merapi"; const commander = require("commander"); @@ -7,7 +7,8 @@ export default class Main extends Component { constructor( private config : IConfigReader, - private injector : IInjector + private injector : IInjector, + private helper : IHelper ) { super(); } @@ -21,6 +22,10 @@ export default class Main extends Component { if (argv.length === 2 || validCommands.indexOf(argv[2]) === -1) { commander.parse([argv[0], argv[1], '-h']); } + + this.sendNotificationTracking() + this.sendDataAnalytics(argv) + this.saveCommandSession(argv) } async compile(commands: CommandList, program: Command, currKey : string = "") { @@ -91,4 +96,21 @@ export default class Main extends Component { handlerMethod(...args); } } + + private sendDataAnalytics(argv:string[]) { + const command = Object.assign([], argv) + + this.helper.sendGoogleAnalytics('commands', 'track', command.splice(2).join(' ')) + } + + private sendNotificationTracking() { + const status:Boolean = this.helper.checkNotificationStatus(); + if (!status) console.log(`\nStarting from Kata CLI vv2.1.0, we added analytics to Kata CLI that will collect usage data every time you typed a command. To learn about what we collect and how we use it, visit https://privacy.kata.ai/kata-cli-analytics\n`) + } + + private saveCommandSession(argv:string[]) { + const command = Object.assign([], argv) + + this.helper.addCommandSession(command.splice(2).join(' ')) + } } diff --git a/components/projects/project.ts b/components/projects/project.ts index 2579316..6a9ca67 100644 --- a/components/projects/project.ts +++ b/components/projects/project.ts @@ -111,6 +111,7 @@ export default class Project { }, ]); this.helper.setProp("projectId", project.id); + this.helper.setProp("projectName", project.name); console.log(colors.green(`Project "${project.name}" (${project.id}) is successfully selected`)); return; } diff --git a/components/scripts/helper.ts b/components/scripts/helper.ts index 1cfdd81..5c637f1 100644 --- a/components/scripts/helper.ts +++ b/components/scripts/helper.ts @@ -8,6 +8,7 @@ const fs = require("fs"); const os = require("os"); const path = require("path"); const inquirer = require("inquirer"); +const analytics = require('universal-analytics'); function wrapError(error: any) { let errorMessage; @@ -30,9 +31,12 @@ export const CatchError = Catch(Error, (error: any) => { export default class Helper extends Component { + private google:any; constructor(private config : IConfig) { super(); + + this.google = analytics(this.config.default('config.trackingId', 'UA-131926842-1')); } public getFiles(dir : string, ending : string) : string[] { @@ -173,7 +177,13 @@ export default class Helper extends Component { } public wrapError(error : any) { - return wrapError(error); + const errorMessage:string = wrapError(error); + + const commands:JsonObject[] = this.getCommandSession() + this.sendGoogleAnalytics('commands', 'debug', '', commands, errorMessage) + this.clearCommandSession() + + return errorMessage } public difference(object : any, base : any) { @@ -201,4 +211,77 @@ export default class Helper extends Component { console.log(jsonProp); } + + public checkNotificationStatus(): Boolean { + const jsonPath = `${os.homedir()}/.katanotif`; + + if (fs.existsSync(jsonPath)) { + return true + } else { + fs.writeFileSync(jsonPath, "true", "utf8"); + return false + } + } + + public addCommandSession(command:string): void { + const jsonPath = `${os.homedir()}/.katacommand`; + let jsonData:JsonObject[] = []; + + if (fs.existsSync(jsonPath)) jsonData = JSON.parse(fs.readFileSync(jsonPath, "utf8")); + + if (jsonData.length > 0) { + const lastData:JsonObject = jsonData[jsonData.length - 1] + const diff:number = Math.abs(Number(lastData.timestamp) - new Date().getTime()) / 36e5; + + if (diff >= 1) jsonData = [] //Lebih dari 1 jam ? + } + + jsonData.push({ timestamp: new Date().getTime(), command: command }) + + fs.writeFileSync(jsonPath, JSON.stringify(jsonData), "utf8"); + } + + public getCommandSession(): JsonObject[] { + const jsonPath = `${os.homedir()}/.katacommand`; + let jsonData:JsonObject[] = []; + + if (fs.existsSync(jsonPath)) jsonData = JSON.parse(fs.readFileSync(jsonPath, "utf8")); + + return jsonData + } + + public clearCommandSession(): void { + const jsonPath = `${os.homedir()}/.katacommand`; + + fs.writeFileSync(jsonPath, "[]", "utf8"); + } + + public sendGoogleAnalytics(event:string, action:string, command:string, lastSession?:JsonObject[], errorMessage?:string): void { + let firstLogin = this.getProp("first_login") as JsonObject; + let projectId = this.getProp("projectId") as string; + let projectName = this.getProp("projectName") as string; + const version = this.config.default("version", "1.0.0") + + if (!firstLogin) firstLogin = { id: null, username: null, type: null } + if (!projectId) projectId = null + if (!projectName) projectName = null + + const data:JsonObject = { + userId: firstLogin.id, + username: firstLogin.username, + currentUserType: firstLogin.type, + activeProjectId: projectId, + activeProjectName: projectName, + command: command, + versionCLI: version, + timestamp: new Date().getTime() + } + + if (lastSession) data.lastSession = lastSession + if (errorMessage) data.errorMessage = errorMessage + + this.google.event(event, action, JSON.stringify(data), (err:any) => { + if (err) console.log(this.wrapError(err)); + }) + } } diff --git a/components/users/user.ts b/components/users/user.ts index 838d056..79267f6 100644 --- a/components/users/user.ts +++ b/components/users/user.ts @@ -109,7 +109,8 @@ export default class User extends Component { } else { console.log("Please log in first"); } - + + this.helper.clearCommandSession(); } catch (e) { console.log(this.helper.wrapError(e)); } diff --git a/interfaces/main.ts b/interfaces/main.ts index 20363ff..dda53d5 100644 --- a/interfaces/main.ts +++ b/interfaces/main.ts @@ -300,6 +300,11 @@ export interface IHelper { delete() : Boolean; wrapError(error : any) : string; difference(object: any, base: any): Object; + checkNotificationStatus() : Boolean; + addCommandSession(command:string): void; + getCommandSession(): JsonObject[]; + clearCommandSession(): void; + sendGoogleAnalytics(event:string, action:string, data:string): void; } export interface ITester { diff --git a/lib/components/main.js b/lib/components/main.js index e026bd7..941e2d3 100644 --- a/lib/components/main.js +++ b/lib/components/main.js @@ -11,10 +11,11 @@ Object.defineProperty(exports, "__esModule", { value: true }); const merapi_1 = require("merapi"); const commander = require("commander"); class Main extends merapi_1.Component { - constructor(config, injector) { + constructor(config, injector, helper) { super(); this.config = config; this.injector = injector; + this.helper = helper; } start(argv) { return __awaiter(this, void 0, void 0, function* () { @@ -26,6 +27,9 @@ class Main extends merapi_1.Component { if (argv.length === 2 || validCommands.indexOf(argv[2]) === -1) { commander.parse([argv[0], argv[1], '-h']); } + this.sendNotificationTracking(); + this.sendDataAnalytics(argv); + this.saveCommandSession(argv); }); } compile(commands, program, currKey = "") { @@ -94,6 +98,19 @@ class Main extends merapi_1.Component { }; }); } + sendDataAnalytics(argv) { + const command = Object.assign([], argv); + this.helper.sendGoogleAnalytics('commands', 'track', command.splice(2).join(' ')); + } + sendNotificationTracking() { + const status = this.helper.checkNotificationStatus(); + if (!status) + console.log(`\nStarting from Kata CLI vv2.1.0, we added analytics to Kata CLI that will collect usage data every time you typed a command. To learn about what we collect and how we use it, visit https://privacy.kata.ai/kata-cli-analytics\n`); + } + saveCommandSession(argv) { + const command = Object.assign([], argv); + this.helper.addCommandSession(command.splice(2).join(' ')); + } } exports.default = Main; //# sourceMappingURL=main.js.map \ No newline at end of file diff --git a/lib/components/projects/project.js b/lib/components/projects/project.js index 05b0e5a..3f2a4cf 100644 --- a/lib/components/projects/project.js +++ b/lib/components/projects/project.js @@ -111,6 +111,7 @@ class Project { }, ]); this.helper.setProp("projectId", project.id); + this.helper.setProp("projectName", project.name); console.log(colors.green(`Project "${project.name}" (${project.id}) is successfully selected`)); return; } diff --git a/lib/components/scripts/helper.js b/lib/components/scripts/helper.js index 3a8778d..a8a736d 100644 --- a/lib/components/scripts/helper.js +++ b/lib/components/scripts/helper.js @@ -16,6 +16,7 @@ const fs = require("fs"); const os = require("os"); const path = require("path"); const inquirer = require("inquirer"); +const analytics = require('universal-analytics'); function wrapError(error) { let errorMessage; if (error.response && error.response.body && error.response.body.message) { @@ -37,6 +38,7 @@ class Helper extends merapi_1.Component { constructor(config) { super(); this.config = config; + this.google = analytics(this.config.default('config.trackingId', 'UA-131926842-1')); } getFiles(dir, ending) { const fileList = fs.readdirSync(dir); @@ -161,7 +163,11 @@ class Helper extends merapi_1.Component { }); } wrapError(error) { - return wrapError(error); + const errorMessage = wrapError(error); + const commands = this.getCommandSession(); + this.sendGoogleAnalytics('commands', 'debug', '', commands, errorMessage); + this.clearCommandSession(); + return errorMessage; } difference(object, base) { function changes(object, base) { @@ -185,6 +191,71 @@ class Helper extends merapi_1.Component { } console.log(jsonProp); } + checkNotificationStatus() { + const jsonPath = `${os.homedir()}/.katanotif`; + if (fs.existsSync(jsonPath)) { + return true; + } + else { + fs.writeFileSync(jsonPath, "true", "utf8"); + return false; + } + } + addCommandSession(command) { + const jsonPath = `${os.homedir()}/.katacommand`; + let jsonData = []; + if (fs.existsSync(jsonPath)) + jsonData = JSON.parse(fs.readFileSync(jsonPath, "utf8")); + if (jsonData.length > 0) { + const lastData = jsonData[jsonData.length - 1]; + const diff = Math.abs(Number(lastData.timestamp) - new Date().getTime()) / 36e5; + if (diff >= 1) + jsonData = []; //Lebih dari 1 jam ? + } + jsonData.push({ timestamp: new Date().getTime(), command: command }); + fs.writeFileSync(jsonPath, JSON.stringify(jsonData), "utf8"); + } + getCommandSession() { + const jsonPath = `${os.homedir()}/.katacommand`; + let jsonData = []; + if (fs.existsSync(jsonPath)) + jsonData = JSON.parse(fs.readFileSync(jsonPath, "utf8")); + return jsonData; + } + clearCommandSession() { + const jsonPath = `${os.homedir()}/.katacommand`; + fs.writeFileSync(jsonPath, "[]", "utf8"); + } + sendGoogleAnalytics(event, action, command, lastSession, errorMessage) { + let firstLogin = this.getProp("first_login"); + let projectId = this.getProp("projectId"); + let projectName = this.getProp("projectName"); + const version = this.config.default("version", "1.0.0"); + if (!firstLogin) + firstLogin = { id: null, username: null, type: null }; + if (!projectId) + projectId = null; + if (!projectName) + projectName = null; + const data = { + userId: firstLogin.id, + username: firstLogin.username, + currentUserType: firstLogin.type, + activeProjectId: projectId, + activeProjectName: projectName, + command: command, + versionCLI: version, + timestamp: new Date().getTime() + }; + if (lastSession) + data.lastSession = lastSession; + if (errorMessage) + data.errorMessage = errorMessage; + this.google.event(event, action, JSON.stringify(data), (err) => { + if (err) + console.log(this.wrapError(err)); + }); + } } exports.default = Helper; //# sourceMappingURL=helper.js.map \ No newline at end of file diff --git a/lib/components/users/user.js b/lib/components/users/user.js index 0b4256b..e1706b5 100644 --- a/lib/components/users/user.js +++ b/lib/components/users/user.js @@ -113,6 +113,7 @@ class User extends merapi_1.Component { else { console.log("Please log in first"); } + this.helper.clearCommandSession(); } catch (e) { console.log(this.helper.wrapError(e)); diff --git a/package-lock.json b/package-lock.json index ce01cb7..b003167 100644 --- a/package-lock.json +++ b/package-lock.json @@ -4887,6 +4887,16 @@ "integrity": "sha512-VCj5UiSyHBjwfYacmDuc/NOk4QQixbE+Wn7MFJuS0nRuPQbof132Pw4u53dm264O8LPc2MVsc7RJNml5szurkg==", "dev": true }, + "universal-analytics": { + "version": "0.4.20", + "resolved": "https://registry.npmjs.org/universal-analytics/-/universal-analytics-0.4.20.tgz", + "integrity": "sha512-gE91dtMvNkjO+kWsPstHRtSwHXz0l2axqptGYp5ceg4MsuurloM0PU3pdOfpb5zBXUvyjT4PwhWK2m39uczZuw==", + "requires": { + "debug": "^3.0.0", + "request": "^2.88.0", + "uuid": "^3.0.0" + } + }, "uri-js": { "version": "4.2.2", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz", diff --git a/package.json b/package.json index 40c4f3a..6b3a55f 100644 --- a/package.json +++ b/package.json @@ -56,6 +56,7 @@ "lodash": "^4.17.11", "merapi": "^0.17.1", "merapi-proxy": "^0.1.7", + "universal-analytics": "^0.4.20", "uuid": "^3.2.1", "zaun": "^2.0.3" }, diff --git a/service.yml b/service.yml index 62f8b3d..d3e38ee 100644 --- a/service.yml +++ b/service.yml @@ -35,6 +35,7 @@ components: config: + trackingId: "UA-131926842-1" channels: type: - line