diff --git a/package.json b/package.json index 87cdd57..dfc2066 100644 --- a/package.json +++ b/package.json @@ -15,7 +15,7 @@ ], "scripts": { "prepublish": "./node_modules/.bin/babel -d ./lib src", - "test": "./node_modules/.bin/mocha test/index.js", + "test": "./node_modules/.bin/mocha test/index.js --timeout 10000", "test-cov": "./node_modules/.bin/istanbul cover ./node_modules/mocha/bin/_mocha --report lcovonly -- -R spec && cat ./coverage/lcov.info | ./node_modules/coveralls/bin/coveralls.js && rm -rf ./coverage", "gen-doc": "./node_modules/.bin/babel --no-babelrc --plugins transform-es2015-spread,transform-es2015-destructuring,transform-strict-mode,transform-es2015-parameters,transform-es2015-shorthand-properties,transform-object-rest-spread,transform-class-properties -d lib-doc src && ./node_modules/.bin/jsdoc2md --src lib-doc/telegram.js -t README.hbs > README.md", "eslint": "./node_modules/.bin/eslint ./src" @@ -201,4 +201,4 @@ "hireable": true } ] -} \ No newline at end of file +} diff --git a/src/telegram.js b/src/telegram.js index c58447d..6bf77f0 100644 --- a/src/telegram.js +++ b/src/telegram.js @@ -22,7 +22,7 @@ class TelegramBot extends EventEmitter { 'location', 'new_chat_participant', 'left_chat_participant', 'new_chat_title', 'new_chat_photo', 'delete_chat_photo', 'group_chat_created' ]; - + /** * Both request method to obtain messages are implemented. To use standard polling, set `polling: true` * on `options`. Notice that [webHook](https://core.telegram.org/bots/api#setwebhook) will need a SSL certificate. @@ -69,6 +69,7 @@ class TelegramBot extends EventEmitter { const message = update.message; const inlineQuery = update.inline_query; const chosenInlineResult = update.chosen_inline_result; + const callbackQuery = update.callback_query; if (message) { debug('Process Update message %j', message); @@ -110,6 +111,9 @@ class TelegramBot extends EventEmitter { } else if (chosenInlineResult) { debug('Process Update chosen_inline_result %j', chosenInlineResult); this.emit('chosen_inline_result', chosenInlineResult); + } else if (callbackQuery) { + debug('Process Update callback_query %j', callbackQuery); + this.emit('callback_query', callbackQuery); } } @@ -454,6 +458,119 @@ class TelegramBot extends EventEmitter { return this._request('sendChatAction', { form }); } + /** + * Use this method to kick a user from a group or a supergroup. + * In the case of supergroups, the user will not be able to return + * to the group on their own using invite links, etc., unless unbanned + * first. The bot must be an administrator in the group for this to work. + * Returns True on success. + * + * @param {Number|String} chatId Unique identifier for the target group or username of the target supergroup + * @param {String} userId Unique identifier of the target user + * @return {Promise} + * @see https://core.telegram.org/bots/api#kickchatmember + */ + kickChatMember(chatId, userId) { + const form = { + chat_id: chatId, + user_id: userId + }; + return this._request('kickChatMember', { form }); + } + + /** + * Use this method to unban a previously kicked user in a supergroup. + * The user will not return to the group automatically, but will be + * able to join via link, etc. The bot must be an administrator in + * the group for this to work. Returns True on success. + * + * @param {Number|String} chatId Unique identifier for the target group or username of the target supergroup + * @param {String} userId Unique identifier of the target user + * @return {Promise} + * @see https://core.telegram.org/bots/api#unbanchatmember + */ + unbanChatMember(chatId, userId) { + const form = { + chat_id: chatId, + user_id: userId + }; + return this._request('unbanChatMember', { form }); + } + + /** + * Use this method to send answers to callback queries sent from + * inline keyboards. The answer will be displayed to the user as + * a notification at the top of the chat screen or as an alert. + * On success, True is returned. + * + * @param {Number|String} callbackQueryId Unique identifier for the query to be answered + * @param {String} text Text of the notification. If not specified, nothing will be shown to the user + * @param {Boolean} showAlert Whether to show an alert or a notification at the top of the screen + * @param {Object} [options] Additional Telegram query options + * @return {Promise} + * @see https://core.telegram.org/bots/api#answercallbackquery + */ + answerCallbackQuery(callbackQueryId, text, showAlert, form = {}) { + form.callback_query_id = callbackQueryId; + form.text = text; + form.show_alert = showAlert; + return this._request('answerCallbackQuery', { form }); + } + + /** + * Use this method to edit text messages sent by the bot or via + * the bot (for inline bots). On success, the edited Message is + * returned. + * + * Note that you must provide one of chat_id, message_id, or + * inline_message_id in your request. + * + * @param {String} text New text of the message + * @param {Object} [options] Additional Telegram query options (provide either one of chat_id, message_id, or inline_message_id here) + * @return {Promise} + * @see https://core.telegram.org/bots/api#editmessagetext + */ + editMessageText(text, form = {}) { + form.text = text; + return this._request('editMessageText', { form }); + } + + /** + * Use this method to edit captions of messages sent by the + * bot or via the bot (for inline bots). On success, the + * edited Message is returned. + * + * Note that you must provide one of chat_id, message_id, or + * inline_message_id in your request. + * + * @param {String} caption New caption of the message + * @param {Object} [options] Additional Telegram query options (provide either one of chat_id, message_id, or inline_message_id here) + * @return {Promise} + * @see https://core.telegram.org/bots/api#editmessagetext + */ + editMessageCaption(caption, form = {}) { + form.caption = caption; + return this._request('editMessageCaption', { form }); + } + + /** + * Use this method to edit only the reply markup of messages + * sent by the bot or via the bot (for inline bots). + * On success, the edited Message is returned. + * + * Note that you must provide one of chat_id, message_id, or + * inline_message_id in your request. + * + * @param {Object} replyMarkup A JSON-serialized object for an inline keyboard. + * @param {Object} [options] Additional Telegram query options (provide either one of chat_id, message_id, or inline_message_id here) + * @return {Promise} + * @see https://core.telegram.org/bots/api#editmessagetext + */ + editMessageReplyMarkup(replyMarkup, form = {}) { + form.reply_markup = replyMarkup; + return this._request('editMessageReplyMarkup', { form }); + } + /** * Use this method to get a list of profile pictures for a user. * Returns a [UserProfilePhotos](https://core.telegram.org/bots/api#userprofilephotos) object. diff --git a/test/index.js b/test/index.js index d8c813a..698f3b6 100644 --- a/test/index.js +++ b/test/index.js @@ -217,6 +217,62 @@ describe('Telegram', function telegramSuite() { }); }); + describe('#editMessageText', function editMessageTextSuite() { + it('should edit a message sent by the bot', function test() { + const bot = new Telegram(TOKEN); + return bot.sendMessage(USERID, 'test').then(resp => { + assert.equal(resp.text, 'test'); + const opts = { + chat_id: USERID, + message_id: resp.message_id + }; + return bot.editMessageText('edit test', opts).then(msg => { + assert.equal(msg.text, 'edit test'); + }); + }); + }); + }); + + describe('#editMessageCaption', function editMessageCaptionSuite() { + it('should edit a caption sent by the bot', function test() { + const bot = new Telegram(TOKEN); + const photo = `${__dirname}/bot.gif`; + const options = { caption: 'test caption' }; + return bot.sendPhoto(USERID, photo, options).then(resp => { + assert.equal(resp.caption, 'test caption'); + const opts = { + chat_id: USERID, + message_id: resp.message_id + }; + return bot.editMessageCaption('new test caption', opts).then(msg => { + assert.equal(msg.caption, 'new test caption'); + }); + }); + }); + }); + + describe('#editMessageReplyMarkup', function editMessageReplyMarkupSuite() { + it('should edit previously-set reply markup', function test() { + const bot = new Telegram(TOKEN); + return bot.sendMessage(USERID, 'test').then(resp => { + const replyMarkup = JSON.stringify({ + inline_keyboard: [[{ + text: 'Test button', + callback_data: 'test' + }]] + }); + const opts = { + chat_id: USERID, + message_id: resp.message_id + }; + return bot.editMessageReplyMarkup(replyMarkup, opts).then(msg => { + // Keyboard markup is not returned, do a simple object check + assert.ok(is.object(msg)); + }); + }); + }); + }); + describe('#sendAudio', function sendAudioSuite() { it('should send an OGG audio', function test() { const bot = new Telegram(TOKEN); @@ -398,7 +454,7 @@ describe('Telegram', function telegramSuite() { describe('#getFile', function getFileSuite() { let fileId; - // To get a file we have to send any file first + // To get a file we have to send any file first it('should send a photo from file', function test() { const bot = new Telegram(TOKEN); const photo = `${__dirname}/bot.gif`; @@ -423,7 +479,7 @@ describe('Telegram', function telegramSuite() { describe('#getFileLink', function getFileLinkSuite() { let fileId; - // To get a file we have to send any file first + // To get a file we have to send any file first it('should send a photo from file', function test() { const bot = new Telegram(TOKEN); const photo = `${__dirname}/bot.gif`;