diff --git a/CHANGELOG.md b/CHANGELOG.md index 381b5b7..d26a338 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,27 @@ All notable changes to this project will be documented in this file. This project adheres to [Semantic Versioning](http://semver.org/). +## [0.58.0][0.58.0] - 2022-06-22 + +1. Support Bot API v6.1: (@danielperez9430) + * Add method *createInvoiceLink()* + +2. Support for setStickerSetThumb (@elihaidv) + +3. Add new test (@danielperez9430) + * createInvoiceLink + +4. Test fixes (@danielperez9430) + * sendVideoNote + * createNewStickerSet + * setStickerSetThumb + * getChatMenuButton + * setWebHook + +5. Bug fixes (@danielperez9430) + * answerWebAppQuery + * Support for send thumb in sendAudio + ## [0.57.0][0.57.0] - 2022-04-23 Added: diff --git a/README.md b/README.md index 08509ff..e609bc4 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ Node.js module to interact with the official [Telegram Bot API](https://core.telegram.org/bots/api). -[![Bot API](https://img.shields.io/badge/Bot%20API-v.5.5-00aced.svg?style=flat-square&logo=telegram)](https://core.telegram.org/bots/api) +[![Bot API](https://img.shields.io/badge/Bot%20API-v.6.1-00aced.svg?style=flat-square&logo=telegram)](https://core.telegram.org/bots/api) [![npm package](https://img.shields.io/npm/v/node-telegram-bot-api?logo=npm&style=flat-square)](https://www.npmjs.org/package/node-telegram-bot-api) [![Build Status](https://img.shields.io/travis/yagop/node-telegram-bot-api/master?style=flat-square&logo=travis)](https://travis-ci.org/yagop/node-telegram-bot-api) [![Coverage Status](https://img.shields.io/codecov/c/github/yagop/node-telegram-bot-api?style=flat-square&logo=codecov)](https://codecov.io/gh/yagop/node-telegram-bot-api) diff --git a/doc/api.md b/doc/api.md index 3589f9e..e6971a3 100644 --- a/doc/api.md +++ b/doc/api.md @@ -109,12 +109,14 @@ TelegramBot * [.getGameHighScores(userId, [options])](#TelegramBot+getGameHighScores) ⇒ Promise * [.deleteMessage(chatId, messageId, [options])](#TelegramBot+deleteMessage) ⇒ Promise * [.sendInvoice(chatId, title, description, payload, providerToken, startParameter, currency, prices, [options])](#TelegramBot+sendInvoice) ⇒ Promise + * [.createInvoiceLink(title, description, payload, providerToken, currency, prices, [options])](#TelegramBot+createInvoiceLink) ⇒ String * [.answerShippingQuery(shippingQueryId, ok, [options])](#TelegramBot+answerShippingQuery) ⇒ Promise * [.answerPreCheckoutQuery(preCheckoutQueryId, ok, [options])](#TelegramBot+answerPreCheckoutQuery) ⇒ Promise * [.getStickerSet(name, [options])](#TelegramBot+getStickerSet) ⇒ Promise * [.uploadStickerFile(userId, pngSticker, [options], [fileOptions])](#TelegramBot+uploadStickerFile) ⇒ Promise * [.createNewStickerSet(userId, name, title, pngSticker, emojis, [options], [fileOptions])](#TelegramBot+createNewStickerSet) ⇒ Promise * [.addStickerToSet(userId, name, pngSticker, emojis, [options], [fileOptions])](#TelegramBot+addStickerToSet) ⇒ Promise + * [.setStickerSetThumb(userId, name, pngThumb, [options], [fileOptions])](#TelegramBot+setStickerSetThumb) ⇒ Promise * [.setStickerPositionInSet(sticker, position, [options])](#TelegramBot+setStickerPositionInSet) ⇒ Promise * [.deleteStickerFromSet(sticker, [options])](#TelegramBot+deleteStickerFromSet) ⇒ Promise * [.sendMediaGroup(chatId, media, [options])](#TelegramBot+sendMediaGroup) ⇒ Promise @@ -1628,10 +1630,29 @@ Use this method to send an invoice. | prices | Array | Breakdown of prices | | [options] | Object | Additional Telegram query options | + + +### telegramBot.createInvoiceLink(title, description, payload, providerToken, currency, prices, [options]) ⇒ String +Create Invoice Link +Use this method to create a link for an invoice. Returns the created invoice link as String on success. + +**Kind**: instance method of [TelegramBot](#TelegramBot) +**See**: https://core.telegram.org/bots/api#createinvoicelink + +| Param | Type | Description | +| --- | --- | --- | +| title | String | Product name, 1-32 characters | +| description | String | Product description, 1-255 characters | +| payload | String | Bot defined invoice payload | +| providerToken | String | Payment provider token | +| currency | String | Three-letter ISO 4217 currency code | +| prices | Array | Breakdown of prices | +| [options] | Object | Additional Telegram query options | + ### telegramBot.answerShippingQuery(shippingQueryId, ok, [options]) ⇒ Promise -Answer shipping query.. +Answer shipping query. Use this method to reply to shipping queries. **Kind**: instance method of [TelegramBot](#TelegramBot) @@ -1733,6 +1754,27 @@ Returns True on success. | [options] | Object | Additional Telegram query options | | [fileOptions] | Object | Optional file related meta-data | + + +### telegramBot.setStickerSetThumb(userId, name, pngThumb, [options], [fileOptions]) ⇒ Promise +Use this method to add a thumb to a set created by the bot. +Returns True on success. + +**Kind**: instance method of [TelegramBot](#TelegramBot) +**See**: https://core.telegram.org/bots/api#setstickersetthumb +**Todo** + +- [ ] Add tests for this method! + + +| Param | Type | Description | +| --- | --- | --- | +| userId | Number | User identifier of sticker set owner | +| name | String | Sticker set name | +| pngThumb | String \| stream.Stream \| Buffer | A PNG image with the thumbnail, must be up to 128 kilobytes in size and have width and height exactly 100px, or a TGS animation with the thumbnail up to 32 kilobytes in size; | +| [options] | Object | Additional Telegram query options | +| [fileOptions] | Object | Optional file related meta-data | + ### telegramBot.setStickerPositionInSet(sticker, position, [options]) ⇒ Promise diff --git a/package.json b/package.json index 7e6399a..f815e4d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "node-telegram-bot-api", - "version": "0.57.0", + "version": "0.58.0", "description": "Telegram Bot API", "main": "./index.js", "directories": { diff --git a/src/telegram.js b/src/telegram.js index b9c3a42..2c964e1 100644 --- a/src/telegram.js +++ b/src/telegram.js @@ -827,7 +827,9 @@ class TelegramBot extends EventEmitter { const opts = { qs: options }; + opts.qs.chat_id = chatId; + try { const sendData = this._formatSendData('audio', audio, fileOptions); opts.formData = sendData[0]; @@ -835,6 +837,25 @@ class TelegramBot extends EventEmitter { } catch (ex) { return Promise.reject(ex); } + + if (options.thumb) { + if (opts.formData === null) { + opts.formData = {}; + } + + try { + const attachName = 'photo'; + const [formData] = this._formatSendData(attachName, options.thumb.replace('attach://', '')); + + if (formData) { + opts.formData[attachName] = formData[attachName]; + opts.qs.thumb = `attach://${attachName}`; + } + } catch (ex) { + return Promise.reject(ex); + } + } + return this._request('sendAudio', opts); } @@ -1482,7 +1503,7 @@ class TelegramBot extends EventEmitter { answerWebAppQuery(webAppQueryId, result, form = {}) { form.web_app_query_id = webAppQueryId; form.result = stringify(result); - return this._request('answerCallbackQuery', { form }); + return this._request('answerWebAppQuery', { form }); } @@ -2195,7 +2216,31 @@ class TelegramBot extends EventEmitter { } /** - * Answer shipping query.. + * Create Invoice Link + * Use this method to create a link for an invoice. Returns the created invoice link as String on success. + * + * @param {String} title Product name, 1-32 characters + * @param {String} description Product description, 1-255 characters + * @param {String} payload Bot defined invoice payload + * @param {String} providerToken Payment provider token + * @param {String} currency Three-letter ISO 4217 currency code + * @param {Array} prices Breakdown of prices + * @param {Object} [options] Additional Telegram query options + * @returns {String} + * @see https://core.telegram.org/bots/api#createinvoicelink + */ + createInvoiceLink(title, description, payload, providerToken, currency, prices, form = {}) { + form.title = title; + form.description = description; + form.payload = payload; + form.provider_token = providerToken; + form.currency = currency; + form.prices = stringify(prices); + return this._request('createInvoiceLink', { form }); + } + + /** + * Answer shipping query. * Use this method to reply to shipping queries. * * @param {String} shippingQueryId Unique identifier for the query to be answered @@ -2335,7 +2380,7 @@ class TelegramBot extends EventEmitter { } return this._request('addStickerToSet', opts); } - + /** * Use this method to add a thumb to a set created by the bot. * Returns True on success. diff --git a/test/data/sticker.png b/test/data/sticker.png index 8eb5c98..971ebc1 100644 Binary files a/test/data/sticker.png and b/test/data/sticker.png differ diff --git a/test/data/sticker_thumb.png b/test/data/sticker_thumb.png new file mode 100644 index 0000000..659e561 Binary files /dev/null and b/test/data/sticker_thumb.png differ diff --git a/test/telegram.js b/test/telegram.js index 0d18816..bd96467 100644 --- a/test/telegram.js +++ b/test/telegram.js @@ -29,6 +29,7 @@ const USERID = process.env.TEST_USER_ID || 777000; const GROUPID = process.env.TEST_GROUP_ID || -1001075450562; const GAME_SHORT_NAME = process.env.TEST_GAME_SHORT_NAME || 'medusalab_test'; const STICKER_SET_NAME = process.env.TEST_STICKER_SET_NAME || 'pusheen'; +const CURRENT_TIMESTAMP = Date.now(); const timeout = 60 * 1000; let portindex = 8091; const staticPort = portindex++; @@ -47,6 +48,7 @@ const FILE_PATH = `${__dirname}/data/photo.png`; let FILE_ID; let GAME_CHAT_ID; let GAME_MSG_ID; +let BOT_USERNAME; before(function beforeAll() { utils.startStaticServer(staticPort); @@ -112,6 +114,10 @@ describe('TelegramBot', function telegramSuite() { return bot.sendGame(USERID, GAME_SHORT_NAME); }).then(resp => { GAME_MSG_ID = resp.message_id; + }).then(() => { + return bot.getMe().then(resp => { + BOT_USERNAME = resp.username; + }); }); }); @@ -152,7 +158,7 @@ describe('TelegramBot', function telegramSuite() { myBot.on('polling_error', (error) => { assert.ifError(error); }); - return myBot.setWebHook(ip).then(() => { + return myBot.setWebHook(ip, {}).then(() => { return myBot.startPolling(); }).then(() => { return myBot.stopPolling(); @@ -395,7 +401,7 @@ describe('TelegramBot', function telegramSuite() { }); it('should set a webHook', function test() { return bot - .setWebHook(ip) + .setWebHook(ip, {}) .then(resp => { assert.strictEqual(resp, true); }); @@ -416,7 +422,7 @@ describe('TelegramBot', function telegramSuite() { }); it('should delete the webHook', function test() { return bot - .setWebHook('') + .setWebHook('', {}) .then(resp => { assert.strictEqual(resp, true); }); @@ -605,6 +611,16 @@ describe('TelegramBot', function telegramSuite() { assert.ok(is.object(resp.audio)); }); }); + it('should send an audio file with thumb', function test() { + const audio = `${__dirname}/data/audio.mp3`; + const thumbImg = `attach://${__dirname}/data/sticker_thumb.png`; + + return bot.sendAudio(USERID, audio, { thumb: thumbImg }).then(resp => { + assert.ok(is.object(resp)); + assert.ok(is.object(resp.audio)); + assert.ok(is.object(resp.audio.thumb)); + }); + }); }); describe('#sendDocument', function sendDocumentSuite() { @@ -740,7 +756,7 @@ describe('TelegramBot', function telegramSuite() { }); }); - describe.skip('#sendVideoNote', function sendVideoNoteSuite() { + describe('#sendVideoNote', function sendVideoNoteSuite() { let videoNoteId; this.timeout(timeout); before(function before() { @@ -750,8 +766,8 @@ describe('TelegramBot', function telegramSuite() { const video = `${__dirname}/data/video.mp4`; return bot.sendVideoNote(USERID, video, { length: 5 }).then(resp => { assert.ok(is.object(resp)); - assert.ok(is.object(resp.video_note)); - videoNoteId = resp.video_note.file_id; + assert.ok(is.object(resp.video)); + videoNoteId = resp.video.file_id; }); }); it('should send a video from id', function test() { @@ -759,21 +775,21 @@ describe('TelegramBot', function telegramSuite() { assert.ok(videoNoteId); return bot.sendVideoNote(USERID, videoNoteId, { length: 5 }).then(resp => { assert.ok(is.object(resp)); - assert.ok(is.object(resp.video_note)); + assert.ok(is.object(resp.video)); }); }); it('should send a video from fs.readStream', function test() { const video = fs.createReadStream(`${__dirname}/data/video.mp4`); return bot.sendVideoNote(USERID, video, { length: 5 }).then(resp => { assert.ok(is.object(resp)); - assert.ok(is.object(resp.video_note)); + assert.ok(is.object(resp.video)); }); }); it('should send a video from a Buffer', function test() { const video = fs.readFileSync(`${__dirname}/data/video.mp4`); return bot.sendVideoNote(USERID, video, { length: 5 }).then(resp => { assert.ok(is.object(resp)); - assert.ok(is.object(resp.video_note)); + assert.ok(is.object(resp.video)); }); }); }); @@ -879,7 +895,7 @@ describe('TelegramBot', function telegramSuite() { describe('#getChatMenuButton', function getChatMenuButtonSuite() { it('should get chat menu button', function test() { - return bot.getChatMenuButton().then(resp => { + return bot.getChatMenuButton({ chat_id: USERID }).then(resp => { assert.ok(is.equal(resp, { type: 'web_app', text: 'Hello', @@ -1589,10 +1605,48 @@ describe('TelegramBot', function telegramSuite() { }); }); + describe('#createInvoiceLink', function createInvoiceLinkSuite() { + before(function before() { + utils.handleRatelimit(bot, 'createInvoiceLink', this); + }); + it('should create an invoice link', function test() { + if (isCI) { + this.skip(); // Skip test for now + } + const title = 'Invoice link product'; + const description = 'Our test invoice link product'; + const payload = 'sku-p002'; + const providerToken = PROVIDER_TOKEN; + const currency = 'EUR'; + const prices = [{ label: 'NTBA API', amount: 12000 }, { label: 'tax', amount: 10000 }]; + return bot.createInvoiceLink(title, description, payload, providerToken, currency, prices).then(resp => { + console.log(resp); + assert.ok(is.string(resp)); + }); + }); + }); + describe.skip('#answerShippingQuery', function answerShippingQuerySuite() { }); describe.skip('#answerPreCheckoutQuery', function answerPreCheckoutQuerySuite() { }); + describe('#createNewStickerSet', function createNewStickerSetSuite() { + before(function before() { + utils.handleRatelimit(bot, 'createNewStickerSet', this); + }); + + it('should create a new sticker set', function test(done) { + const sticker = `${__dirname}/data/sticker.png`; + const stickerPackName = `s${CURRENT_TIMESTAMP}_by_${BOT_USERNAME}`; + + bot.createNewStickerSet(USERID, stickerPackName, 'Sticker Pack Title', sticker, '😍').then((resp) => { + assert.ok(is.boolean(resp)); + }); + setTimeout(() => done(), 2000); + }); + }); + + describe('#getStickerSet', function getStickerSetSuite() { before(function before() { utils.handleRatelimit(bot, 'getStickerSet', this); @@ -1606,6 +1660,31 @@ describe('TelegramBot', function telegramSuite() { assert.ok(is.array(resp.stickers)); }); }); + it('should get the recent sticker set created given the name of the set', function test() { + const stickerPackName = `s${CURRENT_TIMESTAMP}_by_${BOT_USERNAME}`; + return bot.getStickerSet(stickerPackName).then(resp => { + assert.ok(is.object(resp)); + assert.strictEqual(resp.name.toLowerCase(), stickerPackName.toLowerCase()); + assert.ok(is.string(resp.title)); + assert.ok(is.boolean(resp.contains_masks)); + assert.ok(is.array(resp.stickers)); + }); + }); + }); + + describe('#setStickerSetThumb', function setStickerSetThumbSuite() { + before(function before() { + utils.handleRatelimit(bot, 'setStickerSetThumb', this); + }); + + it('should set a sticker set thumb', function test() { + const stickerThumb = `${__dirname}/data/sticker_thumb.png`; + const stickerPackName = `s${CURRENT_TIMESTAMP}_by_${BOT_USERNAME}`; + + bot.setStickerSetThumb(USERID, stickerPackName, stickerThumb).then((resp) => { + assert.ok(is.boolean(resp)); + }); + }); }); describe('#uploadStickerFile', function sendPhotoSuite() {