diff --git a/CHANGELOG.md b/CHANGELOG.md index 17c42be..3d86b0b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +# Changelog + +## [1.0.0] +### Added + - `liff remove` + ## [0.7.0] ### Added - `liff add` diff --git a/README.md b/README.md index 825651e..722f194 100644 --- a/README.md +++ b/README.md @@ -29,8 +29,8 @@ LINE API CLI helps you to work with LINE-API-related projects faster as you do n - `unlink` - `liff` - `add` - - `remove` (upcoming) - - `update` (upcoming) + - `remove` + - `update` - `list` - `things` (upcoming) @@ -158,6 +158,12 @@ liff add liff list ``` +### Remove a LIFF app + +``` +liff remove +``` + ## Comprehensive usage We provide comprehensive usage of each command / operation / option with CLI. Simply run a command with/without operation and follow by `--help` option. For example, diff --git a/bin/apis/liff-remove-request.js b/bin/apis/liff-remove-request.js new file mode 100644 index 0000000..736ebd8 --- /dev/null +++ b/bin/apis/liff-remove-request.js @@ -0,0 +1,24 @@ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = void 0; + +var _liffRequest = _interopRequireDefault(require("./liff-request")); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +class LIFFRemoveRequest extends _liffRequest.default { + constructor(options) { + super(options); + } + + send(liffId) { + return this.axios.delete(`${this.endpoint}/${liffId}`); + } + +} + +exports.default = LIFFRemoveRequest; +//# sourceMappingURL=liff-remove-request.js.map \ No newline at end of file diff --git a/bin/apis/liff-remove-request.js.map b/bin/apis/liff-remove-request.js.map new file mode 100644 index 0000000..6308529 --- /dev/null +++ b/bin/apis/liff-remove-request.js.map @@ -0,0 +1 @@ +{"version":3,"sources":["../../lib/apis/liff-remove-request.js"],"names":["LIFFRemoveRequest","LIFFRequest","constructor","options","send","liffId","axios","delete","endpoint"],"mappings":";;;;;;;AAAA;;;;AAEe,MAAMA,iBAAN,SAAgCC,oBAAhC,CAA4C;AACzDC,EAAAA,WAAW,CAACC,OAAD,EAAU;AACnB,UAAMA,OAAN;AACD;;AACDC,EAAAA,IAAI,CAACC,MAAD,EAAS;AACX,WAAO,KAAKC,KAAL,CAAWC,MAAX,CAAmB,GAAE,KAAKC,QAAS,IAAGH,MAAO,EAA7C,CAAP;AACD;;AANwD","sourcesContent":["import LIFFRequest from './liff-request';\n\nexport default class LIFFRemoveRequest extends LIFFRequest {\n constructor(options) {\n super(options);\n }\n send(liffId) {\n return this.axios.delete(`${this.endpoint}/${liffId}`);\n }\n}\n"],"file":"liff-remove-request.js"} \ No newline at end of file diff --git a/bin/commands/liff-command.js b/bin/commands/liff-command.js index d5f31d2..e41a97b 100644 --- a/bin/commands/liff-command.js +++ b/bin/commands/liff-command.js @@ -17,6 +17,8 @@ var _liffAddOperation = _interopRequireDefault(require("../operations/liff-add-o var _liffListOperation = _interopRequireDefault(require("../operations/liff-list-operation")); +var _liffRemoveOperation = _interopRequireDefault(require("../operations/liff-remove-operation")); + var _theme = _interopRequireDefault(require("../theme")); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } @@ -79,8 +81,12 @@ class LIFFCommand extends _command.default { console.log(commandLineUsage(_liffListOperation.default.usage)); break; + case 'remove': + console.log(commandLineUsage(_liffRemoveOperation.default.usage)); + break; + default: - console.log(commandLineUsage([..._liffAddOperation.default.usage])); + console.log(commandLineUsage([..._liffAddOperation.default.usage, ..._liffListOperation.default.usage, ..._liffRemoveOperation.default.usage])); } process.exit(0); @@ -98,6 +104,8 @@ class LIFFCommand extends _command.default { await _liffAddOperation.default.run(options); } else if (operation === 'list') { await _liffListOperation.default.run(options); + } else if (operation === 'remove') { + await _liffRemoveOperation.default.run(options); } else { await _imageHelper.default.draw('chick-helps'); console.log(`Unknown operation: ${(operation || 'undefined').code}`.warn); diff --git a/bin/commands/liff-command.js.map b/bin/commands/liff-command.js.map index cbe6213..3456b6a 100644 --- a/bin/commands/liff-command.js.map +++ b/bin/commands/liff-command.js.map @@ -1 +1 @@ -{"version":3,"sources":["../../lib/commands/liff-command.js"],"names":["LIFFCommand","Command","getCommandLineArgs","commandLineArgs","require","operation","_unknown","name","defaultOption","stopAtFirstUnknown","argv","options","alias","type","Boolean","cli","colors","setTheme","theme","help","commandLineUsage","ImageHelper","draw","console","log","LIFFAddOperation","usage","LIFFListOperation","process","exit","version","versionText","run","code","warn","error"],"mappings":";;;;;;;AAAA;;AAEA;;AAEA;;AACA;;AACA;;AACA;;AACA;;;;AAEe,MAAMA,WAAN,SAA0BC,gBAA1B,CAAkC;AAC/C;;;AAGA,SAAOC,kBAAP,GAA4B;AAC1B,UAAMC,eAAe,GAAGC,OAAO,CAAC,mBAAD,CAA/B;;AAEA,UAAM;AAAEC,MAAAA,SAAF;AAAaC,MAAAA;AAAb,QAA0BH,eAAe,CAC7C,CAAC;AAAEI,MAAAA,IAAI,EAAE,WAAR;AAAqBC,MAAAA,aAAa,EAAE;AAApC,KAAD,CAD6C,EAE7C;AAAEC,MAAAA,kBAAkB,EAAE;AAAtB,KAF6C,CAA/C;AAIA,UAAMC,IAAI,GAAGJ,QAAQ,IAAI,EAAzB;AACA,UAAMK,OAAO,GAAGR,eAAe,CAC7B,CACE;AAAEI,MAAAA,IAAI,EAAE,MAAR;AAAgBK,MAAAA,KAAK,EAAE,GAAvB;AAA4BC,MAAAA,IAAI,EAAEC;AAAlC,KADF,EAEE;AAAEP,MAAAA,IAAI,EAAE,SAAR;AAAmBK,MAAAA,KAAK,EAAE,GAA1B;AAA+BC,MAAAA,IAAI,EAAEC;AAArC,KAFF,CAD6B,EAK7B;AAAEJ,MAAAA;AAAF,KAL6B,CAA/B;AAQA,WAAO;AAAEL,MAAAA,SAAF;AAAaM,MAAAA,OAAb;AAAsBL,MAAAA;AAAtB,KAAP;AACD;;AAED,eAAaS,GAAb,GAAmB;AACjB,QAAI;AACFC,sBAAOC,QAAP,CAAgBC,cAAhB;;AAEA,YAAM;AAAEb,QAAAA,SAAF;AAAaM,QAAAA;AAAb,UAAyB,KAAKT,kBAAL,EAA/B;;AAEA,UAAIS,OAAO,CAACQ,IAAZ,EAAkB;AAChB,cAAMC,gBAAgB,GAAGhB,OAAO,CAAC,oBAAD,CAAhC;;AAEA,cAAMiB,qBAAYC,IAAZ,CAAiB,aAAjB,CAAN;;AAEA,gBAAQjB,SAAR;AACE,eAAK,KAAL;AACEkB,YAAAA,OAAO,CAACC,GAAR,CAAYJ,gBAAgB,CAACK,0BAAiBC,KAAlB,CAA5B;AACA;;AACF,eAAK,MAAL;AACEH,YAAAA,OAAO,CAACC,GAAR,CAAYJ,gBAAgB,CAACO,2BAAkBD,KAAnB,CAA5B;AACA;;AACF;AACEH,YAAAA,OAAO,CAACC,GAAR,CAAYJ,gBAAgB,CAAC,CAAC,GAAGK,0BAAiBC,KAArB,CAAD,CAA5B;AARJ;;AAUAE,QAAAA,OAAO,CAACC,IAAR,CAAa,CAAb;AACA;AACD;;AAED,UAAIlB,OAAO,CAACmB,OAAZ,EAAqB;AACnB,cAAMT,qBAAYC,IAAZ,CAAiB,aAAjB,CAAN;AACAC,QAAAA,OAAO,CAACC,GAAR,CAAY,KAAKO,WAAjB;AACAH,QAAAA,OAAO,CAACC,IAAR,CAAa,CAAb;AACA;AACD;;AAED,UAAIxB,SAAS,KAAK,KAAlB,EAAyB;AACvB,cAAMoB,0BAAiBO,GAAjB,CAAqBrB,OAArB,CAAN;AACD,OAFD,MAEO,IAAIN,SAAS,KAAK,MAAlB,EAA0B;AAC/B,cAAMsB,2BAAkBK,GAAlB,CAAsBrB,OAAtB,CAAN;AACD,OAFM,MAEA;AACL,cAAMU,qBAAYC,IAAZ,CAAiB,aAAjB,CAAN;AACAC,QAAAA,OAAO,CAACC,GAAR,CACG,sBAAqB,CAACnB,SAAS,IAAI,WAAd,EAA2B4B,IAAK,EAAtD,CAAwDC,IAD1D;AAGD;;AACD;AACD,KA1CD,CA0CE,OAAOC,KAAP,EAAc;AACd,YAAMd,qBAAYC,IAAZ,CAAiB,aAAjB,CAAN;AACAC,MAAAA,OAAO,CAACY,KAAR,CAAcA,KAAd;AACAP,MAAAA,OAAO,CAACC,IAAR,CAAa,CAAb;AACA;AACD;AACF;;AAxE8C","sourcesContent":["import '../typedef';\n\nimport colors from 'colors';\n\nimport Command from './command';\nimport ImageHelper from '../image-helper';\nimport LIFFAddOperation from '../operations/liff-add-operation';\nimport LIFFListOperation from '../operations/liff-list-operation';\nimport theme from '../theme';\n\nexport default class LIFFCommand extends Command {\n /**\n * @return {operation:string, options:LIFFCommandOptions, _unknown: Array}\n */\n static getCommandLineArgs() {\n const commandLineArgs = require('command-line-args');\n\n const { operation, _unknown } = commandLineArgs(\n [{ name: 'operation', defaultOption: true }],\n { stopAtFirstUnknown: true }\n );\n const argv = _unknown || [];\n const options = commandLineArgs(\n [\n { name: 'help', alias: 'h', type: Boolean },\n { name: 'version', alias: 'v', type: Boolean }\n ],\n { argv }\n );\n\n return { operation, options, _unknown };\n }\n\n static async cli() {\n try {\n colors.setTheme(theme);\n\n const { operation, options } = this.getCommandLineArgs();\n\n if (options.help) {\n const commandLineUsage = require('command-line-usage');\n\n await ImageHelper.draw('chick-helps');\n\n switch (operation) {\n case 'add':\n console.log(commandLineUsage(LIFFAddOperation.usage));\n break;\n case 'list':\n console.log(commandLineUsage(LIFFListOperation.usage));\n break;\n default:\n console.log(commandLineUsage([...LIFFAddOperation.usage]));\n }\n process.exit(0);\n return;\n }\n\n if (options.version) {\n await ImageHelper.draw('chick-helps');\n console.log(this.versionText);\n process.exit(0);\n return;\n }\n\n if (operation === 'add') {\n await LIFFAddOperation.run(options);\n } else if (operation === 'list') {\n await LIFFListOperation.run(options);\n } else {\n await ImageHelper.draw('chick-helps');\n console.log(\n `Unknown operation: ${(operation || 'undefined').code}`.warn\n );\n }\n return;\n } catch (error) {\n await ImageHelper.draw('chick-helps');\n console.error(error);\n process.exit(1);\n return;\n }\n }\n}\n"],"file":"liff-command.js"} \ No newline at end of file +{"version":3,"sources":["../../lib/commands/liff-command.js"],"names":["LIFFCommand","Command","getCommandLineArgs","commandLineArgs","require","operation","_unknown","name","defaultOption","stopAtFirstUnknown","argv","options","alias","type","Boolean","cli","colors","setTheme","theme","help","commandLineUsage","ImageHelper","draw","console","log","LIFFAddOperation","usage","LIFFListOperation","LIFFRemoveOperation","process","exit","version","versionText","run","code","warn","error"],"mappings":"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","sourcesContent":["import '../typedef';\n\nimport colors from 'colors';\n\nimport Command from './command';\nimport ImageHelper from '../image-helper';\nimport LIFFAddOperation from '../operations/liff-add-operation';\nimport LIFFListOperation from '../operations/liff-list-operation';\nimport LIFFRemoveOperation from '../operations/liff-remove-operation';\nimport theme from '../theme';\n\nexport default class LIFFCommand extends Command {\n /**\n * @return {operation:string, options:LIFFCommandOptions, _unknown: Array}\n */\n static getCommandLineArgs() {\n const commandLineArgs = require('command-line-args');\n\n const { operation, _unknown } = commandLineArgs(\n [{ name: 'operation', defaultOption: true }],\n { stopAtFirstUnknown: true }\n );\n const argv = _unknown || [];\n const options = commandLineArgs(\n [\n { name: 'help', alias: 'h', type: Boolean },\n { name: 'version', alias: 'v', type: Boolean }\n ],\n { argv }\n );\n\n return { operation, options, _unknown };\n }\n\n static async cli() {\n try {\n colors.setTheme(theme);\n\n const { operation, options } = this.getCommandLineArgs();\n\n if (options.help) {\n const commandLineUsage = require('command-line-usage');\n\n await ImageHelper.draw('chick-helps');\n\n switch (operation) {\n case 'add':\n console.log(commandLineUsage(LIFFAddOperation.usage));\n break;\n case 'list':\n console.log(commandLineUsage(LIFFListOperation.usage));\n break;\n case 'remove':\n console.log(commandLineUsage(LIFFRemoveOperation.usage));\n break;\n default:\n console.log(commandLineUsage([\n ...LIFFAddOperation.usage,\n ...LIFFListOperation.usage,\n ...LIFFRemoveOperation.usage\n ]));\n }\n process.exit(0);\n return;\n }\n\n if (options.version) {\n await ImageHelper.draw('chick-helps');\n console.log(this.versionText);\n process.exit(0);\n return;\n }\n\n if (operation === 'add') {\n await LIFFAddOperation.run(options);\n } else if (operation === 'list') {\n await LIFFListOperation.run(options);\n } else if (operation === 'remove') {\n await LIFFRemoveOperation.run(options);\n } else {\n await ImageHelper.draw('chick-helps');\n console.log(\n `Unknown operation: ${(operation || 'undefined').code}`.warn\n );\n }\n return;\n } catch (error) {\n await ImageHelper.draw('chick-helps');\n console.error(error);\n process.exit(1);\n return;\n }\n }\n}\n"],"file":"liff-command.js"} \ No newline at end of file diff --git a/bin/index.js b/bin/index.js index e3b02e5..8fecab4 100644 --- a/bin/index.js +++ b/bin/index.js @@ -5,6 +5,14 @@ Object.defineProperty(exports, "__esModule", { }); exports.default = void 0; +var _liffAddRequest = _interopRequireDefault(require("./apis/liff-add-request")); + +var _liffListRequest = _interopRequireDefault(require("./apis/liff-list-request")); + +var _liffRemoveRequest = _interopRequireDefault(require("./apis/liff-remove-request")); + +var _liffRequest = _interopRequireDefault(require("./apis/liff-request")); + var _oauthIssueTokenRequest = _interopRequireDefault(require("./apis/oauth-issue-token-request")); var _oauthRequest = _interopRequireDefault(require("./apis/oauth-request")); @@ -26,6 +34,10 @@ var _richMenuUploadRequest = _interopRequireDefault(require("./apis/rich-menu-up function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } const apis = { + LIFFAddRequest: _liffAddRequest.default, + LIFFListRequest: _liffListRequest.default, + LIFFRemoveRequest: _liffRemoveRequest.default, + LIFFRequest: _liffRequest.default, OAuthIssueTokenRequest: _oauthIssueTokenRequest.default, OAuthRequest: _oauthRequest.default, OAuthRevokeTokenRequest: _oauthRevokeTokenRequest.default, diff --git a/bin/index.js.map b/bin/index.js.map index 00675c3..e0abdca 100644 --- a/bin/index.js.map +++ b/bin/index.js.map @@ -1 +1 @@ -{"version":3,"sources":["../lib/index.js"],"names":["apis","OAuthIssueTokenRequest","OAuthRequest","OAuthRevokeTokenRequest","RichMenuAddRequest","RichMenuListRequest","RichMenuRemoveRequest","RichMenuRequest","RichMenuSetDefaultRequest","RichMenuUploadRequest"],"mappings":";;;;;;;AAAA;;AACA;;AACA;;AACA;;AACA;;AACA;;AACA;;AACA;;AACA;;;;AAEA,MAAMA,IAAI,GAAG;AACXC,EAAAA,sBAAsB,EAAtBA,+BADW;AAEXC,EAAAA,YAAY,EAAZA,qBAFW;AAGXC,EAAAA,uBAAuB,EAAvBA,gCAHW;AAIXC,EAAAA,kBAAkB,EAAlBA,2BAJW;AAKXC,EAAAA,mBAAmB,EAAnBA,4BALW;AAMXC,EAAAA,qBAAqB,EAArBA,8BANW;AAOXC,EAAAA,eAAe,EAAfA,wBAPW;AAQXC,EAAAA,yBAAyB,EAAzBA,kCARW;AASXC,EAAAA,qBAAqB,EAArBA;AATW,CAAb;eAYeT,I","sourcesContent":["import OAuthIssueTokenRequest from './apis/oauth-issue-token-request';\nimport OAuthRequest from './apis/oauth-request';\nimport OAuthRevokeTokenRequest from './apis/oauth-revoke-token-request';\nimport RichMenuAddRequest from './apis/rich-menu-add-request';\nimport RichMenuListRequest from './apis/rich-menu-list-request';\nimport RichMenuRemoveRequest from './apis/rich-menu-remove-request';\nimport RichMenuRequest from './apis/rich-menu-request';\nimport RichMenuSetDefaultRequest from './apis/rich-menu-set-default-request';\nimport RichMenuUploadRequest from './apis/rich-menu-upload-request';\n\nconst apis = {\n OAuthIssueTokenRequest,\n OAuthRequest,\n OAuthRevokeTokenRequest,\n RichMenuAddRequest,\n RichMenuListRequest,\n RichMenuRemoveRequest,\n RichMenuRequest,\n RichMenuSetDefaultRequest,\n RichMenuUploadRequest\n};\n\nexport default apis;\n"],"file":"index.js"} \ No newline at end of file +{"version":3,"sources":["../lib/index.js"],"names":["apis","LIFFAddRequest","LIFFListRequest","LIFFRemoveRequest","LIFFRequest","OAuthIssueTokenRequest","OAuthRequest","OAuthRevokeTokenRequest","RichMenuAddRequest","RichMenuListRequest","RichMenuRemoveRequest","RichMenuRequest","RichMenuSetDefaultRequest","RichMenuUploadRequest"],"mappings":";;;;;;;AAAA;;AACA;;AACA;;AACA;;AACA;;AACA;;AACA;;AACA;;AACA;;AACA;;AACA;;AACA;;AACA;;;;AAEA,MAAMA,IAAI,GAAG;AACXC,EAAAA,cAAc,EAAdA,uBADW;AAEXC,EAAAA,eAAe,EAAfA,wBAFW;AAGXC,EAAAA,iBAAiB,EAAjBA,0BAHW;AAIXC,EAAAA,WAAW,EAAXA,oBAJW;AAKXC,EAAAA,sBAAsB,EAAtBA,+BALW;AAMXC,EAAAA,YAAY,EAAZA,qBANW;AAOXC,EAAAA,uBAAuB,EAAvBA,gCAPW;AAQXC,EAAAA,kBAAkB,EAAlBA,2BARW;AASXC,EAAAA,mBAAmB,EAAnBA,4BATW;AAUXC,EAAAA,qBAAqB,EAArBA,8BAVW;AAWXC,EAAAA,eAAe,EAAfA,wBAXW;AAYXC,EAAAA,yBAAyB,EAAzBA,kCAZW;AAaXC,EAAAA,qBAAqB,EAArBA;AAbW,CAAb;eAgBeb,I","sourcesContent":["import LIFFAddRequest from './apis/liff-add-request';\nimport LIFFListRequest from './apis/liff-list-request';\nimport LIFFRemoveRequest from './apis/liff-remove-request';\nimport LIFFRequest from './apis/liff-request';\nimport OAuthIssueTokenRequest from './apis/oauth-issue-token-request';\nimport OAuthRequest from './apis/oauth-request';\nimport OAuthRevokeTokenRequest from './apis/oauth-revoke-token-request';\nimport RichMenuAddRequest from './apis/rich-menu-add-request';\nimport RichMenuListRequest from './apis/rich-menu-list-request';\nimport RichMenuRemoveRequest from './apis/rich-menu-remove-request';\nimport RichMenuRequest from './apis/rich-menu-request';\nimport RichMenuSetDefaultRequest from './apis/rich-menu-set-default-request';\nimport RichMenuUploadRequest from './apis/rich-menu-upload-request';\n\nconst apis = {\n LIFFAddRequest,\n LIFFListRequest,\n LIFFRemoveRequest,\n LIFFRequest,\n OAuthIssueTokenRequest,\n OAuthRequest,\n OAuthRevokeTokenRequest,\n RichMenuAddRequest,\n RichMenuListRequest,\n RichMenuRemoveRequest,\n RichMenuRequest,\n RichMenuSetDefaultRequest,\n RichMenuUploadRequest\n};\n\nexport default apis;\n"],"file":"index.js"} \ No newline at end of file diff --git a/bin/operations/liff-remove-operation.js b/bin/operations/liff-remove-operation.js new file mode 100644 index 0000000..d075e1b --- /dev/null +++ b/bin/operations/liff-remove-operation.js @@ -0,0 +1,92 @@ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = void 0; + +require("console.table"); + +var _commandLineUsage = require("command-line-usage"); + +var _operation = _interopRequireDefault(require("./operation")); + +var _liffListRequest = _interopRequireDefault(require("../apis/liff-list-request")); + +var _liffRemoveRequest = _interopRequireDefault(require("../apis/liff-remove-request")); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } + +class LIFFRemoveOperation extends _operation.default { + static get usage() { + /** @type {Section[]} */ + const sections = [{ + header: 'Remove a LIFF app'.help, + content: `liff remove`.code + }]; + return sections; + } + + static async run() { + if (!this.validateConfig()) { + return false; + } + + const prompts = require('prompts'); + + let apps = []; + + try { + const response = await this.listRequest.send(); + apps = response.data.apps || []; + } catch (error) { + console.error(error); + return false; + } + + if (!apps.length) { + console.log('LIFF app not found'.info); + return true; + } + + const choices = apps.map(app => { + return { + title: `${app.view.type} ${app.view.url} [${app.liffId}]`, + description: app.description, + value: app.liffId + }; + }); + const { + liffId + } = await prompts({ + type: 'select', + name: 'liffId', + message: 'Select a LIFF app to be removed', + choices + }, this.cancelOption); + + try { + await this.removeRequest.send(liffId); + console.log(`Removed LIFF app ID: ${liffId.code}`.success); + } catch (error) { + console.error(error); + return false; + } + + return true; + } + +} + +exports.default = LIFFRemoveOperation; + +_defineProperty(LIFFRemoveOperation, "listRequest", new _liffListRequest.default({ + accessToken: LIFFRemoveOperation.config.channel.accessToken +})); + +_defineProperty(LIFFRemoveOperation, "removeRequest", new _liffRemoveRequest.default({ + accessToken: LIFFRemoveOperation.config.channel.accessToken +})); +//# sourceMappingURL=liff-remove-operation.js.map \ No newline at end of file diff --git a/bin/operations/liff-remove-operation.js.map b/bin/operations/liff-remove-operation.js.map new file mode 100644 index 0000000..143974c --- /dev/null +++ b/bin/operations/liff-remove-operation.js.map @@ -0,0 +1 @@ +{"version":3,"sources":["../../lib/operations/liff-remove-operation.js"],"names":["LIFFRemoveOperation","Operation","usage","sections","header","help","content","code","run","validateConfig","prompts","require","apps","response","listRequest","send","data","error","console","length","log","info","choices","map","app","title","view","type","url","liffId","description","value","name","message","cancelOption","removeRequest","success","LIFFListRequest","accessToken","config","channel","LIFFRemoveRequest"],"mappings":";;;;;;;AAAA;;AACA;;AACA;;AACA;;AACA;;;;;;AAEe,MAAMA,mBAAN,SAAkCC,kBAAlC,CAA4C;AAQzD,aAAWC,KAAX,GAAmB;AACjB;AACA,UAAMC,QAAQ,GAAG,CACf;AACEC,MAAAA,MAAM,EAAE,oBAAoBC,IAD9B;AAEEC,MAAAA,OAAO,EAAG,aAAD,CAAcC;AAFzB,KADe,CAAjB;AAOA,WAAOJ,QAAP;AACD;;AAED,eAAaK,GAAb,GAAmB;AACjB,QAAI,CAAC,KAAKC,cAAL,EAAL,EAA4B;AAC1B,aAAO,KAAP;AACD;;AAED,UAAMC,OAAO,GAAGC,OAAO,CAAC,SAAD,CAAvB;;AAEA,QAAIC,IAAI,GAAG,EAAX;;AAEA,QAAI;AACF,YAAMC,QAAQ,GAAG,MAAM,KAAKC,WAAL,CAAiBC,IAAjB,EAAvB;AAEAH,MAAAA,IAAI,GAAGC,QAAQ,CAACG,IAAT,CAAcJ,IAAd,IAAsB,EAA7B;AACD,KAJD,CAIE,OAAOK,KAAP,EAAc;AACdC,MAAAA,OAAO,CAACD,KAAR,CAAcA,KAAd;AACA,aAAO,KAAP;AACD;;AAED,QAAI,CAACL,IAAI,CAACO,MAAV,EAAkB;AAChBD,MAAAA,OAAO,CAACE,GAAR,CAAY,qBAAqBC,IAAjC;AACA,aAAO,IAAP;AACD;;AAED,UAAMC,OAAO,GAAGV,IAAI,CAACW,GAAL,CAASC,GAAG,IAAI;AAC9B,aAAO;AACLC,QAAAA,KAAK,EAAG,GAAED,GAAG,CAACE,IAAJ,CAASC,IAAK,IAAGH,GAAG,CAACE,IAAJ,CAASE,GAAI,KAAIJ,GAAG,CAACK,MAAO,GADlD;AAELC,QAAAA,WAAW,EAAEN,GAAG,CAACM,WAFZ;AAGLC,QAAAA,KAAK,EAAEP,GAAG,CAACK;AAHN,OAAP;AAKD,KANe,CAAhB;AAQA,UAAM;AAAEA,MAAAA;AAAF,QAAa,MAAMnB,OAAO,CAC9B;AACEiB,MAAAA,IAAI,EAAE,QADR;AAEEK,MAAAA,IAAI,EAAE,QAFR;AAGEC,MAAAA,OAAO,EAAE,iCAHX;AAIEX,MAAAA;AAJF,KAD8B,EAO9B,KAAKY,YAPyB,CAAhC;;AAUA,QAAI;AACF,YAAM,KAAKC,aAAL,CAAmBpB,IAAnB,CAAwBc,MAAxB,CAAN;AACAX,MAAAA,OAAO,CAACE,GAAR,CAAa,wBAAuBS,MAAM,CAACtB,IAAK,EAApC,CAAsC6B,OAAlD;AACD,KAHD,CAGE,OAAOnB,KAAP,EAAc;AACdC,MAAAA,OAAO,CAACD,KAAR,CAAcA,KAAd;AACA,aAAO,KAAP;AACD;;AAED,WAAO,IAAP;AACD;;AAtEwD;;;;gBAAtCjB,mB,iBACE,IAAIqC,wBAAJ,CAAoB;AACvCC,EAAAA,WAAW,EAFMtC,mBAEJ,CAAKuC,MAAL,CAAYC,OAAZ,CAAoBF;AADM,CAApB,C;;gBADFtC,mB,mBAII,IAAIyC,0BAAJ,CAAsB;AAC3CH,EAAAA,WAAW,EALMtC,mBAKJ,CAAKuC,MAAL,CAAYC,OAAZ,CAAoBF;AADU,CAAtB,C","sourcesContent":["import 'console.table';\nimport { Section } from 'command-line-usage';\nimport Operation from './operation';\nimport LIFFListRequest from '../apis/liff-list-request';\nimport LIFFRemoveRequest from '../apis/liff-remove-request';\n\nexport default class LIFFRemoveOperation extends Operation {\n static listRequest = new LIFFListRequest({\n accessToken: this.config.channel.accessToken\n });\n static removeRequest = new LIFFRemoveRequest({\n accessToken: this.config.channel.accessToken\n });\n\n static get usage() {\n /** @type {Section[]} */\n const sections = [\n {\n header: 'Remove a LIFF app'.help,\n content: `liff remove`.code\n }\n ];\n\n return sections;\n }\n\n static async run() {\n if (!this.validateConfig()) {\n return false;\n }\n\n const prompts = require('prompts');\n\n let apps = [];\n\n try {\n const response = await this.listRequest.send();\n\n apps = response.data.apps || [];\n } catch (error) {\n console.error(error);\n return false;\n }\n\n if (!apps.length) {\n console.log('LIFF app not found'.info);\n return true;\n }\n\n const choices = apps.map(app => {\n return {\n title: `${app.view.type} ${app.view.url} [${app.liffId}]`,\n description: app.description,\n value: app.liffId\n };\n });\n\n const { liffId } = await prompts(\n {\n type: 'select',\n name: 'liffId',\n message: 'Select a LIFF app to be removed',\n choices\n },\n this.cancelOption\n );\n\n try {\n await this.removeRequest.send(liffId);\n console.log(`Removed LIFF app ID: ${liffId.code}`.success);\n } catch (error) {\n console.error(error);\n return false;\n }\n\n return true;\n }\n}\n"],"file":"liff-remove-operation.js"} \ No newline at end of file diff --git a/lib/__tests__/index.spec.js b/lib/__tests__/index.spec.js index 95966d3..08c7df9 100644 --- a/lib/__tests__/index.spec.js +++ b/lib/__tests__/index.spec.js @@ -1,6 +1,10 @@ import apis from '../index'; test('index provides access to API classes', () => { + expect(apis.LIFFAddRequest).toBeDefined(); + expect(apis.LIFFListRequest).toBeDefined(); + expect(apis.LIFFRemoveRequest).toBeDefined(); + expect(apis.LIFFRequest).toBeDefined(); expect(apis.OAuthIssueTokenRequest).toBeDefined(); expect(apis.OAuthRequest).toBeDefined(); expect(apis.OAuthRevokeTokenRequest).toBeDefined(); diff --git a/lib/apis/__tests__/liff-remove-request.spec.js b/lib/apis/__tests__/liff-remove-request.spec.js new file mode 100644 index 0000000..4863600 --- /dev/null +++ b/lib/apis/__tests__/liff-remove-request.spec.js @@ -0,0 +1,49 @@ +import Axios from 'axios'; +import LIFFRemoveRequest from '../liff-remove-request'; + +describe('LIFFRemoveRequest', () => { + describe('when create an instance with options.accessToken', () => { + let req; + let accessToken = 'someaccesstoken'; + + beforeAll(() => { + jest.spyOn(Axios, 'create'); + req = new LIFFRemoveRequest({ accessToken }); + }); + + it('should have correct endpoint', () => { + expect(req.endpoint).toEqual('https://api.line.me/liff/v1/apps'); + }); + + it('should create axios instance with correct headers for LINE API', () => { + expect(Axios.create).toHaveBeenCalledWith({ + headers: { + authorization: `Bearer ${accessToken}`, + 'content-type': 'application/json' + } + }); + expect(req.axios).toBeDefined(); + }); + + describe('when send liffId', () => { + let liffId = 'shkf2h39fwef'; + beforeAll(() => { + jest.spyOn(req.axios, 'delete').mockResolvedValue('any'); + req.send(liffId); + }); + it('should call to correct endpoint', () => { + expect(req.axios.delete).toHaveBeenCalledTimes(1); + expect(req.axios.delete).toHaveBeenCalledWith( + `${req.endpoint}/${liffId}` + ); + }); + afterAll(() => { + req.axios.delete.mockRestore(); + }); + }); + + afterAll(() => { + Axios.create.mockRestore(); + }); + }); +}); diff --git a/lib/apis/liff-remove-request.js b/lib/apis/liff-remove-request.js new file mode 100644 index 0000000..aba4fc8 --- /dev/null +++ b/lib/apis/liff-remove-request.js @@ -0,0 +1,10 @@ +import LIFFRequest from './liff-request'; + +export default class LIFFRemoveRequest extends LIFFRequest { + constructor(options) { + super(options); + } + send(liffId) { + return this.axios.delete(`${this.endpoint}/${liffId}`); + } +} diff --git a/lib/commands/__tests__/liff-command.spec.js b/lib/commands/__tests__/liff-command.spec.js index 0fc1e87..69e3350 100644 --- a/lib/commands/__tests__/liff-command.spec.js +++ b/lib/commands/__tests__/liff-command.spec.js @@ -4,6 +4,7 @@ import LIFFCommand from '../liff-command'; import ImageHelper from '../../image-helper'; import LIFFAddOperation from '../../operations/liff-add-operation'; import LIFFListOperation from '../../operations/liff-list-operation'; +import LIFFRemoveOperation from '../../operations/liff-remove-operation'; import theme from '../../theme'; const { spyOn, mock, unmock } = jest; @@ -139,6 +140,27 @@ describe('LIFFCommand', () => { LIFFListOperation.run.mockRestore(); }); }); + + describe('when run with remove operation', () => { + beforeAll(() => { + spyOn(LIFFCommand, 'getCommandLineArgs').mockReturnValue({ + operation: 'remove', + options: {}, + _unknown: [] + }); + spyOn(LIFFRemoveOperation, 'run').mockResolvedValue(undefined); + }); + + it('run correctly', async () => { + await expect(LIFFCommand.cli()).resolves.toEqual(undefined); + expect(LIFFRemoveOperation.run).toHaveBeenCalled(); + }); + + afterAll(() => { + LIFFCommand.getCommandLineArgs.mockRestore(); + LIFFRemoveOperation.run.mockRestore(); + }); + }); describe('when run with unknown operation', () => { beforeEach(() => { diff --git a/lib/commands/__tests__/liff-help.spec.js b/lib/commands/__tests__/liff-help.spec.js index c5b30ec..9d50129 100644 --- a/lib/commands/__tests__/liff-help.spec.js +++ b/lib/commands/__tests__/liff-help.spec.js @@ -2,6 +2,7 @@ import LIFFCommand from '../liff-command'; import ImageHelper from '../../image-helper'; import LIFFAddOperation from '../../operations/liff-add-operation'; import LIFFListOperation from '../../operations/liff-list-operation'; +import LIFFRemoveOperation from '../../operations/liff-remove-operation'; const { spyOn, mock, unmock } = jest; @@ -65,6 +66,26 @@ describe('liff', () => { }); }); + describe('liff remove --help', () => { + beforeAll(() => { + spyOn(LIFFCommand, 'getCommandLineArgs').mockReturnValue({ + operation: 'remove', + options: { + help: true + }, + _unknown: [] + }); + }); + + it('display helps', async () => { + await expect(LIFFCommand.cli()); + expect(ImageHelper.draw).toHaveBeenCalledWith('chick-helps'); + expect(commandLineUsage).toHaveBeenCalledWith(LIFFRemoveOperation.usage); + expect(console.log).toHaveBeenCalledWith(mockUsage); + expect(process.exit).toHaveBeenCalledWith(0); + }); + }); + describe('liff --help', () => { beforeAll(() => { spyOn(LIFFCommand, 'getCommandLineArgs').mockReturnValue({ @@ -80,7 +101,9 @@ describe('liff', () => { await expect(LIFFCommand.cli()); expect(ImageHelper.draw).toHaveBeenCalledWith('chick-helps'); expect(commandLineUsage).toHaveBeenCalledWith([ - ...LIFFAddOperation.usage + ...LIFFAddOperation.usage, + ...LIFFListOperation.usage, + ...LIFFRemoveOperation.usage ]); expect(console.log).toHaveBeenCalledWith(mockUsage); expect(process.exit).toHaveBeenCalledWith(0); diff --git a/lib/commands/liff-command.js b/lib/commands/liff-command.js index ff695f8..d6c696c 100644 --- a/lib/commands/liff-command.js +++ b/lib/commands/liff-command.js @@ -6,6 +6,7 @@ import Command from './command'; import ImageHelper from '../image-helper'; import LIFFAddOperation from '../operations/liff-add-operation'; import LIFFListOperation from '../operations/liff-list-operation'; +import LIFFRemoveOperation from '../operations/liff-remove-operation'; import theme from '../theme'; export default class LIFFCommand extends Command { @@ -49,8 +50,15 @@ export default class LIFFCommand extends Command { case 'list': console.log(commandLineUsage(LIFFListOperation.usage)); break; + case 'remove': + console.log(commandLineUsage(LIFFRemoveOperation.usage)); + break; default: - console.log(commandLineUsage([...LIFFAddOperation.usage])); + console.log(commandLineUsage([ + ...LIFFAddOperation.usage, + ...LIFFListOperation.usage, + ...LIFFRemoveOperation.usage + ])); } process.exit(0); return; @@ -67,6 +75,8 @@ export default class LIFFCommand extends Command { await LIFFAddOperation.run(options); } else if (operation === 'list') { await LIFFListOperation.run(options); + } else if (operation === 'remove') { + await LIFFRemoveOperation.run(options); } else { await ImageHelper.draw('chick-helps'); console.log( diff --git a/lib/index.js b/lib/index.js index c496b34..e68a59f 100644 --- a/lib/index.js +++ b/lib/index.js @@ -1,3 +1,7 @@ +import LIFFAddRequest from './apis/liff-add-request'; +import LIFFListRequest from './apis/liff-list-request'; +import LIFFRemoveRequest from './apis/liff-remove-request'; +import LIFFRequest from './apis/liff-request'; import OAuthIssueTokenRequest from './apis/oauth-issue-token-request'; import OAuthRequest from './apis/oauth-request'; import OAuthRevokeTokenRequest from './apis/oauth-revoke-token-request'; @@ -9,6 +13,10 @@ import RichMenuSetDefaultRequest from './apis/rich-menu-set-default-request'; import RichMenuUploadRequest from './apis/rich-menu-upload-request'; const apis = { + LIFFAddRequest, + LIFFListRequest, + LIFFRemoveRequest, + LIFFRequest, OAuthIssueTokenRequest, OAuthRequest, OAuthRevokeTokenRequest, diff --git a/lib/operations/__tests__/liff-remove-operation.spec.js b/lib/operations/__tests__/liff-remove-operation.spec.js new file mode 100644 index 0000000..63bf2e5 --- /dev/null +++ b/lib/operations/__tests__/liff-remove-operation.spec.js @@ -0,0 +1,266 @@ +import Operation from '../operation'; +import LIFFRemoveOperation from '../liff-remove-operation'; + +const { spyOn, mock, unmock } = jest; + +describe('liff remove', () => { + it('extends Operation', () => { + expect(LIFFRemoveOperation.prototype instanceof Operation).toEqual(true); + }); + + it('has usage', () => { + expect(LIFFRemoveOperation.usage).toEqual([ + { + header: 'Remove a LIFF app'.help, + content: `liff remove`.code + } + ]); + }); + + it('runnable', () => { + expect(typeof LIFFRemoveOperation.run).toEqual('function'); + }); + + describe('when config is invalid', () => { + beforeAll(() => { + spyOn(LIFFRemoveOperation, 'validateConfig').mockReturnValue(false); + }); + + it('handles correctly', async () => { + await expect(LIFFRemoveOperation.run()).resolves.toEqual(false); + }); + + afterAll(() => { + LIFFRemoveOperation.validateConfig.mockRestore(); + }); + }); + + describe('when config is valid', () => { + const mockConfig = { + channel: { + id: 1234, + secret: 'mock secret', + accessToken: 'mock access token' + } + }; + let prompts; + + beforeAll(() => { + spyOn(LIFFRemoveOperation, 'config', 'get').mockReturnValue(mockConfig); + spyOn(LIFFRemoveOperation, 'validateConfig').mockReturnValue(true); + spyOn(console, 'log').mockReturnValue(undefined); + }); + + beforeEach(() => { + console.log.mockClear(); + }); + + describe('when failed to list LIFF apps', () => { + const error = new Error('list failed'); + + beforeAll(() => { + spyOn(LIFFRemoveOperation.listRequest, 'send').mockRejectedValue(error); + spyOn(console, 'error').mockReturnValue(undefined); + }); + + it('handles error', async () => { + await expect(LIFFRemoveOperation.run()).resolves.toEqual(false); + expect(console.error).toHaveBeenCalledWith(error); + }); + + afterAll(() => { + LIFFRemoveOperation.listRequest.send.mockRestore(); + console.error.mockRestore(); + }); + }); + + describe('when no LIFF app data', () => { + beforeAll(() => { + spyOn(LIFFRemoveOperation.listRequest, 'send') + .mockResolvedValueOnce({ + data: { + liffs: [] + } + }) + .mockResolvedValueOnce({ + data: {} + }); + }); + + it('handles error', async () => { + // Test empty liffs + await expect(LIFFRemoveOperation.run()).resolves.toEqual(true); + expect(console.log).toHaveBeenCalledWith('LIFF app not found'.info); + console.log.mockClear(); + // Test no liffs + await expect(LIFFRemoveOperation.run()).resolves.toEqual(true); + expect(console.log).toHaveBeenCalledWith('LIFF app not found'.info); + }); + + afterAll(() => { + LIFFRemoveOperation.listRequest.send.mockRestore(); + }); + }); + + describe('when has LIFF apps', () => { + const apps = [ + { + liffId: 'xxxx', + view: { + type: 'full', + url: 'https://www.intocode.io' + }, + description: 'With BLE', + features: { + ble: true + } + }, + { + liffId: 'yyyy', + view: { + type: 'full', + url: 'https://www.intocode.io' + }, + description: 'Without BLE' + } + ]; + const liffId = 'xxxx'; + const mockResponse = { + data: { + apps + } + }; + const choices = apps.map(app => { + return { + title: `${app.view.type} ${app.view.url} [${app.liffId}]`, + description: app.description, + value: app.liffId + }; + }); + const appsPrompt = { + type: 'select', + name: 'liffId', + message: 'Select a LIFF app to be removed', + choices + }; + + beforeAll(() => { + spyOn(LIFFRemoveOperation.listRequest, 'send').mockResolvedValue( + mockResponse + ); + spyOn(LIFFRemoveOperation.removeRequest, 'send').mockResolvedValue({}); + mock('prompts'); + prompts = require('prompts'); + }); + + beforeEach(() => { + LIFFRemoveOperation.listRequest.send.mockClear(); + LIFFRemoveOperation.removeRequest.send.mockClear(); + }); + + describe('and user cancel', () => { + beforeAll(() => { + prompts.mockImplementationOnce((_, options) => { + options.onCancel(); + }); + spyOn(LIFFRemoveOperation.cancelOption, 'onCancel').mockResolvedValue( + {} + ); + }); + + it('call onCancel', async () => { + await expect( + LIFFRemoveOperation.run().catch(_ => {}) + ).resolves.toEqual(); + expect(LIFFRemoveOperation.listRequest.send).toHaveBeenCalled(); + expect(LIFFRemoveOperation.removeRequest.send).not.toHaveBeenCalled(); + expect(prompts).toHaveBeenCalledWith( + appsPrompt, + LIFFRemoveOperation.cancelOption + ); + expect(LIFFRemoveOperation.cancelOption.onCancel).toHaveBeenCalled(); + }); + + afterAll(() => { + LIFFRemoveOperation.cancelOption.onCancel.mockRestore(); + prompts.mockReset(); + }); + }); + + describe('and user choose a LIFF app', () => { + describe('and able to remove the LIFF app', () => { + beforeAll(() => { + prompts.mockResolvedValueOnce({ liffId }); + spyOn(LIFFRemoveOperation.removeRequest, 'send').mockResolvedValue( + {} + ); + }); + + it('remove the LIFF app', async () => { + await expect(LIFFRemoveOperation.run()).resolves.toEqual(true); + expect(LIFFRemoveOperation.listRequest.send).toHaveBeenCalled(); + expect(prompts).toHaveBeenCalledWith( + appsPrompt, + LIFFRemoveOperation.cancelOption + ); + expect(LIFFRemoveOperation.removeRequest.send).toHaveBeenCalledWith( + liffId + ); + }); + + afterAll(() => { + prompts.mockReset(); + LIFFRemoveOperation.removeRequest.send.mockReset(); + }); + }); + + describe('and NOT able to remove the LIFF app', () => { + const error = new Error('failed to remove'); + + beforeAll(() => { + prompts.mockResolvedValueOnce({ liffId }); + spyOn(LIFFRemoveOperation.removeRequest, 'send').mockRejectedValue( + error + ); + spyOn(console, 'error').mockReturnValue(undefined); + }); + + it('handles error', async () => { + await expect(LIFFRemoveOperation.run()).resolves.toEqual(false); + expect(LIFFRemoveOperation.listRequest.send).toHaveBeenCalled(); + expect(prompts).toHaveBeenCalledWith( + appsPrompt, + LIFFRemoveOperation.cancelOption + ); + expect(LIFFRemoveOperation.removeRequest.send).toHaveBeenCalledWith( + liffId + ); + }); + + afterAll(() => { + console.error.mockRestore(); + prompts.mockReset(); + LIFFRemoveOperation.removeRequest.send.mockReset(); + }); + }); + + afterAll(() => { + prompts.mockReset(); + }); + }); + + afterAll(() => { + LIFFRemoveOperation.removeRequest.send.mockRestore(); + LIFFRemoveOperation.listRequest.send.mockRestore(); + prompts.mockRestore(); + unmock('prompts'); + }); + }); + + afterAll(() => { + LIFFRemoveOperation.config.mockRestore(); + LIFFRemoveOperation.validateConfig.mockRestore(); + console.log.mockRestore(); + }); + }); +}); diff --git a/lib/operations/liff-remove-operation.js b/lib/operations/liff-remove-operation.js new file mode 100644 index 0000000..cc7f79a --- /dev/null +++ b/lib/operations/liff-remove-operation.js @@ -0,0 +1,78 @@ +import 'console.table'; +import { Section } from 'command-line-usage'; +import Operation from './operation'; +import LIFFListRequest from '../apis/liff-list-request'; +import LIFFRemoveRequest from '../apis/liff-remove-request'; + +export default class LIFFRemoveOperation extends Operation { + static listRequest = new LIFFListRequest({ + accessToken: this.config.channel.accessToken + }); + static removeRequest = new LIFFRemoveRequest({ + accessToken: this.config.channel.accessToken + }); + + static get usage() { + /** @type {Section[]} */ + const sections = [ + { + header: 'Remove a LIFF app'.help, + content: `liff remove`.code + } + ]; + + return sections; + } + + static async run() { + if (!this.validateConfig()) { + return false; + } + + const prompts = require('prompts'); + + let apps = []; + + try { + const response = await this.listRequest.send(); + + apps = response.data.apps || []; + } catch (error) { + console.error(error); + return false; + } + + if (!apps.length) { + console.log('LIFF app not found'.info); + return true; + } + + const choices = apps.map(app => { + return { + title: `${app.view.type} ${app.view.url} [${app.liffId}]`, + description: app.description, + value: app.liffId + }; + }); + + const { liffId } = await prompts( + { + type: 'select', + name: 'liffId', + message: 'Select a LIFF app to be removed', + choices + }, + this.cancelOption + ); + + try { + await this.removeRequest.send(liffId); + console.log(`Removed LIFF app ID: ${liffId.code}`.success); + } catch (error) { + console.error(error); + return false; + } + + return true; + } +}