From 65ddf987e6c8b9893993b29d42be4af837661d36 Mon Sep 17 00:00:00 2001 From: Travis-CI Date: Wed, 13 Jan 2016 15:59:25 +0000 Subject: [PATCH 01/23] Automatically push updated documentation [ci skip] --- docs/api/lib/browser.md | 13 ++++++ docs/api/lib/commands/notifications.md | 56 ++++++++++++++++++++++++++ 2 files changed, 69 insertions(+) create mode 100644 docs/api/lib/commands/notifications.md diff --git a/docs/api/lib/browser.md b/docs/api/lib/browser.md index 5f4220f3..c446c618 100644 --- a/docs/api/lib/browser.md +++ b/docs/api/lib/browser.md @@ -33,6 +33,7 @@ Webbrowser abstraction for communicating with discourse * [~login(callback)](#module_browser..login) * [~messageBus(channels, clientId, callback)](#module_browser..messageBus) * [~getNotifications(callback)](#module_browser..getNotifications) + * [~setNotificationLevel(topicId, level, callback)](#module_browser..setNotificationLevel) * [~setPostUrl(post)](#module_browser..setPostUrl) ⇒ external.module_posts.CleanedPost * [~setTrustLevel(post)](#module_browser..setTrustLevel) ⇒ external.module_posts.CleanedPost * [~cleanPostRaw(post)](#module_browser..cleanPostRaw) ⇒ external.module_posts.CleanedPost @@ -381,6 +382,18 @@ Poll for notifications | --- | --- | --- | | callback | notificationsCallback | Completion callback | + +### browser~setNotificationLevel(topicId, level, callback) +Set Notification level + +**Kind**: inner method of [browser](#module_browser) + +| Param | Type | Description | +| --- | --- | --- | +| topicId | number | Topic to alter notification level | +| level | number | Notification level to set (0=muted, 3=watching) | +| callback | function | Completion callback | + ### browser~setPostUrl(post) ⇒ external.module_posts.CleanedPost construct direct post link and direct in reply to link diff --git a/docs/api/lib/commands/notifications.md b/docs/api/lib/commands/notifications.md new file mode 100644 index 00000000..bb808625 --- /dev/null +++ b/docs/api/lib/commands/notifications.md @@ -0,0 +1,56 @@ + +## status +Notification level commands + +**Author:** AccaliaDeElementia +**License**: MIT + +* [status](#module_status) + * [.unmute](#module_status.unmute) + * [.prepare(events, callback)](#module_status.prepare) + * [.mute(command)](#module_status.mute) + * [.watch(command)](#module_status.watch) + + +### status.unmute +Unwatch the current thread + +**Kind**: static property of [status](#module_status) + +| Param | Type | Description | +| --- | --- | --- | +| command | command | the unwatch command | + + +### status.prepare(events, callback) +Prepare the command parser + +Needs to be called to set the internals of the parser after reading config file. + +**Kind**: static method of [status](#module_status) + +| Param | Type | Description | +| --- | --- | --- | +| events | EventEmitter | EventEmitter that will be core comms for SockBot | +| callback | completedCallback | Completion callback | + + +### status.mute(command) +Mute the current Thread + +**Kind**: static method of [status](#module_status) + +| Param | Type | Description | +| --- | --- | --- | +| command | command | the mute command | + + +### status.watch(command) +Watch the current thread + +**Kind**: static method of [status](#module_status) + +| Param | Type | Description | +| --- | --- | --- | +| command | command | the watch command | + From 7e19fc081a05afd911913d7a886f9db02ea99d44 Mon Sep 17 00:00:00 2001 From: Accalia de Elementia Date: Thu, 14 Jan 2016 13:02:05 +0000 Subject: [PATCH 02/23] update outdated packages --- gulpfile.js | 2 -- package.json | 17 ++++++++--------- plugins/anonymize.js | 2 +- 3 files changed, 9 insertions(+), 12 deletions(-) diff --git a/gulpfile.js b/gulpfile.js index 350d4897..ab5bf1e0 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -3,7 +3,6 @@ const gulp = require('gulp'), gulpJsdoc2md = require('gulp-jsdoc-to-markdown'), rename = require('gulp-rename'), istanbul = require('gulp-istanbul'), - istanbulHarmony = require('istanbul-harmony'), mocha = require('gulp-mocha'), eslint = require('gulp-eslint'), git = require('gulp-git'); @@ -152,7 +151,6 @@ gulp.task('test', ['lintCore', 'lintTests'], (done) => { gulp.src(sockFiles) // Instrument code files with istanbulHarmony .pipe(istanbul({ - instrumenter: istanbulHarmony.Instrumenter, includeUntested: true })) // hook require function for complete code coverage diff --git a/package.json b/package.json index 7f740792..3eca8c2c 100644 --- a/package.json +++ b/package.json @@ -21,28 +21,27 @@ "iojs": ">=1.7" }, "dependencies": { - "async": "^1.4.0", - "filesize": "^3.1.3", - "js-yaml": "^3.4.1", + "async": "^1.5.2", + "filesize": "^3.1.5", + "js-yaml": "^3.5.2", "knuth-shuffle": "^1.0.1", "later": "^1.1.9", "request": "^2.60.0", - "xregexp": "^2.0.0", + "xregexp": "^3.0.0", "yargs": "^3.24.0" }, "devDependencies": { "blns": "^2.0.1", "chai": "^3.2.0", - "chai-string": "^1.1.2", - "coveralls": "^2.11.4", + "chai-string": "^1.1.6", + "coveralls": "^2.11.6", "gulp": "^3.9.0", "gulp-eslint": "^1.0.0", - "gulp-git": "^1.4.0", + "gulp-git": "^1.6.1", "gulp-istanbul": "^0.10.0", - "gulp-jsdoc-to-markdown": "^1.1.1", + "gulp-jsdoc-to-markdown": "^1.2.1", "gulp-mocha": "^2.1.3", "gulp-rename": "^1.2.2", - "istanbul-harmony": "^0.3.16", "sinon": "^1.15.1", "sinon-chai": "^2.8.0" }, diff --git a/plugins/anonymize.js b/plugins/anonymize.js index 30eb1214..6352481e 100644 --- a/plugins/anonymize.js +++ b/plugins/anonymize.js @@ -70,7 +70,7 @@ exports.stop = function () {}; * @param {external.posts.CleanedPost} post Post that triggered notification */ exports.handler = function handler(notification, topic, post) { - const match = rQuote.xexec(post.raw); + const match = xRegExp.exec(post.raw, rQuote); //match.topicId is a string, so coerce topic.id type to match if (!match) { mBrowser.createPost(topic.id, post.post_number, parseError, () => 0); From 26021a12f46ac73326cd78587531601531ea36a5 Mon Sep 17 00:00:00 2001 From: Accalia de Elementia Date: Sun, 17 Jan 2016 17:38:04 +0000 Subject: [PATCH 03/23] add extended help registration ability --- lib/commands.js | 37 ++++++++- package.json | 18 ++--- test/lib/commandsTest.js | 167 ++++++++++++++++++++++++++++++++++++++- 3 files changed, 206 insertions(+), 16 deletions(-) diff --git a/lib/commands.js b/lib/commands.js index 44abfdc5..b93e340f 100644 --- a/lib/commands.js +++ b/lib/commands.js @@ -18,6 +18,7 @@ const internals = { parseShortCommand: parseShortCommand, parseMentionCommand: parseMentionCommand, registerCommand: registerCommand, + registerHelp: registerHelp, events: null, commandProtect: commandProtect, getCommandHelps: getCommandHelps, @@ -25,7 +26,8 @@ const internals = { cmdHelp: cmdHelp, cmdShutUp: cmdShutUp, shutdown: shutdown, - commands: {} + commands: {}, + helpMessages: {} }; /** @@ -41,6 +43,7 @@ exports.prepare = function prepare(events, callback) { events.on('command#ERROR', cmdError); events.onCommand = registerCommand; events.on('newListener', commandProtect); + events.registerHelp = registerHelp; async.parallel([ cb => events.onCommand('help', 'print command help listing', cmdHelp, cb), cb => events.onCommand('shutup', 'tell me to shutup', cmdShutUp, cb), @@ -202,8 +205,18 @@ function cmdHelp(command) { if (!command.post) { return; } - const help = internals.getCommandHelps() + '\n\nMore details may be available by passing `help` as ' + - 'the first parameter to a command'; + let ext = ''; + if (command.args && command.args.length > 0) { + ext = command.args.join(' '); + } + if (ext && internals.helpMessages[ext]) { + const txt = 'Extended help for `' + ext + '`\n\n' + internals.helpMessages[ext] + + '\n\nIssue the `help` command without any parameters to see all available commands'; + browser.createPost(command.post.topic_id, command.post.post_number, txt, () => 0); + return; + } + const help = internals.getCommandHelps() + '\n\nMore details may be available by passing a command name as ' + + 'the first parameter to `help`'; browser.createPost(command.post.topic_id, command.post.post_number, help, () => 0); } @@ -244,6 +257,24 @@ function registerCommand(command, helpstring, handler, callback) { return callback(); } +function registerHelp(command, helptext, callback) { + if (!callback || typeof callback !== 'function') { + throw new Error('callback must be provided'); + } + if (!command || typeof command !== 'string') { + return callback(new Error('command must be provided')); + } + if (!helptext || typeof helptext !== 'string') { + return callback(new Error('helptext must be provided')); + } + if (internals.helpMessages[command]) { + internals.events.emit('logWarning', 'Overwriting existing extended help for: `' + command + '`!'); + } + internals.helpMessages[command] = helptext; + internals.events.emit('logMessage', 'Extended help registered for: ' + command); + return callback(); +} + /** * Watch for unauthorized commands and reject them * diff --git a/package.json b/package.json index 3eca8c2c..fb02b7df 100644 --- a/package.json +++ b/package.json @@ -25,24 +25,24 @@ "filesize": "^3.1.5", "js-yaml": "^3.5.2", "knuth-shuffle": "^1.0.1", - "later": "^1.1.9", - "request": "^2.60.0", + "later": "^1.2.0", + "request": "^2.67.0", "xregexp": "^3.0.0", - "yargs": "^3.24.0" + "yargs": "^3.32.0" }, "devDependencies": { - "blns": "^2.0.1", - "chai": "^3.2.0", + "blns": "^2.0.2", + "chai": "^3.4.1", "chai-string": "^1.1.6", "coveralls": "^2.11.6", "gulp": "^3.9.0", - "gulp-eslint": "^1.0.0", + "gulp-eslint": "^1.1.1", "gulp-git": "^1.6.1", - "gulp-istanbul": "^0.10.0", + "gulp-istanbul": "^0.10.3", "gulp-jsdoc-to-markdown": "^1.2.1", "gulp-mocha": "^2.1.3", - "gulp-rename": "^1.2.2", - "sinon": "^1.15.1", + "gulp-rename": "^1.2.2", + "sinon": "^1.17.2", "sinon-chai": "^2.8.0" }, "scripts": { diff --git a/test/lib/commandsTest.js b/test/lib/commandsTest.js index 095562d9..c2bbfef9 100644 --- a/test/lib/commandsTest.js +++ b/test/lib/commandsTest.js @@ -38,11 +38,11 @@ describe('commands', () => { }); }); describe('internals', () => { - const fns = ['parseMentionCommand', 'parseShortCommand', 'registerCommand', + const fns = ['parseMentionCommand', 'parseShortCommand', 'registerCommand', 'registerHelp', 'commandProtect', 'getCommandHelps', 'cmdError', 'cmdHelp', 'cmdShutUp', 'shutdown' ], - objs = ['mention', 'events', 'commands'], + objs = ['mention', 'events', 'commands', 'helpMessages'], vals = []; describe('should include expected functions:', () => { fns.forEach((fn) => { @@ -183,8 +183,8 @@ describe('commands', () => { }); it('should post expected text', () => { const expected = 'Registered commands:\nhelp: print command help listing\n' + - 'shutup: tell me to shutup\n\nMore details may be available by passing' + - ' `help` as the first parameter to a command'; + 'shutup: tell me to shutup\n\nMore details may be available by passing ' + + 'a command name as the first parameter to `help`'; commands.internals.commands.help = { help: 'print command help listing' }; @@ -213,6 +213,93 @@ describe('commands', () => { browser.createPost.lastCall.args[3].should.be.a('function'); browser.createPost.lastCall.args[3]().should.equal(0); }); + describe('with parameters', () => { + it('should post default text without parameters', () => { + const expected = 'Registered commands:'; + cmdHelp({ + command: 'foobar', + post: { + 'topic_id': 15, + 'post_number': 75 + } + }); + browser.createPost.callCount.should.equal(1); + browser.createPost.calledWith(15, 75).should.be.true; + browser.createPost.lastCall.args[2].should.startWith(expected); + }); + it('should post default text when called with empty parameters', () => { + const expected = 'Registered commands:'; + cmdHelp({ + command: 'foobar', + args: [], + post: { + 'topic_id': 15, + 'post_number': 75 + } + }); + browser.createPost.callCount.should.equal(1); + browser.createPost.calledWith(15, 75).should.be.true; + browser.createPost.lastCall.args[2].should.startWith(expected); + }); + it('should post default text when called with unexpected parameters', () => { + const expected = 'Registered commands:'; + cmdHelp({ + command: 'foobar', + args: ['i', 'am', 'not', 'a', 'command'], + post: { + 'topic_id': 15, + 'post_number': 75 + } + }); + browser.createPost.callCount.should.equal(1); + browser.createPost.calledWith(15, 75).should.be.true; + browser.createPost.lastCall.args[2].should.startWith(expected); + }); + it('should post extended help message one word command', () => { + const expected = 'Extended help for `whosit`\n\nwhosit extended help' + + '\n\nIssue the `help` command without any parameters to see all available commands'; + commands.internals.helpMessages.whosit = 'whosit extended help'; + cmdHelp({ + command: 'foobar', + args: ['whosit'], + post: { + 'topic_id': 15, + 'post_number': 75 + } + }); + browser.createPost.callCount.should.equal(1); + browser.createPost.calledWith(15, 75).should.be.true; + browser.createPost.lastCall.args[2].should.equal(expected); + }); + it('should post extended help message multi-word command', () => { + const expected = 'Extended help for `who am i`'; + commands.internals.helpMessages['who am i'] = 'whosit extended help'; + cmdHelp({ + command: 'foobar', + args: ['who', 'am', 'i'], + post: { + 'topic_id': 15, + 'post_number': 75 + } + }); + browser.createPost.callCount.should.equal(1); + browser.createPost.calledWith(15, 75).should.be.true; + browser.createPost.lastCall.args[2].should.startWith(expected); + }); + it('should pass callback to createPost', () => { + commands.internals.helpMessages['who am i'] = 'whosit extended help'; + cmdHelp({ + command: 'foobar', + args: ['who', 'am', 'i'], + post: { + 'topic_id': 1, + 'post_number': 5 + } + }); + browser.createPost.lastCall.args[3].should.be.a('function'); + browser.createPost.lastCall.args[3]().should.equal(0); + }); + }); }); describe('internals.cmdShutUp()', () => { const cmdShutUp = commands.internals.cmdShutUp; @@ -615,6 +702,78 @@ describe('commands', () => { cmd.args.should.deep.equal(['arg1', 'arg2']); }); }); + describe('internals.registerHelp()', () => { + const registerHelp = commands.internals.registerHelp, + spy = sinon.spy(); + let sandbox, events; + beforeEach(() => { + sandbox = sinon.sandbox.create(); + events = { + on: sinon.spy(), + emit: sinon.spy() + }; + commands.internals.events = events; + commands.internals.commands = {}; + }); + afterEach(() => { + sandbox.restore(); + }); + describe('parameter validation', () => { + it('should require a callback', () => { + expect(() => registerHelp()).to.throw('callback must be provided'); + }); + it('should require callback to be a function', () => { + expect(() => { + registerHelp(undefined, undefined, 'not function'); + }).to.throw('callback must be provided'); + }); + it('should require `command`', () => { + registerHelp(undefined, undefined, spy); + spy.called.should.be.true; + spy.lastCall.args[0].should.be.instanceOf(Error); + spy.lastCall.args[0].message.should.equal('command must be provided'); + }); + it('should require `command` to be string', () => { + registerHelp(true, undefined, spy); + spy.called.should.be.true; + spy.lastCall.args[0].should.be.instanceOf(Error); + spy.lastCall.args[0].message.should.equal('command must be provided'); + }); + it('should require `helptext`', () => { + registerHelp('command', undefined, spy); + spy.called.should.be.true; + spy.lastCall.args[0].should.be.instanceOf(Error); + spy.lastCall.args[0].message.should.equal('helptext must be provided'); + }); + it('should require `helptext` to be string', () => { + registerHelp('command', true, spy); + spy.called.should.be.true; + spy.lastCall.args[0].should.be.instanceOf(Error); + spy.lastCall.args[0].message.should.equal('helptext must be provided'); + }); + it('should call callback without error on help registration', () => { + registerHelp('command', 'help', spy); + spy.called.should.be.true; + spy.lastCall.args.should.have.length(0); + }); + }); + it('should add command to help Messages on registration', () => { + registerHelp('commandhelp', 'help', spy); + commands.internals.helpMessages.commandhelp.should.be.ok; + }); + it('should log registration', () => { + const cmd = 'CMD' + Math.random(); + registerHelp(cmd, 'help', spy); + events.emit.calledWith('logMessage', 'Extended help registered for: ' + cmd).should.be.true; + }); + it('should warn on help overwrite', () => { + const cmd = 'CMD' + Math.random(); + commands.internals.helpMessages[cmd] = 'foo'; + registerHelp(cmd, 'help', spy); + events.emit.calledWith('logWarning', 'Overwriting existing extended help for: `' + cmd + + '`!').should.be.true; + }); + }); describe('internals.registerCommand()', () => { const registerCommand = commands.internals.registerCommand, spy = sinon.spy(); From 24e4298be7898ecb12545b5a62db1ee8c86f92d1 Mon Sep 17 00:00:00 2001 From: Accalia de Elementia Date: Mon, 18 Jan 2016 12:47:34 +0000 Subject: [PATCH 04/23] bump minor version number due to additional function on sockevents --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index fb02b7df..b086502f 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "sockbot", - "version": "2.11.10", - "releaseName": "Cheery Chiffon", + "version": "2.12.0", + "releaseName": "Delightful Denim", "description": "A sockpuppet bot to use on http://what.thedailywtf.com.", "repository": "https://github.com/SockDrawer/SockBot", "license": "MIT", From a34391e5889357360f9392e1b1ba8fd113b35e9c Mon Sep 17 00:00:00 2001 From: Accalia de Elementia Date: Mon, 18 Jan 2016 12:49:24 +0000 Subject: [PATCH 05/23] update supported node versions --- .travis.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 2dc3af63..1d6a47ad 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,8 +4,9 @@ node_js: - iojs - '0.11' - '0.12' -- '4.0' - '4.1' +- '4.2' +- '5.3' before_script: - rm -rf ./coverage - git config credential.helper "store --file=.git/credentials" From 7320d819a3e46af4e74bf205340e2b8ad37e1f9d Mon Sep 17 00:00:00 2001 From: Accalia de Elementia Date: Mon, 18 Jan 2016 12:52:48 +0000 Subject: [PATCH 06/23] update docs --- docs/api/lib/commands.md | 16 ++++++++++++++++ lib/commands.js | 10 ++++++++++ 2 files changed, 26 insertions(+) diff --git a/docs/api/lib/commands.md b/docs/api/lib/commands.md index f46a5fe9..587e8c7e 100644 --- a/docs/api/lib/commands.md +++ b/docs/api/lib/commands.md @@ -19,6 +19,7 @@ Command Parser for SockBot2.0 * [~cmdShutUp(command)](#module_commands..cmdShutUp) * [~cmdHelp(command)](#module_commands..cmdHelp) * [~registerCommand(command, helpstring, handler, callback)](#module_commands..registerCommand) ⇒ undefined + * [~registerHelp(command, helptext, callback)](#module_commands..registerHelp) ⇒ undefined * [~commandProtect(event, handler)](#module_commands..commandProtect) ⇒ boolean * [~command](#module_commands..command) : object * [~completedCallback](#module_commands..completedCallback) @@ -134,6 +135,21 @@ will be added to core EventEmitter as .onCommand() | handler | commandHandler | Function to handle the command | | callback | completedCallback | Completion callback | + +### commands~registerHelp(command, helptext, callback) ⇒ undefined +Register extended help + +will be added to core EventEmitter as .registerHelp() + +**Kind**: inner method of [commands](#module_commands) +**Returns**: undefined - No return value + +| Param | Type | Description | +| --- | --- | --- | +| command | string | Command or topic to register help for | +| helptext | string | Extended help text | +| callback | completedCallback | Completion callback | + ### commands~commandProtect(event, handler) ⇒ boolean Watch for unauthorized commands and reject them diff --git a/lib/commands.js b/lib/commands.js index b93e340f..a393a1b8 100644 --- a/lib/commands.js +++ b/lib/commands.js @@ -257,6 +257,16 @@ function registerCommand(command, helpstring, handler, callback) { return callback(); } +/** + * Register extended help + * + * will be added to core EventEmitter as .registerHelp() + * + * @param {string} command Command or topic to register help for + * @param {string} helptext Extended help text + * @param {completedCallback} callback Completion callback + * @returns {undefined} No return value + */ function registerHelp(command, helptext, callback) { if (!callback || typeof callback !== 'function') { throw new Error('callback must be provided'); From 5b4e676367a9a9f262d440a2605da2e52748ea92 Mon Sep 17 00:00:00 2001 From: Accalia de Elementia Date: Mon, 18 Jan 2016 12:55:26 +0000 Subject: [PATCH 07/23] update docs --- external/events.js | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/external/events.js b/external/events.js index 31e5077e..9348862a 100644 --- a/external/events.js +++ b/external/events.js @@ -121,7 +121,7 @@ */ /** - * Add a notification listener + * Add a command listener * * @function * @name onCommand @@ -131,6 +131,16 @@ * @returns {SockEvents} SockEvents for chaining calls */ +/** + * Add Extended help fot a command or topic + * + * @function + * @name registerHelp + * @param {string} command Command or topic to register help for + * @param {string} helptext Extended help text + * @returns {SockEvents} SockEvents for chaining calls + */ + /** * Remove a command listener * From c68d36cc3f07f3733093b566b800f94223c7023d Mon Sep 17 00:00:00 2001 From: Accalia de Elementia Date: Mon, 18 Jan 2016 13:02:09 +0000 Subject: [PATCH 08/23] fix typo --- external/events.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/external/events.js b/external/events.js index 9348862a..9d2a564f 100644 --- a/external/events.js +++ b/external/events.js @@ -132,7 +132,7 @@ */ /** - * Add Extended help fot a command or topic + * Add Extended help for a command or topic * * @function * @name registerHelp From 2626bafa8c2f79f400f1889b4b020036898635dc Mon Sep 17 00:00:00 2001 From: Accalia de Elementia Date: Mon, 18 Jan 2016 13:18:13 +0000 Subject: [PATCH 09/23] add extended help to summoner --- plugins/summoner.js | 7 ++++++- test/plugins/summonerTest.js | 9 ++++++++- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/plugins/summoner.js b/plugins/summoner.js index 5bf53585..24d515aa 100644 --- a/plugins/summoner.js +++ b/plugins/summoner.js @@ -39,7 +39,11 @@ exports.defaultConfig = { '@%username% has summoned me, and so I appear.', 'Yes master %name%, I shall appear as summoned.', 'Yes mistress %name%, I shall appear as summoned.' - ] + ], + /** + * Extended help message + */ + extendedHelp: 'Respond to @mentions with a randomly selected preconfigured phrase' }; /** @@ -87,6 +91,7 @@ exports.prepare = function prepare(plugConfig, config, events, browser) { internals.browser = browser; internals.configuration = config.mergeObjects(true, exports.defaultConfig, plugConfig); events.onNotification('mentioned', exports.mentionHandler); + events.registerHelp('summoner', internals.extendedHelp, () => 0); }; /** diff --git a/test/plugins/summonerTest.js b/test/plugins/summonerTest.js index 427744b4..b238b341 100644 --- a/test/plugins/summonerTest.js +++ b/test/plugins/summonerTest.js @@ -43,7 +43,8 @@ describe('summoner plugin', () => { sandbox = sinon.sandbox.create(); sandbox.stub(dummyCfg, 'mergeObjects'); events = { - onNotification: sinon.spy() + onNotification: sinon.spy(), + registerHelp: sinon.spy() }; }); afterEach(() => sandbox.restore()); @@ -97,6 +98,12 @@ describe('summoner plugin', () => { }); }); }); + it('should register extended help', () => { + summoner.prepare({}, dummyCfg, events); + events.registerHelp.calledWith('summoner', summoner.internals.extendedHelp).should.be.true; + expect(events.registerHelp.firstCall.args[2]).to.be.a('function'); + expect(events.registerHelp.firstCall.args[2]()).to.equal(0); + }); }); describe('mentionHandler()', () => { let sandbox, browser, topic, post; From 85879fb3358afc0801d71e98fe4b08b62bc34270 Mon Sep 17 00:00:00 2001 From: Accalia de Elementia Date: Mon, 18 Jan 2016 19:05:47 +0000 Subject: [PATCH 10/23] add docs link --- plugins/summoner.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/plugins/summoner.js b/plugins/summoner.js index 24d515aa..1266c02b 100644 --- a/plugins/summoner.js +++ b/plugins/summoner.js @@ -43,7 +43,8 @@ exports.defaultConfig = { /** * Extended help message */ - extendedHelp: 'Respond to @mentions with a randomly selected preconfigured phrase' + extendedHelp: 'Respond to @mentions with a randomly selected preconfigured phrase.\n\nFor more information see ' + + 'the [full docs](https://sockbot.readthedocs.org/en/latest/Plugins/summoner/)' }; /** From cf7b2469910a2adf5e3127f2f0eb8ea1db3b908f Mon Sep 17 00:00:00 2001 From: Accalia de Elementia Date: Mon, 18 Jan 2016 19:06:31 +0000 Subject: [PATCH 11/23] add extended help to likes plugin --- plugins/likes.js | 5 ++++- test/plugins/likesTest.js | 26 +++++++++++++++++++++----- 2 files changed, 25 insertions(+), 6 deletions(-) diff --git a/plugins/likes.js b/plugins/likes.js index b2ed84ce..31456640 100644 --- a/plugins/likes.js +++ b/plugins/likes.js @@ -94,7 +94,9 @@ const defaultConfig = { * EventEmitter used for internal communication * @type {externals.events.SockEvents} */ - events:null + events: null, + extendedHelp: 'Automatically likes posts in certain threads.\n\nFor more information see the' + + ' [full docs](https://sockbot.readthedocs.org/en/latest/Plugins/likes/)' }; exports.defaultConfig = defaultConfig; exports.internals = internals; @@ -119,6 +121,7 @@ exports.prepare = function prepare(plugConfig, config, events, browser) { internals.config.bingeHour = Math.floor(Math.random() * 24); internals.config.bingeMinute = Math.floor(Math.random() * 60); } + events.registerHelp('likes', internals.extendedHelp, () => 0); }; /** diff --git a/test/plugins/likesTest.js b/test/plugins/likesTest.js index e90822c7..6cac06db 100644 --- a/test/plugins/likesTest.js +++ b/test/plugins/likesTest.js @@ -36,6 +36,7 @@ describe('likes plugin', () => { let sandbox; beforeEach(() => { sandbox = sinon.sandbox.create(); + dummyEvents.registerHelp = sinon.spy(); }); afterEach(() => { sandbox.restore(); @@ -66,7 +67,8 @@ describe('likes plugin', () => { likes.prepare({ topics: [3, 5, 17] }, dummyCfg, { - onTopic: spy + onTopic: spy, + registerHelp: () => 0 }, null); spy.calledWith(3, likes.messageHandler).should.be.true; spy.calledWith(5, likes.messageHandler).should.be.true; @@ -83,6 +85,12 @@ describe('likes plugin', () => { likes.internals.config.bingeHour.should.equal(0); likes.internals.config.bingeMinute.should.equal(0); }); + it('should register extended help', () => { + likes.prepare({}, dummyCfg, dummyEvents); + dummyEvents.registerHelp.calledWith('likes', likes.internals.extendedHelp).should.be.true; + expect(dummyEvents.registerHelp.firstCall.args[2]).to.be.a('function'); + expect(dummyEvents.registerHelp.firstCall.args[2]()).to.equal(0); + }); }); describe('start()', () => { let sandbox; @@ -110,7 +118,9 @@ describe('likes plugin', () => { }); describe('stop()', () => { it('should stop binging', () => { - likes.internals.bingeInterval = {clear: () => 0}; + likes.internals.bingeInterval = { + clear: () => 0 + }; likes.stop(); expect(likes.internals.bingeInterval).to.be.undefined; }); @@ -178,7 +188,9 @@ describe('likes plugin', () => { it('should retry on server error', () => { const id = Math.random(), spy = sinon.stub(); - spy.onCall(0).yields({statusCode: 500}); + spy.onCall(0).yields({ + statusCode: 500 + }); spy.onCall(1).yields(null); setTimeout.callsArg(0); likes.internals.browser = { @@ -195,7 +207,9 @@ describe('likes plugin', () => { it('should not retry on other error', () => { const id = Math.random(), spy = sinon.stub(); - spy.onCall(0).yields({statusCode: 499}); + spy.onCall(0).yields({ + statusCode: 499 + }); spy.onCall(1).yields(null); setTimeout.callsArg(0); likes.internals.browser = { @@ -229,7 +243,9 @@ describe('likes plugin', () => { it('should not make more than three attempts', () => { const id = Math.random(), spy = sinon.stub(); - spy.yields({statusCode: 500}); + spy.yields({ + statusCode: 500 + }); setTimeout.callsArg(0); likes.internals.browser = { postAction: spy From 287196eb5e3a008c7bb4a8c8eeaf92868c9aa631 Mon Sep 17 00:00:00 2001 From: Accalia de Elementia Date: Mon, 18 Jan 2016 19:11:28 +0000 Subject: [PATCH 12/23] add jsdoc tag --- plugins/likes.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/plugins/likes.js b/plugins/likes.js index 31456640..608fe6a4 100644 --- a/plugins/likes.js +++ b/plugins/likes.js @@ -95,6 +95,9 @@ const defaultConfig = { * @type {externals.events.SockEvents} */ events: null, + /** + * Extended help message + */ extendedHelp: 'Automatically likes posts in certain threads.\n\nFor more information see the' + ' [full docs](https://sockbot.readthedocs.org/en/latest/Plugins/likes/)' }; From 3ab73f32cb29c87b68c90330629813c3e4d7ec4e Mon Sep 17 00:00:00 2001 From: Accalia de Elementia Date: Mon, 18 Jan 2016 19:13:14 +0000 Subject: [PATCH 13/23] add generated docs --- docs/api/external/events.md | 15 ++++++++++++++- docs/api/plugins/likes.md | 7 +++++++ docs/api/plugins/summoner.md | 7 +++++++ 3 files changed, 28 insertions(+), 1 deletion(-) diff --git a/docs/api/external/events.md b/docs/api/external/events.md index 8cb2b9a6..d85928a0 100644 --- a/docs/api/external/events.md +++ b/docs/api/external/events.md @@ -16,6 +16,7 @@ for details. * [~onNotification(type, handler)](#module_SockEvents..onNotification) ⇒ SockEvents * [~removeNotification(type, handler)](#module_SockEvents..removeNotification) ⇒ SockEvents * [~onCommand(type, helpstring, handler)](#module_SockEvents..onCommand) ⇒ SockEvents + * [~registerHelp(command, helptext)](#module_SockEvents..registerHelp) ⇒ SockEvents * [~removeCommand(command, handler)](#module_SockEvents..removeCommand) ⇒ SockEvents * [~command](#module_SockEvents..command) : object * [~messageHandler](#module_SockEvents..messageHandler) @@ -85,7 +86,7 @@ Remove a notification listener ### SockEvents~onCommand(type, helpstring, handler) ⇒ SockEvents -Add a notification listener +Add a command listener **Kind**: inner method of [SockEvents](#module_SockEvents) **Returns**: SockEvents - SockEvents for chaining calls @@ -96,6 +97,18 @@ Add a notification listener | helpstring | string | Short help text for command | | handler | commandHandler | Command handler | + +### SockEvents~registerHelp(command, helptext) ⇒ SockEvents +Add Extended help for a command or topic + +**Kind**: inner method of [SockEvents](#module_SockEvents) +**Returns**: SockEvents - SockEvents for chaining calls + +| Param | Type | Description | +| --- | --- | --- | +| command | string | Command or topic to register help for | +| helptext | string | Extended help text | + ### SockEvents~removeCommand(command, handler) ⇒ SockEvents Remove a command listener diff --git a/docs/api/plugins/likes.md b/docs/api/plugins/likes.md index 0a1a63b1..3240a59d 100644 --- a/docs/api/plugins/likes.md +++ b/docs/api/plugins/likes.md @@ -31,6 +31,7 @@ Watches threads for new posts and likes them, includes "binge" functionality to * [.bingeInterval](#module_likes..internals.bingeInterval) : \* * [.likeCount](#module_likes..internals.likeCount) : number * [.events](#module_likes..internals.events) : externals.events.SockEvents + * [.extendedHelp](#module_likes..internals.extendedHelp) * [~completionCallback](#module_likes..completionCallback) @@ -165,6 +166,7 @@ Internal status store * [.bingeInterval](#module_likes..internals.bingeInterval) : \* * [.likeCount](#module_likes..internals.likeCount) : number * [.events](#module_likes..internals.events) : externals.events.SockEvents + * [.extendedHelp](#module_likes..internals.extendedHelp) #### internals.browser : Browser @@ -190,6 +192,11 @@ Count of likes handed out during latest binge #### internals.events : externals.events.SockEvents EventEmitter used for internal communication +**Kind**: static property of [internals](#module_likes..internals) + +#### internals.extendedHelp +Extended help message + **Kind**: static property of [internals](#module_likes..internals) ### likes~completionCallback diff --git a/docs/api/plugins/summoner.md b/docs/api/plugins/summoner.md index 2cc6fc52..d532668b 100644 --- a/docs/api/plugins/summoner.md +++ b/docs/api/plugins/summoner.md @@ -11,6 +11,7 @@ Watches for @mentions and replies with a canned response * [.defaultConfig](#module_summoner.defaultConfig) * [.cooldown](#module_summoner.defaultConfig.cooldown) : Number * [.messages](#module_summoner.defaultConfig.messages) : Array.<string> + * [.extendedHelp](#module_summoner.defaultConfig.extendedHelp) * [.mentionHandler(_, topic, post)](#module_summoner.mentionHandler) * [.prepare(plugConfig, config, events, browser)](#module_summoner.prepare) * [.start()](#module_summoner.start) @@ -25,6 +26,7 @@ Default plugin configuration * [.defaultConfig](#module_summoner.defaultConfig) * [.cooldown](#module_summoner.defaultConfig.cooldown) : Number * [.messages](#module_summoner.defaultConfig.messages) : Array.<string> + * [.extendedHelp](#module_summoner.defaultConfig.extendedHelp) #### defaultConfig.cooldown : Number @@ -37,6 +39,11 @@ Messages to select reply from. **Kind**: static property of [defaultConfig](#module_summoner.defaultConfig) **Default**: ["@%username% has summoned me, and so I appear.","Yes master %name%, I shall appear as summoned.","Yes mistress %name%, I shall appear as summoned."] + +#### defaultConfig.extendedHelp +Extended help message + +**Kind**: static property of [defaultConfig](#module_summoner.defaultConfig) ### summoner.mentionHandler(_, topic, post) Respond to @mentions From 8de89124e4cbe2a03ad8453951b79304b55dcf55 Mon Sep 17 00:00:00 2001 From: Accalia de Elementia Date: Mon, 18 Jan 2016 19:17:48 +0000 Subject: [PATCH 14/23] add extended help to echo --- plugins/echo.js | 8 ++++++++ test/plugins/echoTest.js | 22 ++++++++++++++++++---- 2 files changed, 26 insertions(+), 4 deletions(-) diff --git a/plugins/echo.js b/plugins/echo.js index 3fd8cf8c..93e9f377 100644 --- a/plugins/echo.js +++ b/plugins/echo.js @@ -7,6 +7,13 @@ */ let mBrowser; + +/** + * Extended help message + */ +exports.extendedHelp = 'Testing plugin that echos your posts back at you.\n\nFor more information see the' + + ' [full docs](https://sockbot.readthedocs.org/en/latest/Plugins/echo/)'; + /** * Prepare Plugin prior to login * @@ -20,6 +27,7 @@ exports.prepare = function (plugConfig, config, events, browser) { events.onNotification('mentioned', exports.handler); events.onNotification('replied', exports.handler); events.onNotification('private_message', exports.handler); + events.registerHelp('echo', exports.extendedHelp, () => 0); }; /** diff --git a/test/plugins/echoTest.js b/test/plugins/echoTest.js index bef6c782..52e2d5b0 100644 --- a/test/plugins/echoTest.js +++ b/test/plugins/echoTest.js @@ -30,31 +30,45 @@ describe('echo', () => { it('should register notification listener for `mentioned`', () => { const spy = sinon.spy(); echo.prepare(undefined, undefined, { - onNotification: spy + onNotification: spy, + registerHelp: sinon.spy() }, undefined); spy.calledWith('mentioned', echo.handler).should.be.true; }); it('should register notification listener for `replied`', () => { const spy = sinon.spy(); echo.prepare(undefined, undefined, { - onNotification: spy + onNotification: spy, + registerHelp: sinon.spy() }, undefined); spy.calledWith('replied', echo.handler).should.be.true; }); it('should register notification listener for `private_message`', () => { const spy = sinon.spy(); echo.prepare(undefined, undefined, { - onNotification: spy + onNotification: spy, + registerHelp: sinon.spy() }, undefined); spy.calledWith('private_message', echo.handler).should.be.true; }); + it('should register extended help', () => { + const evts = { + onNotification: sinon.spy(), + registerHelp: sinon.spy() + }; + echo.prepare({}, {}, evts); + evts.registerHelp.calledWith('echo', echo.extendedHelp).should.be.true; + expect(evts.registerHelp.firstCall.args[2]).to.be.a('function'); + expect(evts.registerHelp.firstCall.args[2]()).to.equal(0); + }); }); describe('handler()', () => { it('should create post from clean data', () => { const spy = sinon.stub(); spy.yields(null); echo.prepare(undefined, undefined, { - onNotification: () => 0 + onNotification: () => 0, + registerHelp: sinon.spy() }, { createPost: spy }); From c956159d55248d47d7a357289929892324391e36 Mon Sep 17 00:00:00 2001 From: Accalia de Elementia Date: Mon, 18 Jan 2016 19:18:36 +0000 Subject: [PATCH 15/23] add generated docs --- docs/api/plugins/echo.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/docs/api/plugins/echo.md b/docs/api/plugins/echo.md index f98cd522..c3f8f0d2 100644 --- a/docs/api/plugins/echo.md +++ b/docs/api/plugins/echo.md @@ -6,11 +6,17 @@ Example plugin, echos your words back at you. **License**: MIT * [echo](#module_echo) + * [.extendedHelp](#module_echo.extendedHelp) * [.prepare(plugConfig, config, events, browser)](#module_echo.prepare) * [.start()](#module_echo.start) * [.stop()](#module_echo.stop) * [.handler(notification, topic, post)](#module_echo.handler) + +### echo.extendedHelp +Extended help message + +**Kind**: static property of [echo](#module_echo) ### echo.prepare(plugConfig, config, events, browser) Prepare Plugin prior to login From b3fa2a07249940f3441ae38a5685085d2d4cdc5b Mon Sep 17 00:00:00 2001 From: Accalia de Elementia Date: Mon, 18 Jan 2016 19:30:25 +0000 Subject: [PATCH 16/23] add extended help for autoreader --- docs/api/plugins/autoreader.md | 7 +++++++ plugins/autoreader.js | 8 +++++++- test/plugins/autoreaderTest.js | 32 ++++++++++++++++++++++++++------ 3 files changed, 40 insertions(+), 7 deletions(-) diff --git a/docs/api/plugins/autoreader.md b/docs/api/plugins/autoreader.md index 01764622..12e8928a 100644 --- a/docs/api/plugins/autoreader.md +++ b/docs/api/plugins/autoreader.md @@ -22,6 +22,7 @@ Automatically read posts older than the configured interval. * [.config](#module_autoreader..internals.config) : object * [.timer](#module_autoreader..internals.timer) : object * [.events](#module_autoreader..internals.events) : externals.events.SockEvents + * [.extendedHelp](#module_autoreader..internals.extendedHelp) ### autoreader.prepare(plugConfig, config, events, browser) @@ -98,6 +99,7 @@ Internal status store * [.config](#module_autoreader..internals.config) : object * [.timer](#module_autoreader..internals.timer) : object * [.events](#module_autoreader..internals.events) : externals.events.SockEvents + * [.extendedHelp](#module_autoreader..internals.extendedHelp) #### internals.browser : Browser @@ -119,3 +121,8 @@ Used to stop the autoreading when the plugin is stopped EventEmitter used for internal communication **Kind**: static property of [internals](#module_autoreader..internals) + +#### internals.extendedHelp +Extended help message + +**Kind**: static property of [internals](#module_autoreader..internals) diff --git a/plugins/autoreader.js b/plugins/autoreader.js index 6c2bb5bd..af7577d8 100644 --- a/plugins/autoreader.js +++ b/plugins/autoreader.js @@ -63,7 +63,12 @@ const defaultConfig = { * EventEmitter used for internal communication * @type {externals.events.SockEvents} */ - events: null + events: null, + /** + * Extended help message + */ + extendedHelp: 'Automatically read posts throughout the forum.\n\nFor more information see the' + + ' [full docs](https://sockbot.readthedocs.org/en/latest/Plugins/autoreader/)' }; /** @@ -85,6 +90,7 @@ exports.prepare = function (plugConfig, config, events, browser) { internals.config.hour = Math.floor(Math.random() * 24); internals.config.minute = Math.floor(Math.random() * 60); } + events.registerHelp('autoreader', internals.extendedHelp, () => 0); }; /** diff --git a/test/plugins/autoreaderTest.js b/test/plugins/autoreaderTest.js index f2e4f9cb..a0bc0626 100644 --- a/test/plugins/autoreaderTest.js +++ b/test/plugins/autoreaderTest.js @@ -31,31 +31,50 @@ describe('autoreader', () => { }); describe('prepare()', () => { it('should use default config', () => { - autoreader.prepare(undefined, dummyCfg, undefined, undefined); + autoreader.prepare(undefined, dummyCfg, { + registerHelp: () => 0 + }, undefined); autoreader.internals.config.minAge.should.equal(3 * 24 * 60 * 60 * 1000); }); it('should use default config if config is not object', () => { - autoreader.prepare(true, dummyCfg, undefined, undefined); + autoreader.prepare(true, dummyCfg, { + registerHelp: () => 0 + }, undefined); autoreader.internals.config.minAge.should.equal(3 * 24 * 60 * 60 * 1000); }); it('should override default config', () => { autoreader.prepare({ minAge: 1 * 24 * 60 * 60 * 1000 - }, dummyCfg, undefined, undefined); + }, dummyCfg, { + registerHelp: () => 0 + }, undefined); autoreader.internals.config.minAge.should.equal(1 * 24 * 60 * 60 * 1000); }); it('should not randomize reader start', () => { autoreader.prepare({ randomize: false - }, dummyCfg, undefined, undefined); + }, dummyCfg, { + registerHelp: () => 0 + }, undefined); autoreader.internals.config.hour.should.equal(0); autoreader.internals.config.minute.should.equal(0); }); it('should store events object in internals', () => { - const events = Math.random(); + const events = { + registerHelp: () => 0 + }; autoreader.prepare(undefined, dummyCfg, events, undefined); autoreader.internals.events.should.equal(events); }); + it('should register extended help', () => { + const events = { + registerHelp: sinon.spy() + }; + autoreader.prepare({}, dummyCfg, events); + events.registerHelp.calledWith('autoreader', autoreader.internals.extendedHelp).should.be.true; + expect(events.registerHelp.firstCall.args[2]).to.be.a('function'); + expect(events.registerHelp.firstCall.args[2]()).to.equal(0); + }); }); describe('start()', () => { let sandbox; @@ -97,7 +116,8 @@ describe('autoreader', () => { complete(); }); events = { - emit: sinon.spy() + emit: sinon.spy(), + registerHelp: sinon.spy() }; autoreader.internals.events = events; }); From 2c7f06f03f9114b74b87497815d698dbba57cb31 Mon Sep 17 00:00:00 2001 From: Accalia de Elementia Date: Mon, 18 Jan 2016 19:39:20 +0000 Subject: [PATCH 17/23] add extended help for anonymize --- plugins/anonymize.js | 40 ++++++++++++++++++++++++---------- test/plugins/anonymizeTest.js | 41 +++++++++++++++++++++++++---------- 2 files changed, 59 insertions(+), 22 deletions(-) diff --git a/plugins/anonymize.js b/plugins/anonymize.js index 6352481e..2161bde8 100644 --- a/plugins/anonymize.js +++ b/plugins/anonymize.js @@ -32,10 +32,27 @@ const rQuote = xRegExp('\\[quote.*post:(?\\d+).*topic:(?\\d let mBrowser, siteUrl; const internals = { + /** + * Posted anonymousely message + */ postSuccess: postSuccess, + /** + * Failed to post because could not parse post to reply to message + */ parseError: parseError, + /** + * Failed to post because you used same topic for source and dest message + */ topicError: topicError, - postError: postError + /** + * Failed to post message because discourse message + */ + postError: postError, + /** + * Extended help message + */ + extendedHelp: 'Anonymize posts for you via PM.\n\nFor more information see the' + + ' [full docs](https://sockbot.readthedocs.org/en/latest/Plugins/anonymize/)' }; /** @@ -45,11 +62,12 @@ const internals = { * @param {Config} config Overall Bot Configuration * @param {externals.events.SockEvents} events EventEmitter used for the bot * @param {Browser} browser Web browser for communicating with discourse -*/ + */ exports.prepare = function (plugConfig, config, events, browser) { mBrowser = browser; siteUrl = config.core.forum; events.onNotification('private_message', exports.handler); + events.registerHelp('anonymize', internals.extendedHelp, () => 0); }; /** @@ -85,16 +103,16 @@ exports.handler = function handler(notification, topic, post) { mBrowser.createPost(topic.id, post.post_number, postError, () => 0); } else { const postUrl = [ - siteUrl, - 't', - aPost.topic_id, - aPost.post_number - ].join('/'); + siteUrl, + 't', + aPost.topic_id, + aPost.post_number + ].join('/'); const message = [ - postSuccess, - 'Post is here:', - postUrl - ].join('\n'); + postSuccess, + 'Post is here:', + postUrl + ].join('\n'); mBrowser.createPost(topic.id, post.post_number, message, () => 0); } }); diff --git a/test/plugins/anonymizeTest.js b/test/plugins/anonymizeTest.js index e449f55d..8074f8bc 100644 --- a/test/plugins/anonymizeTest.js +++ b/test/plugins/anonymizeTest.js @@ -12,10 +12,10 @@ const anonymize = require('../../plugins/anonymize'), const browser = browserModule(); const dummyCfg = { - core: { - forum: 'forumUrl' - } - }; + core: { + forum: 'forumUrl' + } +}; describe('anonymize', () => { it('should export prepare()', () => { @@ -40,10 +40,21 @@ describe('anonymize', () => { it('should register notification listener for `private_message`', () => { const spy = sinon.spy(); anonymize.prepare(undefined, dummyCfg, { - onNotification: spy + onNotification: spy, + registerHelp: sinon.spy() }, undefined); spy.calledWith('private_message', anonymize.handler).should.be.true; }); + it('should register extended help', () => { + const events = { + onNotification: sinon.spy(), + registerHelp: sinon.spy() + }; + anonymize.prepare({}, dummyCfg, events); + events.registerHelp.calledWith('anonymize', anonymize.internals.extendedHelp).should.be.true; + expect(events.registerHelp.firstCall.args[2]).to.be.a('function'); + expect(events.registerHelp.firstCall.args[2]()).to.equal(0); + }); }); describe('handler()', () => { let sandbox; @@ -57,7 +68,8 @@ describe('anonymize', () => { const spy = sandbox.stub(); spy.yields(null); anonymize.prepare(undefined, dummyCfg, { - onNotification: () => 0 + onNotification: () => 0, + registerHelp: sinon.spy() }, { createPost: spy }); @@ -74,7 +86,8 @@ describe('anonymize', () => { const spy = sandbox.stub(); spy.yields(null); anonymize.prepare(undefined, dummyCfg, { - onNotification: () => 0 + onNotification: () => 0, + registerHelp: sinon.spy() }, { createPost: spy }); @@ -92,7 +105,8 @@ describe('anonymize', () => { rawContent = '[quote="SockBot, topic:1"]Anonymized quote![/quote]Anonymized reply!'; spy.yields(null); anonymize.prepare(undefined, dummyCfg, { - onNotification: () => 0 + onNotification: () => 0, + registerHelp: sinon.spy() }, browser); anonymize.handler(undefined, { id: 1 @@ -106,9 +120,13 @@ describe('anonymize', () => { it('should create post in reply to target post', () => { const spy = sandbox.stub(browser, 'createPost'), rawContent = '[quote="SockBot, post:4, topic:3"]Anonymized quote![/quote]Anonymized reply!'; - spy.yields(null, {topic_id: 5, post_number: 6}); //eslint-disable-line camelcase + spy.yields(null, { + topic_id: 5, + post_number: 6 + }); //eslint-disable-line camelcase anonymize.prepare(undefined, dummyCfg, { - onNotification: () => 0 + onNotification: () => 0, + registerHelp: sinon.spy() }, browser); anonymize.handler(undefined, { id: 1 @@ -127,7 +145,8 @@ describe('anonymize', () => { rawContent = '[quote="SockBot, post:4, topic:3"]Anonymized quote![/quote]Anonymized reply!'; spy.yields(true); anonymize.prepare(undefined, dummyCfg, { - onNotification: () => 0 + onNotification: () => 0, + registerHelp: sinon.spy() }, browser); anonymize.handler(undefined, { id: 1 From 3e94696feca4091cc43250ddc07dab512e966cdb Mon Sep 17 00:00:00 2001 From: Accalia de Elementia Date: Tue, 19 Jan 2016 20:20:00 +0000 Subject: [PATCH 18/23] fix typo --- lib/commands.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/commands.js b/lib/commands.js index a393a1b8..59215ba6 100644 --- a/lib/commands.js +++ b/lib/commands.js @@ -197,7 +197,7 @@ function cmdShutUp(command) { } /** - * Reply with help test top the command !help + * Reply with help to the command !help * * @param {command} command help command */ From 471f87db6a96e083ec6f8af8099fae2735d96f1e Mon Sep 17 00:00:00 2001 From: Accalia de Elementia Date: Tue, 19 Jan 2016 20:20:21 +0000 Subject: [PATCH 19/23] fix lint warning --- test/plugins/anonymizeTest.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/plugins/anonymizeTest.js b/test/plugins/anonymizeTest.js index 8074f8bc..993d7058 100644 --- a/test/plugins/anonymizeTest.js +++ b/test/plugins/anonymizeTest.js @@ -121,8 +121,8 @@ describe('anonymize', () => { const spy = sandbox.stub(browser, 'createPost'), rawContent = '[quote="SockBot, post:4, topic:3"]Anonymized quote![/quote]Anonymized reply!'; spy.yields(null, { - topic_id: 5, - post_number: 6 + 'topic_id': 5, + 'post_number': 6 }); //eslint-disable-line camelcase anonymize.prepare(undefined, dummyCfg, { onNotification: () => 0, From 33cb7b89f4113300cd5a921f59c2f7df6eb6d23e Mon Sep 17 00:00:00 2001 From: Accalia de Elementia Date: Tue, 26 Jan 2016 16:24:16 +0000 Subject: [PATCH 20/23] refactor help command to support extended help topics --- lib/commands.js | 39 +++++++++++++++++++---- test/lib/commandsTest.js | 67 +++++++++++++++++++++++++++++++++++----- 2 files changed, 93 insertions(+), 13 deletions(-) diff --git a/lib/commands.js b/lib/commands.js index 59215ba6..2f29a609 100644 --- a/lib/commands.js +++ b/lib/commands.js @@ -144,10 +144,36 @@ exports.parseCommands = function parseCommands(post, topic, callback) { * @returns {string} command list for posting */ function getCommandHelps() { - const cmds = Object.keys(internals.commands), + const cmds = {}, + topics = {}, result = ['Registered commands:']; - cmds.sort(); - cmds.forEach((cmd) => result.push(cmd + ': ' + internals.commands[cmd].help)); + let keys = {}; + Object.keys(internals.commands).map((key) => { + keys[key] = 1; + }); + Object.keys(internals.helpMessages).map((key) => { + keys[key] = 1; + }); + Object.keys(keys).map((key) => { + if (internals.commands[key]) { + cmds[key] = internals.commands[key].help; + if (internals.helpMessages[key]) { + cmds[key] += ' *'; + } + } else { + topics[key] = 'Extended help topic'; + } + }); + keys = Object.keys(cmds); + keys.sort(); + keys.forEach((cmd) => result.push(cmd + ': ' + cmds[cmd])); + keys = Object.keys(topics); + if (keys.length) { + result.push(''); + result.push('Help Topics:'); + keys.sort(); + keys.forEach((topic) => result.push(topic + ': ' + topics[topic])); + } return result.join('\n'); } @@ -210,13 +236,13 @@ function cmdHelp(command) { ext = command.args.join(' '); } if (ext && internals.helpMessages[ext]) { - const txt = 'Extended help for `' + ext + '`\n\n' + internals.helpMessages[ext] + + const txt = 'Help topic for `' + ext + '`\n\n' + internals.helpMessages[ext] + '\n\nIssue the `help` command without any parameters to see all available commands'; browser.createPost(command.post.topic_id, command.post.post_number, txt, () => 0); return; } - const help = internals.getCommandHelps() + '\n\nMore details may be available by passing a command name as ' + - 'the first parameter to `help`'; + const help = internals.getCommandHelps() + '\n\n\* Help topic available.\n\nIssue the `help` command with an ' + + 'available help topic as a parameter to read additonal help'; browser.createPost(command.post.topic_id, command.post.post_number, help, () => 0); } @@ -277,6 +303,7 @@ function registerHelp(command, helptext, callback) { if (!helptext || typeof helptext !== 'string') { return callback(new Error('helptext must be provided')); } + command = command.toLowerCase(); if (internals.helpMessages[command]) { internals.events.emit('logWarning', 'Overwriting existing extended help for: `' + command + '`!'); } diff --git a/test/lib/commandsTest.js b/test/lib/commandsTest.js index c2bbfef9..f236c98b 100644 --- a/test/lib/commandsTest.js +++ b/test/lib/commandsTest.js @@ -158,6 +158,7 @@ describe('commands', () => { let sandbox, events; beforeEach(() => { commands.internals.commands = {}; + commands.internals.helpMessages = {}; sandbox = sinon.sandbox.create(); clock = sandbox.useFakeTimers(); events = { @@ -183,8 +184,8 @@ describe('commands', () => { }); it('should post expected text', () => { const expected = 'Registered commands:\nhelp: print command help listing\n' + - 'shutup: tell me to shutup\n\nMore details may be available by passing ' + - 'a command name as the first parameter to `help`'; + 'shutup: tell me to shutup\n\n* Help topic available.\n\nIssue the `help`' + + ' command with an available help topic as a parameter to read additonal help'; commands.internals.commands.help = { help: 'print command help listing' }; @@ -202,6 +203,57 @@ describe('commands', () => { browser.createPost.calledWith(15, 75).should.be.true; browser.createPost.lastCall.args[2].should.equal(expected); }); + it('should post expected text with help topics', () => { + const expected = 'Registered commands:\nhelp: print command help listing\n\n' + + 'Help Topics:\nshutup: Extended help topic\n\n* Help topic available.\n\n' + + 'Issue the `help` command with an available help topic as a parameter to ' + + 'read additonal help'; + commands.internals.commands.help = { + help: 'print command help listing' + }; + commands.internals.helpMessages.shutup = 'tell me to shutup'; + cmdHelp({ + command: 'foobar', + post: { + 'topic_id': 15, + 'post_number': 75 + } + }); + browser.createPost.callCount.should.equal(1); + browser.createPost.calledWith(15, 75).should.be.true; + browser.createPost.lastCall.args[2].should.equal(expected); + }); + it('should pass callback to createPost', () => { + cmdHelp({ + command: 'foobar', + post: { + 'topic_id': 1, + 'post_number': 5 + } + }); + browser.createPost.lastCall.args[3].should.be.a('function'); + browser.createPost.lastCall.args[3]().should.equal(0); + }); + + it('should indicate presence of help topic on command', () => { + const expected = 'Registered commands:\nhelp: print command help listing *\n\n' + + '* Help topic available.\n\nIssue the `help` command with an available help ' + + 'topic as a parameter to read additonal help'; + commands.internals.commands.help = { + help: 'print command help listing' + }; + commands.internals.helpMessages.help = 'foobar'; + cmdHelp({ + command: 'foobar', + post: { + 'topic_id': 15, + 'post_number': 75 + } + }); + browser.createPost.callCount.should.equal(1); + browser.createPost.calledWith(15, 75).should.be.true; + browser.createPost.lastCall.args[2].should.equal(expected); + }); it('should pass callback to createPost', () => { cmdHelp({ command: 'foobar', @@ -256,7 +308,7 @@ describe('commands', () => { browser.createPost.lastCall.args[2].should.startWith(expected); }); it('should post extended help message one word command', () => { - const expected = 'Extended help for `whosit`\n\nwhosit extended help' + + const expected = 'Help topic for `whosit`\n\nwhosit extended help' + '\n\nIssue the `help` command without any parameters to see all available commands'; commands.internals.helpMessages.whosit = 'whosit extended help'; cmdHelp({ @@ -272,7 +324,7 @@ describe('commands', () => { browser.createPost.lastCall.args[2].should.equal(expected); }); it('should post extended help message multi-word command', () => { - const expected = 'Extended help for `who am i`'; + const expected = 'Help topic for `who am i`'; commands.internals.helpMessages['who am i'] = 'whosit extended help'; cmdHelp({ command: 'foobar', @@ -764,13 +816,14 @@ describe('commands', () => { it('should log registration', () => { const cmd = 'CMD' + Math.random(); registerHelp(cmd, 'help', spy); - events.emit.calledWith('logMessage', 'Extended help registered for: ' + cmd).should.be.true; + events.emit.calledWith('logMessage', 'Extended help registered for: ' + + cmd.toLowerCase()).should.be.true; }); it('should warn on help overwrite', () => { const cmd = 'CMD' + Math.random(); - commands.internals.helpMessages[cmd] = 'foo'; + commands.internals.helpMessages[cmd.toLowerCase()] = 'foo'; registerHelp(cmd, 'help', spy); - events.emit.calledWith('logWarning', 'Overwriting existing extended help for: `' + cmd + + events.emit.calledWith('logWarning', 'Overwriting existing extended help for: `' + cmd.toLowerCase() + '`!').should.be.true; }); }); From 975c0ffa61ecc135a102d3056096694337c27344 Mon Sep 17 00:00:00 2001 From: Accalia de Elementia Date: Tue, 26 Jan 2016 17:08:55 +0000 Subject: [PATCH 21/23] update documentation --- docs/api/lib/commands.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/api/lib/commands.md b/docs/api/lib/commands.md index 587e8c7e..3b8da90d 100644 --- a/docs/api/lib/commands.md +++ b/docs/api/lib/commands.md @@ -111,7 +111,7 @@ Shut the bot up until manually restarted ### commands~cmdHelp(command) -Reply with help test top the command !help +Reply with help to the command !help **Kind**: inner method of [commands](#module_commands) From d9671bd9b65240a5c2bfb80b3a5d4e6e5d314755 Mon Sep 17 00:00:00 2001 From: Accalia de Elementia Date: Tue, 26 Jan 2016 17:20:04 +0000 Subject: [PATCH 22/23] correct capitalization in status test --- test/lib/commands/statusTest.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/lib/commands/statusTest.js b/test/lib/commands/statusTest.js index 3478e446..de7d1d19 100644 --- a/test/lib/commands/statusTest.js +++ b/test/lib/commands/statusTest.js @@ -138,7 +138,7 @@ describe('status', () => { }); describe('memoryUsage', () => { it('should return the correct values', () => { - const expected = 'Memory usage: 1 kB free out of 2 kB'; + const expected = 'Memory usage: 1 KB free out of 2 KB'; sandbox.stub(os, 'freemem', () => 1024); sandbox.stub(os, 'totalmem', () => 2048); expect(status.internals.memoryUsage()).to.be.equal(expected); From 4bcb4fa0edc1278fb1cb24cec0f0f9005e9f0606 Mon Sep 17 00:00:00 2001 From: Accalia de Elementia Date: Tue, 26 Jan 2016 17:58:50 +0000 Subject: [PATCH 23/23] increment version for release --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index b086502f..8d189452 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "sockbot", - "version": "2.12.0", + "version": "2.12.1", "releaseName": "Delightful Denim", "description": "A sockpuppet bot to use on http://what.thedailywtf.com.", "repository": "https://github.com/SockDrawer/SockBot",