From 763f717a041860f1dc38949c6b3aacfdacc4741e Mon Sep 17 00:00:00 2001 From: evolun Date: Mon, 2 May 2016 17:13:05 +0200 Subject: [PATCH 01/10] Added the ability to specify the filename and the content type by sendDocument --- src/telegram.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/telegram.js b/src/telegram.js index c58447d..a65f28f 100644 --- a/src/telegram.js +++ b/src/telegram.js @@ -359,10 +359,11 @@ class TelegramBot extends EventEmitter { * @param {String|stream.Stream|Buffer} doc A file path, Stream or Buffer. * Can also be a `file_id` previously uploaded. * @param {Object} [options] Additional Telegram query options + * @param {Object} [fileOpts] Optional file related meta-data * @return {Promise} * @see https://core.telegram.org/bots/api#sendDocument */ - sendDocument(chatId, doc, options = {}) { + sendDocument(chatId, doc, options = {}, fileOpts = {}) { const opts = { qs: options }; @@ -370,6 +371,9 @@ class TelegramBot extends EventEmitter { const content = this._formatSendData('document', doc); opts.formData = content[0]; opts.qs.document = content[1]; + if (opts.formData && Object.keys(fileOpts).length) { + opts.formData['document'].options = fileOpts; + } return this._request('sendDocument', opts); } From 42a2d242732e15fba4ed9a65f26aa0b160b47bf6 Mon Sep 17 00:00:00 2001 From: evolun Date: Fri, 6 May 2016 12:28:03 +0200 Subject: [PATCH 02/10] Eslint correction --- src/telegram.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/telegram.js b/src/telegram.js index a65f28f..1f21325 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. @@ -372,7 +372,7 @@ class TelegramBot extends EventEmitter { opts.formData = content[0]; opts.qs.document = content[1]; if (opts.formData && Object.keys(fileOpts).length) { - opts.formData['document'].options = fileOpts; + opts.formData.document.options = fileOpts; } return this._request('sendDocument', opts); } From de6f0c8a142988d2c7a448c1e02c35da461dd731 Mon Sep 17 00:00:00 2001 From: TJ Horner Date: Mon, 11 Apr 2016 20:42:32 -0700 Subject: [PATCH 03/10] Update for Telegram Bots 2.0 https://telegram.org/blog/bots-2-0 --- src/telegram.js | 111 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 111 insertions(+) diff --git a/src/telegram.js b/src/telegram.js index 1f21325..d901434 100644 --- a/src/telegram.js +++ b/src/telegram.js @@ -458,6 +458,117 @@ 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 {Object} [options] Additional Telegram query options + * @return {Promise} + * @see https://core.telegram.org/bots/api#answercallbackquery + */ + answerCallbackQuery(callbackQueryId, text, form = {}) { + form.callback_query_id = callbackQueryId; + form.text = text; + 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. From 684691d779479a55ebf77aad87bfd608f8c70900 Mon Sep 17 00:00:00 2001 From: icdevin Date: Mon, 25 Apr 2016 16:03:36 +0900 Subject: [PATCH 04/10] Fixes stream end event never being called For writable streams, like `http.ClientRequest`, there is no `end` event, only `finish`. Thus, `req.end` was never called and never sending a response. This resulted in a nasty bug for WebHook users that basically rendered the library useless because if Telegram doesn't receive a response from the bot server, it will continue to queue and send requests until it does, or until 24 hours have passed. --- src/telegramWebHook.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/telegramWebHook.js b/src/telegramWebHook.js index 6bf265f..19c209d 100644 --- a/src/telegramWebHook.js +++ b/src/telegramWebHook.js @@ -71,7 +71,7 @@ class TelegramBotWebHook { } else if (req.method === 'POST') { req .pipe(bl(this._parseBody)) - .on('end', () => res.end('OK')); + .on('finish', () => res.end('OK')); } else { // Authorized but not a POST debug('WebHook request isn\'t a POST'); From 3947683ad12f10a129e6e88c053063703a24905e Mon Sep 17 00:00:00 2001 From: Devin Doolin Date: Mon, 25 Apr 2016 04:31:36 +0900 Subject: [PATCH 05/10] Further updates for Bots 2.0 - Adds support for callback_query-type messages - Adds a showAlert option to answerCallbackQuery to more-closely align with the real bot API - Adds tests for message editing functionality - Adds a global test timeout of 10s and adds done() calls to all tests for assurance --- package.json | 4 +- src/telegram.js | 8 ++- test/index.js | 153 ++++++++++++++++++++++++++++++++++++++---------- 3 files changed, 130 insertions(+), 35 deletions(-) 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 d901434..7340ed1 100644 --- a/src/telegram.js +++ b/src/telegram.js @@ -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); } } @@ -505,13 +509,15 @@ class TelegramBot extends EventEmitter { * * @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, form = {}) { + answerCallbackQuery(callbackQueryId, text, showAlert, form = {}) { form.callback_query_id = callbackQueryId; form.text = text; + form.show_alert = showAlert; return this._request('answerCallbackQuery', { form }); } diff --git a/test/index.js b/test/index.js index d8c813a..1c9609d 100644 --- a/test/index.js +++ b/test/index.js @@ -17,13 +17,14 @@ const USERID = process.env.TEST_USER_ID || 777000; describe('Telegram', function telegramSuite() { describe('#setWebHook', function setWebHookSuite() { - it('should set a webHook', function test() { + it('should set a webHook', function test(done) { const bot = new Telegram(TOKEN); // Google IP ¯\_(ツ)_/¯ return bot .setWebHook('216.58.210.174') .then(resp => { assert.equal(resp, true); + done(); }); }); @@ -150,13 +151,14 @@ describe('Telegram', function telegramSuite() { }); describe('#forwardMessage', function forwardMessageSuite() { - it('should forward a message', function test() { + it('should forward a message', function test(done) { const bot = new Telegram(TOKEN); return bot.sendMessage(USERID, 'test').then(resp => { const messageId = resp.message_id; return bot.forwardMessage(USERID, USERID, messageId) .then(forwarded => { assert.ok(is.object(forwarded)); + done(); }); }); }); @@ -164,208 +166,290 @@ describe('Telegram', function telegramSuite() { describe('#sendPhoto', function sendPhotoSuite() { let photoId; - it('should send a photo from file', function test() { + it('should send a photo from file', function test(done) { const bot = new Telegram(TOKEN); const photo = `${__dirname}/bot.gif`; return bot.sendPhoto(USERID, photo).then(resp => { assert.ok(is.object(resp)); photoId = resp.photo[0].file_id; + done(); }); }); - it('should send a photo from id', function test() { + it('should send a photo from id', function test(done) { const bot = new Telegram(TOKEN); // Send the same photo as before const photo = photoId; return bot.sendPhoto(USERID, photo).then(resp => { assert.ok(is.object(resp)); + done(); }); }); - it('should send a photo from fs.readStream', function test() { + it('should send a photo from fs.readStream', function test(done) { const bot = new Telegram(TOKEN); const photo = fs.createReadStream(`${__dirname}/bot.gif`); return bot.sendPhoto(USERID, photo).then(resp => { assert.ok(is.object(resp)); + done(); }); }); - it('should send a photo from request Stream', function test() { + it('should send a photo from request Stream', function test(done) { const bot = new Telegram(TOKEN); const photo = request('https://telegram.org/img/t_logo.png'); return bot.sendPhoto(USERID, photo).then(resp => { assert.ok(is.object(resp)); + done(); }); }); - it('should send a photo from a Buffer', function test() { + it('should send a photo from a Buffer', function test(done) { const bot = new Telegram(TOKEN); const photo = fs.readFileSync(`${__dirname}/bot.gif`); return bot.sendPhoto(USERID, photo).then(resp => { assert.ok(is.object(resp)); + done(); }); }); }); describe('#sendChatAction', function sendChatActionSuite() { - it('should send a chat action', function test() { + it('should send a chat action', function test(done) { const bot = new Telegram(TOKEN); const action = 'typing'; return bot.sendChatAction(USERID, action).then(resp => { assert.equal(resp, true); + done(); + }); + }); + }); + + describe('#editMessageText', function editMessageTextSuite() { + it('should edit a message sent by the bot', function test(done) { + 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'); + done(); + }); + }); + }); + }); + + describe('#editMessageCaption', function editMessageCaptionSuite() { + it('should edit a caption sent by the bot', function test(done) { + 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'); + done(); + }); + }); + }); + }); + + describe('#editMessageReplyMarkup', function editMessageReplyMarkupSuite() { + it('should edit previously-set reply markup', function test(done) { + 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)); + done(); + }); }); }); }); describe('#sendAudio', function sendAudioSuite() { - it('should send an OGG audio', function test() { + it('should send an OGG audio', function test(done) { const bot = new Telegram(TOKEN); const audio = request('https://upload.wikimedia.org/wikipedia/commons/c/c8/Example.ogg'); return bot.sendAudio(USERID, audio).then(resp => { assert.ok(is.object(resp)); + done(); }); }); }); describe('#sendDocument', function sendDocumentSuite() { let documentId; - it('should send a document from file', function test() { + it('should send a document from file', function test(done) { const bot = new Telegram(TOKEN); const document = `${__dirname}/bot.gif`; return bot.sendDocument(USERID, document).then(resp => { assert.ok(is.object(resp)); documentId = resp.document.file_id; + done(); }); }); - it('should send a document from id', function test() { + it('should send a document from id', function test(done) { const bot = new Telegram(TOKEN); // Send the same photo as before const document = documentId; return bot.sendDocument(USERID, document).then(resp => { assert.ok(is.object(resp)); + done(); }); }); - it('should send a document from fs.readStream', function test() { + it('should send a document from fs.readStream', function test(done) { const bot = new Telegram(TOKEN); const document = fs.createReadStream(`${__dirname}/bot.gif`); return bot.sendDocument(USERID, document).then(resp => { assert.ok(is.object(resp)); + done(); }); }); - it('should send a document from request Stream', function test() { + it('should send a document from request Stream', function test(done) { const bot = new Telegram(TOKEN); const document = request('https://telegram.org/img/t_logo.png'); return bot.sendDocument(USERID, document).then(resp => { assert.ok(is.object(resp)); + done(); }); }); - it('should send a document from a Buffer', function test() { + it('should send a document from a Buffer', function test(done) { const bot = new Telegram(TOKEN); const document = fs.readFileSync(`${__dirname}/bot.gif`); return bot.sendDocument(USERID, document).then(resp => { assert.ok(is.object(resp)); + done(); }); }); }); describe('#sendSticker', function sendStickerSuite() { let stickerId; - it('should send a sticker from file', function test() { + it('should send a sticker from file', function test(done) { const bot = new Telegram(TOKEN); const sticker = `${__dirname}/sticker.webp`; return bot.sendSticker(USERID, sticker).then(resp => { assert.ok(is.object(resp)); stickerId = resp.sticker.file_id; + done(); }); }); - it('should send a sticker from id', function test() { + it('should send a sticker from id', function test(done) { const bot = new Telegram(TOKEN); // Send the same photo as before return bot.sendSticker(USERID, stickerId).then(resp => { assert.ok(is.object(resp)); + done(); }); }); - it('should send a sticker from fs.readStream', function test() { + it('should send a sticker from fs.readStream', function test(done) { const bot = new Telegram(TOKEN); const sticker = fs.createReadStream(`${__dirname}/sticker.webp`); return bot.sendSticker(USERID, sticker).then(resp => { assert.ok(is.object(resp)); + done(); }); }); - it('should send a sticker from request Stream', function test() { + it('should send a sticker from request Stream', function test(done) { const bot = new Telegram(TOKEN); const sticker = request('https://www.gstatic.com/webp/gallery3/1_webp_ll.webp'); return bot.sendSticker(USERID, sticker).then(resp => { assert.ok(is.object(resp)); + done(); }); }); - it('should send a sticker from a Buffer', function test() { + it('should send a sticker from a Buffer', function test(done) { const bot = new Telegram(TOKEN); const sticker = fs.readFileSync(`${__dirname}/sticker.webp`); return bot.sendDocument(USERID, sticker).then(resp => { assert.ok(is.object(resp)); + done(); }); }); }); describe('#sendVideo', function sendVideoSuite() { let videoId; - it('should send a video from file', function test() { + it('should send a video from file', function test(done) { const bot = new Telegram(TOKEN); const video = `${__dirname}/video.mp4`; return bot.sendVideo(USERID, video).then(resp => { assert.ok(is.object(resp)); videoId = resp.video.file_id; + done(); }); }); - it('should send a video from id', function test() { + it('should send a video from id', function test(done) { const bot = new Telegram(TOKEN); // Send the same photo as before return bot.sendVideo(USERID, videoId).then(resp => { assert.ok(is.object(resp)); + done(); }); }); - it('should send a video from fs.readStream', function test() { + it('should send a video from fs.readStream', function test(done) { const bot = new Telegram(TOKEN); const video = fs.createReadStream(`${__dirname}/video.mp4`); return bot.sendVideo(USERID, video).then(resp => { assert.ok(is.object(resp)); + done(); }); }); - it('should send a video from request Stream', function test() { + it('should send a video from request Stream', function test(done) { const bot = new Telegram(TOKEN); const sticker = request('http://techslides.com/demos/sample-videos/small.mp4'); return bot.sendVideo(USERID, sticker).then(resp => { assert.ok(is.object(resp)); + done(); }); }); - it('should send a video from a Buffer', function test() { + it('should send a video from a Buffer', function test(done) { const bot = new Telegram(TOKEN); const video = fs.readFileSync(`${__dirname}/video.mp4`); return bot.sendVideo(USERID, video).then(resp => { assert.ok(is.object(resp)); + done(); }); }); }); describe('#sendVoice', function sendVoiceSuite() { - it('should send an OGG audio as voice', function test() { + it('should send an OGG audio as voice', function test(done) { const bot = new Telegram(TOKEN); const voice = request('https://upload.wikimedia.org/wikipedia/commons/c/c8/Example.ogg'); return bot.sendVoice(USERID, voice).then(resp => { assert.ok(is.object(resp)); + done(); }); }); }); @@ -398,17 +482,18 @@ describe('Telegram', function telegramSuite() { describe('#getFile', function getFileSuite() { let fileId; - // To get a file we have to send any file first - it('should send a photo from file', function test() { + // To get a file we have to send any file first + it('should send a photo from file', function test(done) { const bot = new Telegram(TOKEN); const photo = `${__dirname}/bot.gif`; return bot.sendPhoto(USERID, photo).then(resp => { assert.ok(is.object(resp)); fileId = resp.photo[0].file_id; + done(); }); }); - it('should get a file', function test() { + it('should get a file', function test(done) { const bot = new Telegram(TOKEN); return bot @@ -416,6 +501,7 @@ describe('Telegram', function telegramSuite() { .then(resp => { assert.ok(is.object(resp)); assert.ok(is.string(resp.file_path)); + done(); }); }); }); @@ -423,17 +509,18 @@ describe('Telegram', function telegramSuite() { describe('#getFileLink', function getFileLinkSuite() { let fileId; - // To get a file we have to send any file first - it('should send a photo from file', function test() { + // To get a file we have to send any file first + it('should send a photo from file', function test(done) { const bot = new Telegram(TOKEN); const photo = `${__dirname}/bot.gif`; return bot.sendPhoto(USERID, photo).then(resp => { assert.ok(is.object(resp)); fileId = resp.photo[0].file_id; + done(); }); }); - it('should get a file link', function test() { + it('should get a file link', function test(done) { const bot = new Telegram(TOKEN); return bot @@ -441,6 +528,7 @@ describe('Telegram', function telegramSuite() { .then(fileURI => { assert.ok(is.string(fileURI)); assert.equal(fileURI.indexOf('https'), 0); + done(); // TODO: validate URL with some library or regexp }); }); @@ -449,7 +537,7 @@ describe('Telegram', function telegramSuite() { describe('#downloadFile', function downloadFileSuite() { const downloadPath = __dirname; - it('should download a file', function test() { + it('should download a file', function test(done) { const bot = new Telegram(TOKEN); const photo = `${__dirname}/bot.gif`; @@ -464,6 +552,7 @@ describe('Telegram', function telegramSuite() { assert.ok(is.string(filePath)); assert.ok(fs.existsSync(filePath)); fs.unlinkSync(filePath); // Delete file after test + done(); }); }); }); From 2c606f6b489d3c2ce28d5e956098907dd2dfecbe Mon Sep 17 00:00:00 2001 From: Devin Doolin Date: Fri, 6 May 2016 19:21:41 +0900 Subject: [PATCH 06/10] Removes unnecessary done() calls in tests --- test/index.js | 99 +++++++++++++++++---------------------------------- 1 file changed, 33 insertions(+), 66 deletions(-) diff --git a/test/index.js b/test/index.js index 1c9609d..698f3b6 100644 --- a/test/index.js +++ b/test/index.js @@ -17,14 +17,13 @@ const USERID = process.env.TEST_USER_ID || 777000; describe('Telegram', function telegramSuite() { describe('#setWebHook', function setWebHookSuite() { - it('should set a webHook', function test(done) { + it('should set a webHook', function test() { const bot = new Telegram(TOKEN); // Google IP ¯\_(ツ)_/¯ return bot .setWebHook('216.58.210.174') .then(resp => { assert.equal(resp, true); - done(); }); }); @@ -151,14 +150,13 @@ describe('Telegram', function telegramSuite() { }); describe('#forwardMessage', function forwardMessageSuite() { - it('should forward a message', function test(done) { + it('should forward a message', function test() { const bot = new Telegram(TOKEN); return bot.sendMessage(USERID, 'test').then(resp => { const messageId = resp.message_id; return bot.forwardMessage(USERID, USERID, messageId) .then(forwarded => { assert.ok(is.object(forwarded)); - done(); }); }); }); @@ -166,67 +164,61 @@ describe('Telegram', function telegramSuite() { describe('#sendPhoto', function sendPhotoSuite() { let photoId; - it('should send a photo from file', function test(done) { + it('should send a photo from file', function test() { const bot = new Telegram(TOKEN); const photo = `${__dirname}/bot.gif`; return bot.sendPhoto(USERID, photo).then(resp => { assert.ok(is.object(resp)); photoId = resp.photo[0].file_id; - done(); }); }); - it('should send a photo from id', function test(done) { + it('should send a photo from id', function test() { const bot = new Telegram(TOKEN); // Send the same photo as before const photo = photoId; return bot.sendPhoto(USERID, photo).then(resp => { assert.ok(is.object(resp)); - done(); }); }); - it('should send a photo from fs.readStream', function test(done) { + it('should send a photo from fs.readStream', function test() { const bot = new Telegram(TOKEN); const photo = fs.createReadStream(`${__dirname}/bot.gif`); return bot.sendPhoto(USERID, photo).then(resp => { assert.ok(is.object(resp)); - done(); }); }); - it('should send a photo from request Stream', function test(done) { + it('should send a photo from request Stream', function test() { const bot = new Telegram(TOKEN); const photo = request('https://telegram.org/img/t_logo.png'); return bot.sendPhoto(USERID, photo).then(resp => { assert.ok(is.object(resp)); - done(); }); }); - it('should send a photo from a Buffer', function test(done) { + it('should send a photo from a Buffer', function test() { const bot = new Telegram(TOKEN); const photo = fs.readFileSync(`${__dirname}/bot.gif`); return bot.sendPhoto(USERID, photo).then(resp => { assert.ok(is.object(resp)); - done(); }); }); }); describe('#sendChatAction', function sendChatActionSuite() { - it('should send a chat action', function test(done) { + it('should send a chat action', function test() { const bot = new Telegram(TOKEN); const action = 'typing'; return bot.sendChatAction(USERID, action).then(resp => { assert.equal(resp, true); - done(); }); }); }); describe('#editMessageText', function editMessageTextSuite() { - it('should edit a message sent by the bot', function test(done) { + 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'); @@ -236,14 +228,13 @@ describe('Telegram', function telegramSuite() { }; return bot.editMessageText('edit test', opts).then(msg => { assert.equal(msg.text, 'edit test'); - done(); }); }); }); }); describe('#editMessageCaption', function editMessageCaptionSuite() { - it('should edit a caption sent by the bot', function test(done) { + 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' }; @@ -255,14 +246,13 @@ describe('Telegram', function telegramSuite() { }; return bot.editMessageCaption('new test caption', opts).then(msg => { assert.equal(msg.caption, 'new test caption'); - done(); }); }); }); }); describe('#editMessageReplyMarkup', function editMessageReplyMarkupSuite() { - it('should edit previously-set reply markup', function test(done) { + 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({ @@ -278,178 +268,160 @@ describe('Telegram', function telegramSuite() { return bot.editMessageReplyMarkup(replyMarkup, opts).then(msg => { // Keyboard markup is not returned, do a simple object check assert.ok(is.object(msg)); - done(); }); }); }); }); describe('#sendAudio', function sendAudioSuite() { - it('should send an OGG audio', function test(done) { + it('should send an OGG audio', function test() { const bot = new Telegram(TOKEN); const audio = request('https://upload.wikimedia.org/wikipedia/commons/c/c8/Example.ogg'); return bot.sendAudio(USERID, audio).then(resp => { assert.ok(is.object(resp)); - done(); }); }); }); describe('#sendDocument', function sendDocumentSuite() { let documentId; - it('should send a document from file', function test(done) { + it('should send a document from file', function test() { const bot = new Telegram(TOKEN); const document = `${__dirname}/bot.gif`; return bot.sendDocument(USERID, document).then(resp => { assert.ok(is.object(resp)); documentId = resp.document.file_id; - done(); }); }); - it('should send a document from id', function test(done) { + it('should send a document from id', function test() { const bot = new Telegram(TOKEN); // Send the same photo as before const document = documentId; return bot.sendDocument(USERID, document).then(resp => { assert.ok(is.object(resp)); - done(); }); }); - it('should send a document from fs.readStream', function test(done) { + it('should send a document from fs.readStream', function test() { const bot = new Telegram(TOKEN); const document = fs.createReadStream(`${__dirname}/bot.gif`); return bot.sendDocument(USERID, document).then(resp => { assert.ok(is.object(resp)); - done(); }); }); - it('should send a document from request Stream', function test(done) { + it('should send a document from request Stream', function test() { const bot = new Telegram(TOKEN); const document = request('https://telegram.org/img/t_logo.png'); return bot.sendDocument(USERID, document).then(resp => { assert.ok(is.object(resp)); - done(); }); }); - it('should send a document from a Buffer', function test(done) { + it('should send a document from a Buffer', function test() { const bot = new Telegram(TOKEN); const document = fs.readFileSync(`${__dirname}/bot.gif`); return bot.sendDocument(USERID, document).then(resp => { assert.ok(is.object(resp)); - done(); }); }); }); describe('#sendSticker', function sendStickerSuite() { let stickerId; - it('should send a sticker from file', function test(done) { + it('should send a sticker from file', function test() { const bot = new Telegram(TOKEN); const sticker = `${__dirname}/sticker.webp`; return bot.sendSticker(USERID, sticker).then(resp => { assert.ok(is.object(resp)); stickerId = resp.sticker.file_id; - done(); }); }); - it('should send a sticker from id', function test(done) { + it('should send a sticker from id', function test() { const bot = new Telegram(TOKEN); // Send the same photo as before return bot.sendSticker(USERID, stickerId).then(resp => { assert.ok(is.object(resp)); - done(); }); }); - it('should send a sticker from fs.readStream', function test(done) { + it('should send a sticker from fs.readStream', function test() { const bot = new Telegram(TOKEN); const sticker = fs.createReadStream(`${__dirname}/sticker.webp`); return bot.sendSticker(USERID, sticker).then(resp => { assert.ok(is.object(resp)); - done(); }); }); - it('should send a sticker from request Stream', function test(done) { + it('should send a sticker from request Stream', function test() { const bot = new Telegram(TOKEN); const sticker = request('https://www.gstatic.com/webp/gallery3/1_webp_ll.webp'); return bot.sendSticker(USERID, sticker).then(resp => { assert.ok(is.object(resp)); - done(); }); }); - it('should send a sticker from a Buffer', function test(done) { + it('should send a sticker from a Buffer', function test() { const bot = new Telegram(TOKEN); const sticker = fs.readFileSync(`${__dirname}/sticker.webp`); return bot.sendDocument(USERID, sticker).then(resp => { assert.ok(is.object(resp)); - done(); }); }); }); describe('#sendVideo', function sendVideoSuite() { let videoId; - it('should send a video from file', function test(done) { + it('should send a video from file', function test() { const bot = new Telegram(TOKEN); const video = `${__dirname}/video.mp4`; return bot.sendVideo(USERID, video).then(resp => { assert.ok(is.object(resp)); videoId = resp.video.file_id; - done(); }); }); - it('should send a video from id', function test(done) { + it('should send a video from id', function test() { const bot = new Telegram(TOKEN); // Send the same photo as before return bot.sendVideo(USERID, videoId).then(resp => { assert.ok(is.object(resp)); - done(); }); }); - it('should send a video from fs.readStream', function test(done) { + it('should send a video from fs.readStream', function test() { const bot = new Telegram(TOKEN); const video = fs.createReadStream(`${__dirname}/video.mp4`); return bot.sendVideo(USERID, video).then(resp => { assert.ok(is.object(resp)); - done(); }); }); - it('should send a video from request Stream', function test(done) { + it('should send a video from request Stream', function test() { const bot = new Telegram(TOKEN); const sticker = request('http://techslides.com/demos/sample-videos/small.mp4'); return bot.sendVideo(USERID, sticker).then(resp => { assert.ok(is.object(resp)); - done(); }); }); - it('should send a video from a Buffer', function test(done) { + it('should send a video from a Buffer', function test() { const bot = new Telegram(TOKEN); const video = fs.readFileSync(`${__dirname}/video.mp4`); return bot.sendVideo(USERID, video).then(resp => { assert.ok(is.object(resp)); - done(); }); }); }); describe('#sendVoice', function sendVoiceSuite() { - it('should send an OGG audio as voice', function test(done) { + it('should send an OGG audio as voice', function test() { const bot = new Telegram(TOKEN); const voice = request('https://upload.wikimedia.org/wikipedia/commons/c/c8/Example.ogg'); return bot.sendVoice(USERID, voice).then(resp => { assert.ok(is.object(resp)); - done(); }); }); }); @@ -483,17 +455,16 @@ describe('Telegram', function telegramSuite() { let fileId; // To get a file we have to send any file first - it('should send a photo from file', function test(done) { + it('should send a photo from file', function test() { const bot = new Telegram(TOKEN); const photo = `${__dirname}/bot.gif`; return bot.sendPhoto(USERID, photo).then(resp => { assert.ok(is.object(resp)); fileId = resp.photo[0].file_id; - done(); }); }); - it('should get a file', function test(done) { + it('should get a file', function test() { const bot = new Telegram(TOKEN); return bot @@ -501,7 +472,6 @@ describe('Telegram', function telegramSuite() { .then(resp => { assert.ok(is.object(resp)); assert.ok(is.string(resp.file_path)); - done(); }); }); }); @@ -510,17 +480,16 @@ describe('Telegram', function telegramSuite() { let fileId; // To get a file we have to send any file first - it('should send a photo from file', function test(done) { + it('should send a photo from file', function test() { const bot = new Telegram(TOKEN); const photo = `${__dirname}/bot.gif`; return bot.sendPhoto(USERID, photo).then(resp => { assert.ok(is.object(resp)); fileId = resp.photo[0].file_id; - done(); }); }); - it('should get a file link', function test(done) { + it('should get a file link', function test() { const bot = new Telegram(TOKEN); return bot @@ -528,7 +497,6 @@ describe('Telegram', function telegramSuite() { .then(fileURI => { assert.ok(is.string(fileURI)); assert.equal(fileURI.indexOf('https'), 0); - done(); // TODO: validate URL with some library or regexp }); }); @@ -537,7 +505,7 @@ describe('Telegram', function telegramSuite() { describe('#downloadFile', function downloadFileSuite() { const downloadPath = __dirname; - it('should download a file', function test(done) { + it('should download a file', function test() { const bot = new Telegram(TOKEN); const photo = `${__dirname}/bot.gif`; @@ -552,7 +520,6 @@ describe('Telegram', function telegramSuite() { assert.ok(is.string(filePath)); assert.ok(fs.existsSync(filePath)); fs.unlinkSync(filePath); // Delete file after test - done(); }); }); }); From c728baee5df5dcae1579ec32a33eb06b466a90af Mon Sep 17 00:00:00 2001 From: Yago Date: Mon, 6 Jun 2016 22:55:17 +0200 Subject: [PATCH 07/10] 0.22.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index dfc2066..f037250 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "node-telegram-bot-api", - "version": "0.21.1", + "version": "0.22.0", "description": "Telegram Bot API", "main": "./lib/telegram.js", "directories": { From 5650ea58aa3ad436bdffc141863f54167abc21d4 Mon Sep 17 00:00:00 2001 From: Yago Date: Mon, 6 Jun 2016 22:57:06 +0200 Subject: [PATCH 08/10] Updated readme --- README.md | 111 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 111 insertions(+) diff --git a/README.md b/README.md index 5a44b47..22d3c90 100644 --- a/README.md +++ b/README.md @@ -71,6 +71,12 @@ TelegramBot * [.sendVideo(chatId, video, [options])](#TelegramBot+sendVideo) ⇒ Promise * [.sendVoice(chatId, voice, [options])](#TelegramBot+sendVoice) ⇒ Promise * [.sendChatAction(chatId, action)](#TelegramBot+sendChatAction) ⇒ Promise + * [.kickChatMember(chatId, userId)](#TelegramBot+kickChatMember) ⇒ Promise + * [.unbanChatMember(chatId, userId)](#TelegramBot+unbanChatMember) ⇒ Promise + * [.answerCallbackQuery(callbackQueryId, text, showAlert, [options])](#TelegramBot+answerCallbackQuery) ⇒ Promise + * [.editMessageText(text, [options])](#TelegramBot+editMessageText) ⇒ Promise + * [.editMessageCaption(caption, [options])](#TelegramBot+editMessageCaption) ⇒ Promise + * [.editMessageReplyMarkup(replyMarkup, [options])](#TelegramBot+editMessageReplyMarkup) ⇒ Promise * [.getUserProfilePhotos(userId, [offset], [limit])](#TelegramBot+getUserProfilePhotos) ⇒ Promise * [.sendLocation(chatId, latitude, longitude, [options])](#TelegramBot+sendLocation) ⇒ Promise * [.getFile(fileId)](#TelegramBot+getFile) ⇒ Promise @@ -275,6 +281,111 @@ Send chat action. | chatId | Number | String | Unique identifier for the message recipient | | action | String | Type of action to broadcast. | + + +### telegramBot.kickChatMember(chatId, userId) ⇒ Promise +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. + +**Kind**: instance method of [TelegramBot](#TelegramBot) +**See**: https://core.telegram.org/bots/api#kickchatmember + +| Param | Type | Description | +| --- | --- | --- | +| chatId | Number | String | Unique identifier for the target group or username of the target supergroup | +| userId | String | Unique identifier of the target user | + + + +### telegramBot.unbanChatMember(chatId, userId) ⇒ Promise +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. + +**Kind**: instance method of [TelegramBot](#TelegramBot) +**See**: https://core.telegram.org/bots/api#unbanchatmember + +| Param | Type | Description | +| --- | --- | --- | +| chatId | Number | String | Unique identifier for the target group or username of the target supergroup | +| userId | String | Unique identifier of the target user | + + + +### telegramBot.answerCallbackQuery(callbackQueryId, text, showAlert, [options]) ⇒ Promise +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. + +**Kind**: instance method of [TelegramBot](#TelegramBot) +**See**: https://core.telegram.org/bots/api#answercallbackquery + +| Param | Type | Description | +| --- | --- | --- | +| callbackQueryId | Number | String | Unique identifier for the query to be answered | +| text | String | Text of the notification. If not specified, nothing will be shown to the user | +| showAlert | Boolean | Whether to show an alert or a notification at the top of the screen | +| [options] | Object | Additional Telegram query options | + + + +### telegramBot.editMessageText(text, [options]) ⇒ Promise +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. + +**Kind**: instance method of [TelegramBot](#TelegramBot) +**See**: https://core.telegram.org/bots/api#editmessagetext + +| Param | Type | Description | +| --- | --- | --- | +| text | String | New text of the message | +| [options] | Object | Additional Telegram query options (provide either one of chat_id, message_id, or inline_message_id here) | + + + +### telegramBot.editMessageCaption(caption, [options]) ⇒ Promise +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. + +**Kind**: instance method of [TelegramBot](#TelegramBot) +**See**: https://core.telegram.org/bots/api#editmessagetext + +| Param | Type | Description | +| --- | --- | --- | +| caption | String | New caption of the message | +| [options] | Object | Additional Telegram query options (provide either one of chat_id, message_id, or inline_message_id here) | + + + +### telegramBot.editMessageReplyMarkup(replyMarkup, [options]) ⇒ Promise +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. + +**Kind**: instance method of [TelegramBot](#TelegramBot) +**See**: https://core.telegram.org/bots/api#editmessagetext + +| Param | Type | Description | +| --- | --- | --- | +| replyMarkup | Object | A JSON-serialized object for an inline keyboard. | +| [options] | Object | Additional Telegram query options (provide either one of chat_id, message_id, or inline_message_id here) | + ### telegramBot.getUserProfilePhotos(userId, [offset], [limit]) ⇒ Promise From 8bacecbbf31d8b57f45a15477e706a115cb302ec Mon Sep 17 00:00:00 2001 From: Yago Date: Mon, 6 Jun 2016 23:11:24 +0200 Subject: [PATCH 09/10] 0.22.1 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index f037250..df820de 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "node-telegram-bot-api", - "version": "0.22.0", + "version": "0.22.1", "description": "Telegram Bot API", "main": "./lib/telegram.js", "directories": { From c9556e3c98424693c34a9bfb084701756b276c65 Mon Sep 17 00:00:00 2001 From: knock-in Date: Mon, 21 Mar 2016 11:33:32 +0100 Subject: [PATCH 10/10] Generate Docs from /src directly --- package.json | 2 +- src/telegram.js | 17 ++++++++++------- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/package.json b/package.json index df820de..f679220 100644 --- a/package.json +++ b/package.json @@ -17,7 +17,7 @@ "prepublish": "./node_modules/.bin/babel -d ./lib src", "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", + "gen-doc": "./node_modules/.bin/jsdoc2md --src src/telegram.js -t README.hbs > README.md", "eslint": "./node_modules/.bin/eslint ./src" }, "author": "Yago Pérez ", diff --git a/src/telegram.js b/src/telegram.js index 7340ed1..0d95788 100644 --- a/src/telegram.js +++ b/src/telegram.js @@ -14,14 +14,17 @@ const URL = require('url'); const fs = require('fs'); const pump = require('pump'); +const _messageTypes = [ + 'text', 'audio', 'document', 'photo', 'sticker', 'video', 'voice', 'contact', + 'location', 'new_chat_participant', 'left_chat_participant', 'new_chat_title', + 'new_chat_photo', 'delete_chat_photo', 'group_chat_created' +]; + class TelegramBot extends EventEmitter { - // Telegram message events - static messageTypes = [ - 'text', 'audio', 'document', 'photo', 'sticker', 'video', 'voice', 'contact', - 'location', 'new_chat_participant', 'left_chat_participant', 'new_chat_title', - 'new_chat_photo', 'delete_chat_photo', 'group_chat_created' - ]; + static get messageTypes() { + return _messageTypes; + } /** * Both request method to obtain messages are implemented. To use standard polling, set `polling: true` @@ -64,7 +67,7 @@ class TelegramBot extends EventEmitter { this._polling = new TelegramBotPolling(this.token, this.options.polling, this.processUpdate); } - processUpdate = (update) => { + processUpdate(update) { debug('Process Update %j', update); const message = update.message; const inlineQuery = update.inline_query;