Intial Commit

This commit is contained in:
valki
2020-10-17 18:42:50 +02:00
commit 664c6d8ca3
5892 changed files with 759183 additions and 0 deletions

View File

@@ -0,0 +1,8 @@
The MIT License (MIT)
Copyright (c) <year> <copyright holders>
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View File

@@ -0,0 +1,611 @@
# Telegram bot nodes for node-red
![License](https://img.shields.io/github/license/windkh/node-red-contrib-telegrambot.svg)
![Release](https://img.shields.io/npm/v/node-red-contrib-telegrambot.svg)
![NPM](https://img.shields.io/npm/dm/node-red-contrib-telegrambot.svg)
[![Known Vulnerabilities](https://snyk.io/test/npm/node-red-contrib-telegrambot/badge.svg)](https://snyk.io/test/npm/node-red-contrib-telegrambot)
[![Telegram](https://img.shields.io/badge/Join-Telegram%20Chat-blue.svg)](https://t.me/nodered_telegrambot)
This package contains a receiver and a sender node which act as a telegram bot.
The only thing required is the token that can be retrieved by the @botfather telegram bot.
https://core.telegram.org/bots
# Thanks for your donation
If you want to support this free project. Any help is welcome. You can donate by clicking one of the following links:
<a target="blank" href="https://blockchain.com/btc/payment_request?address=1PBi7BoZ1mBLQx4ePbwh1MVoK2RaoiDsp5"><img src="https://img.shields.io/badge/Donate-Bitcoin-green.svg"/></a>
<a target="blank" href="https://www.paypal.me/windkh"><img src="https://img.shields.io/badge/Donate-PayPal-blue.svg"/></a>
# Live support
## Get help
If you have an urgent problem, hire a mentor for a 1:1 live session on Git-Start:
[![Get 1:1 live support for your issue.](https://git-start.com/assets/git-start-mentee-banner-medium.svg?sanitize=true)](https://git-start.com/help-request/create/windkh%2Fnode-red-contrib-telegrambot)
## Provide help
Help others in paid 1:1 live sessions to get started.
[![Give paid 1:1 live support.](https://git-start.com/assets/git-start-mentor-banner-medium.svg?sanitize=true)](https://git-start.com/help-request/overview/windkh%2Fnode-red-contrib-telegrambot)
# Credits
dvv (Vladimir Dronnikov) for providing the saveDataDir configuration option.
snippet-java for adding venue messages. And for providing the markdown problem fallback.
greenstone7 for providing the callback query node.
dceejay for cleaning up the project
psyntium for providing the weblink for additional content link videos, pictures, audio files.
MatthiasHunziker for extending the callback query node to support generic events
Skiepp for providing the send chat action idea.
MK-2001 for providing the sendMediaGroup function.
cowchimp for adding the support for node-red 1.x (async)
JokerQyou for adding the support for using webhook without certificate
# Dependencies
The nodes are a simple wrapper around the [node-telegram-bot-api](https://github.com/yagop/node-telegram-bot-api)
It also depends on [socks5-https-client](https://github.com/mattcg/socks5-https-client)
# History
Version 4.x.x
Breaking changes: the former callback query node was replaced by the generic event node.
You can replace the former callback query node in your existing flows with the event node. Please configure this event node
to receive the callback query event.
Version 4.8.0
In this version the result returned by the sender node was changed for direct commands like for example
editMessageLiveLocation, stopMessageLiveLocation, editMessageCaption, ...
in a way that the msg.payload.content contains now the full object returned by the request instead of the
msg.payload.sentMessageId property. All flows that did not make any use of those special functions should snot be affected.
Version 5.0.0
Finally webhooks are supported now. The configuration node was changed so that the required properties for webhook can be configured.
Version 5.2.1
This version contains SOCKS5 support: see https://github.com/windkh/node-red-contrib-telegrambot/issues/43
Version 5.3.0
Improved configuration node: grouped properties. Added support for custom and non custom certificates in webhook mode: see https://github.com/windkh/node-red-contrib-telegrambot/issues/66
Version 5.4.0
Added sendMediaGroup function: see https://github.com/windkh/node-red-contrib-telegrambot/pull/68
Version 5.5.0
Fixed restrictChatMember, kickChatMember, promoteChatMember, unbanChatMember functions: see https://github.com/windkh/node-red-contrib-telegrambot/issues/71
Version 6.0.0
Modified nodes to support node-red 1.x
Version 6.0.1
Removed warning when nodes register twice at the configuration node
Version 7.0.0
Updated https://www.npmjs.com/package/node-telegram-bot-api to version 0.40.0
# Warning
The nodes are tested with nodejs 8.11.1 and node-red 0.20.3. This version shold support node-red 1.x and above but I did not really test it.
# Usage
The input node receives messages from the bot and sends a message object with the following layout:
`msg.payload` contains the message details
- **chatId** : the unique id of the chat. This value needs to be passed to the out node when responding to the same chat.
- **type** : the type of message received: message, photo, audio, location, video, voice, contact
- **content** : received message content: string or file_id, or object with full data (location, contact)
`msg.originalMessage` contains the original message object from the underlying [node-telegram-bot-api](https://github.com/yagop/node-telegram-bot-api) lib.
The output node sends the content to a specified chat.
A simple echo flow looks like:
![Alt text](images/TelegramBotEcho.png?raw=true "Echo Flow")
[echo flow](examples/echo.json)
## Configuration Node
The only thing to be entered here is the token which you received from @botfather when creating a new bot.
The string is automatically trimmed.
The node contains two optional properties: users and chatids. You may enter a list of names and/or chatids that
are authorized to use this bot. This is useful, if the bot should only accept incoming calls from dedicated persons.
The values in the property fields must be separated by a , e.g.:
Hugo,Sepp,Egon
Leave the fields blank if you do not want to use this feature.
saveDataDir is an optional configuration value that can be set to automatically download all contents like music, video, documents, etc.
The "Verbose Logging" flag should only be activated when debugging network problems as this will create cyclic warnings when the network is down.
By default the bot is polling every 300ms for new messages. But you can also make use of the webhook method to avoid polling.
Before that you have to create your own certificate as described here:
https://core.telegram.org/bots/webhooks
https://stackoverflow.com/questions/42713926/what-is-easy-way-to-create-and-use-a-self-signed-certification-for-a-telegram-we
One of many pitfalls when creating certificates (that don't work) is, that the value CN you provided to openssl must match the bots domain name: see "bot host" above.
Create our pair of private and public keys using the following command:
Important:
replace SERVER_NAME_OR_IP with the name you enter in the configuration node under "Webhook Bot Host". Both names must be equal, otherwise the telegram server won't send updates to your bot.
You should also replace YOUR_NAME_OR_COMPANY_NAME with some value. Note that the certificate will expire after 365 days.
```
openssl req -newkey rsa:2048 -sha256 -nodes -keyout PRIVATE.key -x509 -days 365 -out PUBLIC.pem -subj "/C=NG/ST=Lagos/L=Lagos/O=YOUR_NAME_OR_COMPANY_NAME/CN=SERVER_NAME_OR_IP"
```
Webhook can also be used without certificate but then the bot host must be behind a tunnel see https://github.com/windkh/node-red-contrib-telegrambot/pull/93
SOCKS5 proxy support is optional when running behind a SOCKS5 proxy that requires authentication.
## Receiver Node
This node receives all messages from a chat. Simply invite the bot to a chat.
(You can control if the bot receives every message by calling /setprivacy @botfather.)
The original message from the underlying node library is stored in msg.originalMessage.
msg.payload contains the most important data like chatId, type and content. The content depends
on the message type. E.g. if you receive a message then the content is a string. If you receive a location,
then the content is an object containing latitude and longitude.
The second output is triggered when security is applied and the user is not authorized to access the bot. See below.
When the receiver node receives data like videos, documents and so on, the file is downloaded automatically to the local harddisc when
saveDataDir is set in the configuration node. The directory is also part of the message payload: msg.payload.path
In addition to that the message contains the direct download link in the payload: msg.payload.weblink
The following types can be received (see type in output object):
- message - content is text
- photo - content is the file_id of the photo with the highest resolution (all photos are stored in the photos property of the output object)
- audio - content is the file_id of the audio file
- document - content is the file_id of the document
- sticker - content is the file_id of the sticker
- video - content is the file_id of the video file
- video_note - content is the file_id of the video note file
- voice - content is the file_id of the voice file
- location - content is an object with latitude and longitude
- venue - content is the venue object
- contact - content is the contact information object
Note that media groups are received not as group, but as separate messages of type photo and video.
The following types indicate changes in the group or channel itself.
- new_chat_title - content is the new chat title
- new_chat_photo - content is the file_id (see photo)
- new_chat_members - content is an array of new chat members
- left_chat_member - content is an object describing the chat member that left
- delete_chat_photo - content is true
- pinned_message - content is the pinned message object
- channel_chat_created -
- group_chat_created -
- supergroup_chat_created -
- migrate_from_chat_id - content is the chat id. The chat property describes the chat.
- migrate_to_chat_id - content is the chat id. The chat property describes the chat.
## Sender Node
This node sends the payload to the chat. The payload must contain the following fields:
msg.payload.chatId - chatId
msg.payload.type - e.g. "message"
msg.payload.content - your message text
msg.error - is set when an exception occurred
Next to sending content the sender node can be used to issue direct commands to the API. The msg.payload.type
needs to be set to one of the following, the msg.payload.content contains the required arguments while additional
arguments are passed in msg.payload.options (see examples for further details):
- editMessageCaption
- editMessageText
- editMessageReplyMarkup
- deleteMessage
- editMessageLiveLocation
- stopMessageLiveLocation
- callback_query
- inline_query
- action
- leaveChat
- kickChatMember
- unbanChatMember
- restrictChatMember
- promoteChatMember
- exportChatInviteLink
- setChatPhoto
- deleteChatPhoto
- setChatTitle
- setChatDescription
- pinChatMessage
- unpinChatMessage
- getChatAdministrators
- getChatMembersCount
- getChat
- getChatMember
## Command Node
The command node can be used for triggering a message when a specified command is received: e.g. help.
See example below.
It has two outputs
1. is triggered when the command is received
2. is triggered when the command is not received
The second one is useful when you want to use a keyboard. See example below.
Commands usually start with a / like for example /foo. According to the telegram api documentation the command
should be issued following the bot name like /foo@YourBot. This is important when you add several different bots
to one single group chat. To avoid that the bot handles commands that are not directly sent to it using the long notation
you can set the "strict" mode in the options of the command node. In this case the bot only accepts the full command
notation in group chats.
## Event Node
The node receives events from the bot like:
- callback_query of inline keyboards.
See example-flow [inline keyboard flow](examples/inlinekeyboard.json) in examples folder.
- inline_query
- edited_message which is triggered when someone alters an already sent message.
- edited_message_text which is triggered when someone alters an already sent message text.
- edited_message_caption which is triggered when someone alters an already sent caption e.g. of a photo.
- channel_post which is triggered when the bot is member of a public channel (/setprivacy to disabled!).
- edited_channel_post which is triggeren when someone alters an already sent message in a public channel.
- edited_channel_post_text which is triggeren when someone alters an already sent message text in a public channel.
- edited_channel_post_caption which is triggeren when someone alters an already sent caption of e.g. a photo in a public channel.
## Reply Node
The reply node waits for an answer to a specified message. It should be used in conjunction with the sender node:
See example below.
## Implementing a simple echo
This example is self-explaining. The received message is returned to the sender.
![Alt text](images/TelegramBotEcho.png?raw=true "Echo Flow")
[echo flow](examples/echo.json)
## Implementing a /help command
This flow returns the help message of your bot. It receives the command and creates a new message, which is returned:
![Alt text](images/TelegramBotHelp.png?raw=true "Help Command Flow")
![Alt text](images/TelegramBotHelp2.png?raw=true "Help Function")
**Note**: You can access the sender's data via the originalMessage property.
## Implementing a keyboard
Keyboards are very useful for getting additional data from the sender.
When the command is received the first output is triggered and a dialog is opened:
![Alt text](images/TelegramBotConfirmationMessage.png?raw=true "Keyboard Flow")
[keyboard flow](examples/keyboard.json)
![Alt text](images/TelegramBotConfirmationMessage2.png?raw=true "Keyboard Function 1")
The answer is send to the second output triggering the lower flow. Data is passed via global properties here.
![Alt text](images/TelegramBotConfirmationMessage3.png?raw=true "Keyboard Function 2")
## Implementing a on reply node
Next to the keyboard the bot could also ask a question and wait for the answer.
When the user responds to a specified message the telegram reply node can be used:
![Alt text](images/TelegramBotOnReplyMessage.png?raw=true "OnReply Flow")
[onreplymessage flow](examples/onreplymessage.json)
![Alt text](images/TelegramBotOnReplyMessage2.png?raw=true "Create question")
The question is sent to the chat. This node triggers the on reply node waiting for the answer.
**Note**: that the user has to explicitly respond to this message. If the user only writes some text,
the node will not be triggered.
![Alt text](images/TelegramBotOnReplyMessage3.png?raw=true "Switch function")
The last function shows how to evaluate the answer using a function node with two outputs.
## Implementing an inline keyboard
An inline keyboard contains buttons that can send a callback query back to the bot to trigger any kind of function.
When the command is received the first output is triggered and a inline keyboard is shown:
![Alt text](images/TelegramBotInlineKeyboard1.png?raw=true "Inline Keyboard Flow")
[inlinekeyboard flow](examples/inlinekeyboard.json)
![Alt text](images/TelegramBotInlineKeyboard2.png?raw=true "Inline Keyboard Function 1")
The callback query is received by the event node. It must be answered like shown as follows:
Here you can add your code to trigger the desired bot command. The answer contains the callback query data in msg.payload.content.
![Alt text](images/TelegramBotInlineKeyboard3.png?raw=true "Inline Keyboard Function 2")
## Edit an inline keyboard
An inline keyboard can be modified using the 'editMessageReplyMarkup' instruction. To be able to modify an existing message you need
to know the messageId of the message of the keyboard.
A sample flow is provided in the examples folder and could look like this:
![Alt text](images/TelegramBotEditInlineKeyboard1.png?raw=true "Edit Inline Keyboard Flow")
[editinlinekeyboard flow](examples/editinlinekeyboard.json)
![Alt text](images/TelegramBotEditInlineKeyboard2.png?raw=true "Showing the initial keyboard")
The message id needs to be saved in the flow or global context. This is just a demo assuming that there is only one single chat.
![Alt text](images/TelegramBotEditInlineKeyboard3.png?raw=true "Storing the messageId of the keyboard")
Replace the initial keyboard with a modified one using the magic 'editMessageReplyMarkup' command as type.
![Alt text](images/TelegramBotEditInlineKeyboard4.png?raw=true "Replacing the initial keyboard")
The following switch node just handles the response and hides the keyboard using another magic command: 'deleteMessage'
![Alt text](images/TelegramBotEditInlineKeyboard5.png?raw=true "Handling the keyboard response")
As an alternative to 'editMessageReplyMarkup' you can also use 'editMessageText' to replace the keyboard and also the text as follows:
![Alt text](images/TelegramBotEditInlineKeyboard6.png?raw=true "Replacing the initial keyboard and the text")
## Implementing an inline_query
Bots can be called from any chat via inline_query when the bot is set to inline mode in botfather via /setinline
see https://core.telegram.org/bots/api#inline-mode
A sample flow is provided in the examples folder and could look like this:
![Alt text](images/TelegramBotInlineQuery1.png?raw=true "Answer Inline Query Flow")
[inlinequery flow](examples/inlinequery.json)
The inline_query must be answered by sending a results array.
see https://core.telegram.org/bots/api#inlinequeryresult
The example just returns two simple articles, but almost every kind of content can be returned.
![Alt text](images/TelegramBotInlineQuery2.png?raw=true "Creating the results array")
Note that the inline_query can also contain the location of the sender. To enable this call /setinlinegeo in botfather
## Receiving a location
Locations can be send to the chat. The bot can receive the longitude and latitude:
![Alt text](images/TelegramBotLocation.png?raw=true "Location Function")
## Sending messages to a specified chat
If you have the chatId, you can send any message without the need of having received something before.
![Alt text](images/TelegramBotSendToChat.png?raw=true "Sending a message")
[sendmessagetochat flow](examples/sendmessagetochat.json)
## Sending photos, videos, ...
Next to sending text messages you can send almost any content like photos and videos. Set the right type and content and you are done.
If you want to respond to a received message with a picture you could write:
```
msg.payload.content = 'foo.jpg';
msg.payload.type = 'photo';
```
**Note**: that the chatId is already the correct one when you reuse the received msg object from a receiver node.
You can use one of the following types to send your file as content:
- [photo](examples/sendphoto.json)
- audio
- video
- video_note
- sticker
- voice
- document
The content can be downloaded automatically to a local folder by setting the saveDataDir entry in the configuration node.
You can add a caption to photo, audio, document, video, voice by setting the caption property as follows:
```
msg.payload.caption = "You must have a look at this!";
```
The following types require a special content format to be used. See the underlying node api for further details.
- location
- contact
- venue
- mediaGroup
![Alt text](images/TelegramBotSendPhoto.png?raw=true "Sending a photo")
![Alt text](images/TelegramBotSendPhoto2.png?raw=true "Setting the correct content type.")
### Sending a mediaGroup as album
To send several photos as an album you can use the mediaGroup. For the type of media group you have to set the content to an array of object type [InputMediaPhoto](https://core.telegram.org/bots/api#inputmediaphoto).
Please review the Json below.
```javascript
msg.payload = {
"chatId": 123456789,
"messageId": 1,
"type": "mediaGroup",
"content": [
{
"type": "photo",
"media": "/pic/frame_1.jpg"
},
{
"type": "photo",
"media": "/pic/frame_2.jpg"
},
{
"type": "photo",
"media": "/pic/frame_3.jpg"
},
{
"type": "photo",
"media": "/pic/frame_4.jpg"
}
]
}
```
[sendmediagroup flow](examples/sendmediagroup.json)
## Sending contact
Sending a contact is limited to the fields supported by the underlying API to "phone_number" and "first_name".
But you can also receive "last_name" if the client sends it.
```
msg.payload.type = 'contact';
msg.payload.content : { phone_number: "+49 110", first_name: "Polizei" };
```
![Alt text](images/TelegramBotSendContact.png?raw=true "Send Contact Flow")
[sendcontacttochat flow](examples/sendcontacttochat.json)
![Alt text](images/TelegramBotSendContact2.png?raw=true "Send Contact Function")
## Sending chat actions
When the bot needs some time for further processing but you want to give a hint to the user what is going on,
then you can send a chat action which will appear at the top of the channel of the receiver.
```
msg.payload.type = 'action';
msg.payload.content = "typing";
```
The content can be one of the following
- "typing" for text messages
- "upload_photo" for photos
- "record_video" or "upload_video" for videos
- "record_audio" or "upload_audio" for audio files
- "upload_document" for general files
- "find_location" for location data
- "record_video_note" or "upload_video_note" for video notes
The following example illustrate how to send for example "typing...".
Of course a real bot would send the real data after finishing the processing, but this is not part of the example.
[sendchataction flow](examples/sendchataction.json)
## Sending live locations
Locations can be send to the chat as described above and then updated afterwards: live location update.
To achieve this you have to provide the live_period in seconds in the options when sending the location.
```
msg.payload.type = 'location';
msg.payload.content = {
latitude : lat,
longitude : lng
};
msg.payload.options = {
live_period : time
};
```
To be able to update this location message you need to store the message id of that sent message.
This can be done by storing it somewhere in the flow context as follows:
```
var messageId = msg.payload.sentMessageId;
flow.set("messageId", messageId);
```
Now you can edit the location as often as you want within the live_period:
```
var messageId = flow.get("messageId");
var chatId = msg.payload.chatId;
msg.payload.type = 'editMessageLiveLocation';
msg.payload.content = {
latitude : lat,
longitude : lng
};
msg.payload.options = {
chat_id : chatId,
message_id : messageId
};
```
If you want to abort updating the location then you can send the stopMessageLiveLocation command.
```
var messageId = flow.get("messageId");
var chatId = msg.payload.chatId;
msg.payload.type = 'stopMessageLiveLocation';
msg.payload.options = {
chat_id : chatId,
message_id : messageId
};
```
![Alt text](images/TelegramBotLiveLocation.png?raw=true "Live Location Flow")
[livelocation flow](examples/livelocation.json)
## Receiving live location updates
When a user sends his location then it is received by the standard message receiver node.
But when a live location is updated, then you will receive the same message event as one would
edit an already existing message in the chat (edit_message). The example above contains an event handler node that
receives those message edits, and filters for the ones that contain a location.
## Advanced options when sending messages.
Text messages can be in markdown format to support fat and italic style. To enable markdown format
set the parse_mode options property as follows:
```
msg.payload.options = {parse_mode : "Markdown"};
```
Telegram always adds a preview when you send a web link. To suppress this behavior you can disable the preview
by setting the options property as follows:
```
msg.payload.options = {disable_web_page_preview : true};
```
The callback query answer has a show_alert option to control the visibility of the answer on the client.
It is directly mapped to the options property.
```
msg.payload.options = true;
```
## Configuring security
The configuration node contains two properties for applying security to your bot. You can choose between configuring
the single usernames or configure one or more chat-ids that are allowed to access the bot. The values must be separated using a comma like shown in the screenshot.
![Alt text](images/TelegramBotSecurity.png?raw=true "Applying security")
**Note**: that the chat-ids are positive in chats where you talk to the bot in an 1:1 manner. A negative chat-id indicates a group-chat.
Everybody in this group is allowed to use the bot if you enter the chat-id of the group into the lower field of the configuration node.
## Detecting unauthorized access.
The receiver node has a second output, that is triggered when authorization fails. The message is send to this output for further processing.
You can reply on that message or log it to a file to see who wanted to access your bot.
![Alt text](images/TelegramBotUnauthorizedAccess.png?raw=true "Logging unauthorized access")
The message needs to be formatted before the log to file node can be triggered. A simple function could look like this:
![Alt text](images/TelegramBotUnauthorizedAccess2.png?raw=true "Create logging string with full information.")
[unauthorizedaccess flow](examples/unauthorizedaccess.json)
## Implementing a simple bot
Putting all pieces together you will have a simple bot implementing some useful functions.
![Alt text](images/TelegramBotExample.png?raw=true "Bot example")
[simplebot flow](examples/simplebot.json)
All example flows can be found in the examples folder of this package.
# License
Author: Karl-Heinz Wind
The MIT License (MIT)
Copyright (c) <year> <copyright holders>
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View File

@@ -0,0 +1 @@
[{"id":"ff78bc5a.00874","type":"telegram bot","z":"70c3f45a.8f3c0c","botname":"HeinzBot","usernames":"","chatids":""},{"id":"a3b2b972.7ee418","type":"telegram sender","z":"70c3f45a.8f3c0c","name":"","bot":"ff78bc5a.00874","x":405.51483154296875,"y":738.9999771118164,"wires":[[]]},{"id":"2b76dc18.af49e4","type":"telegram command","z":"70c3f45a.8f3c0c","name":"/foo","command":"/foo","bot":"ff78bc5a.00874","x":146.510498046875,"y":744.3689804077148,"wires":[["a3b2b972.7ee418"],[]]}]

View File

@@ -0,0 +1 @@
[{"id":"1f3cb0bd.e0c34f","type":"telegram bot","z":"8fa6460.f7059b8","botname":"HeinzBot"},{"id":"59aeb36e.a6514c","type":"telegram receiver","z":"8fa6460.f7059b8","name":"","bot":"1f3cb0bd.e0c34f","x":109,"y":128,"wires":[["ec7432bc.138bd"]]},{"id":"ec7432bc.138bd","type":"telegram sender","z":"8fa6460.f7059b8","name":"","bot":"","x":386,"y":128,"wires":[]}]

View File

@@ -0,0 +1 @@
[{"id":"7d12e083.5939d","type":"debug","z":"8bdf0264.94609","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","x":370,"y":100,"wires":[]},{"id":"1ee38d5f.5d1373","type":"catch","z":"8bdf0264.94609","name":"","scope":null,"x":120,"y":100,"wires":[["7d12e083.5939d"]]},{"id":"3c4cb8c0.3f7c78","type":"telegram event","z":"8bdf0264.94609","name":"","bot":"19f02f8b.fa0c5","event":"callback_query","autoanswer":true,"x":140,"y":220,"wires":[["cf25334b.055e3","97f67e8e.cd17b"]]},{"id":"49cc02d7.7c80cc","type":"telegram sender","z":"8bdf0264.94609","name":"show inline keyboard","bot":"19f02f8b.fa0c5","x":582.7594223022461,"y":153.3033103942871,"wires":[["84367d6d.d0a5e"]]},{"id":"d336cf2.5aa523","type":"function","z":"8bdf0264.94609","name":"initial inline keyboard message","func":"context.global.keyboard = { pending : true, messageId : msg.payload.messageId };\n\nvar opts = {\n reply_to_message_id: msg.payload.messageId,\n reply_markup: JSON.stringify({\n \"inline_keyboard\": [[\n {\n \"text\": \"Yes\",\n \"callback_data\": \"FOO YES\" \n }, \n {\n \"text\": \"No\",\n \"callback_data\": \"FOO NO\" \n }]\n ]\n })\n};\n\nmsg.payload.content = 'Do you want to hide the inline keyboard?';\nmsg.payload.options = opts;\n\nreturn [ msg ];\n","outputs":"1","noerr":0,"x":321.7592468261719,"y":154.3032283782959,"wires":[["49cc02d7.7c80cc"]]},{"id":"ddf7fd32.336ad","type":"telegram command","z":"8bdf0264.94609","name":"/foo","command":"/foo","bot":"19f02f8b.fa0c5","strict":false,"x":102.75931549072266,"y":160.3032102584839,"wires":[["d336cf2.5aa523"],[]]},{"id":"97f67e8e.cd17b","type":"function","z":"8bdf0264.94609","name":"evaluate callback query","func":"// This is a sample switch to demonstrate the handling of the user input.\nif(msg.payload.content === \"FOO YES REALLY\")\n{\n // Hide the keyboard and forget the messageId\n msg.payload.type = 'deleteMessage';\n msg.payload.content = context.global.keyboard.messageId\n context.global.keyboard.messageId = null;\n \n // You could also send a editMessageReplyMarkup with an empty reply_markup here\n return [ null, msg ];\n}\nelse\n{\n var show_alert = false; // you can set this to true to open a dialog with the answer in the client.\n \n // msg.payload.content contains the callback data from the keyboard.\n // You may change this value here.\n msg.payload.options = show_alert;\n \n return [ msg, null ];\n}","outputs":"2","noerr":0,"x":468.75933837890625,"y":288.3309726715088,"wires":[["fdb9396f.7386a8"],["fdb9396f.7386a8"]]},{"id":"fdb9396f.7386a8","type":"telegram sender","z":"8bdf0264.94609","name":"answer callback query","bot":"19f02f8b.fa0c5","x":812.7593231201172,"y":219.33101081848145,"wires":[[]]},{"id":"cf25334b.055e3","type":"function","z":"8bdf0264.94609","name":"edit inline keyboard message","func":"// This is the message id of the initial keyboard that is simply exchanged by a new one.\nvar messageId = context.global.keyboard.messageId;\n\n// This is a sample of how to send a second inline keyboard with modified buttons\nvar reply_markup = JSON.stringify({\n \"inline_keyboard\": [[\n {\n \"text\": \"Are you really sure?\",\n \"callback_data\": \"FOO YES REALLY\" \n }, \n {\n \"text\": \"No\",\n \"callback_data\": \"FOO NO\" \n }]\n ]\n });\n\n\nvar options = {\n chat_id : msg.payload.chatId,\n reply_markup : reply_markup,\n message_id : messageId\n};\n\nmsg.payload.type = 'editMessageReplyMarkup';\nmsg.payload.content = reply_markup;\nmsg.payload.options = options;\n\nreturn [ msg ];\n","outputs":"1","noerr":0,"x":475.00010681152344,"y":221.00000762939453,"wires":[["fdb9396f.7386a8"]]},{"id":"84367d6d.d0a5e","type":"function","z":"8bdf0264.94609","name":"save messageId","func":"// We store the messageId to be able to edit this reply in the callback query. \ncontext.global.keyboard.messageId = msg.payload.sentMessageId;\nreturn [ msg ];\n","outputs":"1","noerr":0,"x":800.6667861938477,"y":153.6667127609253,"wires":[[]]},{"id":"19f02f8b.fa0c5","type":"telegram bot","z":"","botname":"HeinzBot","usernames":"","chatids":"","baseapiurl":"","updatemode":"webhook","pollinterval":"300","bothost":"ihive.spdns.de","localbotport":"8443","publicbotport":"8443","privatekey":"C:\\\\Temp\\\\SSL\\\\PRIVATE.key","certificate":"C:\\\\Temp\\\\SSL\\\\PUBLIC.pem","verboselogging":true}]

View File

@@ -0,0 +1 @@
[{"id":"5fb5e66e.d8ebe8","type":"debug","z":"1f6b5f62.c79df1","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","x":350,"y":40,"wires":[]},{"id":"ebf5edfa.8c331","type":"catch","z":"1f6b5f62.c79df1","name":"","scope":null,"x":100,"y":40,"wires":[["5fb5e66e.d8ebe8"]]},{"id":"65b3afb9.8d92","type":"telegram event","z":"1f6b5f62.c79df1","name":"","bot":"45ef79a0.ed7688","event":"callback_query","autoanswer":true,"x":120,"y":100,"wires":[["e74381b8.86275"]]},{"id":"3aabea8a.3ea5e6","type":"telegram sender","z":"1f6b5f62.c79df1","name":"show inline keyboard","bot":"45ef79a0.ed7688","x":660,"y":180,"wires":[[]]},{"id":"40d82a14.cf5f64","type":"function","z":"1f6b5f62.c79df1","name":"inline keyboard message","func":"context.global.keyboard = { pending : true };\n\nvar opts = {\n reply_to_message_id: msg.payload.messageId,\n reply_markup: JSON.stringify({\n \"inline_keyboard\": [[\n {\n \"text\": \"Yes\",\n \"callback_data\": \"FOO YES\" \n }, \n {\n \"text\": \"No\",\n \"callback_data\": \"FOO NO\" \n }]\n ]\n })\n};\n\nmsg.payload.content = 'Are you sure?';\nmsg.payload.options = opts;\n\nreturn [ msg ];\n","outputs":"1","noerr":0,"x":390,"y":180,"wires":[["3aabea8a.3ea5e6"]]},{"id":"3c9c3fe.d673ac","type":"telegram command","z":"1f6b5f62.c79df1","name":"/foo","command":"/foo","bot":"45ef79a0.ed7688","x":90,"y":180,"wires":[["40d82a14.cf5f64"],[]]},{"id":"e74381b8.86275","type":"function","z":"1f6b5f62.c79df1","name":"set answer options","func":"var show_alert = false; // you can set this to true to open a dialog with the answer in the client.\n\n// msg.payload.content contains the callback data from the keyboard.\n// You may change this value here.\nmsg.payload.options = show_alert;\n\nreturn [ msg ];\n","outputs":"1","noerr":0,"x":370,"y":100,"wires":[["a8e26f88.1e892"]]},{"id":"a8e26f88.1e892","type":"telegram sender","z":"1f6b5f62.c79df1","name":"answer callback query","bot":"45ef79a0.ed7688","x":660,"y":100,"wires":[[]]},{"id":"45ef79a0.ed7688","type":"telegram bot","z":"","botname":"HeinzBot","usernames":"","chatids":"","baseapiurl":"","pollinterval":""}]

View File

@@ -0,0 +1 @@
[{"id":"5fb5e66e.d8ebe8","type":"debug","z":"1f6b5f62.c79df1","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","x":350,"y":40,"wires":[]},{"id":"ebf5edfa.8c331","type":"catch","z":"1f6b5f62.c79df1","name":"","scope":null,"x":100,"y":40,"wires":[["5fb5e66e.d8ebe8"]]},{"id":"65b3afb9.8d92","type":"telegram event","z":"1f6b5f62.c79df1","name":"","bot":"45ef79a0.ed7688","event":"inline_query","autoanswer":true,"x":110,"y":100,"wires":[["c7f9eaaa.0207c8"]]},{"id":"c7f9eaaa.0207c8","type":"function","z":"1f6b5f62.c79df1","name":"create results","func":"// we have to set the results propery with the answer(s)\n// see https://core.telegram.org/bots/api#inlinequeryresult\nvar results = [\n // result 1 is InlineQueryResultArticle\n {\n type : \"article\",\n id : \"1\",\n title : \"Result 1\",\n \n // InputTextMessageContent see https://core.telegram.org/bots/api#inputmessagecontent\n input_message_content : {\n message_text : \"The message 1\",\n parse_mode : \"Markdown\",\n disable_web_page_preview : true\n }\n },\n \n // result 2 is InlineQueryResultArticle\n {\n type : \"article\",\n id : \"2\",\n title : \"Result 2\",\n \n // InputTextMessageContent see https://core.telegram.org/bots/api#inputmessagecontent\n input_message_content : {\n message_text : \"The message 2\",\n parse_mode : \"Markdown\",\n disable_web_page_preview : false\n }\n }\n ];\n\n\nmsg.payload.results = results;\nreturn msg;","outputs":1,"noerr":0,"x":360,"y":100,"wires":[["2c870509.1e08ca"]]},{"id":"2c870509.1e08ca","type":"telegram sender","z":"1f6b5f62.c79df1","name":"","bot":"45ef79a0.ed7688","x":590,"y":100,"wires":[[]]},{"id":"45ef79a0.ed7688","type":"telegram bot","z":"","botname":"HeinzBot","usernames":"","chatids":"","baseapiurl":"","pollinterval":""}]

View File

@@ -0,0 +1 @@
[{"id":"ff78bc5a.00874","type":"telegram bot","z":"70c3f45a.8f3c0c","botname":"HeinzBot"},{"id":"d94485f4.26bb78","type":"catch","z":"70c3f45a.8f3c0c","name":"","x":134,"y":243,"wires":[["2ae5947d.d51a6c"]]},{"id":"2ae5947d.d51a6c","type":"debug","z":"70c3f45a.8f3c0c","name":"Debug","active":true,"console":"false","complete":"payload","x":606,"y":239,"wires":[]},{"id":"65b4107a.9a4bf","type":"telegram sender","z":"70c3f45a.8f3c0c","name":"show keyboard","bot":"ff78bc5a.00874","x":620,"y":68,"wires":[]},{"id":"a1dabe3a.5e254","type":"function","z":"70c3f45a.8f3c0c","name":"confirmation message","func":"context.global.keyboard = { pending : true };\n\nvar opts = {\n reply_to_message_id: msg.payload.messageId,\n reply_markup: JSON.stringify({\n keyboard: [\n ['Yes'],\n ['No']],\n 'resize_keyboard' : true, \n 'one_time_keyboard' : true\n })\n};\n\nmsg.payload.content = 'Really?';\nmsg.payload.options = opts;\n\nreturn [ msg ];\n","outputs":"1","noerr":0,"x":354,"y":68,"wires":[["65b4107a.9a4bf"]]},{"id":"7da02f32.825fd","type":"telegram command","z":"70c3f45a.8f3c0c","name":"/foo","command":"/foo","bot":"ff78bc5a.00874","x":134,"y":95,"wires":[["a1dabe3a.5e254"],["71b35090.8e4cb"]]},{"id":"71b35090.8e4cb","type":"function","z":"70c3f45a.8f3c0c","name":"create response","func":"if(context.global.keyboard.pending)\n{\n context.global.keyboard.pending = false;\n \n if(msg.payload.content === 'Yes')\n {\n msg.payload.content = 'Yes';\n return [msg, null]; \n }\n else\n {\n msg.payload.content = 'No';\n return [null, msg]; \n }\n}\n","outputs":"2","noerr":0,"x":338,"y":127,"wires":[["fa470b3b.05b8f8"],["2ae5947d.d51a6c"]]},{"id":"fa470b3b.05b8f8","type":"telegram sender","z":"70c3f45a.8f3c0c","name":"send response","bot":"ff78bc5a.00874","x":624,"y":121,"wires":[]}]

View File

@@ -0,0 +1 @@
[{"id":"e1914945.0ecfd8","type":"catch","z":"725879df.541168","name":"","x":160,"y":580,"wires":[["dc7bc908.f6e5f8"]]},{"id":"dc7bc908.f6e5f8","type":"debug","z":"725879df.541168","name":"Debug","active":true,"console":"false","complete":"payload","x":370,"y":580,"wires":[]},{"id":"da4cf949.cb9118","type":"telegram sender","z":"725879df.541168","name":"send location","bot":"ecbcf512.4e9a28","x":690,"y":120,"wires":[["c95ae907.49e268"]]},{"id":"449dc685.098248","type":"telegram command","z":"725879df.541168","name":"/send to send location","command":"/send","bot":"ecbcf512.4e9a28","strict":true,"x":160,"y":120,"wires":[["9d2ef78b.a10f28"],[]]},{"id":"9d2ef78b.a10f28","type":"function","z":"725879df.541168","name":"send initial location","func":"// see https://core.telegram.org/bots/api#sendlocation\n\nvar lat = flow.get(\"lat\");\nvar lng = flow.get(\"lng\");\nvar time = flow.get(\"time\");\n\n\nmsg.payload.type = 'location';\nmsg.payload.content = {\n latitude : lat,\n longitude : lng\n};\n \nmsg.payload.options = {\n live_period : time\n}; \n\nreturn msg;","outputs":1,"noerr":0,"x":410,"y":120,"wires":[["da4cf949.cb9118"]]},{"id":"74bc17cd.97b958","type":"telegram receiver","z":"725879df.541168","name":"message receiver","bot":"ecbcf512.4e9a28","saveDataDir":"","x":170,"y":380,"wires":[["b8b7f3c0.f220a"],[]]},{"id":"b8b7f3c0.f220a","type":"function","z":"725879df.541168","name":"reply location message","func":"if(msg.payload.type == 'location')\n{\n var lat = msg.payload.content.latitude;\n var lng = msg.payload.content.longitude;\n \n msg.payload.type = 'message';\n msg.payload.content = 'lat=' + lat + ' lon=' + lng;\n \n return msg;\n}\nelse\n{\n return null;\n}\n","outputs":1,"noerr":0,"x":420,"y":380,"wires":[["dc174ebf.53e2c"]]},{"id":"cab3ca7f.6f2778","type":"telegram command","z":"725879df.541168","name":"/update to update live location","command":"/update","bot":"ecbcf512.4e9a28","strict":true,"x":140,"y":200,"wires":[["796bfd7b.89ef04"],[]]},{"id":"796bfd7b.89ef04","type":"function","z":"725879df.541168","name":"edit initial location","func":"// see https://core.telegram.org/bots/api#editMessageLiveLocation\n\nvar messageId = flow.get(\"messageId\");\n\nvar lat = flow.get(\"lat\");\nvar lng = flow.get(\"lng\");\nlat += 0.1;\nlng += 0.1;\nflow.set(\"lat\", lat);\nflow.set(\"lng\", lng);\n\n\nvar chatId = msg.payload.chatId;\nmsg.payload.type = 'editMessageLiveLocation';\nmsg.payload.content = {\n latitude : lat,\n longitude : lng\n};\n \nmsg.payload.options = {\n chat_id : chatId,\n message_id : messageId\n}; \n\nreturn msg;","outputs":1,"noerr":0,"x":410,"y":200,"wires":[["dc174ebf.53e2c"]]},{"id":"de720b3.43142f8","type":"telegram command","z":"725879df.541168","name":"/abort to stop live location","command":"/abort","bot":"ecbcf512.4e9a28","strict":true,"x":150,"y":280,"wires":[["ef341f1c.6ab44"],[]]},{"id":"ef341f1c.6ab44","type":"function","z":"725879df.541168","name":"stop live updating","func":"// see https://core.telegram.org/bots/api#stopMessageLiveLocation\n\nvar messageId = flow.get(\"messageId\");\nvar chatId = msg.payload.chatId;\n\nmsg.payload.type = 'stopMessageLiveLocation';\nmsg.payload.options = {\n chat_id : chatId,\n message_id : messageId\n}; \n\n\nreturn msg;","outputs":1,"noerr":0,"x":410,"y":280,"wires":[["dc174ebf.53e2c"]]},{"id":"36afbf82.a7e8a","type":"inject","z":"725879df.541168","name":"","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":true,"onceDelay":"0.1","x":110,"y":60,"wires":[["4cd6fcae.338154"]]},{"id":"4cd6fcae.338154","type":"function","z":"725879df.541168","name":"intialize location","func":"// Here we initialize some sample data \n// for later usage\n\nflow.set(\"lat\", 47);\nflow.set(\"lng\", 10);\n\n// the live_period in seconds\nflow.set(\"time\", 600);\n\nreturn msg;","outputs":1,"noerr":0,"x":400,"y":60,"wires":[[]]},{"id":"dc174ebf.53e2c","type":"telegram sender","z":"725879df.541168","name":"send response","bot":"ecbcf512.4e9a28","x":700,"y":300,"wires":[[]]},{"id":"c95ae907.49e268","type":"function","z":"725879df.541168","name":"store messageId","func":"// Here we store the message id of the live location message, \n// as we need to update exactly this one later\n\nvar messageId = msg.payload.sentMessageId;\nflow.set(\"messageId\", messageId);\nreturn msg;","outputs":1,"noerr":0,"x":900,"y":120,"wires":[[]]},{"id":"ecf89a6f.b65cf8","type":"telegram event","z":"725879df.541168","name":"live location receiver","bot":"ecbcf512.4e9a28","event":"edited_message","autoanswer":"","x":170,"y":480,"wires":[["7c39a13.7fa4c6"]]},{"id":"7c39a13.7fa4c6","type":"function","z":"725879df.541168","name":"filter live location","func":"if(msg.payload.location)\n{\n var lat = msg.payload.location.latitude;\n var lng = msg.payload.location.longitude;\n var user = msg.payload.from.username;\n \n msg.payload.type = 'message';\n msg.payload.content = user + ' moved to lat=' + lat + ' lon=' + lng;\n \n return msg;\n}\nelse\n{\n return null;\n}\n","outputs":1,"noerr":0,"x":400,"y":480,"wires":[["dc174ebf.53e2c"]]},{"id":"ecbcf512.4e9a28","type":"telegram bot","z":"725879df.541168","botname":"HeinzBot","usernames":"","chatids":"","baseapiurl":"","pollinterval":""}]

View File

@@ -0,0 +1 @@
[{"id":"ff78bc5a.00874","type":"telegram bot","z":"70c3f45a.8f3c0c","botname":"HeinzBot","usernames":"","chatids":""},{"id":"a1dabe3a.5e254","type":"function","z":"70c3f45a.8f3c0c","name":"create question","func":"msg.payload.type = 'message';\nmsg.payload.content = 'Really?';\nmsg.payload.options = {reply_to_message_id : msg.payload.messageId}\nreturn [ msg ];\n","outputs":"1","noerr":0,"x":284,"y":115,"wires":[["fa470b3b.05b8f8"]]},{"id":"7da02f32.825fd","type":"telegram command","z":"70c3f45a.8f3c0c","name":"/foo","command":"/foo","bot":"ff78bc5a.00874","x":112,"y":121,"wires":[["a1dabe3a.5e254"],[]]},{"id":"fa470b3b.05b8f8","type":"telegram sender","z":"70c3f45a.8f3c0c","name":"send question","bot":"ff78bc5a.00874","x":474,"y":115,"wires":[["14f02133.eb0fdf"]]},{"id":"14f02133.eb0fdf","type":"telegram reply","z":"70c3f45a.8f3c0c","name":"get reply","bot":"ff78bc5a.00874","x":669,"y":115,"wires":[["c51200a.f3aee"]]},{"id":"c51200a.f3aee","type":"function","z":"70c3f45a.8f3c0c","name":"switch answer","func":"if(msg.payload.content === 'Yes')\n{\n return [msg, null]; \n}\nelse\n{\n return [null, msg]; \n}\n","outputs":"2","noerr":0,"x":841,"y":115,"wires":[["99233690.66dcc8"],["8deb3205.7214d"]]},{"id":"99233690.66dcc8","type":"debug","z":"70c3f45a.8f3c0c","name":"Yes","active":true,"console":"false","complete":"payload","x":1043,"y":99,"wires":[]},{"id":"8deb3205.7214d","type":"debug","z":"70c3f45a.8f3c0c","name":"No","active":true,"console":"false","complete":"payload","x":1043,"y":146,"wires":[]}]

View File

@@ -0,0 +1 @@
[{"id":"bcd88438.e77e68","type":"telegram receiver","z":"c513a2fb.133e3","name":"","bot":"19f02f8b.fa0c5","saveDataDir":"","x":150,"y":80,"wires":[["d518a4a2.1bded8"],[]]},{"id":"ba1931f2.6acf9","type":"telegram sender","z":"c513a2fb.133e3","name":"","bot":"19f02f8b.fa0c5","x":630,"y":80,"wires":[[]]},{"id":"d518a4a2.1bded8","type":"function","z":"c513a2fb.133e3","name":"reply to message","func":"var opts = {\n reply_to_message_id: msg.payload.messageId\n};\n\nmsg.payload.content = 'I received your message';\nmsg.payload.options = opts;\n\nreturn msg;\n","outputs":"1","noerr":0,"x":370,"y":60,"wires":[["ba1931f2.6acf9"]]},{"id":"19f02f8b.fa0c5","type":"telegram bot","z":"c513a2fb.133e3","botname":"HeinzBot","usernames":"Windhose","chatids":"","baseapiurl":"","updatemode":"polling","pollinterval":"300","usesocks":false,"sockshost":"188.40.170.80","socksport":"1080","socksusername":"anonymous","sockspassword":"none","bothost":"ihive.spdns.de","localbotport":"","publicbotport":"","privatekey":"C:\\\\Temp\\\\SSL\\\\PRIVATE.key","certificate":"C:\\\\Temp\\\\SSL\\\\PUBLIC.pem","useselfsignedcertificate":true,"verboselogging":true}]

View File

@@ -0,0 +1 @@
[{"id":"e76a862e.a03858","type":"telegram receiver","z":"725879df.541168","name":"","bot":"bd029d64.0546a","saveDataDir":"","x":150,"y":140,"wires":[["594c315e.57fec"],[]]},{"id":"cc0d5363.33275","type":"telegram sender","z":"725879df.541168","name":"","bot":"bd029d64.0546a","x":610,"y":140,"wires":[[]]},{"id":"594c315e.57fec","type":"function","z":"725879df.541168","name":"send chat action","func":"// demonstrates sending a chat action (see https://core.telegram.org/bots/api#sendchataction)\nvar type = msg.payload.type;\nmsg.payload.type = \"action\";\n\nswitch(type){\n case \"message\":\n msg.payload.content = \"typing\"; \n break;\n\n case \"photo\":\n msg.payload.content = \"upload_photo\"; \n break;\n\n case \"video\":\n msg.payload.content = \"upload_video\"; \n break;\n\n case \"audio\":\n msg.payload.content = \"upload_audio\"; \n break;\n\n case \"document\":\n msg.payload.content = \"upload_document\"; \n break;\n\n case \"location\":\n msg.payload.content = \"find_location\"; \n break;\n\n case \"video_note\":\n msg.payload.content = \"upload_video_note\"; \n break;\n \n default:\n msg = null;\n break;\n}\n\nreturn msg;","outputs":1,"noerr":0,"x":380,"y":140,"wires":[["cc0d5363.33275"]]},{"id":"bd029d64.0546a","type":"telegram bot","z":"","botname":"HeinzBot","usernames":"","chatids":"","baseapiurl":"","pollinterval":"300"}]

View File

@@ -0,0 +1 @@
[{"id":"648c6ebc.8637e8","type":"telegram sender","z":"725879df.541168","name":"","bot":"ccc4a708.ce4228","x":521.5000305175781,"y":261.33334827423096,"wires":[[]]},{"id":"88d27cfb.a968e","type":"function","z":"725879df.541168","name":"contact","func":"msg.payload = \n{\n chatId : 12345,\n type : \"contact\",\n content : \n {\n phone_number: \"+49 110\",\n first_name: \"first\",\n last_name: \"last\"\n },\n options :\n {\n disable_notification : true\n }\n}\n\nreturn msg;","outputs":1,"noerr":0,"x":331.1667289733887,"y":261.6667022705078,"wires":[["648c6ebc.8637e8"]]},{"id":"3ab929c7.76bb36","type":"inject","z":"725879df.541168","name":"","topic":"","payload":"","payloadType":"json","repeat":"","crontab":"","once":false,"x":153.16671752929688,"y":261.0000762939453,"wires":[["88d27cfb.a968e"]]},{"id":"ccc4a708.ce4228","type":"telegram bot","z":"","botname":"HeinzBot","usernames":"","chatids":""}]

View File

@@ -0,0 +1 @@
[{"id":"d69380f4.8f204","type":"function","z":"3068ac13.951064","name":"create response","func":"if(context.global.keyboard.pending)\n{\n context.global.keyboard.pending = false;\n \n if(msg.payload.content === 'Yes')\n {\n msg.payload.content = 'Yes';\n return [msg, null]; \n }\n else\n {\n msg.payload.content = 'No';\n return [null, msg]; \n }\n}\n","outputs":"2","noerr":0,"x":335.0000457763672,"y":135.0000343322754,"wires":[["c9c5ff32.8db61"],[]]},{"id":"c9c5ff32.8db61","type":"telegram sender","z":"3068ac13.951064","name":"sender","bot":"6cc03fc7.9b8fb","x":529.0000991821289,"y":108.0000228881836,"wires":[[]]},{"id":"44bd3c3f.c0a614","type":"inject","z":"3068ac13.951064","name":"","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":99.16667175292969,"y":43,"wires":[["a293fe2.aa058"]]},{"id":"e936d5da.8433f8","type":"telegram receiver","z":"3068ac13.951064","name":"receiver","bot":"6cc03fc7.9b8fb","saveDataDir":"","x":89.16667175292969,"y":140.33334732055664,"wires":[["d69380f4.8f204"],[]]},{"id":"a293fe2.aa058","type":"function","z":"3068ac13.951064","name":"create keyboard message","func":"// Here you must adapt the chatId.\nvar chatId = 123;\n\ncontext.global.keyboard = { pending : true };\n\nvar opts = {\n reply_to_message_id: 0,\n reply_markup: JSON.stringify({\n keyboard: [\n ['Yes'],\n ['No']],\n 'resize_keyboard' : true, \n 'one_time_keyboard' : true\n })\n};\n\nvar payload = {\n chatId : chatId,\n type : 'message',\n content : 'Really?',\n options : opts,\n};\n\n\nmsg.payload = payload;\nreturn [ msg ];","outputs":1,"noerr":0,"x":304.16668701171875,"y":44,"wires":[["c9c5ff32.8db61"]]},{"id":"6cc03fc7.9b8fb","type":"telegram bot","z":"","botname":"HeinzBot","usernames":"Windhose","chatids":"","baseapiurl":"","updatemode":"polling","pollinterval":"300","usesocks":false,"sockshost":"","socksport":"6667","socksusername":"anonymous","sockspassword":"","bothost":"","localbotport":"8443","publicbotport":"8443","privatekey":"","certificate":"","useselfsignedcertificate":false,"verboselogging":false}]

View File

@@ -0,0 +1 @@
[{"id":"409e1419.30961c","type":"telegram receiver","z":"3068ac13.951064","name":"","bot":"6cc03fc7.9b8fb","saveDataDir":"c:\\Temp","x":119,"y":132,"wires":[["fdc09042.ec252"],[]]},{"id":"43b875cb.e6353c","type":"telegram sender","z":"3068ac13.951064","name":"","bot":"6cc03fc7.9b8fb","x":470,"y":43,"wires":[[]]},{"id":"f4383c1b.82d6f","type":"telegram command","z":"3068ac13.951064","name":"","command":"/send","bot":"6cc03fc7.9b8fb","strict":false,"x":79.5,"y":50,"wires":[["a93a639a.b8a88"],[]]},{"id":"fdc09042.ec252","type":"debug","z":"3068ac13.951064","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","x":322,"y":126,"wires":[]},{"id":"a93a639a.b8a88","type":"function","z":"3068ac13.951064","name":"create media group","func":"// sendMediaGroup example: send between 2 and 10 media.\n// Note that type can also be video.\n// and the caption property is optional.\n// see https://core.telegram.org/bots/api#inputmediaphoto\n// see https://core.telegram.org/bots/api#inputmediavideo\n\nmsg.payload.type = \"mediaGroup\";\nmsg.payload.content = [\n {\n type : \"photo\",\n media : \"c:\\\\Temp\\\\1.jpg\",\n caption : \"Photo 1\"\n },\n {\n type : \"photo\",\n media : \"c:\\\\Temp\\\\2.jpg\",\n caption : \"Photo 2\"\n }\n];\n\nreturn msg;","outputs":1,"noerr":0,"x":254,"y":43,"wires":[["43b875cb.e6353c"]]},{"id":"6cc03fc7.9b8fb","type":"telegram bot","z":"","botname":"HeinzBot","usernames":"Windhose","chatids":"","baseapiurl":"","updatemode":"polling","pollinterval":"300","usesocks":false,"sockshost":"","socksport":"6667","socksusername":"anonymous","sockspassword":"","bothost":"","localbotport":"8443","publicbotport":"8443","privatekey":"","certificate":"","useselfsignedcertificate":false,"verboselogging":false}]

View File

@@ -0,0 +1 @@
[{"id":"ff78bc5a.00874","type":"telegram bot","z":"70c3f45a.8f3c0c","botname":"HeinzBot","usernames":"","chatids":""},{"id":"8369d2d4.722d7","type":"telegram sender","z":"70c3f45a.8f3c0c","name":"","bot":"ff78bc5a.00874","x":526.5148315429688,"y":708.5407104492188,"wires":[[]]},{"id":"49cf240b.2ca1ac","type":"function","z":"70c3f45a.8f3c0c","name":"send markdown","func":"var message = 'You can also send *markdown* formatted messages.';\nmsg.payload = {chatId : 138708568, type : 'message', content : message};\n\n// activate markdown\nmsg.payload.options = {disable_web_page_preview : true, parse_mode : \"Markdown\"};\nreturn msg;","outputs":1,"noerr":0,"x":305.51483154296875,"y":706.5407333374023,"wires":[["8369d2d4.722d7"]]},{"id":"df89602b.3cc31","type":"inject","z":"70c3f45a.8f3c0c","name":"Trigger","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":false,"x":104.83332824707031,"y":706.0000839233398,"wires":[["49cf240b.2ca1ac"]]}]

View File

@@ -0,0 +1 @@
[{"id":"ff78bc5a.00874","type":"telegram bot","z":"70c3f45a.8f3c0c","botname":"HeinzBot","usernames":"","chatids":""},{"id":"8369d2d4.722d7","type":"telegram sender","z":"70c3f45a.8f3c0c","name":"","bot":"ff78bc5a.00874","x":526.5148315429688,"y":708.5407104492188,"wires":[[]]},{"id":"49cf240b.2ca1ac","type":"function","z":"70c3f45a.8f3c0c","name":"send picture","func":"msg.payload.content = 'foo.jpeg';\nmsg.payload.type = 'photo';\n\n/* type can be one of the following\nphoto\naudio\nvideo\nsticker\nvoice\ndocument\n*/\n\nreturn msg;","outputs":1,"noerr":0,"x":312.51483154296875,"y":709.5407104492188,"wires":[["8369d2d4.722d7"]]},{"id":"34b94dc0.38f9f2","type":"telegram command","z":"70c3f45a.8f3c0c","name":"/foo","command":"/foo","bot":"ff78bc5a.00874","x":119.510498046875,"y":715.3689575195312,"wires":[["49cf240b.2ca1ac"],[]]}]

View File

@@ -0,0 +1 @@
[{"id":"3b4f84c3.c4b07c","type":"telegram bot","z":"70c3f45a.8f3c0c","botname":"HeinzBot"},{"id":"d94485f4.26bb78","type":"catch","z":"70c3f45a.8f3c0c","name":"","x":123,"y":757,"wires":[["2ae5947d.d51a6c"]]},{"id":"2ae5947d.d51a6c","type":"debug","z":"70c3f45a.8f3c0c","name":"Debug","active":true,"console":"false","complete":"payload","x":559,"y":755,"wires":[]},{"id":"a1dabe3a.5e254","type":"function","z":"70c3f45a.8f3c0c","name":"confirmation message","func":"context.global.keyboard = { pending : true };\n\nvar opts = {\n reply_to_message_id: msg.payload.messageId,\n reply_markup: JSON.stringify({\n keyboard: [\n ['Yes'],\n ['No']],\n 'resize_keyboard' : true, \n 'one_time_keyboard' : true\n })\n};\n\nmsg.payload.content = 'Really?';\nmsg.payload.options = opts;\n\nreturn [ msg ];\n","outputs":"1","noerr":0,"x":354,"y":68,"wires":[["fa470b3b.05b8f8"]]},{"id":"7da02f32.825fd","type":"telegram command","z":"70c3f45a.8f3c0c","name":"/foo","command":"/foo","bot":"3b4f84c3.c4b07c","x":137,"y":121,"wires":[["a1dabe3a.5e254"],["71b35090.8e4cb"]]},{"id":"71b35090.8e4cb","type":"function","z":"70c3f45a.8f3c0c","name":"create response","func":"if(context.global.keyboard.pending)\n{\n context.global.keyboard.pending = false;\n \n if(msg.payload.content === 'Yes')\n {\n msg.payload.content = 'Yes';\n return [msg, null]; \n }\n else\n {\n msg.payload.content = 'No';\n return [null, msg]; \n }\n}\n","outputs":"2","noerr":0,"x":338,"y":127,"wires":[["fa470b3b.05b8f8"],[]]},{"id":"fa470b3b.05b8f8","type":"telegram sender","z":"70c3f45a.8f3c0c","name":"send response","bot":"3b4f84c3.c4b07c","x":578,"y":121,"wires":[]},{"id":"9a4d31ae.65b2d","type":"telegram command","z":"70c3f45a.8f3c0c","name":"/help","command":"/help","bot":"3b4f84c3.c4b07c","x":133,"y":233,"wires":[["871bb4c3.78e448"],[]]},{"id":"871bb4c3.78e448","type":"function","z":"70c3f45a.8f3c0c","name":"create help text","func":"\nvar helpMessage = \"/help - shows help\\r\\n\";\nhelpMessage += \"/foo - opens a dialog\\r\\n\";\nhelpMessage += \"Your chat id is \" + msg.payload.chatId;\n\nhelpMessage += \"\\r\\n\";\nhelpMessage += \"You are welcome: \"+msg.originalMessage.from.username;\nhelpMessage += \"\\r\\n\";\n\n\n\nmsg.payload.content = helpMessage;\nreturn msg;","outputs":1,"noerr":0,"x":334,"y":227,"wires":[["fa470b3b.05b8f8"]]},{"id":"54e15dbb.ab1ea4","type":"telegram receiver","z":"70c3f45a.8f3c0c","name":"location","bot":"3b4f84c3.c4b07c","x":136,"y":319,"wires":[["effec97.f100138"]]},{"id":"effec97.f100138","type":"function","z":"70c3f45a.8f3c0c","name":"create location message","func":"if(msg.payload.type == 'location')\n{\n var lat = msg.payload.content.latitude;\n var lng = msg.payload.content.longitude;\n \n msg.payload.type = 'message';\n msg.payload.content = 'lat=' + lat + ' lon=' + lng;\n return msg;\n}\nelse\n{\n return null;\n}\n","outputs":1,"noerr":0,"x":359,"y":319,"wires":[["fa470b3b.05b8f8"]]},{"id":"6f1941f0.90e6c","type":"inject","z":"70c3f45a.8f3c0c","name":"ping","topic":"","payload":"ping","payloadType":"string","repeat":"","crontab":"","once":false,"x":133,"y":421,"wires":[["c61b4d93.39e4b"]]},{"id":"c61b4d93.39e4b","type":"function","z":"70c3f45a.8f3c0c","name":"send to specific chat","func":"\nmsg.payload = {chatId : 138708568, type : 'message', content : 'ping'}\nreturn msg;","outputs":1,"noerr":0,"x":341,"y":421,"wires":[["fa470b3b.05b8f8"]]}]

View File

@@ -0,0 +1 @@
[{"id":"51481804.ffa4e8","type":"telegram receiver","z":"1f6b5f62.c79df1","name":"","bot":"45ef79a0.ed7688","saveDataDir":"","x":200,"y":60,"wires":[[],["7d693fc7.9db0d"]]},{"id":"7d693fc7.9db0d","type":"function","z":"1f6b5f62.c79df1","name":"create log string","func":"var chatId = msg.payload.chatId;\nvar username = msg.originalMessage.from.username;\nmsg.originalMessage.timestamp = new Date();\nvar message = JSON.stringify(msg.originalMessage);\n\nmsg.topic = username + ' ' + chatId;\nmsg.payload = [msg.topic, message];\nreturn msg;","outputs":1,"noerr":0,"x":420,"y":80,"wires":[["3a8044a2.4c34ac"]]},{"id":"3a8044a2.4c34ac","type":"file","z":"1f6b5f62.c79df1","name":"LogFile","filename":"c:\\unauthorized.txt","appendNewline":true,"createDir":false,"overwriteFile":"false","x":600,"y":80,"wires":[]},{"id":"45ef79a0.ed7688","type":"telegram bot","z":"","botname":"HeinzBot","usernames":"","chatids":"1","baseapiurl":"","pollinterval":""}]

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 69 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 60 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 66 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 90 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 113 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 89 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 49 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 55 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 49 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 70 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 74 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 56 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 49 KiB

View File

@@ -0,0 +1,57 @@
{
"_from": "node-red-contrib-telegrambot@7.1.1",
"_id": "node-red-contrib-telegrambot@7.1.1",
"_inBundle": false,
"_integrity": "sha512-E48VVw4hhqsaX8M6MIROnEN1AmG7iRX4Mhy7tmz2PDHI12kOhPO9/j6/p2zQSZWLQkrcJaGTeBbbWDjaM/5kZw==",
"_location": "/node-red-contrib-telegrambot",
"_phantomChildren": {},
"_requested": {
"type": "version",
"registry": true,
"raw": "node-red-contrib-telegrambot@7.1.1",
"name": "node-red-contrib-telegrambot",
"escapedName": "node-red-contrib-telegrambot",
"rawSpec": "7.1.1",
"saveSpec": null,
"fetchSpec": "7.1.1"
},
"_requiredBy": [
"#USER",
"/"
],
"_resolved": "https://registry.npmjs.org/node-red-contrib-telegrambot/-/node-red-contrib-telegrambot-7.1.1.tgz",
"_shasum": "0a02718d7c6e9e85b97d017aed54309fbf3e4a60",
"_spec": "node-red-contrib-telegrambot@7.1.1",
"_where": "/data",
"author": {
"name": "Karl-Heinz Wind"
},
"bugs": {
"url": "https://github.com/windkh/node-red-contrib-telegrambot/issues"
},
"bundleDependencies": false,
"dependencies": {
"node-telegram-bot-api": "^0.40.0",
"socks5-https-client": "1.2.1"
},
"deprecated": false,
"description": "Telegram bot nodes.",
"homepage": "https://github.com/windkh/node-red-contrib-telegrambot#readme",
"keywords": [
"node-red",
"telegram",
"bot"
],
"license": "MIT",
"name": "node-red-contrib-telegrambot",
"node-red": {
"nodes": {
"telegrambot": "telegrambot/99-telegrambot.js"
}
},
"repository": {
"type": "git",
"url": "git+https://github.com/windkh/node-red-contrib-telegrambot.git"
},
"version": "7.1.1"
}

View File

@@ -0,0 +1,550 @@
<!-- Created by Karl-Heinz Wind -->
<!-- ------------------------------------------------------------------------------------------ -->
<script type="text/javascript">
RED.nodes.registerType('telegram bot', {
category: 'config',
defaults: {
botname: { value: "", required: true },
usernames: { value: "", required: false },
chatids: { value: "", required: false },
baseapiurl: { value: "", required: false },
updatemode: { value: "polling", required: true },
// only for polling mode
pollinterval: { value: 300, required: false, validate:function(v) { return ((v === "") || (RED.validators.number(v) && (v >= 0) && (v <= 2147483))) }},
// only for socks5 proxy support
usesocks: { value: false, required: false },
sockshost: { value: "", required: false },
socksport: { value: 6667, required: false, validate:function(v) { return ((v === "") || (RED.validators.number(v) && (v >= 0) && (v <= 2147483))) }},
socksusername: { value: "anonymous", required: false },
sockspassword: { value: "", required: false },
// only for webhook mode
bothost: { value: "", required: false },
localbotport: { value: 8443, required: false, validate:function(v) { return ((v === "") || (RED.validators.number(v) && (v >= 0) && (v <= 2147483))) }},
publicbotport: { value: 8443, required: false, validate:function(v) { return ((v === "") || (RED.validators.number(v) && (v >= 0) && (v <= 2147483))) }},
// only for webhook and certificate
privatekey: { value: "", required: false },
certificate: { value: "", required: false },
useselfsignedcertificate: { value: false, required: false },
sslterminated: { value: false, required: false },
verboselogging: { value: false, required: false }
},
credentials: {
token: { type: "text" }
},
label: function () {
return this.botname;
},
oneditprepare: function() {
// polling or webhook
var updateOptions = function() {
var mode = $("#node-config-input-updatemode").val();
if (mode == "webhook") {
$("#webhook").show();
$("#polling").hide();
} else if (mode == "polling"){
$("#webhook").hide();
$("#polling").show();
} else {
// option not supported
}
};
updateOptions();
$("#node-config-input-updatemode").change(updateOptions);
// sslTerminated on / off
var sslTerminated = function() {
var mode = $('#node-config-input-sslterminated').prop('checked');
if (mode === false) {
$('#node-config-input-privatekey').parent().show();
$('#node-config-input-certificate').parent().show();
} else {
$('#node-config-input-privatekey').parent().hide();
$('#node-config-input-certificate').parent().hide();
}
};
sslTerminated();
$('#node-config-input-sslterminated').change(sslTerminated);
// socks5 on / off
var useSocks5 = function() {
var mode = $("#node-config-input-usesocks").prop('checked');
if (mode === false) {
$("#socks").hide();
} else {
$("#socks").show();
}
};
useSocks5();
$("#node-config-input-usesocks").change(useSocks5);
}
});
</script>
<script type="text/x-red" data-template-name="telegram bot">
<div class="form-row" style="min-width: 700px">
<div class="form-row">
<label for="node-config-input-botname"><i class="fa fa-telegram"></i> Bot-Name</label>
<input type="text" id="node-config-input-botname" placeholder="(Name of bot to connect to)">
</div>
<div class="form-row">
<label for="node-config-input-token"><i class="fa fa-key"></i> Token</label>
<input type="text" id="node-config-input-token" placeholder="(Enter the bot token from botfather here)">
</div>
<hr align="middle"/>
<div class="form-row">
<label for="node-config-input-usernames"><i class="fa fa-user"></i> Users</label>
<input type="text" id="node-config-input-usernames" placeholder="(Optional list of authorized user names e.g.: hugo,sepp,egon)">
</div>
<div class="form-row">
<label for="node-config-input-chatids"><i class="fa fa-comment"></i> ChatIds</label>
<input type="text" id="node-config-input-chatids" placeholder="(Optional list of authorized chat-ids e.g.: -1234567,2345678,-3456789)">
</div>
<div class="form-row">
<label for="node-config-input-baseapiurl"><i class="fa fa-server"></i> Server URL</label>
<input type="text" id="node-config-input-baseapiurl" placeholder="(Optional URL for proxying and testing e.g.: https://api.telegram.org)">
</div>
<div class="form-row">
<label for="node-config-input-updatemode"><i class="fa fa-link"></i> Update Mode</label>
<select id="node-config-input-updatemode">
<option value="polling">Polling</option>
<option value="webhook">Webhook</option>
</select>
</div>
<hr align="middle"/>
<div class="form-row hidden" id="polling" style="background: #fbfbfb">
<label style="width: auto"><i class="fa fa-cogs"></i> Polling Options:</label>
<div class="form-row" style="margin-left: 20px">
<div class="form-row">
<label for="node-config-input-pollinterval"><i class="fa fa-clock-o"></i> Poll Interval</label>
<input type="text" id="node-config-input-pollinterval" placeholder="(Optional poll interval in milliseconds. The default is 300.)">
</div>
</div>
<div class="form-tips" style="width: auto"><b>Tip:</b> Polling mode is very robust and easy to set up. Nevertheless it creates more traffic on the network over time.</div>
</div>
<div class="form-row hidden" id="webhook" style="background: #fbfbfb">
<label style="width: auto"><i class="fa fa-cogs"></i> Webhook Options:</label>
<div class="form-row" style="margin-left: 20px">
<div class="form-row">
<label for="node-config-input-bothost"><i class="fa fa-desktop"></i> Bot Host</label>
<input type="text" id="node-config-input-bothost" placeholder="(Optional public IP or hostname of your bot when using webhook. e.g.: mybot.domain.com)">
</div>
<div class="form-row">
<label for="node-config-input-publicbotport"><i class="fa fa-random"></i> Public Bot Port</label>
<input type="text" id="node-config-input-publicbotport" placeholder="(Optional public port for your bot when using webhook. The default is 8443.)">
</div>
<div class="form-row">
<label for="node-config-input-localbotport"><i class="fa fa-random"></i> Local Bot Port</label>
<input type="text" id="node-config-input-localbotport" placeholder="(Optional local port for your bot when using webhook. The default is 8443.)">
</div>
<div class="form-row">
<label for="node-config-input-privatekey"><i class="fa fa-id-card"></i> Private Key</label>
<input type="text" id="node-config-input-privatekey" placeholder="(Optional local path to your private key file. e.g.: C:\temp\\key.pem)">
</div>
<div class="form-row">
<label for="node-config-input-certificate"><i class="fa fa-id-card-o"></i> Certificate</label>
<input type="text" id="node-config-input-certificate" placeholder="(Optional local path to your certificate file. e.g.: C:\temp\\crt.pem)">
</div>
<div class="form-row">
<label for="node-config-input-useselfsignedcertificate"><i class="fa fa-pencil"></i> Certificate is self-signed</label>
<input type="checkbox" id="node-config-input-useselfsignedcertificate" style="display: inline-block; width: auto; vertical-align: top;">
</div>
<div class="form-row">
<label for="node-config-input-sslterminated"><i class="fa fa-pencil"></i> SSL terminated by reverse proxy</label>
<input type="checkbox" id="node-config-input-sslterminated" style="display: inline-block; width: auto; vertical-align: top;">
</div>
<div class="form-tips" style="width: auto"><b>Tip:</b> Webhook mode requires a HTTPS certificate. The certificate can also be a self-signed (=custom) one. If any of the host, key, certificate properties is left blank the bot will default to polling mode. If SSL termination is already handled by reverse proxy, key and certificate is not required.</div>
</div>
</div>
<hr align="middle"/>
<div class="form-row">
<label for="node-config-input-usesocks"><i class="fa fa-lock"></i> Use SOCKS5</label>
<input type="checkbox" id="node-config-input-usesocks" style="display: inline-block; width: auto; vertical-align: top;">
</div>
<div class="form-row hidden" id="socks" style="background: #fbfbfb">
<label style="width: auto"><i class="fa fa-cogs"></i> SOCKS5 Options:</label>
<div class="form-row" style="background: #fff; margin-left: 20px">
<div class="form-row">
<label for="node-config-input-sockshost"><i class="fa fa-desktop"></i> Host</label>
<input type="text" id="node-config-input-sockshost" placeholder="(Optional IP or hostname of the socks proxy when using polling mode.)">
</div>
<div class="form-row">
<label for="node-config-input-socksport"><i class="fa fa-random"></i> Port</label>
<input type="text" id="node-config-input-socksport" placeholder="(Optional port of the socks proxy when using polling mode.)">
</div>
<div class="form-row">
<label for="node-config-input-socksusername"><i class="fa fa-user"></i> Username</label>
<input type="text" id="node-config-input-socksusername" placeholder="(Optional username of the socks proxy when using polling mode.)">
</div>
<div class="form-row">
<label for="node-config-input-sockspassword"><i class="fa fa-key"></i> Password</label>
<input type="text" id="node-config-input-sockspassword" placeholder="(Optional password of the socks proxy when using polling mode.)">
</div>
</div>
<div class="form-tips" style="width: auto"><b>Tip:</b> SOCKS5 support is optional can can only be used with a valid proxy server, port, username and password.</div>
</div>
<hr align="middle"/>
<div class="form-row">
<label for="node-config-input-verboselogging"><i class="fa fa-search"></i> Verbose Logging</label>
<input type="checkbox" id="node-config-input-verboselogging" style="display: inline-block; width: auto; vertical-align: top;">
</div>
<div class="form-tips" style="width: auto"><b>Tip:</b> When verbose logging is turned on additional log messages will be printed to the node-red console.</div>
<hr align="middle"/>
</div>
</script>
<script type="text/x-red" data-help-name="telegram bot">
<p>A configuration node that holds the token of the telegram bot.</p>
<h3>Details</h3>
<p>It communicates with the telegram server. Do not create several configurations nodes with the same token!</p>
<p>The usernames and chat ids properties can be used to limit authorization to the bot. Enter values in comma separated format e.g. a,b,c</p>
<p>Usernames and chat ids are optional. Leave field blank if you do not want to use this feature.</p>
<p>The API Base URL can be changed for testing or when using a proxy.</p>
<p>You can enable verbose logging to get more details when debugging, but keep in mind that whis could fill your log file very rapidly.</p>
<p></p>
<h3>Operation Modes: Polling vs Webhook</h3>
<p>By default the bot polls the telegram api server every 300ms. But you can also create a webhook so that the telegram server sends updates via HTTPS POST directly to your host machine.</p>
<p>You can enable the webhook by providing the required data:</p>
<p>- private key</p>
<p>- public key</p>
<p>- the publicly reachable IP or hostname of your bot</p>
<p>- the public port (e.g.: 8443, 443, ...)</p>
<p>- the local port (e.g.: 8443. This value is only different to the public port when you are behind a router that maps ports from public to private ones) </p>
<p></p>
<h3>References</h3>
<p>See also </p>
<p>https://core.telegram.org/bots/webhooks</p>
<p>https://stackoverflow.com/questions/42713926/what-is-easy-way-to-create-and-use-a-self-signed-certification-for-a-telegram-we</p>
<p>One common pitfall when creating certificates that don't work is that the value CN you provided to openssl must match the bots domain name: see "bot host" above. </p>
</script>
<!-- ------------------------------------------------------------------------------------------ -->
<script type="text/javascript">
RED.nodes.registerType('telegram receiver', {
category: 'telegram',
color: '#3BABDD',
defaults: {
name: { value: "" },
bot: { value:"", type: "telegram bot", required: true },
saveDataDir: { value: "" }
},
inputs: 0,
outputs: 2,
icon: "telegram.png",
paletteLabel: "receiver",
label: function () {
return this.name || "Telegram receiver";
},
labelStyle: function() {
return this.name?"node_label_italic":"";
}
});
</script>
<script type="text/x-red" data-template-name="telegram receiver">
<div class="form-row">
<label for="node-input-bot"><i class="fa fa-telegram"></i> Bot</label>
<input type="text" id="node-input-bot" placeholder="Bot">
</div>
<div class="form-row">
<label for="node-input-saveDataDir"><i class="fa fa-hdd-o"></i> Download Directory</label>
<input type="text" id="node-input-saveDataDir" placeholder="Download directory">
</div>
<div class="form-row">
<label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
<input type="text" id="node-input-name" placeholder="Name">
</div>
</script>
<script type="text/x-red" data-help-name="telegram receiver">
<p>A telegram node that triggers the output when some message is received from the chat.</p>
<p>The node receives all messages polled from/sent by the telegram server.</p>
<h3>Outputs</h3>
<p>1. Standard Ouput: Message is sent to output 1 if it is from an authorized user.</p>
<p>2. Unauthorized Output: Message is sent to output 2 if it is from a non-authorized user.</p>
<h3>Details</h3>
<p><code>msg.payload</code> typically contains the parsed data as follows:</p>
<ul>
<li><code>content</code> the message contents</li>
<li><code>type</code> the type of message contents</li>
<li><code>messageId</code> the messageId number</li>
<li><code>chatId</code> the chatId number</li>
</ul>
<p>Other properties may be present depending on the type of message.</p>
<code>msg.originalMessage</code> contains the raw data object from the underlying library,
and contains many useful properties.</p>
</script>
<!-- ------------------------------------------------------------------------------------------ -->
<script type="text/javascript">
RED.nodes.registerType('telegram command', {
category: 'telegram',
color: '#3BABDD',
defaults: {
name: { value: "" },
command: { value: ""},
bot: { value: "", type: "telegram bot", required: true },
strict : { value: false }
},
inputs: 0,
outputs: 2,
icon: "telegramc.png",
paletteLabel: "command",
label: function () {
return this.name || this.command || "Telegram command";
},
labelStyle: function() {
return this.name?"node_label_italic":"";
}
});
</script>
<script type="text/x-red" data-template-name="telegram command">
<div class="form-row">
<label for="node-input-command"><i class="fa fa-envelope"></i> Command</label>
<input type="text" id="node-input-command" placeholder="Command">
</div>
<div class="form-row">
<label for="node-input-bot"><i class="fa fa-telegram"></i> Bot</label>
<input type="text" id="node-input-bot" placeholder="Bot">
</div>
<div class="form-row">
<label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
<input type="text" id="node-input-name" placeholder="Name">
</div>
<div class="form-row">
<label for="node-input-strict"><i class="fa fa-tag"></i> Strict in group chats</label>
<input type="checkbox" id="node-input-strict" style="display: inline-block; width: auto; vertical-align: top;">
</div>
</script>
<script type="text/x-red" data-help-name="telegram command">
<p>A telegram node that triggers the output when a specified command is received from the chat.</p>
<h3>Outputs</h3>
<p>1. Standard Ouput: Message is sent to output 1 if it is from an authorized user and it contains the command at the beginning of the message.</p>
<p>2. Error Ouput: Message is sent to output 2 if it is from an authorized user but does not contain the specified command.</p>
</script>
<!-- ------------------------------------------------------------------------------------------ -->
<script type="text/javascript">
RED.nodes.registerType('telegram event', {
category: 'telegram',
color: '#3BABDD',
defaults: {
name: { value: "" },
bot: { value: "", type: "telegram bot", required: true },
event: { value: "callback_query", required: true },
autoanswer: { value: false, required: false }
},
inputs: 0,
outputs: 1,
icon: "telegram.png",
paletteLabel: "event",
label: function () {
return this.name || this.event;
},
labelStyle: function() {
return this.name?"node_label_italic":"";
}
});
</script>
<script type="text/x-red" data-template-name="telegram event">
<div class="form-row">
<label for="node-input-bot"><i class="fa fa-telegram"></i> Bot</label>
<input type="text" id="node-input-bot" placeholder="Bot">
</div>
<div class="form-row">
<label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
<input type="text" id="node-input-name" placeholder="Name">
</div>
<div class="form-row">
<label for="node-input-event"><i class="fa fa-mail-reply-all"></i> Event</label>
<div style="display: inline-block; position: relative; width: 70%; height: 19.1333px;">
<div style="position: absolute; left: 0; right: 0;">
<select id="node-input-event" style="width:100%">
<option value="callback_query">Callback Query</option>
<option value="inline_query">Inline Query</option>
<option value="edited_message">Edited Message</option>
<option value="edited_message_text">Edited Message Text</option>
<option value="edited_message_caption">Edited Message Caption</option>
<option value="channel_post">Channel Post</option>
<option value="edited_channel_post">Edited Channel Post</option>
<option value="edited_channel_post_text">Edited Channel Post Text</option>
<option value="edited_channel_post_caption">Edited Channel Post Caption</option>
</select>
</div>
</div>
</div>
<div class="form-row">
<label for="node-input-autoanswer"><i class="fa fa-retweet"></i> Auto-Answer</label>
<input type="checkbox" id="node-input-autoanswer" style="display:inline-block; width:auto; vertical-align:top;">
</div>
</script>
<script type="text/x-red" data-help-name="telegram event">
<p>A telegram node that triggers the output when a event is received from a chat.</p>
<h3>Outputs</h3>
<p>1. Standard Output: The output is triggered when the configured event was received.</p>
<h3>Details</h3>
<p>The event type can be selected.</p>
<p><code>msg.payload</code> typically contains the parsed data as follows:</p>
<ul>
<li><code>chatId</code>Unique identifier for this chat.</li>
<li><code>messageId</code>Message identifier.</li>
<li><code>type</code>event type</li>
<li><code>date</code>timestamp</li>
<li><code>content</code>the actual UTF-8 text of the message</li>
</ul>
<p>Other properties may be present depending on the type of message.</p>
<code>msg.originalMessage</code> contains the raw data object from the underlying library,
and contains many useful properties.</p>
<p>The autoanswer checkbox can be set for callback_query.</p>
<p>Then you won't have to send an explicit answer to the bot on your own.</p>
</script>
<!-- ------------------------------------------------------------------------------------------ -->
<script type="text/javascript">
RED.nodes.registerType('telegram sender', {
category: 'telegram',
color: '#3BABDD',
defaults: {
name: { value: "" },
bot: { value: "", type: "telegram bot", required: true }
},
inputs: 1,
outputs: 1,
icon: "telegram.png",
align: "right",
paletteLabel: "sender",
label: function () {
return this.name || "Telegram sender";
},
labelStyle: function() {
return this.name?"node_label_italic":"";
}
});
</script>
<script type="text/x-red" data-template-name="telegram sender">
<div class="form-row">
<label for="node-input-bot"><i class="fa fa-telegram"></i> Bot</label>
<input type="text" id="node-input-bot" placeholder="Bot">
</div>
<div class="form-row">
<label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
<input type="text" id="node-input-name" placeholder="Name">
</div>
</script>
<script type="text/x-red" data-help-name="telegram sender">
<p>A telegram node that sends the <code>msg.payload</code> to the chat.</p>
<h3>Inputs</h3>
<p>1. Standard Input: receives a message object containing the chatId. It can be directly connected to the receiver node's output 1.</p>
<h3>Details</h3>
<p>The <code>msg.payload</code> must be an object that contains a complete set of telegram message properties,
at a minimum these should contain:
<ul>
<li><code>content</code> the message contents</li>
<li><code>type</code> the type of message contents</li>
<li><code>chatId</code> the chatId number</li>
</ul>
<p>The output message contains an error property if an exception occured.</p>
</script>
<!-- ------------------------------------------------------------------------------------------ -->
<!-- ------------------------------------------------------------------------------------------ -->
<script type="text/javascript">
RED.nodes.registerType('telegram reply', {
category: 'telegram',
color: '#3BABDD',
defaults: {
name: { value: "" },
bot: { value: "", type: "telegram bot", required: true }
},
inputs: 1,
outputs: 1,
icon: "telegram.png",
align: "right",
paletteLabel: "reply",
label: function () {
return this.name || "Telegram reply";
},
labelStyle: function() {
return this.name?"node_label_italic":"";
}
});
</script>
<script type="text/x-red" data-template-name="telegram reply">
<div class="form-row">
<label for="node-input-bot"><i class="fa fa-telegram"></i> Bot</label>
<input type="text" id="node-input-bot" placeholder="Bot">
</div>
<div class="form-row">
<label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
<input type="text" id="node-input-name" placeholder="Name">
</div>
</script>
<script type="text/x-red" data-help-name="telegram reply">
<p>A telegram node that is triggered when someone answered to a specified message.</p>
<h3>Inputs</h3>
<p>1. Standard Input: calls the onReplyToMessage of the bot.</p>
<h3>Outputs</h3>
<p>1. Standard Output: contains the result from the onReplyToMessage call.</p>
<h3>Details</h3>
<p>This can be useful, when the bot for example sent a message and you want to take some action</p>
<p>when someone responded to this specified message.</p>
<p>Responding to messages is done by clicking on the message in your client and choose "answer" from the popup.</p>
<p>The <code>msg.payload</code> should be an object that contains:</p>
<ul><li><code>chatId</code> destination chatId.</li>
<li><code>sentMessageId</code> the id of the previously sent message in the chat.</li>
<li><code>content</code> the message content.</li></ul>
</script>
<!-- ------------------------------------------------------------------------------------------ -->

View File

@@ -0,0 +1,1388 @@
/**
* Created by Karl-Heinz Wind
**/
// Temporary fix for 0.30.0 api
process.env["NTBA_FIX_319"] = 1;
module.exports = function (RED) {
"use strict";
var telegramBot = require('node-telegram-bot-api');
const Agent = require('socks5-https-client/lib/Agent')
// --------------------------------------------------------------------------------------------
// The configuration node
// holds the token
// and establishes the connection to the telegram bot
// you can either select between polling mode and webhook mode.
function TelegramBotNode(n) {
RED.nodes.createNode(this, n);
var self = this;
// contains all the nodes that make use of the bot connection maintained by this configuration node.
this.users = [];
this.status = "disconnected";
// Reading configuration properties...
this.botname = n.botname;
this.verbose = n.verboselogging;
this.usernames = [];
if (n.usernames) {
this.usernames = n.usernames.split(',');
}
this.chatids = [];
if (n.chatids) {
this.chatids = n.chatids.split(',').map(function (item) {
return parseInt(item, 10);
});
}
this.baseApiUrl = n.baseapiurl;
this.updateMode = n.updatemode;
if(!this.updateMode){
this.updateMode = "polling";
}
// 1. optional when polling mode is used
this.pollInterval = parseInt(n.pollinterval);
if (isNaN(this.pollInterval)) {
this.pollInterval = 300;
}
// 2. optional when webhook is used.
this.botHost = n.bothost;
this.publicBotPort = parseInt(n.publicbotport);
if (isNaN(this.publicBotPort)) {
this.publicBotPort = 8443;
}
this.localBotPort = parseInt(n.localbotport);
if (isNaN(this.localBotPort)) {
this.localBotPort = this.publicBotPort;
}
// 3. optional when webhook and self signed certificate is used
this.privateKey = n.privatekey;
this.certificate = n.certificate;
this.useSelfSignedCertificate = n.useselfsignedcertificate;
this.sslTerminated = n.sslterminated;
// 4. optional when request via SOCKS5 is used.
this.useSocks = n.usesocks;
if(this.useSocks){
this.socksRequest = {
agentClass: Agent,
agentOptions: {
socksHost: n.sockshost,
socksPort: n.socksport,
socksUsername: n.socksusername,
socksPassword: n.sockspassword,
},
};
}
this.useWebhook = false;
if (this.updateMode == "webhook") {
if (this.botHost && (this.sslTerminated || (this.privateKey && this.certificate))) {
this.useWebhook = true;
} else{
self.error("Configuration data for webhook is not complete. Defaulting to polling mode.");
}
}
// Activates the bot or returns the already activated bot.
this.getTelegramBot = function () {
if (!this.telegramBot) {
if (this.credentials) {
this.token = this.credentials.token;
if (this.token) {
this.token = this.token.trim();
if (!this.telegramBot) {
if (this.useWebhook){
var webHook =
{
autoOpen: true,
port : this.localBotPort,
};
if (!this.sslTerminated) {
webHook.key = this.privateKey;
webHook.cert = this.certificate;
}
var options =
{
webHook: webHook,
baseApiUrl: this.baseApiUrl,
request: this.socksRequest,
};
this.telegramBot = new telegramBot(this.token, options);
this.telegramBot.on('webhook_error', function (error) {
self.setUsersStatus({ fill: "red", shape: "ring", text: "webhook error" })
if(self.verbose) {
self.warn("Webhook error: " + error.message);
}
// TODO: check if we should abort in future when this happens
// self.abortBot(error.message, function () {
// self.warn("Bot stopped: Webhook error.");
// });
});
var botUrl = "https://" + this.botHost + ":" + this.publicBotPort + "/" + this.token;
var setWebHookOptions;
if (!this.sslTerminated && this.useSelfSignedCertificate){
setWebHookOptions = {
certificate: options.webHook.cert,
};
}
this.telegramBot.setWebHook(botUrl, setWebHookOptions).then(function (success) {
if(self.verbose) {
self.telegramBot.getWebHookInfo().then(function (result) {
self.log("Webhook enabled: " + JSON.stringify(result));
});
}
if(success) {
self.status = "connected";
}
else {
self.abortBot("Failed to set webhook " + botUrl, function () {
self.warn("Bot stopped: Webhook not set.");
});
}
});
}
else {
var polling = {
autoStart: true,
interval: this.pollInterval
}
var options = {
polling: polling,
baseApiUrl: this.baseApiUrl,
request: this.socksRequest,
};
this.telegramBot = new telegramBot(this.token, options);
self.status = "connected";
this.telegramBot.on('polling_error', function (error) {
self.setUsersStatus({ fill: "red", shape: "ring", text: "polling error" })
if(self.verbose) {
self.warn(error.message);
var stopPolling = false;
var hint;
if (error.message === "ETELEGRAM: 401 Unauthorized") {
hint = "Please check if the bot token is valid: " + self.credentials.token;
stopPolling = true;
}
else if (error.message.startsWith("EFATAL: Error: connect ETIMEDOUT")) {
hint = "Timeout connecting to server. Trying again.";
}
else if (error.message.startsWith("EFATAL: Error: read ECONNRESET")) {
hint = "Network connection may be down. Trying again.";
}
else if (error.message.startsWith("EFATAL: Error: getaddrinfo EAI_AGAIN")) {
hint = "Network connection may be down. Trying again.";
}
else if (error.message.startsWith("EFATAL: Error: getaddrinfo ENOTFOUND")) {
hint = "Network connection may be down. Trying again.";
}
else if (error.message.startsWith("EFATAL: Error: SOCKS connection failed. Connection refused.")) {
hint = "Username or password may be be wrong. Aborting.";
stopPolling = true;
}
else if (error.message.startsWith("EFATAL: Error: connect ETIMEDOUT")) {
hint = "Server did not respond. Maybe proxy blocked polling. Trying again.";
}
else {
// unknown error occured... we simply ignore it.
hint = "Unknown error. Trying again.";
}
if (stopPolling) {
self.abortBot(error.message, function () {
self.warn("Bot stopped: " + hint);
});
}
else {
// here we simply ignore the bug and continue polling.
// The following line is removed as this would create endless log files
if(self.verbose){
self.warn(hint);
}
}
}
});
}
this.telegramBot.on('error', function (error) {
self.warn("Bot error: " + error.message);
self.abortBot(error.message, function () {
self.warn("Bot stopped: Fatal Error.");
});
});
}
}
}
}
return this.telegramBot;
}
this.on('close', function (done) {
self.abortBot("closing", done);
});
this.abortBot = function (hint, done) {
if (self.telegramBot !== null) {
if (self.telegramBot._polling){
self.telegramBot.stopPolling()
.then(function () {
self.telegramBot = null;
self.status = "disconnected";
self.setUsersStatus({ fill: "red", shape: "ring", text: "bot stopped. " + hint })
done();
});
}
if (self.telegramBot._webHook){
self.telegramBot.deleteWebHook();
self.telegramBot.closeWebHook()
.then(function () {
self.telegramBot = null;
self.status = "disconnected";
self.setUsersStatus({ fill: "red", shape: "ring", text: "bot stopped. " + hint })
done();
});
}
}
else {
self.status = "disconnected";
self.setUsersStatus({ fill: "red", shape: "ring", text: "bot stopped. " + hint })
done();
}
}
this.isAuthorizedUser = function (user) {
var isAuthorized = false;
if (self.usernames.length > 0) {
if (self.usernames.indexOf(user) >= 0) {
isAuthorized = true;
}
}
return isAuthorized;
}
this.isAuthorizedChat = function (chatid) {
var isAuthorized = false;
var length = self.chatids.length;
if (length > 0) {
for (var i = 0; i < length; i++) {
var id = self.chatids[i];
if (id === chatid) {
isAuthorized = true;
break;
}
}
}
return isAuthorized;
}
this.isAuthorized = function (chatid, user) {
var isAuthorizedUser = self.isAuthorizedUser(user);
var isAuthorizedChatId = self.isAuthorizedChat(chatid);
var isAuthorized = false;
if (isAuthorizedUser || isAuthorizedChatId) {
isAuthorized = true;
} else {
if (self.chatids.length === 0 && self.usernames.length === 0) {
isAuthorized = true;
}
}
return isAuthorized;
}
this.register = function (node) {
var id = node.id;
if (self.users.indexOf(id) === -1) {
self.users.push(id);
}
else {
if(self.verbose) {
// This warnin was removed as it caused confusion: see https://github.com/windkh/node-red-contrib-telegrambot/issues/87
// self.warn("Node " + id + " registered twice at the configuration node: ignoring.");
}
}
}
this.setUsersStatus = function (status) {
self.users.forEach(function (nodeId) {
var userNode = RED.nodes.getNode(nodeId);
if(userNode) {
userNode.status(status);
}
});
}
}
RED.nodes.registerType("telegram bot", TelegramBotNode, {
credentials: {
token: { type: "text" }
}
});
// adds the caption of the message into the options.
function addCaptionToMessageOptions(msg) {
var options = msg.payload.options;
if (options === undefined) {
options = {};
}
if (msg.payload.caption !== undefined) {
options.caption = msg.payload.caption;
}
msg.payload.options = options;
return msg;
}
function getPhotoIndexWithHighestResolution(photoArray) {
var photoIndex = 0;
var highestResolution = 0;
photoArray.forEach(function (photo, index, array) {
var resolution = photo.width * photo.height;
if (resolution > highestResolution) {
highestResolution = resolution;
photoIndex = index;
}
});
return photoIndex;
}
// creates the message details object from the original message
function getMessageDetails(botMsg) {
// Note that photos and videos can be sent as media group. The bot will receive the contents as single messages.
// Therefore the photo and video messages can contain a mediaGroupId if so....
var messageDetails;
if (botMsg.text) {
messageDetails = { chatId: botMsg.chat.id, messageId: botMsg.message_id, type: 'message', content: botMsg.text };
} else if (botMsg.photo) {
// photos are sent using several resolutions. Therefore photo is an array. We choose the one with the highest resolution in the array.
var index = getPhotoIndexWithHighestResolution(botMsg.photo);
messageDetails = { chatId: botMsg.chat.id, messageId: botMsg.message_id, type: 'photo', content: botMsg.photo[index].file_id, caption: botMsg.caption, date: botMsg.date, blob: true, photos: botMsg.photo, mediaGroupId: botMsg.media_group_id };
} else if (botMsg.audio) {
messageDetails = { chatId: botMsg.chat.id, messageId: botMsg.message_id, type: 'audio', content: botMsg.audio.file_id, caption: botMsg.caption, date: botMsg.date, blob: true };
} else if (botMsg.document) {
messageDetails = { chatId: botMsg.chat.id, messageId: botMsg.message_id, type: 'document', content: botMsg.document.file_id, caption: botMsg.caption, date: botMsg.date, blob: true };
} else if (botMsg.sticker) {
messageDetails = { chatId: botMsg.chat.id, messageId: botMsg.message_id, type: 'sticker', content: botMsg.sticker.file_id, date: botMsg.date, blob: true };
} else if (botMsg.video) {
messageDetails = { chatId: botMsg.chat.id, messageId: botMsg.message_id, type: 'video', content: botMsg.video.file_id, caption: botMsg.caption, date: botMsg.date, blob: true, mediaGroupId: botMsg.media_group_id };
} else if (botMsg.video_note) {
messageDetails = { chatId: botMsg.chat.id, messageId: botMsg.message_id, type: 'video_note', content: botMsg.video_note.file_id, caption: botMsg.caption, date: botMsg.date, blob: true };
} else if (botMsg.voice) {
messageDetails = { chatId: botMsg.chat.id, messageId: botMsg.message_id, type: 'voice', content: botMsg.voice.file_id, caption: botMsg.caption, date: botMsg.date, blob: true };
} else if (botMsg.location) {
messageDetails = { chatId: botMsg.chat.id, messageId: botMsg.message_id, type: 'location', content: botMsg.location, date: botMsg.date };
} else if (botMsg.venue) {
messageDetails = { chatId: botMsg.chat.id, messageId: botMsg.message_id, type: 'venue', content: botMsg.venue, date: botMsg.date };
} else if (botMsg.contact) {
messageDetails = { chatId: botMsg.chat.id, messageId: botMsg.message_id, type: 'contact', content: botMsg.contact, date: botMsg.date };
} else if (botMsg.new_chat_title) {
messageDetails = { chatId: botMsg.chat.id, messageId: botMsg.message_id, type: 'new_chat_title', content: botMsg.new_chat_title, date: botMsg.date };
} else if (botMsg.new_chat_photo) {
// photos are sent using several resolutions. Therefore photo is an array. We choose the one with the highest resolution in the array.
var index = getPhotoIndexWithHighestResolution(botMsg.new_chat_photo);
messageDetails = { chatId: botMsg.chat.id, messageId: botMsg.message_id, type: 'new_chat_photo', content: botMsg.new_chat_photo[index].file_id, date: botMsg.date, blob: true, photos: botMsg.new_chat_photo };
} else if (botMsg.new_chat_members) {
messageDetails = { chatId: botMsg.chat.id, messageId: botMsg.message_id, type: 'new_chat_members', content: botMsg.new_chat_members, date: botMsg.date, };
} else if (botMsg.left_chat_member) {
messageDetails = { chatId: botMsg.chat.id, messageId: botMsg.message_id, type: 'left_chat_member', content: botMsg.left_chat_member, date: botMsg.date, };
} else if (botMsg.delete_chat_photo) {
messageDetails = { chatId: botMsg.chat.id, messageId: botMsg.message_id, type: 'delete_chat_photo', content: botMsg.delete_chat_photo, date: botMsg.date };
} else if (botMsg.pinned_message) {
messageDetails = { chatId: botMsg.chat.id, messageId: botMsg.message_id, type: 'pinned_message', content: botMsg.pinned_message, date: botMsg.date };
} else if (botMsg.channel_chat_created) {
messageDetails = { chatId: botMsg.chat.id, messageId: botMsg.message_id, type: 'channel_chat_created', content: botMsg.channel_chat_created, date: botMsg.date };
} else if (botMsg.group_chat_created) {
messageDetails = { chatId: botMsg.chat.id, messageId: botMsg.message_id, type: 'group_chat_created', content: botMsg.group_chat_created, chat: botMsg.chat, date: botMsg.date };
} else if (botMsg.supergroup_chat_created) {
messageDetails = { chatId: botMsg.chat.id, messageId: botMsg.message_id, type: 'supergroup_chat_created', content: botMsg.supergroup_chat_created, chat: botMsg.chat, date: botMsg.date };
} else if (botMsg.migrate_from_chat_id) {
messageDetails = { chatId: botMsg.chat.id, messageId: botMsg.message_id, type: 'migrate_from_chat_id', content: botMsg.migrate_from_chat_id, chat: botMsg.chat, date: botMsg.date };
} else if (botMsg.migrate_to_chat_id) {
messageDetails = { chatId: botMsg.chat.id, messageId: botMsg.message_id, type: 'migrate_to_chat_id', content: botMsg.migrate_to_chat_id, chat: botMsg.chat, date: botMsg.date };
} else {
// unknown type --> no output
// TODO:
// 'successful_payment',
// 'invoice',
// 'game',
}
return messageDetails;
}
// --------------------------------------------------------------------------------------------
// The input node receives messages from the chat.
// the message details are stored in the payload
// chatId
// type
// content
// depending on type caption and date is part of the output, too.
// The original message is stored next to payload.
//
// The message ist send to output 1 if the message is from an authorized user
// and to output2 if the message is not from an authorized user.
//
// message : content string
// photo : content file_id of first image in array
// audio : content file_id
// document: content file_id of document
// sticker : content file_id
// video : content file_id
// voice : content file_id
// location: content is object with latitude and longitude
// contact : content is full contact object
function TelegramInNode(config) {
RED.nodes.createNode(this, config);
var node = this;
this.bot = config.bot;
this.config = RED.nodes.getNode(this.bot);
if (this.config) {
this.config.register(node);
node.status({ fill: "red", shape: "ring", text: "not connected" });
node.telegramBot = this.config.getTelegramBot();
if (node.telegramBot) {
node.status({ fill: "green", shape: "ring", text: "connected" });
node.telegramBot.on('message', function (botMsg) {
node.status({ fill: "green", shape: "ring", text: "connected" });
var username = botMsg.from.username;
var chatid = botMsg.chat.id;
var messageDetails = getMessageDetails(botMsg);
if (messageDetails) {
var msg = { payload: messageDetails, originalMessage: botMsg };
if (node.config.isAuthorized(chatid, username)) {
// downloadable "blob" message?
if (messageDetails.blob) {
var fileId = msg.payload.content;
node.telegramBot.getFileLink(fileId).then(function (weblink) {
msg.payload.weblink = weblink;
// download and provide with path
if (config.saveDataDir) {
node.telegramBot.downloadFile(fileId, config.saveDataDir).then(function (path) {
msg.payload.path = path;
node.send([msg, null]);
});
} else {
node.send([msg, null]);
}
});
// vanilla message
} else {
node.send([msg, null]);
}
} else {
if(node.config.verbose){
node.warn("Unauthorized incoming call from " + username);
}
node.send([null, msg]);
}
}
});
} else {
node.warn("bot not initialized");
node.status({ fill: "red", shape: "ring", text: "bot not initialized" });
}
} else {
node.warn("config node failed to initialize.");
node.status({ fill: "red", shape: "ring", text: "config node failed to initialize" });
}
this.on("close", function () {
node.telegramBot.off('message');
node.status({});
});
}
RED.nodes.registerType("telegram receiver", TelegramInNode);
// --------------------------------------------------------------------------------------------
// The input node receives a command from the chat.
// The message details are stored in the payload
// chatId
// type
// content
// depending on type caption and date is part of the output, too.
// The original message is stored next to payload.
//
// message : content string
function TelegramCommandNode(config) {
RED.nodes.createNode(this, config);
var node = this;
var command = config.command;
var strict = config.strict;
this.bot = config.bot;
this.config = RED.nodes.getNode(this.bot);
if (this.config) {
this.config.register(node);
node.status({ fill: "red", shape: "ring", text: "not connected" });
node.telegramBot = this.config.getTelegramBot();
node.botname = this.config.botname;
if (node.telegramBot) {
node.status({ fill: "green", shape: "ring", text: "connected" });
node.telegramBot.on('message', function (botMsg) {
node.status({ fill: "green", shape: "ring", text: "connected" });
var username = botMsg.from.username;
var chatid = botMsg.chat.id;
if (node.config.isAuthorized(chatid, username)) {
var msg;
var messageDetails;
if (botMsg.text) {
var message = botMsg.text;
var tokens = message.split(" ");
var isChatCommand = tokens[0] === command;
var command2 = command + "@" + node.botname;
var isDirectCommand = tokens[0] === command2;
var isGroupChat = chatid < 0;
if (isDirectCommand ||
(isChatCommand && !isGroupChat) ||
(isChatCommand && isGroupChat && !strict)) {
var remainingText;
if(isDirectCommand)
{
remainingText = message.replace(command2, "");
}
else
{
remainingText = message.replace(command, "");
}
messageDetails = { chatId: botMsg.chat.id, messageId: botMsg.message_id, type: 'message', content: remainingText };
msg = { payload: messageDetails, originalMessage: botMsg };
node.send([msg, null]);
} else {
messageDetails = { chatId: botMsg.chat.id, messageId: botMsg.message_id, type: 'message', content: botMsg.text };
msg = { payload: messageDetails, originalMessage: botMsg };
node.send([null, msg]);
}
} else {
// unknown type --> no output
}
} else {
// ignoring unauthorized calls
if(node.config.verbose){
node.warn("Unauthorized incoming call from " + username);
}
}
});
} else {
node.warn("bot not initialized.");
node.status({ fill: "red", shape: "ring", text: "no bot token found in config" });
}
} else {
node.warn("config node failed to initialize.");
node.status({ fill: "red", shape: "ring", text: "config node failed to initialize" });
}
this.on("close", function () {
node.telegramBot.off('message');
node.status({});
});
}
RED.nodes.registerType("telegram command", TelegramCommandNode);
// --------------------------------------------------------------------------------------------
// The input node receives an event from the chat.
// The type of event can be configured:
// - callback_query
// - inline_query
// - edited_message
// - channel_post
// - edited_channel_post
// - edited_message_text
// The message details are stored in the payload
// chatId
// messageId
// type
// content
// depending on type from and date is part of the output, too.
// The original message is stored next to payload.
// callback_query : content string
function TelegramEventNode(config) {
RED.nodes.createNode(this, config);
var node = this;
this.bot = config.bot;
this.event = config.event;
this.autoAnswerCallback = config.autoanswer;
this.config = RED.nodes.getNode(this.bot);
if (this.config) {
this.config.register(node);
node.status({ fill: "red", shape: "ring", text: "not connected" });
node.telegramBot = this.config.getTelegramBot();
node.botname = this.config.botname;
if (node.telegramBot) {
node.status({ fill: "green", shape: "ring", text: "connected" });
node.telegramBot.on(this.event, (botMsg) => {
node.status({ fill: "green", shape: "ring", text: "connected" });
var username;
var chatid;
if (botMsg.chat) { //channel
username = botMsg.chat.username;
chatid = botMsg.chat.id;
} else if (botMsg.from) { //private, group, supergroup
username = botMsg.from.username;
chatid = botMsg.from.id;
} else {
node.error("username or chatid undefined");
}
if (node.config.isAuthorized(chatid, username)) {
var msg;
var messageDetails;
switch (this.event) {
case 'callback_query':
var callbackQueryId = botMsg.id;
messageDetails = {
chatId: chatid,
messageId: botMsg.message.message_id,
type: 'callback_query',
content: botMsg.data,
callbackQueryId: callbackQueryId,
from: botMsg.from
};
if (node.autoAnswer) {
node.telegramBot.answerCallbackQuery(callbackQueryId).then(function (result) {
// Nothing to do here
;
});
}
break;
// /setinline must be set before in botfather see https://core.telegram.org/bots/inline
case 'inline_query':
var inlineQueryId = botMsg.id;
messageDetails = {
chatId: chatid,
type: 'inline_query',
content: botMsg.query,
inlineQueryId: inlineQueryId,
offset: botMsg.offset,
from: botMsg.from,
location: botMsg.location // location is only available when /setinlinegeo is set in botfather
};
// Right now this is not supported as a result is required!
//if (node.autoAnswer) {
// // result = https://core.telegram.org/bots/api#inlinequeryresult
// node.telegramBot.answerInlineQuery(inlineQueryId, results).then(function (result) {
// // Nothing to do here
// ;
// });
//}
break;
case 'edited_message':
messageDetails = {
chatId: chatid,
messageId: botMsg.message_id,
type: "edited_message",
content: botMsg.text,
editDate: botMsg.edit_date,
date: botMsg.date,
from: botMsg.from,
chat: botMsg.chat,
location: botMsg.location // for live location updates
};
break;
// the text of an already sent message.
case 'edited_message_text':
messageDetails = {
chatId: chatid,
type: "edited_message_text",
messageId: botMsg.message_id,
content: botMsg.text,
editDate: botMsg.edit_date,
date: botMsg.date,
chat: botMsg.chat
};
break;
// the caption of a document or an image ...
case 'edited_message_caption':
messageDetails = {
chatId: chatid,
type: "edited_message_caption",
messageId: botMsg.message_id,
content: botMsg.caption,
editDate: botMsg.edit_date,
date: botMsg.date,
chat: botMsg.chat
};
break;
case 'channel_post':
messageDetails = {
chatId: chatid,
messageId: botMsg.message_id,
type: "channel_post",
content: botMsg.text,
date: botMsg.date,
chat: botMsg.chat
};
break;
case 'edited_channel_post':
messageDetails = {
chatId: chatid,
type: "edited_channel_post",
messageId: botMsg.message_id,
content: botMsg.text,
editDate: botMsg.edit_date,
date: botMsg.date,
chat: botMsg.chat
};
break;
case 'edited_channel_post_text':
messageDetails = {
chatId: chatid,
type: "edited_channel_post_text",
messageId: botMsg.message_id,
content: botMsg.text,
editDate: botMsg.edit_date,
date: botMsg.date,
chat: botMsg.chat
};
break;
case 'edited_channel_post_caption':
messageDetails = {
chatId: chatid,
type: "edited_channel_post_caption",
messageId: botMsg.message_id,
content: botMsg.caption,
editDate: botMsg.edit_date,
date: botMsg.date,
chat: botMsg.chat
};
break;
// TODO: implement those
// chosen_inline_result,
// shippingQuery, preCheckoutQuery
default:
}
if (messageDetails != null) {
msg = {
payload: messageDetails,
originalMessage: botMsg
};
node.send(msg);
}
} else {
// ignoring unauthorized calls
if(node.config.verbose){
node.warn("Unauthorized incoming call from " + username);
}
}
});
} else {
node.warn("bot not initialized.");
node.status({ fill: "red", shape: "ring", text: "no bot token found in config" });
}
} else {
node.warn("config node failed to initialize.");
node.status({ fill: "red", shape: "ring", text: "config node failed to initialize" });
}
this.on("close", function () {
node.telegramBot.off(this.event);
node.status({});
});
}
RED.nodes.registerType("telegram event", TelegramEventNode);
// --------------------------------------------------------------------------------------------
// The output node sends to the chat and passes the msg through.
// The payload needs three fields
// chatId : string destination chat
// type : string type of message to send
// content : message content
// The type is a string can be any of the following:
// message content is String
// photo content is String|stream.Stream|Buffer
// audio content is String|stream.Stream|Buffer
// document content is String|stream.Stream|Buffer
// sticker content is String|stream.Stream|Buffer
// video content is String|stream.Stream|Buffer
// voice content is String|stream.Stream|Buffer
// location content is an object that contains latitude and logitude
// contact content is full contact object
// mediaGroup content is array of mediaObject
// action content is one of the following:
// typing, upload_photo, record_video, upload_video, record_audio, upload_audio,
// upload_document, find_location, record_video_note, upload_video_note
function TelegramOutNode(config) {
RED.nodes.createNode(this, config);
var node = this;
this.bot = config.bot;
this.config = RED.nodes.getNode(this.bot);
if (this.config) {
this.config.register(node);
node.status({ fill: "red", shape: "ring", text: "not connected" });
node.telegramBot = this.config.getTelegramBot();
if (node.telegramBot) {
node.status({ fill: "green", shape: "ring", text: "connected" });
} else {
node.warn("bot not initialized.");
node.status({ fill: "red", shape: "ring", text: "bot not initialized" });
}
} else {
node.warn("config node failed to initialize.");
node.status({ fill: "red", shape: "ring", text: "config node failed to initialize" });
}
this.hasContent = function (msg) {
var hasContent;
if (msg.payload.content) {
hasContent = true;
}
else {
node.warn("msg.payload.content is empty");
hasContent = false;
}
return hasContent;
}
this.on('input', function (msg, nodeSend, nodeDone) {
nodeSend = nodeSend || function() { node.send.apply(node,arguments) };
node.status({ fill: "green", shape: "ring", text: "connected" });
if (msg.payload) {
if (msg.payload.chatId) {
if (msg.payload.type) {
var chatId = msg.payload.chatId;
var type = msg.payload.type;
addCaptionToMessageOptions(msg);
switch (type) {
// --------------------------------------------------------------------
case 'message':
if (this.hasContent(msg)) {
// the maximum message size is 4096 so we must split the message into smaller chunks.
var chunkSize = 4000;
var message = msg.payload.content;
var done = false;
do {
var messageToSend;
if (message.length > chunkSize) {
messageToSend = message.substr(0, chunkSize);
message = message.substr(chunkSize);
} else {
messageToSend = message;
done = true;
}
node.telegramBot.sendMessage(chatId, messageToSend, msg.payload.options).then(function (result) {
msg.payload.content = result;
msg.payload.sentMessageId = result.message_id;
nodeSend(msg);
if (nodeDone) {
nodeDone();
}
}).catch(function (err) {
// markdown error? try plain mode
if (
String(err).includes("can't parse entities in message text:") &&
msg.payload.options && msg.payload.options.parse_mode === 'Markdown'
) {
delete msg.payload.options.parse_mode;
node.telegramBot.sendMessage(chatId, messageToSend, msg.payload.options).then(function (result) {
msg.payload.content = result;
msg.payload.sentMessageId = result.message_id;
nodeSend(msg);
if (nodeDone) {
nodeDone();
}
});
return;
}
if (nodeDone) {
nodeDone(err);
} else {
throw err;
}
});
} while (!done)
}
break;
case 'photo':
if (this.hasContent(msg)) {
node.telegramBot.sendPhoto(chatId, msg.payload.content, msg.payload.options).then(function (result) {
msg.payload.content = result;
msg.payload.sentMessageId = result.message_id;
nodeSend(msg);
if (nodeDone) {
nodeDone();
}
});
}
break;
case 'mediaGroup':
if(this.hasContent(msg)) {
if(Array.isArray(msg.payload.content)) {
for (var i = 0; i < msg.payload.content.length; i++) {
var mediaItem = msg.payload.content[i];
if(typeof mediaItem.type !== "string") {
node.warn("msg.payload.content[" + i + "].type is not a string it is " + typeof mediaItem.type);
break;
}
if(mediaItem.media === undefined) {
node.warn("msg.payload.content[" + i + "].media is not defined");
break;
}
}
node.telegramBot.sendMediaGroup(chatId, msg.payload.content, msg.payload.options).then(function (result) {
msg.payload.content = result;
msg.payload.sentMessageId = result.message_id;
nodeSend(msg);
if (nodeDone) {
nodeDone();
}
});
} else {
node.warn("msg.payload.content for mediaGroup is not an array of mediaItem");
}
}
break;
case 'audio':
if (this.hasContent(msg)) {
node.telegramBot.sendAudio(chatId, msg.payload.content, msg.payload.options).then(function (result) {
msg.payload.content = result;
msg.payload.sentMessageId = result.message_id;
nodeSend(msg);
if (nodeDone) {
nodeDone();
}
});
}
break;
case 'document':
if (this.hasContent(msg)) {
node.telegramBot.sendDocument(chatId, msg.payload.content, msg.payload.options).then(function (result) {
msg.payload.content = result;
msg.payload.sentMessageId = result.message_id;
nodeSend(msg);
if (nodeDone) {
nodeDone();
}
});
}
break;
case 'sticker':
if (this.hasContent(msg)) {
node.telegramBot.sendSticker(chatId, msg.payload.content, msg.payload.options).then(function (result) {
msg.payload.content = result;
msg.payload.sentMessageId = result.message_id;
nodeSend(msg);
if (nodeDone) {
nodeDone();
}
});
}
break;
case 'video':
if (this.hasContent(msg)) {
node.telegramBot.sendVideo(chatId, msg.payload.content, msg.payload.options).then(function (result) {
msg.payload.content = result;
msg.payload.sentMessageId = result.message_id;
nodeSend(msg);
if (nodeDone) {
nodeDone();
}
});
}
break;
case 'video_note':
if (this.hasContent(msg)) {
node.telegramBot.sendVideoNote(chatId, msg.payload.content, msg.payload.options).then(function (result) {
msg.payload.content = result;
msg.payload.sentMessageId = result.message_id;
nodeSend(msg);
if (nodeDone) {
nodeDone();
}
});
}
break;
case 'voice':
if (this.hasContent(msg)) {
node.telegramBot.sendVoice(chatId, msg.payload.content, msg.payload.options).then(function (result) {
msg.payload.content = result;
msg.payload.sentMessageId = result.message_id;
nodeSend(msg);
if (nodeDone) {
nodeDone();
}
});
}
break;
case 'location':
if (this.hasContent(msg)) {
node.telegramBot.sendLocation(chatId, msg.payload.content.latitude, msg.payload.content.longitude, msg.payload.options).then(function (result) {
msg.payload.content = result;
msg.payload.sentMessageId = result.message_id;
nodeSend(msg);
if (nodeDone) {
nodeDone();
}
});
}
break;
case 'venue':
if (this.hasContent(msg)) {
node.telegramBot.sendVenue(chatId, msg.payload.content.latitude, msg.payload.content.longitude, msg.payload.content.title, msg.payload.content.address, msg.payload.options).then(function (result) {
msg.payload.content = result;
msg.payload.sentMessageId = result.message_id;
nodeSend(msg);
if (nodeDone) {
nodeDone();
}
});
}
break;
case 'contact':
if (this.hasContent(msg)) {
if (msg.payload.content.last_name) {
if (!msg.payload.options) {
msg.payload.options = {};
}
msg.payload.options.last_name = msg.payload.content.last_name;
}
node.telegramBot.sendContact(chatId, msg.payload.content.phone_number, msg.payload.content.first_name, msg.payload.options).then(function (result) {
msg.payload.content = result;
msg.payload.sentMessageId = result.message_id;
nodeSend(msg);
if (nodeDone) {
nodeDone();
}
});
}
break;
// --------------------------------------------------------------------
case 'editMessageLiveLocation':
if (this.hasContent(msg)) {
node.telegramBot.editMessageLiveLocation(msg.payload.content.latitude, msg.payload.content.longitude, msg.payload.options).then(function (result) {
msg.payload.content = result;
msg.payload.sentMessageId = result.message_id;
nodeSend(msg);
if (nodeDone) {
nodeDone();
}
});
}
break;
case 'stopMessageLiveLocation':
// This message requires the options to be set!
//if (this.hasContent(msg)) {
node.telegramBot.stopMessageLiveLocation(msg.payload.options).then(function (result) {
msg.payload.content = result;
msg.payload.sentMessageId = result.message_id;
nodeSend(msg);
if (nodeDone) {
nodeDone();
}
});
//}
break;
case 'editMessageCaption':
case 'editMessageText':
case 'editMessageReplyMarkup':
if (this.hasContent(msg)) {
node.telegramBot[type](msg.payload.content, msg.payload.options).then(function (result) {
msg.payload.content = result;
msg.payload.sentMessageId = result.message_id;
nodeSend(msg);
if (nodeDone) {
nodeDone();
}
});
}
break;
case 'callback_query':
if (this.hasContent(msg)) {
// The new signature expects one object instead of three arguments.
var callbackQueryId = msg.payload.callbackQueryId;
var options = {
callback_query_id: callbackQueryId,
text: msg.payload.content,
show_alert: msg.payload.options
};
node.telegramBot.answerCallbackQuery(callbackQueryId, options).then(function (result) {
msg.payload.content = result; // true if succeeded
nodeSend(msg);
if (nodeDone) {
nodeDone();
}
});
}
break;
case 'inline_query':
if (this.hasContent(msg)) {
var inlineQueryId = msg.payload.inlineQueryId;
var results = msg.payload.results; // this type requires results to be set: see https://core.telegram.org/bots/api#inlinequeryresult
node.telegramBot.answerInlineQuery(inlineQueryId, results).then(function (result) {
msg.payload.content = result;
nodeSend(msg);
if (nodeDone) {
nodeDone();
}
});
}
break;
case 'action':
if (this.hasContent(msg)) {
node.telegramBot.sendChatAction(chatId, msg.payload.content).then(function (result) {
msg.payload.content = result; // true if succeeded
nodeSend(msg);
if (nodeDone) {
nodeDone();
}
});
}
break;
// --------------------------------------------------------------------
// Some of the following functions require the bot to be administrator of the chat/channel
case 'getChatAdministrators':
case 'getChatMembersCount':
case 'getChat':
case 'leaveChat':
case 'exportChatInviteLink':
case 'unpinChatMessage':
case 'deleteChatPhoto':
node.telegramBot[type](chatId).then(function (result) {
msg.payload.content = result;
nodeSend(msg);
if (nodeDone) {
nodeDone();
}
});
break;
case 'kickChatMember':
case 'unbanChatMember':
case 'restrictChatMember':
case 'promoteChatMember':
case 'getChatMember':
// The userId must be passed in msg.payload.content: note that this is is a number not the username.
// Right now there is no way for resolving the user_id by username in the official API.
if (this.hasContent(msg)) {
node.telegramBot[type](chatId, msg.payload.content, msg.payload.options).then(function (result) {
msg.payload.content = result;
nodeSend(msg);
if (nodeDone) {
nodeDone();
}
});
}
break;
// --------------------------------------------------------------------
case 'setChatTitle':
case 'setChatDescription':
case 'pinChatMessage':
case 'deleteMessage':
if (this.hasContent(msg)) {
node.telegramBot[type](chatId, msg.payload.content).then(function (result) {
msg.payload.content = result;
nodeSend(msg);
if (nodeDone) {
nodeDone();
}
});
}
break;
case 'setChatPhoto':
if (this.hasContent(msg)) {
node.telegramBot[type](chatId, msg.payload.content, msg.payload.options).then(function (result) {
msg.payload.content = result;
nodeSend(msg);
if (nodeDone) {
nodeDone();
}
});
}
break;
// TODO:
// getUserProfilePhotos, getFile,
// setChatStickerSet, deleteChatStickerSet
// sendGame, setGameScore, getGameHighScores
// sendInvoice, answerShippingQuery, answerPreCheckoutQuery
// getStickerSet, uploadStickerFile, createNewStickerSet, addStickerToSet, setStickerPositionInSet, deleteStickerFromSet
default:
// unknown type nothing to send.
}
} else {
node.warn("msg.payload.type is empty");
}
} else {
node.warn("msg.payload.chatId is empty");
}
} else {
node.warn("msg.payload is empty");
}
});
}
RED.nodes.registerType("telegram sender", TelegramOutNode);
// --------------------------------------------------------------------------------------------
// The output node receices the reply for a specified message and passes the msg through.
// The payload needs three fields
// chatId : string destination chat
// sentMessageId : string the id of the message the reply coresponds to.
// content : message content
function TelegramReplyNode(config) {
RED.nodes.createNode(this, config);
var node = this;
this.bot = config.bot;
this.config = RED.nodes.getNode(this.bot);
if (this.config) {
this.config.register(node);
node.status({ fill: "red", shape: "ring", text: "not connected" });
node.telegramBot = this.config.getTelegramBot();
if (node.telegramBot) {
node.status({ fill: "green", shape: "ring", text: "connected" });
} else {
node.warn("bot not initialized.");
node.status({ fill: "red", shape: "ring", text: "bot not initialized" });
}
} else {
node.warn("config node failed to initialize.");
node.status({ fill: "red", shape: "ring", text: "config node failed to initialize" });
}
this.on('input', function (msg, nodeSend, nodeDone) {
node.status({ fill: "green", shape: "ring", text: "connected" });
if (msg.payload) {
if (msg.payload.chatId) {
if (msg.payload.sentMessageId) {
var chatId = msg.payload.chatId;
var messageId = msg.payload.sentMessageId;
node.telegramBot.onReplyToMessage(chatId, messageId, function (botMsg) {
var messageDetails = getMessageDetails(botMsg);
if (messageDetails) {
var newMsg = { payload: messageDetails, originalMessage: botMsg };
nodeSend(newMsg);
if (nodeDone) {
nodeDone();
}
}
});
} else {
node.warn("msg.payload.sentMessageId is empty");
}
} else {
node.warn("msg.payload.chatId is empty");
}
} else {
node.warn("msg.payload is empty");
}
});
}
RED.nodes.registerType("telegram reply", TelegramReplyNode);
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 845 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB