commit
6b17b2c9d8
@ -27,16 +27,16 @@ Just import add the library to your project with one of these options:
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.telegram</groupId>
|
<groupId>org.telegram</groupId>
|
||||||
<artifactId>telegrambots</artifactId>
|
<artifactId>telegrambots</artifactId>
|
||||||
<version>3.4</version>
|
<version>3.5</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
```
|
```
|
||||||
|
|
||||||
```gradle
|
```gradle
|
||||||
compile "org.telegram:telegrambots:3.4"
|
compile "org.telegram:telegrambots:3.5"
|
||||||
```
|
```
|
||||||
|
|
||||||
2. Using Jitpack from [here](https://jitpack.io/#rubenlagus/TelegramBots/3.4)
|
2. Using Jitpack from [here](https://jitpack.io/#rubenlagus/TelegramBots/3.5)
|
||||||
3. Download the jar(including all dependencies) from [here](https://github.com/rubenlagus/TelegramBots/releases/tag/v3.4)
|
3. Download the jar(including all dependencies) from [here](https://github.com/rubenlagus/TelegramBots/releases/tag/v3.5)
|
||||||
|
|
||||||
In order to use Long Polling mode, just create your own bot extending `org.telegram.telegrambots.bots.TelegramLongPollingBot`.
|
In order to use Long Polling mode, just create your own bot extending `org.telegram.telegrambots.bots.TelegramLongPollingBot`.
|
||||||
|
|
||||||
|
@ -1,3 +1,11 @@
|
|||||||
|
### <a id="3.5"></a>3.5 ###
|
||||||
|
1. Support for Api Version [3.5](https://core.telegram.org/bots/api-changelog#november-17-2017)
|
||||||
|
2. Bug fixing: #168, #329 and #335
|
||||||
|
3. Added processInvalidCommandUpdate (#337)
|
||||||
|
4. AbilitiyBot update and tutorial (#324)
|
||||||
|
5. Add DefaultBotCommand with message ID (#330)
|
||||||
|
6. New wiki content (#326 and #327)
|
||||||
|
|
||||||
### <a id="3.4"></a>3.4 ###
|
### <a id="3.4"></a>3.4 ###
|
||||||
1. Support for Api Version [3.4](https://core.telegram.org/bots/api-changelog#october-11-2017)
|
1. Support for Api Version [3.4](https://core.telegram.org/bots/api-changelog#october-11-2017)
|
||||||
2. Use regular expressions to split parameters in `TelegramLongPollingCommandBot` (#309)
|
2. Use regular expressions to split parameters in `TelegramLongPollingCommandBot` (#309)
|
||||||
|
@ -1,5 +1,13 @@
|
|||||||
* [Terminated by other long poll or webhook](#terminted_by_other)
|
* [Terminated by other long poll or webhook](#terminted_by_other)
|
||||||
|
* ["No implementation for org.telegram.telegrambots.generics.BotSession was bound"](#no_implementation_was_bound)
|
||||||
|
|
||||||
## <a id="terminted_by_other"></a>Terminated by other long poll or webhook ##
|
## <a id="terminted_by_other"></a>Terminated by other long poll or webhook ##
|
||||||
|
|
||||||
It means that you have already a running instance of your bot. To solve it, close all running ones and then you can start a new instance.
|
It means that you have already a running instance of your bot. To solve it, close all running ones and then you can start a new instance.
|
||||||
|
|
||||||
|
## <a id="no_implementation_was_bound"></a>No implementation for org.telegram.telegrambots.generics.BotSession was bound ##
|
||||||
|
Please follow the steps as explained [here](https://github.com/rubenlagus/TelegramBots/wiki/How-To-Update#to-version-243) in "How To Update"
|
||||||
|
> At the beginning of your program (before creating your TelegramBotsApi instance, add the following line:
|
||||||
|
```
|
||||||
|
ApiContextInitializer.init();
|
||||||
|
```
|
||||||
|
@ -4,7 +4,8 @@
|
|||||||
* [How to use custom keyboards?](#how_to_use_custom_keyboards)
|
* [How to use custom keyboards?](#how_to_use_custom_keyboards)
|
||||||
* [How can I run my bot?](#how_to_host)
|
* [How can I run my bot?](#how_to_host)
|
||||||
* [How can I compile my project?](#how_to_compile)
|
* [How can I compile my project?](#how_to_compile)
|
||||||
|
* [Method ```sendMessage()``` (or other) is deprecated, what should I do?](#sendmessage_deprecated)
|
||||||
|
* [Is there any example for WebHook?](#example_webhook)
|
||||||
|
|
||||||
## <a id="how_to_get_picture"></a>How to download photo? ##
|
## <a id="how_to_get_picture"></a>How to download photo? ##
|
||||||
|
|
||||||
@ -42,8 +43,8 @@ public String getFilePath(PhotoSize photo) {
|
|||||||
GetFile getFileMethod = new GetFile();
|
GetFile getFileMethod = new GetFile();
|
||||||
getFileMethod.setFileId(photo.getFileId());
|
getFileMethod.setFileId(photo.getFileId());
|
||||||
try {
|
try {
|
||||||
// We execute the method using AbsSender::getFile method.
|
// We execute the method using AbsSender::execute method.
|
||||||
File file = getFile(getFileMethod);
|
File file = execute(getFileMethod);
|
||||||
// We now have the file_path
|
// We now have the file_path
|
||||||
return file.getFilePath();
|
return file.getFilePath();
|
||||||
} catch (TelegramApiException e) {
|
} catch (TelegramApiException e) {
|
||||||
@ -186,7 +187,7 @@ Custom keyboards can be appended to messages using the `setReplyMarkup`. In this
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
// Send the message
|
// Send the message
|
||||||
sendMessage(message);
|
execute(message);
|
||||||
} catch (TelegramApiException e) {
|
} catch (TelegramApiException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
@ -199,8 +200,24 @@ You don't need to spend a lot of money into hosting your own telegram bot. Basic
|
|||||||
|
|
||||||
1. Hosting on your own hardware. It can be a Mini-PC like a Raspberry Pi. The costs for the hardware (~35€) and annual costs for power (~7-8€) are low. Keep in mind that your internet connection might be limited and a Mini-Pc is not ideal for a large users base.
|
1. Hosting on your own hardware. It can be a Mini-PC like a Raspberry Pi. The costs for the hardware (~35€) and annual costs for power (~7-8€) are low. Keep in mind that your internet connection might be limited and a Mini-Pc is not ideal for a large users base.
|
||||||
2. Run your bot in a Virtual Server/dedicated root server. There are many hosters out there that are providing cheap servers that fit your needs. The cheapest one should be openVZ-Containers or a KVM vServer. Example providers are [Hetzner](https://www.hetzner.de/ot/), [DigitalOcean](https://www.digitalocean.com/), (are providing systems that have a high availability but cost's a bit more) and [OVH](https://ovh.com)
|
2. Run your bot in a Virtual Server/dedicated root server. There are many hosters out there that are providing cheap servers that fit your needs. The cheapest one should be openVZ-Containers or a KVM vServer. Example providers are [Hetzner](https://www.hetzner.de/ot/), [DigitalOcean](https://www.digitalocean.com/), (are providing systems that have a high availability but cost's a bit more) and [OVH](https://ovh.com)
|
||||||
|
For a deeper explanation for deploying your bot on DigitalOcean please see the [Lesson 5. Deploy your bot](https://monsterdeveloper.gitbooks.io/writing-telegram-bots-on-java/content/lesson-5.-deploy-your-bot.html) chapter in [MonsterDeveloper](https://github.com/MonsterDeveloper)'s book
|
||||||
|
|
||||||
## <a id="how_to_compile"></a>How can I compile my project? ##
|
## <a id="how_to_compile"></a>How can I compile my project? ##
|
||||||
|
|
||||||
This is just one way, how you can compile it (here with maven). The example below below is compiling the TelegramBotsExample repo.
|
This is just one way, how you can compile it (here with maven). The example below below is compiling the TelegramBotsExample repo.
|
||||||
[![asciicast](https://asciinema.org/a/4np9i2u9onuitkg287ism23kj.png)](https://asciinema.org/a/4np9i2u9onuitkg287ism23kj)
|
[![asciicast](https://asciinema.org/a/4np9i2u9onuitkg287ism23kj.png)](https://asciinema.org/a/4np9i2u9onuitkg287ism23kj)
|
||||||
|
|
||||||
|
## <a id="sendmessage_deprecated"></a>Method ```sendMessage()``` (or other) is deprecated, what should I do? ##
|
||||||
|
Please use ```execute()``` instead.
|
||||||
|
Example:
|
||||||
|
```java
|
||||||
|
SendMessage sn = new SendMessage();
|
||||||
|
//add chat id and text
|
||||||
|
execute(sn);
|
||||||
|
```
|
||||||
|
|
||||||
|
If you extend ```TelegramLongPollingCommandBot```, then use ```AbsSender.execute()``` instead.
|
||||||
|
|
||||||
|
|
||||||
|
## <a id="example_webhook"></a>Is there any example for WebHook? ##
|
||||||
|
Please see the example Bot for https://telegram.me/SnowcrashBot in the [TelegramBotsExample]() repo and also an [example bot for Sping Boot](https://github.com/UnAfraid/SpringTelegramBot) from [UnAfraid](https://github.com/UnAfraid) [here](https://github.com/UnAfraid/SpringTelegramBot/blob/master/src/main/java/com/github/unafraid/spring/bot/TelegramWebhookBot.java)
|
||||||
|
@ -11,13 +11,13 @@ First you need ot get the library and add it to your project. There are few poss
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.telegram</groupId>
|
<groupId>org.telegram</groupId>
|
||||||
<artifactId>telegrambots</artifactId>
|
<artifactId>telegrambots</artifactId>
|
||||||
<version>3.4</version>
|
<version>3.5</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
```
|
```
|
||||||
* With **Gradle**:
|
* With **Gradle**:
|
||||||
|
|
||||||
```groovy
|
```groovy
|
||||||
compile group: 'org.telegram', name: 'telegrambots', version: '3.4'
|
compile group: 'org.telegram', name: 'telegrambots', version: '3.5'
|
||||||
```
|
```
|
||||||
|
|
||||||
2. Don't like **Maven Central Repository**? It can also be taken from [Jitpack](https://jitpack.io/#rubenlagus/TelegramBots).
|
2. Don't like **Maven Central Repository**? It can also be taken from [Jitpack](https://jitpack.io/#rubenlagus/TelegramBots).
|
||||||
@ -88,7 +88,7 @@ Now that we have the library, we can start coding. There are few steps to follow
|
|||||||
.setChatId(update.getMessage().getChatId())
|
.setChatId(update.getMessage().getChatId())
|
||||||
.setText(update.getMessage().getText());
|
.setText(update.getMessage().getText());
|
||||||
try {
|
try {
|
||||||
sendMessage(message); // Call method to send the message
|
execute(message); // Call method to send the message
|
||||||
} catch (TelegramApiException e) {
|
} catch (TelegramApiException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
|
@ -2,5 +2,13 @@
|
|||||||
* [[Getting Started]]
|
* [[Getting Started]]
|
||||||
* [[Errors Handling]]
|
* [[Errors Handling]]
|
||||||
* [[FAQ]]
|
* [[FAQ]]
|
||||||
|
* AbilityBot
|
||||||
|
* [[Simple Example]]
|
||||||
|
* [[Hello Ability]]
|
||||||
|
* [[Using Replies]]
|
||||||
|
* [[Database Handling]]
|
||||||
|
* [[Bot Testing]]
|
||||||
|
* [[Bot Recovery]]
|
||||||
|
* [[Advanced]]
|
||||||
* [[Changelog]]
|
* [[Changelog]]
|
||||||
* [[How To Update]]
|
* [[How To Update]]
|
34
TelegramBots.wiki/abilities/Advanced.md
Normal file
34
TelegramBots.wiki/abilities/Advanced.md
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
# Advanced
|
||||||
|
This will be more of a FAQ on some important notes before you embark on your next big bot project!
|
||||||
|
|
||||||
|
## Default Abilties
|
||||||
|
|
||||||
|
It is possible to declare "DEFAULT" abilities that process non-command messages. This is quite close to a reply. If a user says "Hey there" and the default ability is implemented, it will process this input.
|
||||||
|
```java
|
||||||
|
/**
|
||||||
|
* This ability has an extra "flag". It needs a photo to activate! This feature is activated by default if there is no /command given.
|
||||||
|
*/
|
||||||
|
public Ability sayNiceToPhoto() {
|
||||||
|
return Ability.builder()
|
||||||
|
.name(DEFAULT) // DEFAULT ability is executed if user did not specify a command -> Bot needs to have access to messages (check FatherBot)
|
||||||
|
.flag(PHOTO)
|
||||||
|
.privacy(PUBLIC)
|
||||||
|
.locality(ALL)
|
||||||
|
.input(0)
|
||||||
|
.action(ctx -> silent.send("Daaaaang, what a nice photo!", ctx.chatId()))
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
This ability will send a *"Daaaaang, what a nice photo!"* whenever the bot receives a photo. This is one use case where replies and abilities are interchangeable.
|
||||||
|
|
||||||
|
## The Global Flag
|
||||||
|
There is a global flag in AbilityBot that restricts the kind of "updates" it can process. The default implementation is passthrough - it allows all updates to be processed.
|
||||||
|
As an example, if you want to restrict the updates to photos only, then you may do:
|
||||||
|
|
||||||
|
```java
|
||||||
|
@Override
|
||||||
|
public boolean checkGlobalFlags(Update update) {
|
||||||
|
return Flag.PHOTO;
|
||||||
|
}
|
||||||
|
```
|
8
TelegramBots.wiki/abilities/Bot-Recovery.md
Normal file
8
TelegramBots.wiki/abilities/Bot-Recovery.md
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
# Bot Recovery
|
||||||
|
With recovery, we specifically mean recovering the DB in-case of false data being committed. This is a neat feature supported by DBContext, you can /backup and /recover your bot whenever needed.
|
||||||
|
|
||||||
|
Once you /backup, the bot will respond back with a valid JSON object that represents all the data in the DB.
|
||||||
|
|
||||||
|
On /recover, the bot will ask for the JSON file. A reply to the message with the file attached will recover the bot with the previous state DB.
|
||||||
|
|
||||||
|
Try to experiment using the counter ability introduced in [[Database Handling|Database-Handling]]!
|
193
TelegramBots.wiki/abilities/Bot-Testing.md
Normal file
193
TelegramBots.wiki/abilities/Bot-Testing.md
Normal file
@ -0,0 +1,193 @@
|
|||||||
|
# Testing
|
||||||
|
It is super important to be able to test your bot prior to "release". In this case, release would mean that you're presenting the bot to your designated audience. Nobody likes bots that are buggy, faulty and do clumsy actions.
|
||||||
|
As developers, we appreciate frameworks that provide an ease in testing. Of course, you might no tbe able to catch all bugs that can occur in production, but you'd be far more comfortable in releasing a bot that is well-tested.
|
||||||
|
|
||||||
|
## Limitations
|
||||||
|
|
||||||
|
The issue with the basic API is that all DefaultAbsSender methods (the bot methods you use to send message) are statically defined without interfacing. If you declare your bot and try to do some testing, you won't be able to know that you've executed a method... unless you actually execute it! As an example:
|
||||||
|
```java
|
||||||
|
public void sayHello() {
|
||||||
|
SendMessage snd = new SendMessage();
|
||||||
|
snd.setText("Hello!");
|
||||||
|
snd.setChatId(123);
|
||||||
|
|
||||||
|
try {
|
||||||
|
// We want to test that we actually sent out this message with the contents "Hello!"
|
||||||
|
execute(snd);
|
||||||
|
} catch (TelegramApiException e) {}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
This is how you would define a method that says hello in the basic API. How do you go around testing it? If you do attempt to Junit test this method, what will you be testing? If you change the method signature to return the string sent, then you can test the hello message content. However, can you test that you've actually `executed` the command?
|
||||||
|
|
||||||
|
## Mock Testing
|
||||||
|
*This section assumes you're familiar with mock testing. Mock testing is basically replacing a real object X with a fake object Y (a mock) of the same type. By doing that, you're able to test whether certain functions were executed.*
|
||||||
|
|
||||||
|
Obviously, you can't, but there's a twist to it. You can always mock the whole bot, but with that you're also mocking the method `sayHello` when you actually need its contents and code! We need to extract the bot-sending-specific-methods into their own interface and try to mock that interface instead.
|
||||||
|
|
||||||
|
## MessageSender Interface
|
||||||
|
All ability bots declare two utility objects.
|
||||||
|
### The Sender Object
|
||||||
|
The `sender` object is an implementation of the [MessageSender](../../telegrambots-abilities/src/main/java/org/telegram/abilitybots/api/sender/MessageSender.java) interface. The interface mirrors
|
||||||
|
all the bot sending methods. A user can supply his own MessageSender, but the AbilityBot module specifies a [DefaultSender](../../telegrambots-abilities/src/main/java/org/telegram/abilitybots/api/sender/DefaultSender.java) As you might guess, the default sender is simply a proxy for the bot API methods.
|
||||||
|
|
||||||
|
### The Silent Object
|
||||||
|
The `silent` object is exactly like the sender object, but silent. Its methods return `Optional<T>`. On exception, it will be an empty optional. The sender object is provided to reduce verboseness of the code (reducing try-catch blocks with something more elegant).
|
||||||
|
## AbilityBot Testing
|
||||||
|
Let's suppose that you have an ability that says "Hello World!" declared as such:
|
||||||
|
```java
|
||||||
|
public Ability saysHelloWorld() {
|
||||||
|
return Ability.builder()
|
||||||
|
.name("hello")
|
||||||
|
.info("Says hello world!")
|
||||||
|
.privacy(PUBLIC)
|
||||||
|
.locality(ALL)
|
||||||
|
.action(ctx -> {
|
||||||
|
try{
|
||||||
|
sender.execute(new SendMessage().setChatId(ctx.getChatId()).setText("Hello World!"));
|
||||||
|
} catch (TelgramApiException e){}
|
||||||
|
})
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
The test for this ability would be:
|
||||||
|
|
||||||
|
```java
|
||||||
|
@Test
|
||||||
|
public void canSayHelloWorld() {
|
||||||
|
Update upd = new Update();
|
||||||
|
// Create a new EndUser - EndUser is a class similar to Telegram User, but contains
|
||||||
|
// some utility methods like fullName() and shortName() for ease of use
|
||||||
|
EndUser endUser = EndUser.endUser(USER_ID, "Abbas", "Abou Daya", "addo37");
|
||||||
|
// This is the context that you're used to, it is the necessary conumer item for the ability
|
||||||
|
MessageContext context = MessageContext.newContext(upd, endUser, CHAT_ID);
|
||||||
|
|
||||||
|
// We consume a context in the lamda declaration, so we pass the context to the action logic
|
||||||
|
bot.saysHelloWorld().action().accept(context);
|
||||||
|
|
||||||
|
// We verify that the sender was called only ONCE and sent Hello World to CHAT_ID
|
||||||
|
// The sender here is a mock!
|
||||||
|
Mockito.verify(sender, times(1)).send("Hello World!", CHAT_ID);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
The comments explain every step in the test. In a single assertion with Mockito, we assert that:
|
||||||
|
* We've sent the message once
|
||||||
|
* The message content was "Hello World!"
|
||||||
|
* The message was sent to a specific chat ID
|
||||||
|
|
||||||
|
There are some preparations involved before we can perform such a test. Here's the full code snippet for running this test:
|
||||||
|
```java
|
||||||
|
import org.junit.After;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.mockito.Mockito;
|
||||||
|
import org.telegram.abilitybots.api.db.DBContext;
|
||||||
|
import org.telegram.abilitybots.api.db.MapDBContext;
|
||||||
|
import org.telegram.abilitybots.api.objects.EndUser;
|
||||||
|
import org.telegram.abilitybots.api.objects.MessageContext;
|
||||||
|
import org.telegram.abilitybots.api.sender.MessageSender;
|
||||||
|
import org.telegram.telegrambots.api.objects.Update;
|
||||||
|
|
||||||
|
import static org.mockito.Mockito.*;
|
||||||
|
|
||||||
|
public class ExampleBotTest {
|
||||||
|
public static final int USER_ID = 1337;
|
||||||
|
public static final long CHAT_ID = 1337L;
|
||||||
|
|
||||||
|
// Your bot handle here
|
||||||
|
private ExampleBot bot;
|
||||||
|
// Your sender here
|
||||||
|
private MessageSender sender;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setUp() {
|
||||||
|
// Create your bot
|
||||||
|
bot = new ExampleBot();
|
||||||
|
// Create a new sender as a mock
|
||||||
|
sender = mock(MessageSender.class);
|
||||||
|
// Set your bot sender to the mocked sender
|
||||||
|
// THIS is the line that prevents your bot from communicating with Telegram servers when it's running its own abilities
|
||||||
|
// All method calls will go through the mocked interface -> which would do nothing except logging the fact that you've called this function with the specific arguments
|
||||||
|
bot.sender = sender;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void canSayHelloWorld() {
|
||||||
|
Update upd = new Update();
|
||||||
|
// Create a new EndUser - EndUser is a class similar to Telegram User, but contains
|
||||||
|
// some utility methods like fullName() and shortName() for ease of use
|
||||||
|
EndUser endUser = EndUser.endUser(USER_ID, "Abbas", "Abou Daya", "addo37");
|
||||||
|
// This is the context that you're used to, it is the necessary conumer item for the ability
|
||||||
|
MessageContext context = MessageContext.newContext(upd, endUser, CHAT_ID);
|
||||||
|
|
||||||
|
// We consume a context in the lamda declaration, so we pass the context to the action logic
|
||||||
|
bot.saysHelloWorld().action().accept(context);
|
||||||
|
|
||||||
|
// We verify that the sender was called only ONCE and sent Hello World to CHAT_ID
|
||||||
|
// The sender here is a mock!
|
||||||
|
Mockito.verify(sender, times(1)).send("Hello World!", CHAT_ID);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## DB Abilities
|
||||||
|
What if the ability performs a DB interaction? We don't want testing procedures to modify the database of the bot.
|
||||||
|
|
||||||
|
This is where we differentiate between an online DB and an offline DB. The online DB is the default DB when the bot is instantiated. However, AbilityBot supplies a constructor that reveals a DBContext argument. We can supply another instance of a DB (an offline one) so that the tests don't modify our online DB.
|
||||||
|
|
||||||
|
In ExampleBot, we do:
|
||||||
|
```java
|
||||||
|
public ExampleBot(DBContext db) {
|
||||||
|
super(BOT_TOKEN, BOT_USERNAME, db);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
In ExampleBotTest:
|
||||||
|
```java
|
||||||
|
public class ExampleBotTest {
|
||||||
|
...
|
||||||
|
|
||||||
|
private DBContext db;
|
||||||
|
private MessageSender sender;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setUp() {
|
||||||
|
// Offline instance will get deleted at JVM shutdown
|
||||||
|
db = MapDBContext.offlineInstance("test");
|
||||||
|
bot = new ExampleBot(db);
|
||||||
|
|
||||||
|
...
|
||||||
|
}
|
||||||
|
...
|
||||||
|
|
||||||
|
// We should clear the DB after every test as such
|
||||||
|
@After
|
||||||
|
public void tearDown() {
|
||||||
|
db.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Silent Testing
|
||||||
|
As mentioned before, we also have another object that is able to send messages silently called `silent`. The constructor of the silent sender requires a MessageSender object. If your abilities use the `silent` object, be sure to:
|
||||||
|
```java
|
||||||
|
public class ExampleBotTest {
|
||||||
|
...
|
||||||
|
private DBContext db;
|
||||||
|
private MessageSender sender;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setUp() {
|
||||||
|
bot = new ExampleBot(db);
|
||||||
|
sender = mock(MessageSender.class);
|
||||||
|
bot.silent = new SilentSender(sender);
|
||||||
|
...
|
||||||
|
}
|
||||||
|
|
||||||
|
...
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Do note that in your test assertions, don't use the silent object. Mocked assertion require the mock object. If you recall, the silent object uses the sender object, so your tests will still be correct if you're asserting on the `sender` object rather than the silent one.
|
57
TelegramBots.wiki/abilities/Database-Handling.md
Normal file
57
TelegramBots.wiki/abilities/Database-Handling.md
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
# Database Handling
|
||||||
|
AbilityBots come with an embedded DB. Users are free to implement their own databases via implementing the [DBContext](../../telegrambots-abilities/src/main/java/org/telegram/abilitybots/api/db/DBContext.java) class.
|
||||||
|
The abstraction has multiple constructors to accommodate user-defined implementations of [DBContext](../../telegrambots-abilities/src/main/java/org/telegram/abilitybots/api/db/DBContext.java) and [MessageSender](../../telegrambots-abilities/src/main/java/org/telegram/abilitybots/api/sender/MessageSender.java). We'll talk about the message sender interface in the [[Bot Testing|Bot-Testing]] section.
|
||||||
|
|
||||||
|
## Example
|
||||||
|
We'll be introducing an ability that maintains a special counter for every user. At every /increment, the user will receive a message with the previous number + 1. We'll initially start from zero and increment upwards.
|
||||||
|
|
||||||
|
```java
|
||||||
|
/**
|
||||||
|
* Use the database to fetch a count per user and increments.
|
||||||
|
* <p>
|
||||||
|
* Use /count to experiment with this ability.
|
||||||
|
*/
|
||||||
|
public Ability useDatabaseToCountPerUser() {
|
||||||
|
return Ability.builder()
|
||||||
|
.name("count")
|
||||||
|
.info("Increments a counter per user")
|
||||||
|
.privacy(PUBLIC)
|
||||||
|
.locality(ALL)
|
||||||
|
.input(0)
|
||||||
|
.action(ctx -> {
|
||||||
|
// db.getMap takes in a string, this must be unique and the same everytime you want to call the exact same map
|
||||||
|
// TODO: Using integer as a key in this db map is not recommended, it won't be serialized/deserialized properly if you ever decide to recover/backup db
|
||||||
|
Map<String, Integer> countMap = db.getMap("COUNTERS");
|
||||||
|
int userId = ctx.user().id();
|
||||||
|
|
||||||
|
// Get and increment counter, put it back in the map
|
||||||
|
Integer counter = countMap.compute(String.valueOf(userId), (id, count) -> count == null ? 1 : ++count);
|
||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
Without lambdas implementation of incrementing
|
||||||
|
|
||||||
|
int counter;
|
||||||
|
if (countMap.containsKey(userId))
|
||||||
|
counter = countMap.get(userId) + 1;
|
||||||
|
else
|
||||||
|
counter = 1;
|
||||||
|
countMap.put(userId, counter);
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Send formatted will enable markdown
|
||||||
|
String message = String.format("%s, your count is now *%d*!", ctx.user().shortName(), counter);
|
||||||
|
silent.send(message, ctx.chatId());
|
||||||
|
})
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
After successfully adding that ability to your bot, try to /count and watch as the number increases at every message.
|
||||||
|
Other important functions in the `db` object:
|
||||||
|
* getSet - gets a set of data
|
||||||
|
* getList - gets a list of data
|
||||||
|
* summary - gets a summary of the present structs
|
||||||
|
|
||||||
|
Be sure to check out [DBContext](../../telegrambots-abilities/src/main/java/org/telegram/abilitybots/api/db/DBContext.java) for all the implemented methods.
|
117
TelegramBots.wiki/abilities/Hello-Ability.md
Normal file
117
TelegramBots.wiki/abilities/Hello-Ability.md
Normal file
@ -0,0 +1,117 @@
|
|||||||
|
Motivation
|
||||||
|
----------
|
||||||
|
After implementing your own bot via the basic API, you'll quickly realize how verbose it is. Once you get multiple commands up and running, your routing logic and handling per command start to become cumbersome.
|
||||||
|
Dealing with a basic API has its advantages and disadvantages. Obviously, there's nothing hidden. If it's there on Telegram, it's here in the Java API. However, can we do better than just a basic API?
|
||||||
|
|
||||||
|
When you want to implement a feature in your bot, you start asking these questions:
|
||||||
|
|
||||||
|
* The **WHO**?
|
||||||
|
* Who is going to use this feature? Should they be allowed to use all the features?
|
||||||
|
* The **WHAT**?
|
||||||
|
* Under what conditions should I allow this feature?
|
||||||
|
* Should the message have a photo? A document? Oh, maybe a callback query?
|
||||||
|
* The **HOW**?
|
||||||
|
* If my bot crashes, how can I resume my operation?
|
||||||
|
* Should I utilize a DB?
|
||||||
|
* How can I separate logic execution of different features?
|
||||||
|
* How can I unit-test my feature outside of Telegram?
|
||||||
|
|
||||||
|
Every time you write a command or a feature, you will need to answer these questions and ensure that your feature logic works.
|
||||||
|
|
||||||
|
Ability
|
||||||
|
----------------------
|
||||||
|
Simply put, the abilities module was developed to make your life easier. Whether you're counting numbers, fetching images or handling large data, AbilityBot is here to augment your development.
|
||||||
|
|
||||||
|
The AbilityBot abstraction intends to provide the following:
|
||||||
|
* New feature is a new **Ability**, a new method - no fuss, zero overhead, no cross-code with other features
|
||||||
|
* Argument length on a command is as easy as changing a single integer
|
||||||
|
* Privacy settings per Ability - access levels to Abilities! User | Admin | Creator
|
||||||
|
* Embedded database - available for every declared ability
|
||||||
|
* Proxy sender interface - enhances testability; accurate results pre-release
|
||||||
|
|
||||||
|
Alongside these exciting core features of the AbilityBot, the following have been introduced:
|
||||||
|
* The bot automatically maintains an up-to-date set of all the users who have contacted the bot
|
||||||
|
* Backup and recovery for the DB
|
||||||
|
* Ban and unban users from accessing your bots
|
||||||
|
* Promote and demote users as bot administrators
|
||||||
|
|
||||||
|
Abstraction
|
||||||
|
--------------
|
||||||
|
|
||||||
|
The AbilityBot abstraction defines a new object, named **Ability**. An ability combines conditions, flags, action, post-action and replies.
|
||||||
|
As an example, here is a code-snippet of an ability that creates a ***/hello*** command:
|
||||||
|
|
||||||
|
```java
|
||||||
|
public Ability sayHelloWorld() {
|
||||||
|
return Ability
|
||||||
|
.builder()
|
||||||
|
.name("hello")
|
||||||
|
.info("says hello world!")
|
||||||
|
.input(0)
|
||||||
|
.locality(USER)
|
||||||
|
.privacy(ADMIN)
|
||||||
|
.action(ctx -> silent.send("Hello world!", ctx.chatId()))
|
||||||
|
.post(ctx -> silent.send("Bye world!", ctx.chatId()))
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
```
|
||||||
|
Here is a breakdown of the above code snippet:
|
||||||
|
* *.name()* - the name of the ability (essentially, this is the command)
|
||||||
|
* *.info()* - provides information for the command
|
||||||
|
* More on this later, but it basically centralizes command information in-code.
|
||||||
|
* *.input()* - the number of input arguments needed, 0 is for do-not-care
|
||||||
|
* *.locality()* - this answers where you want the ability to be available
|
||||||
|
* In GROUP, USER private chats or ALL (both)
|
||||||
|
* *.privacy()* - this answers who you want to access your ability
|
||||||
|
* CREATOR, ADMIN, or everyone as PUBLIC
|
||||||
|
* *.action()* - the feature logic resides here (a lambda function that takes a *MessageContext*)
|
||||||
|
* *MessageContext* provides fast accessors for the **chatId**, **user** and the underlying **update**. It also conforms to the specifications of the basic API.
|
||||||
|
* *.post()* - the logic executed **after** your main action finishes execution
|
||||||
|
|
||||||
|
The `silent` object is created with every AbilityBot. It provides helper and utility functions that execute "silently". In this context, silent execution of bot API methods are ones that don't throw an exception. However, all methods in silent return an Optional object. If an exception occurs, the optional would be empty. The developer would still be able to
|
||||||
|
manage errors by checking for the presence of the optional `.isPresent()`. This decreases verboseness while still being able to execute routines correctly.
|
||||||
|
Do note that:
|
||||||
|
* You can still access the bot's methods and functions inside the lambda function in your action definition. That includes all the DefaultAbsSender methods execute, executeAsync, setChatPhoto, etc....
|
||||||
|
* `silent` uses another accessible object named `sender`. Refer to [[Bot Testing|Bot-Testing]] for the main use case of sender as an interface to all bot methods.
|
||||||
|
|
||||||
|
With abilities, you can specify the context of the feature. If you only want the command to be available for groups, then you can set `.locality(GROUP)`. If it is a very sensitive command that only admins should have access to, then set `.privacy(ADMIN)`.
|
||||||
|
This allows for abilities with protection guarantees on who can use it and where it can be used.
|
||||||
|
|
||||||
|
All abilities have access to the following important methods.
|
||||||
|
* `users()` - Returns a map of ID -> User
|
||||||
|
* `userIds()` - Returns a map of Username -> ID
|
||||||
|
* `blacklist()` - Returns a set of IDs of banned users
|
||||||
|
* `admins()` - Returns a set of IDs of bot administrators
|
||||||
|
|
||||||
|
`users()` and `userIds()` accumulate data of all the users who have contacted your bot. Even when a user changes some information (like his or her nickname), the bot will be able to detect the change and update its DB accordingly.
|
||||||
|
|
||||||
|
The following is a snippet of how this ability would look like with the plain basic API.
|
||||||
|
```java
|
||||||
|
@Override
|
||||||
|
public void onUpdateReceived(Update update) {
|
||||||
|
// Global checks...
|
||||||
|
// Switch, if, logic to route to hello world method
|
||||||
|
// Execute method
|
||||||
|
}
|
||||||
|
|
||||||
|
public void sayHelloWorld(Update update) {
|
||||||
|
if (!update.hasMessage() || !update.getMessage().isUserMessage() || !update.getMessage().hasText() || update.getMessage.getText().isEmpty())
|
||||||
|
return;
|
||||||
|
User maybeAdmin = update.getMessage().getFrom();
|
||||||
|
/* Query DB for if the user is an admin, can be SQL, Reddis, Ignite, etc...
|
||||||
|
If user is not an admin, then return here.
|
||||||
|
*/
|
||||||
|
|
||||||
|
SendMessage snd = new SendMessage();
|
||||||
|
snd.setChatId(update.getMessage().getChatId());
|
||||||
|
snd.setText("Hello world!");
|
||||||
|
|
||||||
|
try {
|
||||||
|
execute(snd);
|
||||||
|
} catch (TelegramApiException e) {
|
||||||
|
BotLogger.error("Could not send message", TAG, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
I will leave you the choice to decide between the two snippets as to which is more **readable**, **writable** and **testable**.
|
117
TelegramBots.wiki/abilities/Simple-Example.md
Normal file
117
TelegramBots.wiki/abilities/Simple-Example.md
Normal file
@ -0,0 +1,117 @@
|
|||||||
|
# AbilityBot
|
||||||
|
This section of the tutorial will present a barebone example on creating your first AbilityBot! It is highly recommended to write your very first bot via the [[Getting Started|Getting-Started]]. That will give you a sense of how the basic API allows you to handle commands and features.
|
||||||
|
|
||||||
|
## Dependencies
|
||||||
|
As with any Java project, you will need to set your dependencies.
|
||||||
|
|
||||||
|
* **Maven**
|
||||||
|
```xml
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.telegram</groupId>
|
||||||
|
<artifactId>telegrambots-abilties</artifactId>
|
||||||
|
<version>3.5</version>
|
||||||
|
</dependency>
|
||||||
|
```
|
||||||
|
* **Gradle**
|
||||||
|
```groovy
|
||||||
|
compile group: 'org.telegram', name: 'telegrambots-abilties', version: '3.5'
|
||||||
|
```
|
||||||
|
* [JitPack](https://jitpack.io/#rubenlagus/TelegramBots)
|
||||||
|
|
||||||
|
* [Plain Imports/Jars](https://github.com/rubenlagus/TelegramBots/releases)
|
||||||
|
|
||||||
|
## Bot Declaration
|
||||||
|
To use the abilities module, you will need to extend AbilityBot.
|
||||||
|
```java
|
||||||
|
import org.telegram.abilitybots.api.bot.AbilityBot;
|
||||||
|
|
||||||
|
public class HelloBot extends AbilityBot {
|
||||||
|
...
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Bot Implementation
|
||||||
|
Bot token and nickname are passed via the constructor and don't require an override.
|
||||||
|
```java
|
||||||
|
public HelloBot(String token, String username) {
|
||||||
|
super(token, username);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
However, since the token and username of a bot are usually constants, you can do the following:
|
||||||
|
```java
|
||||||
|
public static String BOT_TOKEN = "...";
|
||||||
|
public static String BOT_USERNAME = "...";
|
||||||
|
|
||||||
|
public HelloBot() {
|
||||||
|
super(BOT_TOKEN, BOT_USERNAME);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
AbilityBot forces a single implementation of creator ID. This ID corresponds to you, the bot developer. The bot needs to know its master since it has sensitive commands that only the master can use.
|
||||||
|
So, if your Telegram ID Is 123456789, then add the following method:
|
||||||
|
```java
|
||||||
|
@Override
|
||||||
|
public int creatorId() {
|
||||||
|
return 123456789;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
That's it to have a valid, compilable and ready to be deployed bot. However, your bot doesn't have a single command to use. Let's declare one!
|
||||||
|
|
||||||
|
## Hello Ability
|
||||||
|
To add a feature to your bot, you add an ability. That's it! No routing from onUpdateReceived, no separate checks and no crossovers. Let's write our first ability that simply says hello!
|
||||||
|
|
||||||
|
```java
|
||||||
|
public Ability sayHelloWorld() {
|
||||||
|
return Ability
|
||||||
|
.builder()
|
||||||
|
.name("hello")
|
||||||
|
.info("says hello world!")
|
||||||
|
.locality(ALL)
|
||||||
|
.privacy(PUBLIC)
|
||||||
|
.action(ctx -> silent.send("Hello world!", ctx.chatId()))
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Save your questions for later! Abilities are described in detail in the following sections of the tutorial.
|
||||||
|
## Running Your Bot
|
||||||
|
Running the bot is just like running the regular Telegram bots. Create a Java class similar to the one below.
|
||||||
|
```java
|
||||||
|
public class Application {
|
||||||
|
public static void main(String[] args) {
|
||||||
|
// Initializes dependencies necessary for the base bot - Guice
|
||||||
|
ApiContextInitializer.init();
|
||||||
|
|
||||||
|
// Create the TelegramBotsApi object to register your bots
|
||||||
|
TelegramBotsApi botsApi = new TelegramBotsApi();
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Register your newly created AbilityBot
|
||||||
|
botsApi.registerBot(new HelloBot());
|
||||||
|
} catch (TelegramApiException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
If you're in doubt that you're missing some code, the full code example can be inspected [here](https://github.com/addo37/ExampleBots/tree/master/src/main/java/org/telegram/examplebots).
|
||||||
|
## Testing Your Bot
|
||||||
|
Go ahead and "/hello" to your bot. It should respond back with "Hello World!".
|
||||||
|
|
||||||
|
Since you've implemented an AbilityBot, you get **factory abilities** as well. Try:
|
||||||
|
* /commands - Prints all commands supported by the bot
|
||||||
|
* This will essentially print "hello - says hello world!". Yes! This is the information we supplied to the ability. The bot prints the commands in the format accepted by BotFather. So, whenever you change, add or remove commands, you can simply /commands and forward that message to BotFather.
|
||||||
|
* /claim - Claims this bot
|
||||||
|
* /backup - returns a backup of the bot database
|
||||||
|
* /recover - recovers the database
|
||||||
|
* /promote @username - promotes user to bot admin
|
||||||
|
* /demote @username - demotes bot admin to user
|
||||||
|
* /ban @username - bans the user from accessing your bot commands and features
|
||||||
|
* /unban @username - lifts the ban from the user
|
||||||
|
|
||||||
|
## Conclusion
|
||||||
|
Congratulation on creating your first AbilityBot. What's next? So far we've only considered the case of commands, but what about images and inline replies? AbilityBots can also handle that! Oh and, did you know that all ability bots have an embedded database that you can use?
|
||||||
|
The following sections of the tutorial will describe in detail **abilities** and **replies**. It will also bring into attention how to effectively in-code test your bot, handle the embedded DB and administer your user access levels.
|
77
TelegramBots.wiki/abilities/Using-Replies.md
Normal file
77
TelegramBots.wiki/abilities/Using-Replies.md
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
# Replies
|
||||||
|
|
||||||
|
A reply is AbilityBot's swiss army knife. It comes in two variants and is able to handle all possible use cases.
|
||||||
|
|
||||||
|
## Standalone Reply
|
||||||
|
Standalone replies are replies declared on their own without being attached to an ability. Here's an example of a possible reply declaration:
|
||||||
|
```java
|
||||||
|
/**
|
||||||
|
* A reply that says "yuck" to all images sent to the bot.
|
||||||
|
*/
|
||||||
|
public Reply sayYuckOnImage() {
|
||||||
|
// getChatId is a public utility function in rg.telegram.abilitybots.api.util.AbilityUtils
|
||||||
|
Consumer<Update> action = upd -> silent.send("Yuck", getChatId(upd));
|
||||||
|
|
||||||
|
return Reply.of(upd, Flag.PHOTO)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Let's break this down. Replies require a lambda function (consumer) that is able to consume our update. In this case, our consumer simply fetches the chatId
|
||||||
|
from the update and sends a "Yuck" message. `Reply.of(upd)` would be enough. However, replies accept a var-arg of type `Predicate<Update>`. These predicates are the necessary conditions so that the bot acts the reply. We specify Flag.PHOTO to let the bot know
|
||||||
|
that we only want the reply to act on images only! The Flag is a public enum at your disposal. It contains other conditionals like checking for videos, messages, voice, documents, etc...
|
||||||
|
|
||||||
|
## Ability Reply
|
||||||
|
In exactly the same manner, you are able to attach replies to abilities. This way you can localize replies that relate to the same ability.
|
||||||
|
```java
|
||||||
|
public Ability playWithMe() {
|
||||||
|
String playMessage = "Play with me!";
|
||||||
|
|
||||||
|
return Ability.builder()
|
||||||
|
.name("play")
|
||||||
|
.info("Do you want to play with me?")
|
||||||
|
.privacy(PUBLIC)
|
||||||
|
.locality(ALL)
|
||||||
|
.input(0)
|
||||||
|
.action(ctx -> sender.forceReply(playMessage, ctx.chatId()))
|
||||||
|
// The signature of a reply is -> (Consumer<Update> action, Predicate<Update>... conditions)
|
||||||
|
// So, we first declare the action that takes an update (NOT A MESSAGECONTEXT) like the action above
|
||||||
|
// The reason of that is that a reply can be so versatile depending on the message, context becomes an inefficient wrapping
|
||||||
|
.reply(upd -> {
|
||||||
|
// Prints to console
|
||||||
|
System.out.println("I'm in a reply!");
|
||||||
|
// Sends message
|
||||||
|
sender.send("It's been nice playing with you!", upd.getMessage().getChatId());
|
||||||
|
},
|
||||||
|
// Now we start declaring conditions, MESSAGE is a member of the enum Flag class
|
||||||
|
// That class contains out-of-the-box predicates for your replies!
|
||||||
|
// MESSAGE means that the update must have a message
|
||||||
|
// This is imported statically, Flag.MESSAGE
|
||||||
|
MESSAGE,
|
||||||
|
// REPLY means that the update must be a reply, Flag.REPLY
|
||||||
|
REPLY,
|
||||||
|
// A new predicate user-defined
|
||||||
|
// The reply must be to the bot
|
||||||
|
isReplyToBot(),
|
||||||
|
// If we process similar logic in other abilities, then we have to make this reply specific to this message
|
||||||
|
// The reply is to the playMessage
|
||||||
|
isReplyToMessage(playMessage)
|
||||||
|
)
|
||||||
|
// You can add more replies by calling .reply(...)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
private Predicate<Update> isReplyToMessage(String message) {
|
||||||
|
return upd -> {
|
||||||
|
Message reply = upd.getMessage().getReplyToMessage();
|
||||||
|
return reply.hasText() && reply.getText().equalsIgnoreCase(message);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private Predicate<Update> isReplyToBot() {
|
||||||
|
return upd -> upd.getMessage().getReplyToMessage().getFrom().getUserName().equalsIgnoreCase(getBotUsername());
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
In this example, we showcase how we can supply our own predicates. The two new predicates are `isReplyToMessage` and `isReplyToBot`.
|
||||||
|
The checks are made so that, once you execute your logic there is no need to check for the validity of the reply.
|
||||||
|
They were all made once the action logic is being executed.
|
4
pom.xml
4
pom.xml
@ -7,7 +7,7 @@
|
|||||||
<groupId>org.telegram</groupId>
|
<groupId>org.telegram</groupId>
|
||||||
<artifactId>Bots</artifactId>
|
<artifactId>Bots</artifactId>
|
||||||
<packaging>pom</packaging>
|
<packaging>pom</packaging>
|
||||||
<version>3.4</version>
|
<version>3.5</version>
|
||||||
|
|
||||||
<modules>
|
<modules>
|
||||||
<module>telegrambots</module>
|
<module>telegrambots</module>
|
||||||
@ -26,6 +26,6 @@
|
|||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
<maven.deploy.skip>true</maven.deploy.skip>
|
<maven.deploy.skip>true</maven.deploy.skip>
|
||||||
<bots.version>3.4</bots.version>
|
<bots.version>3.5</bots.version>
|
||||||
</properties>
|
</properties>
|
||||||
</project>
|
</project>
|
@ -18,19 +18,19 @@ Usage
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.telegram</groupId>
|
<groupId>org.telegram</groupId>
|
||||||
<artifactId>telegrambots-abilities</artifactId>
|
<artifactId>telegrambots-abilities</artifactId>
|
||||||
<version>3.4</version>
|
<version>3.5</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
```
|
```
|
||||||
|
|
||||||
**Gradle**
|
**Gradle**
|
||||||
|
|
||||||
```gradle
|
```gradle
|
||||||
compile "org.telegram:telegrambots-abilities:3.4"
|
compile "org.telegram:telegrambots-abilities:3.5"
|
||||||
```
|
```
|
||||||
|
|
||||||
**JitPack** - [JitPack](https://jitpack.io/#rubenlagus/TelegramBots/v3.4)
|
**JitPack** - [JitPack](https://jitpack.io/#rubenlagus/TelegramBots/v3.5)
|
||||||
|
|
||||||
**Plain imports** - [Here](https://github.com/rubenlagus/TelegramBots/releases/tag/v3.4)
|
**Plain imports** - [Here](https://github.com/rubenlagus/TelegramBots/releases/tag/v3.5)
|
||||||
|
|
||||||
Motivation
|
Motivation
|
||||||
----------
|
----------
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
<groupId>org.telegram</groupId>
|
<groupId>org.telegram</groupId>
|
||||||
<artifactId>telegrambots-abilities</artifactId>
|
<artifactId>telegrambots-abilities</artifactId>
|
||||||
<version>3.4</version>
|
<version>3.5</version>
|
||||||
<packaging>jar</packaging>
|
<packaging>jar</packaging>
|
||||||
|
|
||||||
<name>Telegram Ability Bot</name>
|
<name>Telegram Ability Bot</name>
|
||||||
@ -65,7 +65,7 @@
|
|||||||
<properties>
|
<properties>
|
||||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
|
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
|
||||||
<bots.version>3.4</bots.version>
|
<bots.version>3.5</bots.version>
|
||||||
<commonslang.version>3.5</commonslang.version>
|
<commonslang.version>3.5</commonslang.version>
|
||||||
<mapdb.version>3.0.4</mapdb.version>
|
<mapdb.version>3.0.4</mapdb.version>
|
||||||
<guava.version>19.0</guava.version>
|
<guava.version>19.0</guava.version>
|
||||||
|
@ -3,8 +3,9 @@ package org.telegram.abilitybots.api.bot;
|
|||||||
import org.apache.commons.io.IOUtils;
|
import org.apache.commons.io.IOUtils;
|
||||||
import org.telegram.abilitybots.api.db.DBContext;
|
import org.telegram.abilitybots.api.db.DBContext;
|
||||||
import org.telegram.abilitybots.api.objects.*;
|
import org.telegram.abilitybots.api.objects.*;
|
||||||
import org.telegram.abilitybots.api.sender.DefaultMessageSender;
|
import org.telegram.abilitybots.api.sender.DefaultSender;
|
||||||
import org.telegram.abilitybots.api.sender.MessageSender;
|
import org.telegram.abilitybots.api.sender.MessageSender;
|
||||||
|
import org.telegram.abilitybots.api.sender.SilentSender;
|
||||||
import org.telegram.abilitybots.api.util.AbilityUtils;
|
import org.telegram.abilitybots.api.util.AbilityUtils;
|
||||||
import org.telegram.abilitybots.api.util.Pair;
|
import org.telegram.abilitybots.api.util.Pair;
|
||||||
import org.telegram.abilitybots.api.util.Trio;
|
import org.telegram.abilitybots.api.util.Trio;
|
||||||
@ -110,6 +111,7 @@ public abstract class AbilityBot extends TelegramLongPollingBot {
|
|||||||
// DB and sender
|
// DB and sender
|
||||||
protected final DBContext db;
|
protected final DBContext db;
|
||||||
protected MessageSender sender;
|
protected MessageSender sender;
|
||||||
|
protected SilentSender silent;
|
||||||
|
|
||||||
// Bot token and username
|
// Bot token and username
|
||||||
private final String botToken;
|
private final String botToken;
|
||||||
@ -121,13 +123,16 @@ public abstract class AbilityBot extends TelegramLongPollingBot {
|
|||||||
// Reply registry
|
// Reply registry
|
||||||
private List<Reply> replies;
|
private List<Reply> replies;
|
||||||
|
|
||||||
|
public abstract int creatorId();
|
||||||
|
|
||||||
protected AbilityBot(String botToken, String botUsername, DBContext db, DefaultBotOptions botOptions) {
|
protected AbilityBot(String botToken, String botUsername, DBContext db, DefaultBotOptions botOptions) {
|
||||||
super(botOptions);
|
super(botOptions);
|
||||||
|
|
||||||
this.botToken = botToken;
|
this.botToken = botToken;
|
||||||
this.botUsername = botUsername;
|
this.botUsername = botUsername;
|
||||||
this.db = db;
|
this.db = db;
|
||||||
this.sender = new DefaultMessageSender(this);
|
this.sender = new DefaultSender(this);
|
||||||
|
silent = new SilentSender(sender);
|
||||||
|
|
||||||
registerAbilities();
|
registerAbilities();
|
||||||
}
|
}
|
||||||
@ -144,8 +149,6 @@ public abstract class AbilityBot extends TelegramLongPollingBot {
|
|||||||
this(botToken, botUsername, onlineInstance(botUsername));
|
this(botToken, botUsername, onlineInstance(botUsername));
|
||||||
}
|
}
|
||||||
|
|
||||||
public abstract int creatorId();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the map of ID -> EndUser
|
* @return the map of ID -> EndUser
|
||||||
*/
|
*/
|
||||||
@ -217,15 +220,15 @@ public abstract class AbilityBot extends TelegramLongPollingBot {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test the update against the provided global flags. The default implementation requires a {@link Flag#MESSAGE}.
|
* Test the update against the provided global flags. The default implementation is a passthrough to all updates.
|
||||||
* <p>
|
* <p>
|
||||||
* This method should be <b>overridden</b> if the user wants updates that don't require a MESSAGE to pass through.
|
* This method should be <b>overridden</b> if the user wants to restrict bot usage to only certain updates.
|
||||||
*
|
*
|
||||||
* @param update a Telegram {@link Update}
|
* @param update a Telegram {@link Update}
|
||||||
* @return <tt>true</tt> if the update satisfies the global flags
|
* @return <tt>true</tt> if the update satisfies the global flags
|
||||||
*/
|
*/
|
||||||
protected boolean checkGlobalFlags(Update update) {
|
protected boolean checkGlobalFlags(Update update) {
|
||||||
return MESSAGE.test(update);
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -268,7 +271,7 @@ public abstract class AbilityBot extends TelegramLongPollingBot {
|
|||||||
try {
|
try {
|
||||||
return getUser(username).id();
|
return getUser(username).id();
|
||||||
} catch (IllegalStateException ex) {
|
} catch (IllegalStateException ex) {
|
||||||
sender.send(format("Sorry, I could not find the user [%s].", username), chatId);
|
silent.send(format("Sorry, I could not find the user [%s].", username), chatId);
|
||||||
throw propagate(ex);
|
throw propagate(ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -307,7 +310,7 @@ public abstract class AbilityBot extends TelegramLongPollingBot {
|
|||||||
.reduce((a, b) -> format("%s%n%s", a, b))
|
.reduce((a, b) -> format("%s%n%s", a, b))
|
||||||
.orElse("No public commands found.");
|
.orElse("No public commands found.");
|
||||||
|
|
||||||
sender.send(commands, ctx.chatId());
|
silent.send(commands, ctx.chatId());
|
||||||
})
|
})
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
@ -360,7 +363,7 @@ public abstract class AbilityBot extends TelegramLongPollingBot {
|
|||||||
.locality(USER)
|
.locality(USER)
|
||||||
.privacy(CREATOR)
|
.privacy(CREATOR)
|
||||||
.input(0)
|
.input(0)
|
||||||
.action(ctx -> sender.forceReply(RECOVERY_MESSAGE, ctx.chatId()))
|
.action(ctx -> silent.forceReply(RECOVERY_MESSAGE, ctx.chatId()))
|
||||||
.reply(update -> {
|
.reply(update -> {
|
||||||
Long chatId = update.getMessage().getChatId();
|
Long chatId = update.getMessage().getChatId();
|
||||||
String fileId = update.getMessage().getDocument().getFileId();
|
String fileId = update.getMessage().getDocument().getFileId();
|
||||||
@ -368,13 +371,13 @@ public abstract class AbilityBot extends TelegramLongPollingBot {
|
|||||||
try (FileReader reader = new FileReader(downloadFileWithId(fileId))) {
|
try (FileReader reader = new FileReader(downloadFileWithId(fileId))) {
|
||||||
String backupData = IOUtils.toString(reader);
|
String backupData = IOUtils.toString(reader);
|
||||||
if (db.recover(backupData)) {
|
if (db.recover(backupData)) {
|
||||||
sender.send(RECOVER_SUCCESS, chatId);
|
silent.send(RECOVER_SUCCESS, chatId);
|
||||||
} else {
|
} else {
|
||||||
sender.send("Oops, something went wrong during recovery.", chatId);
|
silent.send("Oops, something went wrong during recovery.", chatId);
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
BotLogger.error("Could not recover DB from backup", TAG, e);
|
BotLogger.error("Could not recover DB from backup", TAG, e);
|
||||||
sender.send("I have failed to recover.", chatId);
|
silent.send("I have failed to recover.", chatId);
|
||||||
}
|
}
|
||||||
}, MESSAGE, DOCUMENT, REPLY, isReplyTo(RECOVERY_MESSAGE))
|
}, MESSAGE, DOCUMENT, REPLY, isReplyTo(RECOVERY_MESSAGE))
|
||||||
.build();
|
.build();
|
||||||
@ -410,10 +413,10 @@ public abstract class AbilityBot extends TelegramLongPollingBot {
|
|||||||
|
|
||||||
Set<Integer> blacklist = blacklist();
|
Set<Integer> blacklist = blacklist();
|
||||||
if (blacklist.contains(userId))
|
if (blacklist.contains(userId))
|
||||||
sender.sendMd(format("%s is already *banned*.", bannedUser), ctx.chatId());
|
silent.sendMd(format("%s is already *banned*.", bannedUser), ctx.chatId());
|
||||||
else {
|
else {
|
||||||
blacklist.add(userId);
|
blacklist.add(userId);
|
||||||
sender.sendMd(format("%s is now *banned*.", bannedUser), ctx.chatId());
|
silent.sendMd(format("%s is now *banned*.", bannedUser), ctx.chatId());
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.post(commitTo(db))
|
.post(commitTo(db))
|
||||||
@ -438,9 +441,9 @@ public abstract class AbilityBot extends TelegramLongPollingBot {
|
|||||||
Set<Integer> blacklist = blacklist();
|
Set<Integer> blacklist = blacklist();
|
||||||
|
|
||||||
if (!blacklist.remove(userId))
|
if (!blacklist.remove(userId))
|
||||||
sender.sendMd(format("@%s is *not* on the *blacklist*.", username), ctx.chatId());
|
silent.sendMd(format("@%s is *not* on the *blacklist*.", username), ctx.chatId());
|
||||||
else {
|
else {
|
||||||
sender.sendMd(format("@%s, your ban has been *lifted*.", username), ctx.chatId());
|
silent.sendMd(format("@%s, your ban has been *lifted*.", username), ctx.chatId());
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.post(commitTo(db))
|
.post(commitTo(db))
|
||||||
@ -462,10 +465,10 @@ public abstract class AbilityBot extends TelegramLongPollingBot {
|
|||||||
|
|
||||||
Set<Integer> admins = admins();
|
Set<Integer> admins = admins();
|
||||||
if (admins.contains(userId))
|
if (admins.contains(userId))
|
||||||
sender.sendMd(format("@%s is already an *admin*.", username), ctx.chatId());
|
silent.sendMd(format("@%s is already an *admin*.", username), ctx.chatId());
|
||||||
else {
|
else {
|
||||||
admins.add(userId);
|
admins.add(userId);
|
||||||
sender.sendMd(format("@%s has been *promoted*.", username), ctx.chatId());
|
silent.sendMd(format("@%s has been *promoted*.", username), ctx.chatId());
|
||||||
}
|
}
|
||||||
}).post(commitTo(db))
|
}).post(commitTo(db))
|
||||||
.build();
|
.build();
|
||||||
@ -486,9 +489,9 @@ public abstract class AbilityBot extends TelegramLongPollingBot {
|
|||||||
|
|
||||||
Set<Integer> admins = admins();
|
Set<Integer> admins = admins();
|
||||||
if (admins.remove(userId)) {
|
if (admins.remove(userId)) {
|
||||||
sender.sendMd(format("@%s has been *demoted*.", username), ctx.chatId());
|
silent.sendMd(format("@%s has been *demoted*.", username), ctx.chatId());
|
||||||
} else {
|
} else {
|
||||||
sender.sendMd(format("@%s is *not* an *admin*.", username), ctx.chatId());
|
silent.sendMd(format("@%s is *not* an *admin*.", username), ctx.chatId());
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.post(commitTo(db))
|
.post(commitTo(db))
|
||||||
@ -513,10 +516,10 @@ public abstract class AbilityBot extends TelegramLongPollingBot {
|
|||||||
long chatId = ctx.chatId();
|
long chatId = ctx.chatId();
|
||||||
|
|
||||||
if (admins.contains(id))
|
if (admins.contains(id))
|
||||||
sender.send("You're already my master.", chatId);
|
silent.send("You're already my master.", chatId);
|
||||||
else {
|
else {
|
||||||
admins.add(id);
|
admins.add(id);
|
||||||
sender.send("You're now my master.", chatId);
|
silent.send("You're now my master.", chatId);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// This is not a joke
|
// This is not a joke
|
||||||
@ -614,7 +617,7 @@ public abstract class AbilityBot extends TelegramLongPollingBot {
|
|||||||
boolean isOk = abilityTokens == 0 || (tokens.length > 0 && tokens.length == abilityTokens);
|
boolean isOk = abilityTokens == 0 || (tokens.length > 0 && tokens.length == abilityTokens);
|
||||||
|
|
||||||
if (!isOk)
|
if (!isOk)
|
||||||
sender.send(String.format("Sorry, this feature requires %d additional %s.", abilityTokens, abilityTokens == 1 ? "input" : "inputs"), getChatId(trio.a()));
|
silent.send(String.format("Sorry, this feature requires %d additional %s.", abilityTokens, abilityTokens == 1 ? "input" : "inputs"), getChatId(trio.a()));
|
||||||
return isOk;
|
return isOk;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -626,7 +629,7 @@ public abstract class AbilityBot extends TelegramLongPollingBot {
|
|||||||
boolean isOk = abilityLocality == ALL || locality == abilityLocality;
|
boolean isOk = abilityLocality == ALL || locality == abilityLocality;
|
||||||
|
|
||||||
if (!isOk)
|
if (!isOk)
|
||||||
sender.send(String.format("Sorry, %s-only feature.", abilityLocality.toString().toLowerCase()), getChatId(trio.a()));
|
silent.send(String.format("Sorry, %s-only feature.", abilityLocality.toString().toLowerCase()), getChatId(trio.a()));
|
||||||
return isOk;
|
return isOk;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -641,7 +644,7 @@ public abstract class AbilityBot extends TelegramLongPollingBot {
|
|||||||
boolean isOk = privacy.compareTo(trio.b().privacy()) >= 0;
|
boolean isOk = privacy.compareTo(trio.b().privacy()) >= 0;
|
||||||
|
|
||||||
if (!isOk)
|
if (!isOk)
|
||||||
sender.send(String.format("Sorry, %s-only feature.", trio.b().privacy().toString().toLowerCase()), getChatId(trio.a()));
|
silent.send(String.format("Sorry, %s-only feature.", trio.b().privacy().toString().toLowerCase()), getChatId(trio.a()));
|
||||||
return isOk;
|
return isOk;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -738,6 +741,6 @@ public abstract class AbilityBot extends TelegramLongPollingBot {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private File downloadFileWithId(String fileId) throws TelegramApiException {
|
private File downloadFileWithId(String fileId) throws TelegramApiException {
|
||||||
return sender.downloadFile(sender.getFile(new GetFile().setFileId(fileId)));
|
return sender.downloadFile(sender.execute(new GetFile().setFileId(fileId)));
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -149,7 +149,7 @@ public final class Ability {
|
|||||||
private Consumer<MessageContext> consumer;
|
private Consumer<MessageContext> consumer;
|
||||||
private Consumer<MessageContext> postConsumer;
|
private Consumer<MessageContext> postConsumer;
|
||||||
private List<Reply> replies;
|
private List<Reply> replies;
|
||||||
private Flag[] flags;
|
private Predicate<Update>[] flags;
|
||||||
|
|
||||||
private AbilityBuilder() {
|
private AbilityBuilder() {
|
||||||
replies = newArrayList();
|
replies = newArrayList();
|
||||||
@ -170,7 +170,7 @@ public final class Ability {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public AbilityBuilder flag(Flag... flags) {
|
public AbilityBuilder flag(Predicate<Update>... flags) {
|
||||||
this.flags = flags;
|
this.flags = flags;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
@ -1,493 +0,0 @@
|
|||||||
package org.telegram.abilitybots.api.sender;
|
|
||||||
|
|
||||||
import org.telegram.telegrambots.api.methods.*;
|
|
||||||
import org.telegram.telegrambots.api.methods.games.GetGameHighScores;
|
|
||||||
import org.telegram.telegrambots.api.methods.games.SetGameScore;
|
|
||||||
import org.telegram.telegrambots.api.methods.groupadministration.*;
|
|
||||||
import org.telegram.telegrambots.api.methods.pinnedmessages.PinChatMessage;
|
|
||||||
import org.telegram.telegrambots.api.methods.pinnedmessages.UnpinChatMessage;
|
|
||||||
import org.telegram.telegrambots.api.methods.send.*;
|
|
||||||
import org.telegram.telegrambots.api.methods.updates.DeleteWebhook;
|
|
||||||
import org.telegram.telegrambots.api.methods.updatingmessages.DeleteMessage;
|
|
||||||
import org.telegram.telegrambots.api.methods.updatingmessages.EditMessageCaption;
|
|
||||||
import org.telegram.telegrambots.api.methods.updatingmessages.EditMessageReplyMarkup;
|
|
||||||
import org.telegram.telegrambots.api.methods.updatingmessages.EditMessageText;
|
|
||||||
import org.telegram.telegrambots.api.objects.*;
|
|
||||||
import org.telegram.telegrambots.api.objects.games.GameHighScore;
|
|
||||||
import org.telegram.telegrambots.api.objects.replykeyboard.ForceReplyKeyboard;
|
|
||||||
import org.telegram.telegrambots.bots.DefaultAbsSender;
|
|
||||||
import org.telegram.telegrambots.exceptions.TelegramApiException;
|
|
||||||
import org.telegram.telegrambots.logging.BotLogger;
|
|
||||||
import org.telegram.telegrambots.updateshandlers.DownloadFileCallback;
|
|
||||||
import org.telegram.telegrambots.updateshandlers.SentCallback;
|
|
||||||
|
|
||||||
import java.io.Serializable;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Optional;
|
|
||||||
|
|
||||||
import static java.util.Optional.empty;
|
|
||||||
import static java.util.Optional.ofNullable;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The default implementation of the {@link MessageSender}. This serves as a proxy to the {@link DefaultAbsSender} methods.
|
|
||||||
* <p>Most of the methods below will be directly calling the bot's similar functions. However, there are some methods introduced to ease sending messages such as:</p>
|
|
||||||
* <ol>
|
|
||||||
* <li>{@link DefaultMessageSender#sendMd(String, long)} - with markdown</li>
|
|
||||||
* <li>{@link DefaultMessageSender#send(String, long)} - without markdown</li>
|
|
||||||
* </ol>
|
|
||||||
*
|
|
||||||
* @author Abbas Abou Daya
|
|
||||||
*/
|
|
||||||
public class DefaultMessageSender implements MessageSender {
|
|
||||||
private static final String TAG = MessageSender.class.getName();
|
|
||||||
|
|
||||||
private DefaultAbsSender bot;
|
|
||||||
|
|
||||||
public DefaultMessageSender(DefaultAbsSender bot) {
|
|
||||||
this.bot = bot;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Optional<Message> send(String message, long id) {
|
|
||||||
return doSendMessage(message, id, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Optional<Message> sendMd(String message, long id) {
|
|
||||||
return doSendMessage(message, id, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Optional<Message> forceReply(String message, long id) {
|
|
||||||
SendMessage msg = new SendMessage();
|
|
||||||
msg.setText(message);
|
|
||||||
msg.setChatId(id);
|
|
||||||
msg.setReplyMarkup(new ForceReplyKeyboard());
|
|
||||||
|
|
||||||
return optionalSendMessage(msg);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Boolean answerInlineQuery(AnswerInlineQuery answerInlineQuery) throws TelegramApiException {
|
|
||||||
return bot.execute(answerInlineQuery);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Boolean sendChatAction(SendChatAction sendChatAction) throws TelegramApiException {
|
|
||||||
return bot.execute(sendChatAction);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Message forwardMessage(ForwardMessage forwardMessage) throws TelegramApiException {
|
|
||||||
return bot.execute(forwardMessage);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Message sendLocation(SendLocation sendLocation) throws TelegramApiException {
|
|
||||||
return bot.execute(sendLocation);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Message sendVenue(SendVenue sendVenue) throws TelegramApiException {
|
|
||||||
return bot.execute(sendVenue);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Message sendContact(SendContact sendContact) throws TelegramApiException {
|
|
||||||
return bot.execute(sendContact);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Boolean kickMember(KickChatMember kickChatMember) throws TelegramApiException {
|
|
||||||
return bot.execute(kickChatMember);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Boolean unbanMember(UnbanChatMember unbanChatMember) throws TelegramApiException {
|
|
||||||
return bot.execute(unbanChatMember);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Boolean leaveChat(LeaveChat leaveChat) throws TelegramApiException {
|
|
||||||
return bot.execute(leaveChat);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Chat getChat(GetChat getChat) throws TelegramApiException {
|
|
||||||
return bot.execute(getChat);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<ChatMember> getChatAdministrators(GetChatAdministrators getChatAdministrators) throws TelegramApiException {
|
|
||||||
return bot.execute(getChatAdministrators);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public ChatMember getChatMember(GetChatMember getChatMember) throws TelegramApiException {
|
|
||||||
return bot.execute(getChatMember);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Integer getChatMemberCount(GetChatMemberCount getChatMemberCount) throws TelegramApiException {
|
|
||||||
return bot.execute(getChatMemberCount);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Boolean setChatPhoto(SetChatPhoto setChatPhoto) throws TelegramApiException {
|
|
||||||
return bot.setChatPhoto(setChatPhoto);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Boolean deleteChatPhoto(DeleteChatPhoto deleteChatPhoto) throws TelegramApiException {
|
|
||||||
return bot.execute(deleteChatPhoto);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void deleteChatPhoto(DeleteChatPhoto deleteChatPhoto, SentCallback<Boolean> sentCallback) throws TelegramApiException {
|
|
||||||
bot.executeAsync(deleteChatPhoto, sentCallback);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Boolean pinChatMessage(PinChatMessage pinChatMessage) throws TelegramApiException {
|
|
||||||
return bot.execute(pinChatMessage);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void pinChatMessage(PinChatMessage pinChatMessage, SentCallback<Boolean> sentCallback) throws TelegramApiException {
|
|
||||||
bot.executeAsync(pinChatMessage, sentCallback);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Boolean unpinChatMessage(UnpinChatMessage unpinChatMessage) throws TelegramApiException {
|
|
||||||
return bot.execute(unpinChatMessage);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void unpinChatMessage(UnpinChatMessage unpinChatMessage, SentCallback<Boolean> sentCallback) throws TelegramApiException {
|
|
||||||
bot.executeAsync(unpinChatMessage, sentCallback);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Boolean promoteChatMember(PromoteChatMember promoteChatMember) throws TelegramApiException {
|
|
||||||
return bot.execute(promoteChatMember);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void promoteChatMember(PromoteChatMember promoteChatMember, SentCallback<Boolean> sentCallback) throws TelegramApiException {
|
|
||||||
bot.executeAsync(promoteChatMember, sentCallback);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Boolean restrictChatMember(RestrictChatMember restrictChatMember) throws TelegramApiException {
|
|
||||||
return bot.execute(restrictChatMember);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void restrictChatMember(RestrictChatMember restrictChatMember, SentCallback<Boolean> sentCallback) throws TelegramApiException {
|
|
||||||
bot.executeAsync(restrictChatMember, sentCallback);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Boolean setChatDescription(SetChatDescription setChatDescription) throws TelegramApiException {
|
|
||||||
return bot.execute(setChatDescription);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setChatDescription(SetChatDescription setChatDescription, SentCallback<Boolean> sentCallback) throws TelegramApiException {
|
|
||||||
bot.executeAsync(setChatDescription, sentCallback);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Boolean setChatTite(SetChatTitle setChatTitle) throws TelegramApiException {
|
|
||||||
return bot.execute(setChatTitle);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setChatTite(SetChatTitle setChatTitle, SentCallback<Boolean> sentCallback) throws TelegramApiException {
|
|
||||||
bot.executeAsync(setChatTitle, sentCallback);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String exportChatInviteLink(ExportChatInviteLink exportChatInviteLink) throws TelegramApiException {
|
|
||||||
return bot.execute(exportChatInviteLink);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void exportChatInviteLinkAsync(ExportChatInviteLink exportChatInviteLink, SentCallback<String> sentCallback) throws TelegramApiException {
|
|
||||||
bot.executeAsync(exportChatInviteLink, sentCallback);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Boolean deleteMessage(DeleteMessage deleteMessage) throws TelegramApiException {
|
|
||||||
return bot.execute(deleteMessage);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void deleteMessageAsync(DeleteMessage deleteMessage, SentCallback<Boolean> sentCallback) throws TelegramApiException {
|
|
||||||
bot.executeAsync(deleteMessage, sentCallback);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Serializable editMessageText(EditMessageText editMessageText) throws TelegramApiException {
|
|
||||||
return bot.execute(editMessageText);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Serializable editMessageCaption(EditMessageCaption editMessageCaption) throws TelegramApiException {
|
|
||||||
return bot.execute(editMessageCaption);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Serializable editMessageReplyMarkup(EditMessageReplyMarkup editMessageReplyMarkup) throws TelegramApiException {
|
|
||||||
return bot.execute(editMessageReplyMarkup);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Boolean answerCallbackQuery(AnswerCallbackQuery answerCallbackQuery) throws TelegramApiException {
|
|
||||||
return bot.execute(answerCallbackQuery);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public UserProfilePhotos getUserProfilePhotos(GetUserProfilePhotos getUserProfilePhotos) throws TelegramApiException {
|
|
||||||
return bot.execute(getUserProfilePhotos);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public java.io.File downloadFile(String path) throws TelegramApiException {
|
|
||||||
return bot.downloadFile(path);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void downloadFileAsync(String path, DownloadFileCallback<String> callback) throws TelegramApiException {
|
|
||||||
bot.downloadFileAsync(path, callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public java.io.File downloadFile(File file) throws TelegramApiException {
|
|
||||||
return bot.downloadFile(file);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void downloadFileAsync(File file, DownloadFileCallback<File> callback) throws TelegramApiException {
|
|
||||||
bot.downloadFileAsync(file, callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public File getFile(GetFile getFile) throws TelegramApiException {
|
|
||||||
return bot.execute(getFile);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public User getMe() throws TelegramApiException {
|
|
||||||
return bot.getMe();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public WebhookInfo getWebhookInfo() throws TelegramApiException {
|
|
||||||
return bot.getWebhookInfo();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Serializable setGameScore(SetGameScore setGameScore) throws TelegramApiException {
|
|
||||||
return bot.execute(setGameScore);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Serializable getGameHighScores(GetGameHighScores getGameHighScores) throws TelegramApiException {
|
|
||||||
return bot.execute(getGameHighScores);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Message sendGame(SendGame sendGame) throws TelegramApiException {
|
|
||||||
return bot.execute(sendGame);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Boolean deleteWebhook(DeleteWebhook deleteWebhook) throws TelegramApiException {
|
|
||||||
return bot.execute(deleteWebhook);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Message sendMessage(SendMessage sendMessage) throws TelegramApiException {
|
|
||||||
return bot.execute(sendMessage);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void sendMessageAsync(SendMessage sendMessage, SentCallback<Message> sentCallback) throws TelegramApiException {
|
|
||||||
bot.executeAsync(sendMessage, sentCallback);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void answerInlineQueryAsync(AnswerInlineQuery answerInlineQuery, SentCallback<Boolean> sentCallback) throws TelegramApiException {
|
|
||||||
bot.executeAsync(answerInlineQuery, sentCallback);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void sendChatActionAsync(SendChatAction sendChatAction, SentCallback<Boolean> sentCallback) throws TelegramApiException {
|
|
||||||
bot.executeAsync(sendChatAction, sentCallback);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void forwardMessageAsync(ForwardMessage forwardMessage, SentCallback<Message> sentCallback) throws TelegramApiException {
|
|
||||||
bot.executeAsync(forwardMessage, sentCallback);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void sendLocationAsync(SendLocation sendLocation, SentCallback<Message> sentCallback) throws TelegramApiException {
|
|
||||||
bot.executeAsync(sendLocation, sentCallback);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void sendVenueAsync(SendVenue sendVenue, SentCallback<Message> sentCallback) throws TelegramApiException {
|
|
||||||
bot.executeAsync(sendVenue, sentCallback);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void sendContactAsync(SendContact sendContact, SentCallback<Message> sentCallback) throws TelegramApiException {
|
|
||||||
bot.executeAsync(sendContact, sentCallback);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void kickMemberAsync(KickChatMember kickChatMember, SentCallback<Boolean> sentCallback) throws TelegramApiException {
|
|
||||||
bot.executeAsync(kickChatMember, sentCallback);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void unbanMemberAsync(UnbanChatMember unbanChatMember, SentCallback<Boolean> sentCallback) throws TelegramApiException {
|
|
||||||
bot.executeAsync(unbanChatMember, sentCallback);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void leaveChatAsync(LeaveChat leaveChat, SentCallback<Boolean> sentCallback) throws TelegramApiException {
|
|
||||||
bot.executeAsync(leaveChat, sentCallback);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void getChatAsync(GetChat getChat, SentCallback<Chat> sentCallback) throws TelegramApiException {
|
|
||||||
bot.executeAsync(getChat, sentCallback);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void getChatAdministratorsAsync(GetChatAdministrators getChatAdministrators, SentCallback<ArrayList<ChatMember>> sentCallback) throws TelegramApiException {
|
|
||||||
bot.executeAsync(getChatAdministrators, sentCallback);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void getChatMemberAsync(GetChatMember getChatMember, SentCallback<ChatMember> sentCallback) throws TelegramApiException {
|
|
||||||
bot.executeAsync(getChatMember, sentCallback);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void getChatMemberCountAsync(GetChatMemberCount getChatMemberCount, SentCallback<Integer> sentCallback) throws TelegramApiException {
|
|
||||||
bot.executeAsync(getChatMemberCount, sentCallback);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void editMessageTextAsync(EditMessageText editMessageText, SentCallback<Serializable> sentCallback) throws TelegramApiException {
|
|
||||||
bot.executeAsync(editMessageText, sentCallback);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void editMessageCaptionAsync(EditMessageCaption editMessageCaption, SentCallback<Serializable> sentCallback) throws TelegramApiException {
|
|
||||||
bot.executeAsync(editMessageCaption, sentCallback);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void editMessageReplyMarkup(EditMessageReplyMarkup editMessageReplyMarkup, SentCallback<Serializable> sentCallback) throws TelegramApiException {
|
|
||||||
bot.executeAsync(editMessageReplyMarkup, sentCallback);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void answerCallbackQueryAsync(AnswerCallbackQuery answerCallbackQuery, SentCallback<Boolean> sentCallback) throws TelegramApiException {
|
|
||||||
bot.executeAsync(answerCallbackQuery, sentCallback);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void getUserProfilePhotosAsync(GetUserProfilePhotos getUserProfilePhotos, SentCallback<UserProfilePhotos> sentCallback) throws TelegramApiException {
|
|
||||||
bot.executeAsync(getUserProfilePhotos, sentCallback);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void getFileAsync(GetFile getFile, SentCallback<File> sentCallback) throws TelegramApiException {
|
|
||||||
bot.executeAsync(getFile, sentCallback);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void getMeAsync(SentCallback<User> sentCallback) throws TelegramApiException {
|
|
||||||
bot.getMeAsync(sentCallback);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void getWebhookInfoAsync(SentCallback<WebhookInfo> sentCallback) throws TelegramApiException {
|
|
||||||
bot.getWebhookInfoAsync(sentCallback);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setGameScoreAsync(SetGameScore setGameScore, SentCallback<Serializable> sentCallback) throws TelegramApiException {
|
|
||||||
bot.executeAsync(setGameScore, sentCallback);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void getGameHighScoresAsync(GetGameHighScores getGameHighScores, SentCallback<ArrayList<GameHighScore>> sentCallback) throws TelegramApiException {
|
|
||||||
bot.executeAsync(getGameHighScores, sentCallback);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void sendGameAsync(SendGame sendGame, SentCallback<Message> sentCallback) throws TelegramApiException {
|
|
||||||
bot.executeAsync(sendGame, sentCallback);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void deleteWebhook(DeleteWebhook deleteWebhook, SentCallback<Boolean> sentCallback) throws TelegramApiException {
|
|
||||||
bot.executeAsync(deleteWebhook, sentCallback);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Message sendDocument(SendDocument sendDocument) throws TelegramApiException {
|
|
||||||
return bot.sendDocument(sendDocument);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Message sendPhoto(SendPhoto sendPhoto) throws TelegramApiException {
|
|
||||||
return bot.sendPhoto(sendPhoto);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Message sendVideo(SendVideo sendVideo) throws TelegramApiException {
|
|
||||||
return bot.sendVideo(sendVideo);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Message sendSticker(SendSticker sendSticker) throws TelegramApiException {
|
|
||||||
return bot.sendSticker(sendSticker);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Message sendAudio(SendAudio sendAudio) throws TelegramApiException {
|
|
||||||
return bot.sendAudio(sendAudio);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Message sendVoice(SendVoice sendVoice) throws TelegramApiException {
|
|
||||||
return bot.sendVoice(sendVoice);
|
|
||||||
}
|
|
||||||
|
|
||||||
private Optional<Message> doSendMessage(String txt, long groupId, boolean format) {
|
|
||||||
SendMessage smsg = new SendMessage();
|
|
||||||
smsg.setChatId(groupId);
|
|
||||||
smsg.setText(txt);
|
|
||||||
smsg.enableMarkdown(format);
|
|
||||||
|
|
||||||
return optionalSendMessage(smsg);
|
|
||||||
}
|
|
||||||
|
|
||||||
private Optional<Message> optionalSendMessage(SendMessage smsg) {
|
|
||||||
try {
|
|
||||||
return ofNullable(sendMessage(smsg));
|
|
||||||
} catch (TelegramApiException e) {
|
|
||||||
BotLogger.error("Could not send message", TAG, e);
|
|
||||||
return empty();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,139 @@
|
|||||||
|
package org.telegram.abilitybots.api.sender;
|
||||||
|
|
||||||
|
import org.telegram.telegrambots.api.methods.BotApiMethod;
|
||||||
|
import org.telegram.telegrambots.api.methods.groupadministration.SetChatPhoto;
|
||||||
|
import org.telegram.telegrambots.api.methods.send.*;
|
||||||
|
import org.telegram.telegrambots.api.methods.stickers.AddStickerToSet;
|
||||||
|
import org.telegram.telegrambots.api.methods.stickers.CreateNewStickerSet;
|
||||||
|
import org.telegram.telegrambots.api.methods.stickers.UploadStickerFile;
|
||||||
|
import org.telegram.telegrambots.api.objects.File;
|
||||||
|
import org.telegram.telegrambots.api.objects.Message;
|
||||||
|
import org.telegram.telegrambots.api.objects.User;
|
||||||
|
import org.telegram.telegrambots.api.objects.WebhookInfo;
|
||||||
|
import org.telegram.telegrambots.bots.DefaultAbsSender;
|
||||||
|
import org.telegram.telegrambots.exceptions.TelegramApiException;
|
||||||
|
import org.telegram.telegrambots.updateshandlers.DownloadFileCallback;
|
||||||
|
import org.telegram.telegrambots.updateshandlers.SentCallback;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The default implementation of the {@link MessageSender}. This serves as a proxy to the {@link DefaultAbsSender} methods.
|
||||||
|
*
|
||||||
|
* @author Abbas Abou Daya
|
||||||
|
*/
|
||||||
|
public class DefaultSender implements MessageSender {
|
||||||
|
private static final String TAG = MessageSender.class.getName();
|
||||||
|
|
||||||
|
private DefaultAbsSender bot;
|
||||||
|
|
||||||
|
public DefaultSender(DefaultAbsSender bot) {
|
||||||
|
this.bot = bot;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <T extends Serializable, Method extends BotApiMethod<T>, Callback extends SentCallback<T>> void executeAsync(Method method, Callback callback) throws TelegramApiException {
|
||||||
|
bot.executeAsync(method, callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <T extends Serializable, Method extends BotApiMethod<T>> T execute(Method method) throws TelegramApiException {
|
||||||
|
return bot.execute(method);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Boolean addStickerToSet(AddStickerToSet addStickerToSet) throws TelegramApiException {
|
||||||
|
return bot.addStickerToSet(addStickerToSet);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Boolean createNewStickerSet(CreateNewStickerSet createNewStickerSet) throws TelegramApiException {
|
||||||
|
return bot.createNewStickerSet(createNewStickerSet);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public File uploadStickerFile(UploadStickerFile uploadStickerFile) throws TelegramApiException {
|
||||||
|
return bot.uploadStickerFile(uploadStickerFile);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Boolean setChatPhoto(SetChatPhoto setChatPhoto) throws TelegramApiException {
|
||||||
|
return bot.setChatPhoto(setChatPhoto);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public java.io.File downloadFile(String path) throws TelegramApiException {
|
||||||
|
return bot.downloadFile(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void downloadFileAsync(String path, DownloadFileCallback<String> callback) throws TelegramApiException {
|
||||||
|
bot.downloadFileAsync(path, callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public java.io.File downloadFile(File file) throws TelegramApiException {
|
||||||
|
return bot.downloadFile(file);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void downloadFileAsync(File file, DownloadFileCallback<File> callback) throws TelegramApiException {
|
||||||
|
bot.downloadFileAsync(file, callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public User getMe() throws TelegramApiException {
|
||||||
|
return bot.getMe();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public WebhookInfo getWebhookInfo() throws TelegramApiException {
|
||||||
|
return bot.getWebhookInfo();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void getMeAsync(SentCallback<User> sentCallback) throws TelegramApiException {
|
||||||
|
bot.getMeAsync(sentCallback);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void getWebhookInfoAsync(SentCallback<WebhookInfo> sentCallback) throws TelegramApiException {
|
||||||
|
bot.getWebhookInfoAsync(sentCallback);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Message sendDocument(SendDocument sendDocument) throws TelegramApiException {
|
||||||
|
return bot.sendDocument(sendDocument);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Message sendPhoto(SendPhoto sendPhoto) throws TelegramApiException {
|
||||||
|
return bot.sendPhoto(sendPhoto);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Message sendVideo(SendVideo sendVideo) throws TelegramApiException {
|
||||||
|
return bot.sendVideo(sendVideo);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Message sendSticker(SendSticker sendSticker) throws TelegramApiException {
|
||||||
|
return bot.sendSticker(sendSticker);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Message sendAudio(SendAudio sendAudio) throws TelegramApiException {
|
||||||
|
return bot.sendAudio(sendAudio);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Message sendVoice(SendVoice sendVoice) throws TelegramApiException {
|
||||||
|
return bot.sendVoice(sendVoice);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Message sendVideoNote(SendVideoNote sendVideoNote) throws TelegramApiException {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
@ -1,28 +1,21 @@
|
|||||||
package org.telegram.abilitybots.api.sender;
|
package org.telegram.abilitybots.api.sender;
|
||||||
|
|
||||||
import org.telegram.telegrambots.api.methods.*;
|
import org.telegram.telegrambots.api.methods.BotApiMethod;
|
||||||
import org.telegram.telegrambots.api.methods.games.GetGameHighScores;
|
import org.telegram.telegrambots.api.methods.groupadministration.SetChatPhoto;
|
||||||
import org.telegram.telegrambots.api.methods.games.SetGameScore;
|
|
||||||
import org.telegram.telegrambots.api.methods.groupadministration.*;
|
|
||||||
import org.telegram.telegrambots.api.methods.pinnedmessages.PinChatMessage;
|
|
||||||
import org.telegram.telegrambots.api.methods.pinnedmessages.UnpinChatMessage;
|
|
||||||
import org.telegram.telegrambots.api.methods.send.*;
|
import org.telegram.telegrambots.api.methods.send.*;
|
||||||
import org.telegram.telegrambots.api.methods.updates.DeleteWebhook;
|
import org.telegram.telegrambots.api.methods.stickers.AddStickerToSet;
|
||||||
import org.telegram.telegrambots.api.methods.updatingmessages.DeleteMessage;
|
import org.telegram.telegrambots.api.methods.stickers.CreateNewStickerSet;
|
||||||
import org.telegram.telegrambots.api.methods.updatingmessages.EditMessageCaption;
|
import org.telegram.telegrambots.api.methods.stickers.UploadStickerFile;
|
||||||
import org.telegram.telegrambots.api.methods.updatingmessages.EditMessageReplyMarkup;
|
import org.telegram.telegrambots.api.objects.File;
|
||||||
import org.telegram.telegrambots.api.methods.updatingmessages.EditMessageText;
|
import org.telegram.telegrambots.api.objects.Message;
|
||||||
import org.telegram.telegrambots.api.objects.*;
|
import org.telegram.telegrambots.api.objects.User;
|
||||||
import org.telegram.telegrambots.api.objects.games.GameHighScore;
|
import org.telegram.telegrambots.api.objects.WebhookInfo;
|
||||||
import org.telegram.telegrambots.bots.DefaultAbsSender;
|
import org.telegram.telegrambots.bots.DefaultAbsSender;
|
||||||
import org.telegram.telegrambots.exceptions.TelegramApiException;
|
import org.telegram.telegrambots.exceptions.TelegramApiException;
|
||||||
import org.telegram.telegrambots.updateshandlers.DownloadFileCallback;
|
import org.telegram.telegrambots.updateshandlers.DownloadFileCallback;
|
||||||
import org.telegram.telegrambots.updateshandlers.SentCallback;
|
import org.telegram.telegrambots.updateshandlers.SentCallback;
|
||||||
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Optional;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A sender interface that replicates {@link DefaultAbsSender} methods.
|
* A sender interface that replicates {@link DefaultAbsSender} methods.
|
||||||
@ -30,86 +23,19 @@ import java.util.Optional;
|
|||||||
* @author Abbas Abou Daya
|
* @author Abbas Abou Daya
|
||||||
*/
|
*/
|
||||||
public interface MessageSender {
|
public interface MessageSender {
|
||||||
Optional<Message> send(String message, long id);
|
|
||||||
|
|
||||||
Optional<Message> sendMd(String message, long id);
|
<T extends Serializable, Method extends BotApiMethod<T>, Callback extends SentCallback<T>> void executeAsync(Method method, Callback callback) throws TelegramApiException;
|
||||||
|
|
||||||
Optional<Message> forceReply(String message, long id);
|
<T extends Serializable, Method extends BotApiMethod<T>> T execute(Method method) throws TelegramApiException;
|
||||||
|
|
||||||
Boolean answerInlineQuery(AnswerInlineQuery answerInlineQuery) throws TelegramApiException;
|
Boolean addStickerToSet(AddStickerToSet addStickerToSet) throws TelegramApiException;
|
||||||
|
|
||||||
Boolean sendChatAction(SendChatAction sendChatAction) throws TelegramApiException;
|
public Boolean createNewStickerSet(CreateNewStickerSet createNewStickerSet) throws TelegramApiException;
|
||||||
|
|
||||||
Message forwardMessage(ForwardMessage forwardMessage) throws TelegramApiException;
|
public File uploadStickerFile(UploadStickerFile uploadStickerFile) throws TelegramApiException;
|
||||||
|
|
||||||
Message sendLocation(SendLocation sendLocation) throws TelegramApiException;
|
|
||||||
|
|
||||||
Message sendVenue(SendVenue sendVenue) throws TelegramApiException;
|
|
||||||
|
|
||||||
Message sendContact(SendContact sendContact) throws TelegramApiException;
|
|
||||||
|
|
||||||
Boolean kickMember(KickChatMember kickChatMember) throws TelegramApiException;
|
|
||||||
|
|
||||||
Boolean unbanMember(UnbanChatMember unbanChatMember) throws TelegramApiException;
|
|
||||||
|
|
||||||
Boolean leaveChat(LeaveChat leaveChat) throws TelegramApiException;
|
|
||||||
|
|
||||||
Chat getChat(GetChat getChat) throws TelegramApiException;
|
|
||||||
|
|
||||||
List<ChatMember> getChatAdministrators(GetChatAdministrators getChatAdministrators) throws TelegramApiException;
|
|
||||||
|
|
||||||
ChatMember getChatMember(GetChatMember getChatMember) throws TelegramApiException;
|
|
||||||
|
|
||||||
Integer getChatMemberCount(GetChatMemberCount getChatMemberCount) throws TelegramApiException;
|
|
||||||
|
|
||||||
Boolean setChatPhoto(SetChatPhoto setChatPhoto) throws TelegramApiException;
|
Boolean setChatPhoto(SetChatPhoto setChatPhoto) throws TelegramApiException;
|
||||||
|
|
||||||
Boolean deleteChatPhoto(DeleteChatPhoto deleteChatPhoto) throws TelegramApiException;
|
|
||||||
|
|
||||||
void deleteChatPhoto(DeleteChatPhoto deleteChatPhoto, SentCallback<Boolean> sentCallback) throws TelegramApiException;
|
|
||||||
|
|
||||||
Boolean pinChatMessage(PinChatMessage pinChatMessage) throws TelegramApiException;
|
|
||||||
|
|
||||||
void pinChatMessage(PinChatMessage pinChatMessage, SentCallback<Boolean> sentCallback) throws TelegramApiException;
|
|
||||||
|
|
||||||
Boolean unpinChatMessage(UnpinChatMessage unpinChatMessage) throws TelegramApiException;
|
|
||||||
|
|
||||||
void unpinChatMessage(UnpinChatMessage unpinChatMessage, SentCallback<Boolean> sentCallback) throws TelegramApiException;
|
|
||||||
|
|
||||||
Boolean promoteChatMember(PromoteChatMember promoteChatMember) throws TelegramApiException;
|
|
||||||
|
|
||||||
void promoteChatMember(PromoteChatMember promoteChatMember, SentCallback<Boolean> sentCallback) throws TelegramApiException;
|
|
||||||
|
|
||||||
Boolean restrictChatMember(RestrictChatMember restrictChatMember) throws TelegramApiException;
|
|
||||||
|
|
||||||
void restrictChatMember(RestrictChatMember restrictChatMember, SentCallback<Boolean> sentCallback) throws TelegramApiException;
|
|
||||||
|
|
||||||
Boolean setChatDescription(SetChatDescription setChatDescription) throws TelegramApiException;
|
|
||||||
|
|
||||||
void setChatDescription(SetChatDescription setChatDescription, SentCallback<Boolean> sentCallback) throws TelegramApiException;
|
|
||||||
|
|
||||||
Boolean setChatTite(SetChatTitle setChatTitle) throws TelegramApiException;
|
|
||||||
|
|
||||||
void setChatTite(SetChatTitle setChatTitle, SentCallback<Boolean> sentCallback) throws TelegramApiException;
|
|
||||||
|
|
||||||
String exportChatInviteLink(ExportChatInviteLink exportChatInviteLink) throws TelegramApiException;
|
|
||||||
|
|
||||||
void exportChatInviteLinkAsync(ExportChatInviteLink exportChatInviteLink, SentCallback<String> sentCallback) throws TelegramApiException;
|
|
||||||
|
|
||||||
Boolean deleteMessage(DeleteMessage deleteMessage) throws TelegramApiException;
|
|
||||||
|
|
||||||
void deleteMessageAsync(DeleteMessage deleteMessage, SentCallback<Boolean> sentCallback) throws TelegramApiException;
|
|
||||||
|
|
||||||
Serializable editMessageText(EditMessageText editMessageText) throws TelegramApiException;
|
|
||||||
|
|
||||||
Serializable editMessageCaption(EditMessageCaption editMessageCaption) throws TelegramApiException;
|
|
||||||
|
|
||||||
Serializable editMessageReplyMarkup(EditMessageReplyMarkup editMessageReplyMarkup) throws TelegramApiException;
|
|
||||||
|
|
||||||
Boolean answerCallbackQuery(AnswerCallbackQuery answerCallbackQuery) throws TelegramApiException;
|
|
||||||
|
|
||||||
UserProfilePhotos getUserProfilePhotos(GetUserProfilePhotos getUserProfilePhotos) throws TelegramApiException;
|
|
||||||
|
|
||||||
java.io.File downloadFile(String path) throws TelegramApiException;
|
java.io.File downloadFile(String path) throws TelegramApiException;
|
||||||
|
|
||||||
void downloadFileAsync(String path, DownloadFileCallback<String> callback) throws TelegramApiException;
|
void downloadFileAsync(String path, DownloadFileCallback<String> callback) throws TelegramApiException;
|
||||||
@ -118,83 +44,25 @@ public interface MessageSender {
|
|||||||
|
|
||||||
void downloadFileAsync(File file, DownloadFileCallback<File> callback) throws TelegramApiException;
|
void downloadFileAsync(File file, DownloadFileCallback<File> callback) throws TelegramApiException;
|
||||||
|
|
||||||
File getFile(GetFile getFile) throws TelegramApiException;
|
|
||||||
|
|
||||||
User getMe() throws TelegramApiException;
|
User getMe() throws TelegramApiException;
|
||||||
|
|
||||||
WebhookInfo getWebhookInfo() throws TelegramApiException;
|
WebhookInfo getWebhookInfo() throws TelegramApiException;
|
||||||
|
|
||||||
Serializable setGameScore(SetGameScore setGameScore) throws TelegramApiException;
|
|
||||||
|
|
||||||
Serializable getGameHighScores(GetGameHighScores getGameHighScores) throws TelegramApiException;
|
|
||||||
|
|
||||||
Message sendGame(SendGame sendGame) throws TelegramApiException;
|
|
||||||
|
|
||||||
Boolean deleteWebhook(DeleteWebhook deleteWebhook) throws TelegramApiException;
|
|
||||||
|
|
||||||
Message sendMessage(SendMessage sendMessage) throws TelegramApiException;
|
|
||||||
|
|
||||||
void sendMessageAsync(SendMessage sendMessage, SentCallback<Message> sentCallback) throws TelegramApiException;
|
|
||||||
|
|
||||||
void answerInlineQueryAsync(AnswerInlineQuery answerInlineQuery, SentCallback<Boolean> sentCallback) throws TelegramApiException;
|
|
||||||
|
|
||||||
void sendChatActionAsync(SendChatAction sendChatAction, SentCallback<Boolean> sentCallback) throws TelegramApiException;
|
|
||||||
|
|
||||||
void forwardMessageAsync(ForwardMessage forwardMessage, SentCallback<Message> sentCallback) throws TelegramApiException;
|
|
||||||
|
|
||||||
void sendLocationAsync(SendLocation sendLocation, SentCallback<Message> sentCallback) throws TelegramApiException;
|
|
||||||
|
|
||||||
void sendVenueAsync(SendVenue sendVenue, SentCallback<Message> sentCallback) throws TelegramApiException;
|
|
||||||
|
|
||||||
void sendContactAsync(SendContact sendContact, SentCallback<Message> sentCallback) throws TelegramApiException;
|
|
||||||
|
|
||||||
void kickMemberAsync(KickChatMember kickChatMember, SentCallback<Boolean> sentCallback) throws TelegramApiException;
|
|
||||||
|
|
||||||
void unbanMemberAsync(UnbanChatMember unbanChatMember, SentCallback<Boolean> sentCallback) throws TelegramApiException;
|
|
||||||
|
|
||||||
void leaveChatAsync(LeaveChat leaveChat, SentCallback<Boolean> sentCallback) throws TelegramApiException;
|
|
||||||
|
|
||||||
void getChatAsync(GetChat getChat, SentCallback<Chat> sentCallback) throws TelegramApiException;
|
|
||||||
|
|
||||||
void getChatAdministratorsAsync(GetChatAdministrators getChatAdministrators, SentCallback<ArrayList<ChatMember>> sentCallback) throws TelegramApiException;
|
|
||||||
|
|
||||||
void getChatMemberAsync(GetChatMember getChatMember, SentCallback<ChatMember> sentCallback) throws TelegramApiException;
|
|
||||||
|
|
||||||
void getChatMemberCountAsync(GetChatMemberCount getChatMemberCount, SentCallback<Integer> sentCallback) throws TelegramApiException;
|
|
||||||
|
|
||||||
void editMessageTextAsync(EditMessageText editMessageText, SentCallback<Serializable> sentCallback) throws TelegramApiException;
|
|
||||||
|
|
||||||
void editMessageCaptionAsync(EditMessageCaption editMessageCaption, SentCallback<Serializable> sentCallback) throws TelegramApiException;
|
|
||||||
|
|
||||||
void editMessageReplyMarkup(EditMessageReplyMarkup editMessageReplyMarkup, SentCallback<Serializable> sentCallback) throws TelegramApiException;
|
|
||||||
|
|
||||||
void answerCallbackQueryAsync(AnswerCallbackQuery answerCallbackQuery, SentCallback<Boolean> sentCallback) throws TelegramApiException;
|
|
||||||
|
|
||||||
void getUserProfilePhotosAsync(GetUserProfilePhotos getUserProfilePhotos, SentCallback<UserProfilePhotos> sentCallback) throws TelegramApiException;
|
|
||||||
|
|
||||||
void getFileAsync(GetFile getFile, SentCallback<File> sentCallback) throws TelegramApiException;
|
|
||||||
|
|
||||||
void getMeAsync(SentCallback<User> sentCallback) throws TelegramApiException;
|
void getMeAsync(SentCallback<User> sentCallback) throws TelegramApiException;
|
||||||
|
|
||||||
void getWebhookInfoAsync(SentCallback<WebhookInfo> sentCallback) throws TelegramApiException;
|
void getWebhookInfoAsync(SentCallback<WebhookInfo> sentCallback) throws TelegramApiException;
|
||||||
|
|
||||||
void setGameScoreAsync(SetGameScore setGameScore, SentCallback<Serializable> sentCallback) throws TelegramApiException;
|
|
||||||
|
|
||||||
void getGameHighScoresAsync(GetGameHighScores getGameHighScores, SentCallback<ArrayList<GameHighScore>> sentCallback) throws TelegramApiException;
|
|
||||||
|
|
||||||
void sendGameAsync(SendGame sendGame, SentCallback<Message> sentCallback) throws TelegramApiException;
|
|
||||||
|
|
||||||
void deleteWebhook(DeleteWebhook deleteWebhook, SentCallback<Boolean> sentCallback) throws TelegramApiException;
|
|
||||||
|
|
||||||
Message sendDocument(SendDocument sendDocument) throws TelegramApiException;
|
Message sendDocument(SendDocument sendDocument) throws TelegramApiException;
|
||||||
|
|
||||||
Message sendPhoto(SendPhoto sendPhoto) throws TelegramApiException;
|
Message sendPhoto(SendPhoto sendPhoto) throws TelegramApiException;
|
||||||
|
|
||||||
Message sendVideo(SendVideo sendVideo) throws TelegramApiException;
|
Message sendVideo(SendVideo sendVideo) throws TelegramApiException;
|
||||||
|
|
||||||
Message sendSticker(SendSticker sendSticker) throws TelegramApiException;
|
|
||||||
|
|
||||||
Message sendAudio(SendAudio sendAudio) throws TelegramApiException;
|
Message sendAudio(SendAudio sendAudio) throws TelegramApiException;
|
||||||
|
|
||||||
Message sendVoice(SendVoice sendVoice) throws TelegramApiException;
|
Message sendVoice(SendVoice sendVoice) throws TelegramApiException;
|
||||||
|
|
||||||
|
Message sendVideoNote(SendVideoNote sendVideoNote) throws TelegramApiException;
|
||||||
|
|
||||||
|
Message sendSticker(SendSticker sendSticker) throws TelegramApiException;
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,71 @@
|
|||||||
|
package org.telegram.abilitybots.api.sender;
|
||||||
|
|
||||||
|
import org.telegram.telegrambots.api.methods.BotApiMethod;
|
||||||
|
import org.telegram.telegrambots.api.methods.send.SendMessage;
|
||||||
|
import org.telegram.telegrambots.api.objects.Message;
|
||||||
|
import org.telegram.telegrambots.api.objects.replykeyboard.ForceReplyKeyboard;
|
||||||
|
import org.telegram.telegrambots.exceptions.TelegramApiException;
|
||||||
|
import org.telegram.telegrambots.logging.BotLogger;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A silent sender that returns {@link Optional} objects upon execution. Mainly used to decrease verboseness of exception handling.
|
||||||
|
*
|
||||||
|
* @author Abbas Abou Daya
|
||||||
|
*/
|
||||||
|
public class SilentSender {
|
||||||
|
private static final String TAG = SilentSender.class.getSimpleName();
|
||||||
|
|
||||||
|
private final MessageSender sender;
|
||||||
|
|
||||||
|
public SilentSender(MessageSender sender) {
|
||||||
|
this.sender = sender;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Optional<Message> send(String message, long id) {
|
||||||
|
return doSendMessage(message, id, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Optional<Message> sendMd(String message, long id) {
|
||||||
|
return doSendMessage(message, id, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Optional<Message> forceReply(String message, long id) {
|
||||||
|
SendMessage msg = new SendMessage();
|
||||||
|
msg.setText(message);
|
||||||
|
msg.setChatId(id);
|
||||||
|
msg.setReplyMarkup(new ForceReplyKeyboard());
|
||||||
|
|
||||||
|
return execute(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
public <T extends Serializable, Method extends BotApiMethod<T>> Optional<T> execute(Method method) {
|
||||||
|
try {
|
||||||
|
return Optional.ofNullable(sender.execute(method));
|
||||||
|
} catch (TelegramApiException e) {
|
||||||
|
BotLogger.error("Could not execute bot API method", TAG, e);
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public <T extends Serializable, Method extends BotApiMethod<T>> Optional<T> executeAsync(Method method) {
|
||||||
|
try {
|
||||||
|
return Optional.ofNullable(sender.execute(method));
|
||||||
|
} catch (TelegramApiException e) {
|
||||||
|
BotLogger.error("Could not execute bot API method", TAG, e);
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Optional<Message> doSendMessage(String txt, long groupId, boolean format) {
|
||||||
|
SendMessage smsg = new SendMessage();
|
||||||
|
smsg.setChatId(groupId);
|
||||||
|
smsg.setText(txt);
|
||||||
|
smsg.enableMarkdown(format);
|
||||||
|
|
||||||
|
return execute(smsg);
|
||||||
|
}
|
||||||
|
}
|
@ -2,14 +2,15 @@ package org.telegram.abilitybots.api.bot;
|
|||||||
|
|
||||||
import com.google.common.collect.ImmutableMap;
|
import com.google.common.collect.ImmutableMap;
|
||||||
import com.google.common.io.Files;
|
import com.google.common.io.Files;
|
||||||
|
import org.apache.commons.io.FileUtils;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.junit.After;
|
import org.junit.After;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.mockito.Matchers;
|
|
||||||
import org.telegram.abilitybots.api.db.DBContext;
|
import org.telegram.abilitybots.api.db.DBContext;
|
||||||
import org.telegram.abilitybots.api.objects.*;
|
import org.telegram.abilitybots.api.objects.*;
|
||||||
import org.telegram.abilitybots.api.sender.MessageSender;
|
import org.telegram.abilitybots.api.sender.MessageSender;
|
||||||
|
import org.telegram.abilitybots.api.sender.SilentSender;
|
||||||
import org.telegram.abilitybots.api.util.Pair;
|
import org.telegram.abilitybots.api.util.Pair;
|
||||||
import org.telegram.abilitybots.api.util.Trio;
|
import org.telegram.abilitybots.api.util.Trio;
|
||||||
import org.telegram.telegrambots.api.objects.*;
|
import org.telegram.telegrambots.api.objects.*;
|
||||||
@ -25,9 +26,11 @@ import java.util.Set;
|
|||||||
import static com.google.common.collect.Sets.newHashSet;
|
import static com.google.common.collect.Sets.newHashSet;
|
||||||
import static java.lang.String.format;
|
import static java.lang.String.format;
|
||||||
import static java.util.Collections.emptySet;
|
import static java.util.Collections.emptySet;
|
||||||
|
import static org.apache.commons.io.FileUtils.deleteQuietly;
|
||||||
import static org.apache.commons.lang3.ArrayUtils.addAll;
|
import static org.apache.commons.lang3.ArrayUtils.addAll;
|
||||||
import static org.apache.commons.lang3.StringUtils.EMPTY;
|
import static org.apache.commons.lang3.StringUtils.EMPTY;
|
||||||
import static org.junit.Assert.*;
|
import static org.junit.Assert.*;
|
||||||
|
import static org.mockito.Matchers.any;
|
||||||
import static org.mockito.Mockito.*;
|
import static org.mockito.Mockito.*;
|
||||||
import static org.mockito.internal.verification.VerificationModeFactory.times;
|
import static org.mockito.internal.verification.VerificationModeFactory.times;
|
||||||
import static org.telegram.abilitybots.api.bot.AbilityBot.RECOVERY_MESSAGE;
|
import static org.telegram.abilitybots.api.bot.AbilityBot.RECOVERY_MESSAGE;
|
||||||
@ -54,13 +57,18 @@ public class AbilityBotTest {
|
|||||||
private DefaultBot bot;
|
private DefaultBot bot;
|
||||||
private DBContext db;
|
private DBContext db;
|
||||||
private MessageSender sender;
|
private MessageSender sender;
|
||||||
|
private SilentSender silent;
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void setUp() {
|
public void setUp() {
|
||||||
db = offlineInstance("db");
|
db = offlineInstance("db");
|
||||||
bot = new DefaultBot(EMPTY, EMPTY, db);
|
bot = new DefaultBot(EMPTY, EMPTY, db);
|
||||||
|
|
||||||
sender = mock(MessageSender.class);
|
sender = mock(MessageSender.class);
|
||||||
bot.setSender(sender);
|
silent = mock(SilentSender.class);
|
||||||
|
|
||||||
|
bot.sender = sender;
|
||||||
|
bot.silent = silent;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -69,7 +77,7 @@ public class AbilityBotTest {
|
|||||||
|
|
||||||
bot.onUpdateReceived(update);
|
bot.onUpdateReceived(update);
|
||||||
|
|
||||||
verify(sender, times(1)).send(format("Sorry, %s-only feature.", "admin"), MUSER.id());
|
verify(silent, times(1)).send(format("Sorry, %s-only feature.", "admin"), MUSER.id());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -78,7 +86,7 @@ public class AbilityBotTest {
|
|||||||
|
|
||||||
bot.onUpdateReceived(update);
|
bot.onUpdateReceived(update);
|
||||||
|
|
||||||
verify(sender, times(1)).send(format("Sorry, %s-only feature.", "group"), MUSER.id());
|
verify(silent, times(1)).send(format("Sorry, %s-only feature.", "group"), MUSER.id());
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -88,7 +96,7 @@ public class AbilityBotTest {
|
|||||||
|
|
||||||
bot.onUpdateReceived(update);
|
bot.onUpdateReceived(update);
|
||||||
|
|
||||||
verify(sender, times(1)).send(format("Sorry, this feature requires %d additional inputs.", 4), MUSER.id());
|
verify(silent, times(1)).send(format("Sorry, this feature requires %d additional inputs.", 4), MUSER.id());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -97,7 +105,7 @@ public class AbilityBotTest {
|
|||||||
|
|
||||||
// False means the update was not pushed down the stream since it has been consumed by the reply
|
// False means the update was not pushed down the stream since it has been consumed by the reply
|
||||||
assertFalse(bot.filterReply(update));
|
assertFalse(bot.filterReply(update));
|
||||||
verify(sender, times(1)).send("reply", MUSER.id());
|
verify(silent, times(1)).send("reply", MUSER.id());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -105,6 +113,7 @@ public class AbilityBotTest {
|
|||||||
MessageContext context = defaultContext();
|
MessageContext context = defaultContext();
|
||||||
|
|
||||||
bot.backupDB().action().accept(context);
|
bot.backupDB().action().accept(context);
|
||||||
|
deleteQuietly(new java.io.File("backup.json"));
|
||||||
|
|
||||||
verify(sender, times(1)).sendDocument(any());
|
verify(sender, times(1)).sendDocument(any());
|
||||||
}
|
}
|
||||||
@ -115,10 +124,10 @@ public class AbilityBotTest {
|
|||||||
Object backup = getDbBackup();
|
Object backup = getDbBackup();
|
||||||
java.io.File backupFile = createBackupFile(backup);
|
java.io.File backupFile = createBackupFile(backup);
|
||||||
|
|
||||||
when(sender.downloadFile(Matchers.any(File.class))).thenReturn(backupFile);
|
when(sender.downloadFile(any(File.class))).thenReturn(backupFile);
|
||||||
bot.recoverDB().replies().get(0).actOn(update);
|
bot.recoverDB().replies().get(0).actOn(update);
|
||||||
|
|
||||||
verify(sender, times(1)).send(RECOVER_SUCCESS, GROUP_ID);
|
verify(silent, times(1)).send(RECOVER_SUCCESS, GROUP_ID);
|
||||||
assertEquals("Bot recovered but the DB is still not in sync", db.getSet(TEST), newHashSet(TEST));
|
assertEquals("Bot recovered but the DB is still not in sync", db.getSet(TEST), newHashSet(TEST));
|
||||||
assertTrue("Could not delete backup file", backupFile.delete());
|
assertTrue("Could not delete backup file", backupFile.delete());
|
||||||
}
|
}
|
||||||
@ -401,13 +410,9 @@ public class AbilityBotTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void canCheckGlobalFlags() {
|
public void defaultGlobalFlagIsTrue() {
|
||||||
Update update = mock(Update.class);
|
Update update = mock(Update.class);
|
||||||
Message message = mock(Message.class);
|
assertEquals("Unexpected result when checking for the default global flags", true, bot.checkGlobalFlags(update));
|
||||||
|
|
||||||
when(update.hasMessage()).thenReturn(true);
|
|
||||||
when(update.getMessage()).thenReturn(message);
|
|
||||||
assertEquals("Unexpected result when checking for locality", true, bot.checkGlobalFlags(update));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(expected = ArithmeticException.class)
|
@Test(expected = ArithmeticException.class)
|
||||||
@ -492,7 +497,7 @@ public class AbilityBotTest {
|
|||||||
|
|
||||||
bot.reportCommands().action().accept(context);
|
bot.reportCommands().action().accept(context);
|
||||||
|
|
||||||
verify(sender, times(1)).send("default - dis iz default command", GROUP_ID);
|
verify(silent, times(1)).send("default - dis iz default command", GROUP_ID);
|
||||||
}
|
}
|
||||||
|
|
||||||
@After
|
@After
|
||||||
|
@ -1,10 +1,8 @@
|
|||||||
package org.telegram.abilitybots.api.bot;
|
package org.telegram.abilitybots.api.bot;
|
||||||
|
|
||||||
import com.google.common.annotations.VisibleForTesting;
|
|
||||||
import org.telegram.abilitybots.api.db.DBContext;
|
import org.telegram.abilitybots.api.db.DBContext;
|
||||||
import org.telegram.abilitybots.api.objects.Ability;
|
import org.telegram.abilitybots.api.objects.Ability;
|
||||||
import org.telegram.abilitybots.api.objects.Ability.AbilityBuilder;
|
import org.telegram.abilitybots.api.objects.Ability.AbilityBuilder;
|
||||||
import org.telegram.abilitybots.api.sender.MessageSender;
|
|
||||||
|
|
||||||
import static org.telegram.abilitybots.api.objects.Ability.builder;
|
import static org.telegram.abilitybots.api.objects.Ability.builder;
|
||||||
import static org.telegram.abilitybots.api.objects.Flag.CALLBACK_QUERY;
|
import static org.telegram.abilitybots.api.objects.Flag.CALLBACK_QUERY;
|
||||||
@ -38,8 +36,8 @@ public class DefaultBot extends AbilityBot {
|
|||||||
return getDefaultBuilder()
|
return getDefaultBuilder()
|
||||||
.name(DEFAULT)
|
.name(DEFAULT)
|
||||||
.info("dis iz default command")
|
.info("dis iz default command")
|
||||||
.reply(upd -> sender.send("reply", upd.getMessage().getChatId()), MESSAGE, update -> update.getMessage().getText().equals("must reply"))
|
.reply(upd -> silent.send("reply", upd.getMessage().getChatId()), MESSAGE, update -> update.getMessage().getText().equals("must reply"))
|
||||||
.reply(upd -> sender.send("reply", upd.getCallbackQuery().getMessage().getChatId()), CALLBACK_QUERY)
|
.reply(upd -> silent.send("reply", upd.getCallbackQuery().getMessage().getChatId()), CALLBACK_QUERY)
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -70,9 +68,4 @@ public class DefaultBot extends AbilityBot {
|
|||||||
public Ability testAbility() {
|
public Ability testAbility() {
|
||||||
return getDefaultBuilder().build();
|
return getDefaultBuilder().build();
|
||||||
}
|
}
|
||||||
|
|
||||||
@VisibleForTesting
|
|
||||||
void setSender(MessageSender sender) {
|
|
||||||
this.sender = sender;
|
|
||||||
}
|
|
||||||
}
|
}
|
@ -0,0 +1,43 @@
|
|||||||
|
package org.telegram.abilitybots.api.sender;
|
||||||
|
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.telegram.telegrambots.exceptions.TelegramApiException;
|
||||||
|
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
import static junit.framework.TestCase.assertEquals;
|
||||||
|
import static junit.framework.TestCase.assertFalse;
|
||||||
|
import static org.mockito.Matchers.any;
|
||||||
|
import static org.mockito.Mockito.mock;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
|
public class SilentSenderTest {
|
||||||
|
private SilentSender silent;
|
||||||
|
private MessageSender sender;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setUp() {
|
||||||
|
sender = mock(MessageSender.class);
|
||||||
|
silent = new SilentSender(sender);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void returnsEmptyOnError() throws TelegramApiException {
|
||||||
|
when(sender.execute(any())).thenThrow(TelegramApiException.class);
|
||||||
|
|
||||||
|
Optional execute = silent.execute(null);
|
||||||
|
|
||||||
|
assertFalse("Execution of a bot API method with execption results in a nonempty optional", execute.isPresent());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void returnOptionalOnSuccess() throws TelegramApiException {
|
||||||
|
String data = "data";
|
||||||
|
when(sender.execute(any())).thenReturn(data);
|
||||||
|
|
||||||
|
Optional execute = silent.execute(null);
|
||||||
|
|
||||||
|
assertEquals("Silent execution resulted in a different object", data, execute.get());
|
||||||
|
}
|
||||||
|
}
|
@ -16,12 +16,12 @@ Just import add the library to your project with one of these options:
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.telegram</groupId>
|
<groupId>org.telegram</groupId>
|
||||||
<artifactId>telegrambotsextensions</artifactId>
|
<artifactId>telegrambotsextensions</artifactId>
|
||||||
<version>3.4</version>
|
<version>3.5</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
```
|
```
|
||||||
|
|
||||||
2. Using Gradle:
|
2. Using Gradle:
|
||||||
|
|
||||||
```gradle
|
```gradle
|
||||||
compile "org.telegram:telegrambotsextensions:3.4"
|
compile "org.telegram:telegrambotsextensions:3.5"
|
||||||
```
|
```
|
@ -5,7 +5,7 @@
|
|||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
<groupId>org.telegram</groupId>
|
<groupId>org.telegram</groupId>
|
||||||
<artifactId>telegrambotsextensions</artifactId>
|
<artifactId>telegrambotsextensions</artifactId>
|
||||||
<version>3.4</version>
|
<version>3.5</version>
|
||||||
<packaging>jar</packaging>
|
<packaging>jar</packaging>
|
||||||
|
|
||||||
<name>Telegram Bots Extensions</name>
|
<name>Telegram Bots Extensions</name>
|
||||||
@ -59,7 +59,7 @@
|
|||||||
<properties>
|
<properties>
|
||||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
|
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
|
||||||
<bots.version>3.4</bots.version>
|
<bots.version>3.5</bots.version>
|
||||||
</properties>
|
</properties>
|
||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
|
@ -38,7 +38,8 @@ public abstract class TelegramLongPollingCommandBot extends TelegramLongPollingB
|
|||||||
* Creates a TelegramLongPollingCommandBot with custom options and allowing commands with
|
* Creates a TelegramLongPollingCommandBot with custom options and allowing commands with
|
||||||
* usernames
|
* usernames
|
||||||
* Use ICommandRegistry's methods on this bot to register commands
|
* Use ICommandRegistry's methods on this bot to register commands
|
||||||
* @param options Bot options
|
*
|
||||||
|
* @param options Bot options
|
||||||
* @param botUsername Username of the bot
|
* @param botUsername Username of the bot
|
||||||
*/
|
*/
|
||||||
public TelegramLongPollingCommandBot(DefaultBotOptions options, String botUsername) {
|
public TelegramLongPollingCommandBot(DefaultBotOptions options, String botUsername) {
|
||||||
@ -48,10 +49,11 @@ public abstract class TelegramLongPollingCommandBot extends TelegramLongPollingB
|
|||||||
/**
|
/**
|
||||||
* Creates a TelegramLongPollingCommandBot
|
* Creates a TelegramLongPollingCommandBot
|
||||||
* Use ICommandRegistry's methods on this bot to register commands
|
* Use ICommandRegistry's methods on this bot to register commands
|
||||||
* @param options Bot options
|
*
|
||||||
|
* @param options Bot options
|
||||||
* @param allowCommandsWithUsername true to allow commands with parameters (default),
|
* @param allowCommandsWithUsername true to allow commands with parameters (default),
|
||||||
* false otherwise
|
* false otherwise
|
||||||
* @param botUsername bot username of this bot
|
* @param botUsername bot username of this bot
|
||||||
*/
|
*/
|
||||||
public TelegramLongPollingCommandBot(DefaultBotOptions options, boolean allowCommandsWithUsername, String botUsername) {
|
public TelegramLongPollingCommandBot(DefaultBotOptions options, boolean allowCommandsWithUsername, String botUsername) {
|
||||||
super(options);
|
super(options);
|
||||||
@ -64,26 +66,39 @@ public abstract class TelegramLongPollingCommandBot extends TelegramLongPollingB
|
|||||||
if (update.hasMessage()) {
|
if (update.hasMessage()) {
|
||||||
Message message = update.getMessage();
|
Message message = update.getMessage();
|
||||||
if (message.isCommand() && !filter(message)) {
|
if (message.isCommand() && !filter(message)) {
|
||||||
if (commandRegistry.executeCommand(this, message)) {
|
if (!commandRegistry.executeCommand(this, message)) {
|
||||||
return;
|
//we have received a not registered command, handle it as invalid
|
||||||
|
processInvalidCommandUpdate(update);
|
||||||
}
|
}
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
processNonCommandUpdate(update);
|
processNonCommandUpdate(update);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method is called when user sends a not registered command. By default it will just call processNonCommandUpdate(),
|
||||||
|
* override it in your implementation if you want your bot to do other things, such as sending an error message
|
||||||
|
*
|
||||||
|
* @param update Received update from Telegram
|
||||||
|
*/
|
||||||
|
protected void processInvalidCommandUpdate(Update update) {
|
||||||
|
processNonCommandUpdate(update);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Override this function in your bot implementation to filter messages with commands
|
* Override this function in your bot implementation to filter messages with commands
|
||||||
*
|
* <p>
|
||||||
* For example, if you want to prevent commands execution incoming from group chat:
|
* For example, if you want to prevent commands execution incoming from group chat:
|
||||||
* #
|
* #
|
||||||
* # return !message.getChat().isGroupChat();
|
* # return !message.getChat().isGroupChat();
|
||||||
* #
|
* #
|
||||||
*
|
*
|
||||||
* @note Default implementation doesn't filter anything
|
|
||||||
* @param message Received message
|
* @param message Received message
|
||||||
* @return true if the message must be ignored by the command bot and treated as a non command message,
|
* @return true if the message must be ignored by the command bot and treated as a non command message,
|
||||||
* false otherwise
|
* false otherwise
|
||||||
|
* @note Default implementation doesn't filter anything
|
||||||
*/
|
*/
|
||||||
protected boolean filter(Message message) {
|
protected boolean filter(Message message) {
|
||||||
return false;
|
return false;
|
||||||
@ -134,10 +149,10 @@ public abstract class TelegramLongPollingCommandBot extends TelegramLongPollingB
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Process all updates, that are not commands.
|
* Process all updates, that are not commands.
|
||||||
* @warning Commands that have valid syntax but are not registered on this bot,
|
|
||||||
* won't be forwarded to this method <b>if a default action is present</b>.
|
|
||||||
*
|
*
|
||||||
* @param update the update
|
* @param update the update
|
||||||
|
* @warning Commands that have valid syntax but are not registered on this bot,
|
||||||
|
* won't be forwarded to this method <b>if a default action is present</b>.
|
||||||
*/
|
*/
|
||||||
public abstract void processNonCommandUpdate(Update update);
|
public abstract void processNonCommandUpdate(Update update);
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package org.telegram.telegrambots.bots.commandbot.commands;
|
package org.telegram.telegrambots.bots.commandbot.commands;
|
||||||
|
|
||||||
import org.telegram.telegrambots.api.objects.Chat;
|
import org.telegram.telegrambots.api.objects.Chat;
|
||||||
|
import org.telegram.telegrambots.api.objects.Message;
|
||||||
import org.telegram.telegrambots.api.objects.User;
|
import org.telegram.telegrambots.api.objects.User;
|
||||||
import org.telegram.telegrambots.bots.AbsSender;
|
import org.telegram.telegrambots.bots.AbsSender;
|
||||||
|
|
||||||
@ -66,6 +67,17 @@ public abstract class BotCommand {
|
|||||||
"</b>\n" + getDescription();
|
"</b>\n" + getDescription();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Process the message and execute the command
|
||||||
|
*
|
||||||
|
* @param absSender absSender to send messages over
|
||||||
|
* @param message the message to process
|
||||||
|
* @param arguments passed arguments
|
||||||
|
*/
|
||||||
|
void processMessage(AbsSender absSender, Message message, String[] arguments) {
|
||||||
|
execute(absSender, message.getFrom(), message.getChat(), arguments);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Execute the command
|
* Execute the command
|
||||||
*
|
*
|
||||||
|
@ -103,7 +103,7 @@ public final class CommandRegistry implements ICommandRegistry {
|
|||||||
|
|
||||||
if (commandRegistryMap.containsKey(command)) {
|
if (commandRegistryMap.containsKey(command)) {
|
||||||
String[] parameters = Arrays.copyOfRange(commandSplit, 1, commandSplit.length);
|
String[] parameters = Arrays.copyOfRange(commandSplit, 1, commandSplit.length);
|
||||||
commandRegistryMap.get(command).execute(absSender, message.getFrom(), message.getChat(), parameters);
|
commandRegistryMap.get(command).processMessage(absSender, message, parameters);
|
||||||
return true;
|
return true;
|
||||||
} else if (defaultConsumer != null) {
|
} else if (defaultConsumer != null) {
|
||||||
defaultConsumer.accept(absSender, message);
|
defaultConsumer.accept(absSender, message);
|
||||||
|
@ -0,0 +1,53 @@
|
|||||||
|
package org.telegram.telegrambots.bots.commandbot.commands;
|
||||||
|
|
||||||
|
import org.telegram.telegrambots.api.objects.Chat;
|
||||||
|
import org.telegram.telegrambots.api.objects.Message;
|
||||||
|
import org.telegram.telegrambots.api.objects.User;
|
||||||
|
import org.telegram.telegrambots.bots.AbsSender;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Bot command with message ID in execute method
|
||||||
|
*
|
||||||
|
* @author Vadim Goroshevsky (@vadimgoroshevsky)
|
||||||
|
*/
|
||||||
|
public abstract class DefaultBotCommand extends BotCommand {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Construct a command
|
||||||
|
*
|
||||||
|
* @param commandIdentifier the unique identifier of this command (e.g. the command string to
|
||||||
|
* enter into chat)
|
||||||
|
* @param description the description of this command
|
||||||
|
*/
|
||||||
|
public DefaultBotCommand(String commandIdentifier, String description) {
|
||||||
|
super(commandIdentifier, description);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Process the message and execute the command
|
||||||
|
*
|
||||||
|
* @param absSender absSender to send messages over
|
||||||
|
* @param message the message to process
|
||||||
|
* @param arguments passed arguments
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
void processMessage(AbsSender absSender, Message message, String[] arguments) {
|
||||||
|
execute(absSender, message.getFrom(), message.getChat(), message.getMessageId(), arguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
// We'll override this method here for not repeating it in DefaultBotCommand's children
|
||||||
|
@Override
|
||||||
|
public final void execute(AbsSender absSender, User user, Chat chat, String[] arguments) {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Execute the command
|
||||||
|
*
|
||||||
|
* @param absSender absSender to send messages over
|
||||||
|
* @param user the user who sent the command
|
||||||
|
* @param chat the chat, to be able to send replies
|
||||||
|
* @param messageId message id for interaction
|
||||||
|
* @param arguments passed arguments
|
||||||
|
*/
|
||||||
|
public abstract void execute(AbsSender absSender, User user, Chat chat, Integer messageId, String[] arguments);
|
||||||
|
}
|
@ -5,7 +5,7 @@
|
|||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
<groupId>org.telegram</groupId>
|
<groupId>org.telegram</groupId>
|
||||||
<artifactId>telegrambots-meta</artifactId>
|
<artifactId>telegrambots-meta</artifactId>
|
||||||
<version>3.4</version>
|
<version>3.5</version>
|
||||||
<packaging>jar</packaging>
|
<packaging>jar</packaging>
|
||||||
|
|
||||||
<name>Telegram Bots Meta</name>
|
<name>Telegram Bots Meta</name>
|
||||||
|
@ -51,7 +51,7 @@ public class PromoteChatMember extends BotApiMethod<Boolean> {
|
|||||||
@JsonProperty(CANRESTRICTMEMBERS_FIELD)
|
@JsonProperty(CANRESTRICTMEMBERS_FIELD)
|
||||||
private Boolean canRestrictMembers; ///< Pass True, if the administrator can restrict, ban or unban chat members
|
private Boolean canRestrictMembers; ///< Pass True, if the administrator can restrict, ban or unban chat members
|
||||||
@JsonProperty(CANPINMESSAGES_FIELD)
|
@JsonProperty(CANPINMESSAGES_FIELD)
|
||||||
private Boolean canPinMessages; ///< Pass True, if the administrator can pin messages, supergroups only
|
private Boolean canPinMessages; ///< Pass True, if the administrator can pin messages
|
||||||
@JsonProperty(CANPROMOTEMEMBERS_FIELD)
|
@JsonProperty(CANPROMOTEMEMBERS_FIELD)
|
||||||
private Boolean canPromoteMembers; ///< Pass True, if the administrator can add new administrators with a subset of his own privileges or demote administrators that he has promoted, directly or indirectly (promoted by administators that were appointed by the him)
|
private Boolean canPromoteMembers; ///< Pass True, if the administrator can add new administrators with a subset of his own privileges or demote administrators that he has promoted, directly or indirectly (promoted by administators that were appointed by the him)
|
||||||
|
|
||||||
|
@ -15,8 +15,9 @@ import static com.google.common.base.Preconditions.checkNotNull;
|
|||||||
/**
|
/**
|
||||||
* @author Ruben Bermudez
|
* @author Ruben Bermudez
|
||||||
* @version 3.1
|
* @version 3.1
|
||||||
* Use this method to pin a message in a supergroup.
|
* Use this method to pin a message in a supergroup or channel.
|
||||||
* The bot must be an administrator in the chat for this to work and must have the appropriate admin rights.
|
* The bot must be an administrator in the chat for this to work and must have the ‘can_pin_messages’
|
||||||
|
* admin right in the supergroup or ‘can_edit_messages’ admin right in the channel.
|
||||||
* Returns True on success.
|
* Returns True on success.
|
||||||
*/
|
*/
|
||||||
public class PinChatMessage extends BotApiMethod<Boolean> {
|
public class PinChatMessage extends BotApiMethod<Boolean> {
|
||||||
@ -27,11 +28,15 @@ public class PinChatMessage extends BotApiMethod<Boolean> {
|
|||||||
private static final String DISABLENOTIFICATION_FIELD = "disable_notification";
|
private static final String DISABLENOTIFICATION_FIELD = "disable_notification";
|
||||||
|
|
||||||
@JsonProperty(CHATID_FIELD)
|
@JsonProperty(CHATID_FIELD)
|
||||||
private String chatId; ///< Required. Unique identifier for the target chat or username of the target supergroup (in the format @supergroupusername)
|
private String chatId; ///< Required. Unique identifier for the target chat or username of the target channel (in the format @channelusername)
|
||||||
@JsonProperty(MESSAGEID_FIELD)
|
@JsonProperty(MESSAGEID_FIELD)
|
||||||
private Integer messageId; ///< Required. Identifier of a message to pin
|
private Integer messageId; ///< Required. Identifier of a message to pin
|
||||||
@JsonProperty(DISABLENOTIFICATION_FIELD)
|
@JsonProperty(DISABLENOTIFICATION_FIELD)
|
||||||
private Boolean disableNotification; ///< Pass true, if it is not necessary to send a notification to all group members about the new pinned message
|
/**
|
||||||
|
* Pass True, if it is not necessary to send a notification to all chat members about the new pinned message.
|
||||||
|
* Notifications are always disabled in channels.
|
||||||
|
*/
|
||||||
|
private Boolean disableNotification;
|
||||||
|
|
||||||
public PinChatMessage() {
|
public PinChatMessage() {
|
||||||
super();
|
super();
|
||||||
|
@ -8,7 +8,6 @@ import org.telegram.telegrambots.exceptions.TelegramApiRequestException;
|
|||||||
import org.telegram.telegrambots.exceptions.TelegramApiValidationException;
|
import org.telegram.telegrambots.exceptions.TelegramApiValidationException;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.Serializable;
|
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
||||||
import static com.google.common.base.Preconditions.checkNotNull;
|
import static com.google.common.base.Preconditions.checkNotNull;
|
||||||
@ -16,7 +15,7 @@ import static com.google.common.base.Preconditions.checkNotNull;
|
|||||||
/**
|
/**
|
||||||
* @author Ruben Bermudez
|
* @author Ruben Bermudez
|
||||||
* @version 3.1
|
* @version 3.1
|
||||||
* Use this method to unpin a message in a supergroup chat.
|
* Use this method to unpin a message in a supergroup or channel.
|
||||||
* The bot must be an administrator in the chat for this to work and must have the appropriate admin rights.
|
* The bot must be an administrator in the chat for this to work and must have the appropriate admin rights.
|
||||||
* Returns True on success.
|
* Returns True on success.
|
||||||
*/
|
*/
|
||||||
@ -26,7 +25,7 @@ public class UnpinChatMessage extends BotApiMethod<Boolean> {
|
|||||||
private static final String CHATID_FIELD = "chat_id";
|
private static final String CHATID_FIELD = "chat_id";
|
||||||
|
|
||||||
@JsonProperty(CHATID_FIELD)
|
@JsonProperty(CHATID_FIELD)
|
||||||
private String chatId; ///< Required. Unique identifier for the target chat or username of the target supergroup (in the format @supergroupusername)
|
private String chatId; ///< Required. Unique identifier for the target chat or username of the target channel (in the format @channelusername)
|
||||||
|
|
||||||
public UnpinChatMessage() {
|
public UnpinChatMessage() {
|
||||||
super();
|
super();
|
||||||
|
@ -42,7 +42,8 @@ public class SendInvoice extends BotApiMethod<Message> {
|
|||||||
private static final String IS_FLEXIBLE_FIELD = "is_flexible";
|
private static final String IS_FLEXIBLE_FIELD = "is_flexible";
|
||||||
private static final String DISABLE_NOTIFICATION_FIELD = "disable_notification";
|
private static final String DISABLE_NOTIFICATION_FIELD = "disable_notification";
|
||||||
private static final String REPLY_TO_MESSAGE_ID_FIELD = "reply_to_message_id";
|
private static final String REPLY_TO_MESSAGE_ID_FIELD = "reply_to_message_id";
|
||||||
private static final String REPLY_MARKUP_FIELD = "reply_markup\t";
|
private static final String REPLY_MARKUP_FIELD = "reply_markup";
|
||||||
|
private static final String PRIVIDER_DATA_FIELD = "provider_data";
|
||||||
|
|
||||||
@JsonProperty(CHATID_FIELD)
|
@JsonProperty(CHATID_FIELD)
|
||||||
private Integer chatId; ///< Unique identifier for the target private chat
|
private Integer chatId; ///< Unique identifier for the target private chat
|
||||||
@ -93,6 +94,13 @@ public class SendInvoice extends BotApiMethod<Message> {
|
|||||||
* @note If empty, one 'Buy title' button will be shown. If not empty, the first button must be a Pay button.
|
* @note If empty, one 'Buy title' button will be shown. If not empty, the first button must be a Pay button.
|
||||||
*/
|
*/
|
||||||
private InlineKeyboardMarkup replyMarkup;
|
private InlineKeyboardMarkup replyMarkup;
|
||||||
|
@JsonProperty(PRIVIDER_DATA_FIELD)
|
||||||
|
/**
|
||||||
|
* Optional JSON-encoded data about the invoice, which will be shared with the payment provider.
|
||||||
|
*
|
||||||
|
* @note A detailed description of required fields should be provided by the payment provider.
|
||||||
|
*/
|
||||||
|
private String providerData;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -305,6 +313,15 @@ public class SendInvoice extends BotApiMethod<Message> {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getProviderData() {
|
||||||
|
return providerData;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SendInvoice setProviderData(String providerData) {
|
||||||
|
this.providerData = providerData;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getMethod() {
|
public String getMethod() {
|
||||||
return PATH;
|
return PATH;
|
||||||
@ -363,7 +380,7 @@ public class SendInvoice extends BotApiMethod<Message> {
|
|||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "SendInvoice{" +
|
return "SendInvoice{" +
|
||||||
"chatId='" + chatId + '\'' +
|
"chatId=" + chatId +
|
||||||
", title='" + title + '\'' +
|
", title='" + title + '\'' +
|
||||||
", description='" + description + '\'' +
|
", description='" + description + '\'' +
|
||||||
", payload='" + payload + '\'' +
|
", payload='" + payload + '\'' +
|
||||||
@ -383,6 +400,7 @@ public class SendInvoice extends BotApiMethod<Message> {
|
|||||||
", disableNotification=" + disableNotification +
|
", disableNotification=" + disableNotification +
|
||||||
", replyToMessageId=" + replyToMessageId +
|
", replyToMessageId=" + replyToMessageId +
|
||||||
", replyMarkup=" + replyMarkup +
|
", replyMarkup=" + replyMarkup +
|
||||||
|
", providerData='" + providerData + '\'' +
|
||||||
'}';
|
'}';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,144 @@
|
|||||||
|
package org.telegram.telegrambots.api.methods.send;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
|
import com.fasterxml.jackson.core.type.TypeReference;
|
||||||
|
import org.telegram.telegrambots.api.methods.PartialBotApiMethod;
|
||||||
|
import org.telegram.telegrambots.api.objects.Message;
|
||||||
|
import org.telegram.telegrambots.api.objects.media.InputMedia;
|
||||||
|
import org.telegram.telegrambots.api.objects.replykeyboard.ApiResponse;
|
||||||
|
import org.telegram.telegrambots.exceptions.TelegramApiRequestException;
|
||||||
|
import org.telegram.telegrambots.exceptions.TelegramApiValidationException;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import static com.google.common.base.Preconditions.checkNotNull;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Ruben Bermudez
|
||||||
|
* @version 3.5
|
||||||
|
*
|
||||||
|
* Use this method to send a group of photos or videos as an album.
|
||||||
|
* On success, an array of the sent Messages is returned.
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
public class SendMediaGroup extends PartialBotApiMethod<ArrayList<Message>> {
|
||||||
|
public static final String PATH = "sendMediaGroup";
|
||||||
|
|
||||||
|
public static final String CHATID_FIELD = "chat_id";
|
||||||
|
public static final String MEDIA_FIELD = "media";
|
||||||
|
public static final String REPLYTOMESSAGEID_FIELD = "reply_to_message_id";
|
||||||
|
public static final String DISABLENOTIFICATION_FIELD = "disable_notification";
|
||||||
|
|
||||||
|
@JsonProperty(CHATID_FIELD)
|
||||||
|
private String chatId; ///< Unique identifier for the target chat or username of the target channel (in the format @channelusername)
|
||||||
|
@JsonProperty(MEDIA_FIELD)
|
||||||
|
private List<InputMedia> media; ///< A JSON-serialized array describing photos and videos to be sent
|
||||||
|
@JsonProperty(REPLYTOMESSAGEID_FIELD)
|
||||||
|
private Integer replyToMessageId; ///< Optional. If the messages are a reply, ID of the original message
|
||||||
|
@JsonProperty(DISABLENOTIFICATION_FIELD)
|
||||||
|
private Boolean disableNotification; ///< Optional. Sends the messages silently. Users will receive a notification with no sound.
|
||||||
|
|
||||||
|
public SendMediaGroup() {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
public SendMediaGroup(String chatId, List<InputMedia> media) {
|
||||||
|
super();
|
||||||
|
this.chatId = checkNotNull(chatId);
|
||||||
|
this.media = checkNotNull(media);
|
||||||
|
}
|
||||||
|
|
||||||
|
public SendMediaGroup(Long chatId, List<InputMedia> media) {
|
||||||
|
super();
|
||||||
|
this.chatId = checkNotNull(chatId).toString();
|
||||||
|
this.media = checkNotNull(media);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getChatId() {
|
||||||
|
return chatId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SendMediaGroup setChatId(String chatId) {
|
||||||
|
this.chatId = checkNotNull(chatId);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SendMediaGroup setChatId(Long chatId) {
|
||||||
|
this.chatId = checkNotNull(chatId).toString();
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getReplyToMessageId() {
|
||||||
|
return replyToMessageId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SendMediaGroup setReplyToMessageId(Integer replyToMessageId) {
|
||||||
|
this.replyToMessageId = replyToMessageId;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Boolean getDisableNotification() {
|
||||||
|
return disableNotification;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SendMediaGroup enableNotification() {
|
||||||
|
this.disableNotification = false;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SendMediaGroup disableNotification() {
|
||||||
|
this.disableNotification = true;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<InputMedia> getMedia() {
|
||||||
|
return media;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMedia(List<InputMedia> media) {
|
||||||
|
this.media = media;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ArrayList<Message> deserializeResponse(String answer) throws TelegramApiRequestException {
|
||||||
|
try {
|
||||||
|
ApiResponse<ArrayList<Message>> result = OBJECT_MAPPER.readValue(answer,
|
||||||
|
new TypeReference<ApiResponse<ArrayList<Message>>>() {
|
||||||
|
});
|
||||||
|
if (result.getOk()) {
|
||||||
|
return result.getResult();
|
||||||
|
} else {
|
||||||
|
throw new TelegramApiRequestException("Error sending media group", result);
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new TelegramApiRequestException("Unable to deserialize response", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void validate() throws TelegramApiValidationException {
|
||||||
|
if (chatId == null) {
|
||||||
|
throw new TelegramApiValidationException("ChatId parameter can't be empty", this);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (media == null || media.isEmpty()) {
|
||||||
|
throw new TelegramApiValidationException("Media parameter can't be empty", this);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (InputMedia inputMedia : media) {
|
||||||
|
inputMedia.validate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "SendMediaGroup{" +
|
||||||
|
"chatId='" + chatId + '\'' +
|
||||||
|
", media=" + media +
|
||||||
|
", replyToMessageId=" + replyToMessageId +
|
||||||
|
", disableNotification=" + disableNotification +
|
||||||
|
'}';
|
||||||
|
}
|
||||||
|
}
|
@ -85,7 +85,7 @@ public class DeleteMessage extends BotApiMethod<Boolean> {
|
|||||||
if (result.getOk()) {
|
if (result.getOk()) {
|
||||||
return result.getResult();
|
return result.getResult();
|
||||||
} else {
|
} else {
|
||||||
throw new TelegramApiRequestException("Error editing message caption", result);
|
throw new TelegramApiRequestException("Error deleting message", result);
|
||||||
}
|
}
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
throw new TelegramApiRequestException("Unable to deserialize response", e);
|
throw new TelegramApiRequestException("Unable to deserialize response", e);
|
||||||
|
@ -41,7 +41,7 @@ public class ChatMember implements BotApiObject {
|
|||||||
@JsonProperty(CANPOSTMESSAGES_FIELD)
|
@JsonProperty(CANPOSTMESSAGES_FIELD)
|
||||||
private Boolean canPostMessages; ///< Optional. Administrators only. True, if the administrator can post in the channel, channels only
|
private Boolean canPostMessages; ///< Optional. Administrators only. True, if the administrator can post in the channel, channels only
|
||||||
@JsonProperty(CANEDITMESSAGES_FIELD)
|
@JsonProperty(CANEDITMESSAGES_FIELD)
|
||||||
private Boolean canEditMessages; ///< Optional. Administrators only. True, if the administrator can edit messages of other users, channels only
|
private Boolean canEditMessages; ///< Optional. Administrators only. True, if the administrator can edit messages of other users and can pin messages, channels only
|
||||||
@JsonProperty(CANDELETEMESSAGES_FIELD)
|
@JsonProperty(CANDELETEMESSAGES_FIELD)
|
||||||
private Boolean canDeleteMessages; ///< Optional. Administrators only. True, if the administrator can delete messages of other users
|
private Boolean canDeleteMessages; ///< Optional. Administrators only. True, if the administrator can delete messages of other users
|
||||||
@JsonProperty(CANINVITEUSERS_FIELD)
|
@JsonProperty(CANINVITEUSERS_FIELD)
|
||||||
@ -49,7 +49,7 @@ public class ChatMember implements BotApiObject {
|
|||||||
@JsonProperty(CANRESTRICTUSERS_FIELD)
|
@JsonProperty(CANRESTRICTUSERS_FIELD)
|
||||||
private Boolean canRestrictUsers; ///< Optional. Administrators only. True, if the administrator can restrict, ban or unban chat members
|
private Boolean canRestrictUsers; ///< Optional. Administrators only. True, if the administrator can restrict, ban or unban chat members
|
||||||
@JsonProperty(CANPINMESSAGES_FIELD)
|
@JsonProperty(CANPINMESSAGES_FIELD)
|
||||||
private Boolean canPinMessages; ///< Optional. Administrators only. True, if the administrator can pin messages, supergroups only
|
private Boolean canPinMessages; ///< Optional. Administrators only. True, if the administrator can pin messages
|
||||||
@JsonProperty(CANPROMOTEMEMBERS_FIELD)
|
@JsonProperty(CANPROMOTEMEMBERS_FIELD)
|
||||||
private Boolean canPromoteMembers; ///< Optional. Administrators only. True, if the administrator can add new administrators with a subset of his own privileges or demote administrators that it has promoted, directly or indirectly (promoted by administators that were appointed by the bot)
|
private Boolean canPromoteMembers; ///< Optional. Administrators only. True, if the administrator can add new administrators with a subset of his own privileges or demote administrators that it has promoted, directly or indirectly (promoted by administators that were appointed by the bot)
|
||||||
@JsonProperty(CANSENDMESSAGES_FIELD)
|
@JsonProperty(CANSENDMESSAGES_FIELD)
|
||||||
|
@ -55,6 +55,7 @@ public class Message implements BotApiObject {
|
|||||||
private static final String VIDEO_NOTE_FIELD = "video_note";
|
private static final String VIDEO_NOTE_FIELD = "video_note";
|
||||||
private static final String AUTHORSIGNATURE_FIELD = "author_signature";
|
private static final String AUTHORSIGNATURE_FIELD = "author_signature";
|
||||||
private static final String FORWARDSIGNATURE_FIELD = "forward_signature";
|
private static final String FORWARDSIGNATURE_FIELD = "forward_signature";
|
||||||
|
private static final String MEDIAGROUPID_FIELD = "media_group_id";
|
||||||
|
|
||||||
@JsonProperty(MESSAGEID_FIELD)
|
@JsonProperty(MESSAGEID_FIELD)
|
||||||
private Integer messageId; ///< Integer Unique message identifier
|
private Integer messageId; ///< Integer Unique message identifier
|
||||||
@ -172,7 +173,8 @@ public class Message implements BotApiObject {
|
|||||||
private String authorSignature; ///< Optional. Post author signature for posts in channel chats
|
private String authorSignature; ///< Optional. Post author signature for posts in channel chats
|
||||||
@JsonProperty(FORWARDSIGNATURE_FIELD)
|
@JsonProperty(FORWARDSIGNATURE_FIELD)
|
||||||
private String forwardSignature; ///< Optional. Post author signature for messages forwarded from channel chats
|
private String forwardSignature; ///< Optional. Post author signature for messages forwarded from channel chats
|
||||||
|
@JsonProperty(MEDIAGROUPID_FIELD)
|
||||||
|
private String mediaGroupId;
|
||||||
|
|
||||||
public Message() {
|
public Message() {
|
||||||
super();
|
super();
|
||||||
@ -412,6 +414,10 @@ public class Message implements BotApiObject {
|
|||||||
return forwardSignature;
|
return forwardSignature;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getMediaGroupId() {
|
||||||
|
return mediaGroupId;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "Message{" +
|
return "Message{" +
|
||||||
@ -455,6 +461,7 @@ public class Message implements BotApiObject {
|
|||||||
", videoNote=" + videoNote +
|
", videoNote=" + videoNote +
|
||||||
", authorSignature='" + authorSignature + '\'' +
|
", authorSignature='" + authorSignature + '\'' +
|
||||||
", forwardSignature='" + forwardSignature + '\'' +
|
", forwardSignature='" + forwardSignature + '\'' +
|
||||||
|
", mediaGroupId='" + mediaGroupId + '\'' +
|
||||||
'}';
|
'}';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,132 @@
|
|||||||
|
package org.telegram.telegrambots.api.objects.media;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||||
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
|
import org.telegram.telegrambots.api.interfaces.InputBotApiObject;
|
||||||
|
import org.telegram.telegrambots.api.interfaces.Validable;
|
||||||
|
import org.telegram.telegrambots.exceptions.TelegramApiValidationException;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.InputStream;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Ruben Bermudez
|
||||||
|
* @version 3.5
|
||||||
|
*/
|
||||||
|
public abstract class InputMedia<T> implements InputBotApiObject, Validable {
|
||||||
|
protected static final String TYPE_FIELD = "type";
|
||||||
|
private static final String MEDIA_FIELD = "media";
|
||||||
|
private static final String CAPTION_FIELD = "caption";
|
||||||
|
|
||||||
|
@JsonProperty(MEDIA_FIELD)
|
||||||
|
/**
|
||||||
|
* File to send. Pass a file_id to send a file that exists on the Telegram servers (recommended),
|
||||||
|
* pass an HTTP URL for Telegram to get a file from the Internet, or pass "attach://<file_attach_name>"
|
||||||
|
* to upload a new one using multipart/form-data under <file_attach_name> name.
|
||||||
|
*/
|
||||||
|
private String media;
|
||||||
|
@JsonProperty(CAPTION_FIELD)
|
||||||
|
private String caption; ///< Optional. Caption of the media to be sent, 0-200 characters
|
||||||
|
|
||||||
|
@JsonIgnore
|
||||||
|
private boolean isNewMedia; ///< True to upload a new media, false to use a fileId or URL
|
||||||
|
@JsonIgnore
|
||||||
|
private String mediaName; ///< Name of the media to upload
|
||||||
|
@JsonIgnore
|
||||||
|
private File newMediaFile; ///< New media file
|
||||||
|
@JsonIgnore
|
||||||
|
private InputStream newMediaStream; ///< New media stream
|
||||||
|
|
||||||
|
public InputMedia() {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
public InputMedia(String media, String caption) {
|
||||||
|
this.media = media;
|
||||||
|
this.caption = caption;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getMedia() {
|
||||||
|
return media;
|
||||||
|
}
|
||||||
|
|
||||||
|
public File getMediaFile() {
|
||||||
|
return newMediaFile;
|
||||||
|
}
|
||||||
|
|
||||||
|
public InputStream getNewMediaStream() {
|
||||||
|
return newMediaStream;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getMediaName() {
|
||||||
|
return mediaName;
|
||||||
|
}
|
||||||
|
|
||||||
|
@JsonIgnore
|
||||||
|
public boolean isNewMedia() {
|
||||||
|
return isNewMedia;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Use this setter to send an existing file (using file_id) or an url.
|
||||||
|
* @param media File_id or URL of the file to send
|
||||||
|
* @return This object
|
||||||
|
*/
|
||||||
|
public T setMedia(String media) {
|
||||||
|
this.media = media;
|
||||||
|
this.isNewMedia = false;
|
||||||
|
return (T) this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Use this setter to send new file.
|
||||||
|
* @param mediaFile File to send
|
||||||
|
* @return This object
|
||||||
|
*/
|
||||||
|
public T setMedia(File mediaFile, String fileName) {
|
||||||
|
this.newMediaFile = mediaFile;
|
||||||
|
this.isNewMedia = true;
|
||||||
|
this.mediaName = fileName;
|
||||||
|
this.media = "attach://" + fileName;
|
||||||
|
return (T) this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Use this setter to send new file as stream.
|
||||||
|
* @param mediaStream File to send
|
||||||
|
* @return This object
|
||||||
|
*/
|
||||||
|
public T setMedia(InputStream mediaStream, String fileName) {
|
||||||
|
this.newMediaStream = mediaStream;
|
||||||
|
this.isNewMedia = true;
|
||||||
|
this.mediaName = fileName;
|
||||||
|
this.media = "attach://" + fileName;
|
||||||
|
return (T) this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getCaption() {
|
||||||
|
return caption;
|
||||||
|
}
|
||||||
|
|
||||||
|
public InputMedia setCaption(String caption) {
|
||||||
|
this.caption = caption;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void validate() throws TelegramApiValidationException {
|
||||||
|
if (isNewMedia) {
|
||||||
|
if (mediaName == null || mediaName.isEmpty()) {
|
||||||
|
throw new TelegramApiValidationException("Media name can't be empty", this);
|
||||||
|
}
|
||||||
|
if (newMediaFile == null && newMediaStream == null) {
|
||||||
|
throw new TelegramApiValidationException("Media can't be empty", this);
|
||||||
|
}
|
||||||
|
} else if (media == null || media.isEmpty()) {
|
||||||
|
throw new TelegramApiValidationException("Media can't be empty", this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@JsonProperty(TYPE_FIELD)
|
||||||
|
public abstract String getType();
|
||||||
|
}
|
@ -0,0 +1,32 @@
|
|||||||
|
package org.telegram.telegrambots.api.objects.media;
|
||||||
|
|
||||||
|
import org.telegram.telegrambots.exceptions.TelegramApiValidationException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Ruben Bermudez
|
||||||
|
* @version 3.5
|
||||||
|
*
|
||||||
|
* Represents a photo.
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
public class InputMediaPhoto extends InputMedia<InputMediaPhoto> {
|
||||||
|
private static final String TYPE = "photo";
|
||||||
|
|
||||||
|
public InputMediaPhoto() {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
public InputMediaPhoto(String media, String caption) {
|
||||||
|
super(media, caption);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getType() {
|
||||||
|
return TYPE;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void validate() throws TelegramApiValidationException {
|
||||||
|
super.validate();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,71 @@
|
|||||||
|
package org.telegram.telegrambots.api.objects.media;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
|
import org.telegram.telegrambots.exceptions.TelegramApiValidationException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Ruben Bermudez
|
||||||
|
* @version 3.5
|
||||||
|
*
|
||||||
|
* Represents a video.
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
public class InputMediaVideo extends InputMedia<InputMediaVideo> {
|
||||||
|
private static final String TYPE = "video";
|
||||||
|
|
||||||
|
private static final String WIDTH_FIELD = "width";
|
||||||
|
private static final String HEIGHT_FIELD = "height";
|
||||||
|
private static final String DURATION_FIELD = "duration";
|
||||||
|
|
||||||
|
@JsonProperty(WIDTH_FIELD)
|
||||||
|
private int width; ///< Optional. Video width
|
||||||
|
@JsonProperty(HEIGHT_FIELD)
|
||||||
|
private int height; ///< Optional. Video height
|
||||||
|
@JsonProperty(DURATION_FIELD)
|
||||||
|
private int duration; ///< Optional. Video duration
|
||||||
|
|
||||||
|
public InputMediaVideo() {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
public InputMediaVideo(String media, String caption) {
|
||||||
|
super(media, caption);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getWidth() {
|
||||||
|
return width;
|
||||||
|
}
|
||||||
|
|
||||||
|
public InputMediaVideo setWidth(int width) {
|
||||||
|
this.width = width;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getHeight() {
|
||||||
|
return height;
|
||||||
|
}
|
||||||
|
|
||||||
|
public InputMediaVideo setHeight(int height) {
|
||||||
|
this.height = height;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getDuration() {
|
||||||
|
return duration;
|
||||||
|
}
|
||||||
|
|
||||||
|
public InputMediaVideo setDuration(int duration) {
|
||||||
|
this.duration = duration;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getType() {
|
||||||
|
return TYPE;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void validate() throws TelegramApiValidationException {
|
||||||
|
super.validate();
|
||||||
|
}
|
||||||
|
}
|
@ -825,6 +825,13 @@ public abstract class AbsSender {
|
|||||||
*/
|
*/
|
||||||
public abstract Message sendVoice(SendVoice sendVoice) throws TelegramApiException;
|
public abstract Message sendVoice(SendVoice sendVoice) throws TelegramApiException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send a media group (https://core.telegram.org/bots/api#sendMediaGroup)
|
||||||
|
* @return If success, list of generated messages
|
||||||
|
* @throws TelegramApiException If there is any error sending the media group
|
||||||
|
*/
|
||||||
|
public abstract List<Message> sendMediaGroup(SendMediaGroup sendMediaGroup) throws TelegramApiException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set chat profile photo (https://core.telegram.org/bots/api#setChatPhoto)
|
* Set chat profile photo (https://core.telegram.org/bots/api#setChatPhoto)
|
||||||
* @param setChatPhoto Information to set the photo
|
* @param setChatPhoto Information to set the photo
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
<groupId>org.telegram</groupId>
|
<groupId>org.telegram</groupId>
|
||||||
<artifactId>telegrambots</artifactId>
|
<artifactId>telegrambots</artifactId>
|
||||||
<version>3.4</version>
|
<version>3.5</version>
|
||||||
<packaging>jar</packaging>
|
<packaging>jar</packaging>
|
||||||
|
|
||||||
<name>Telegram Bots</name>
|
<name>Telegram Bots</name>
|
||||||
@ -66,7 +66,7 @@
|
|||||||
<jackson.version>2.8.7</jackson.version>
|
<jackson.version>2.8.7</jackson.version>
|
||||||
<jacksonanotation.version>2.8.0</jacksonanotation.version>
|
<jacksonanotation.version>2.8.0</jacksonanotation.version>
|
||||||
<commonio.version>2.5</commonio.version>
|
<commonio.version>2.5</commonio.version>
|
||||||
<bots.version>3.4</bots.version>
|
<bots.version>3.5</bots.version>
|
||||||
</properties>
|
</properties>
|
||||||
|
|
||||||
<dependencyManagement>
|
<dependencyManagement>
|
||||||
|
@ -22,6 +22,7 @@ import org.telegram.telegrambots.api.methods.stickers.CreateNewStickerSet;
|
|||||||
import org.telegram.telegrambots.api.methods.stickers.UploadStickerFile;
|
import org.telegram.telegrambots.api.methods.stickers.UploadStickerFile;
|
||||||
import org.telegram.telegrambots.api.objects.File;
|
import org.telegram.telegrambots.api.objects.File;
|
||||||
import org.telegram.telegrambots.api.objects.Message;
|
import org.telegram.telegrambots.api.objects.Message;
|
||||||
|
import org.telegram.telegrambots.api.objects.media.InputMedia;
|
||||||
import org.telegram.telegrambots.exceptions.TelegramApiException;
|
import org.telegram.telegrambots.exceptions.TelegramApiException;
|
||||||
import org.telegram.telegrambots.exceptions.TelegramApiRequestException;
|
import org.telegram.telegrambots.exceptions.TelegramApiRequestException;
|
||||||
import org.telegram.telegrambots.exceptions.TelegramApiValidationException;
|
import org.telegram.telegrambots.exceptions.TelegramApiValidationException;
|
||||||
@ -33,6 +34,7 @@ import java.io.Serializable;
|
|||||||
import java.net.MalformedURLException;
|
import java.net.MalformedURLException;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.util.List;
|
||||||
import java.util.concurrent.ExecutorService;
|
import java.util.concurrent.ExecutorService;
|
||||||
import java.util.concurrent.Executors;
|
import java.util.concurrent.Executors;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
@ -497,6 +499,49 @@ public abstract class DefaultAbsSender extends AbsSender {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<Message> sendMediaGroup(SendMediaGroup sendMediaGroup) throws TelegramApiException {
|
||||||
|
assertParamNotNull(sendMediaGroup, "sendMediaGroup");
|
||||||
|
sendMediaGroup.validate();
|
||||||
|
|
||||||
|
try {
|
||||||
|
String url = getBaseUrl() + SendMediaGroup.PATH;
|
||||||
|
HttpPost httppost = configuredHttpPost(url);
|
||||||
|
|
||||||
|
MultipartEntityBuilder builder = MultipartEntityBuilder.create();
|
||||||
|
builder.setLaxMode();
|
||||||
|
builder.setCharset(StandardCharsets.UTF_8);
|
||||||
|
builder.addTextBody(SendMediaGroup.CHATID_FIELD, sendMediaGroup.getChatId(), TEXT_PLAIN_CONTENT_TYPE);
|
||||||
|
builder.addTextBody(SendMediaGroup.MEDIA_FIELD, objectMapper.writeValueAsString(sendMediaGroup.getMedia()), TEXT_PLAIN_CONTENT_TYPE);
|
||||||
|
|
||||||
|
for (InputMedia inputMedia : sendMediaGroup.getMedia()) {
|
||||||
|
if (inputMedia.isNewMedia()) {
|
||||||
|
if (inputMedia.getMediaFile() != null) {
|
||||||
|
builder.addBinaryBody(inputMedia.getMediaName(), inputMedia.getMediaFile(), ContentType.APPLICATION_OCTET_STREAM, inputMedia.getMediaName());
|
||||||
|
} else if (inputMedia.getNewMediaStream() != null) {
|
||||||
|
builder.addBinaryBody(inputMedia.getMediaName(), inputMedia.getNewMediaStream(), ContentType.APPLICATION_OCTET_STREAM, inputMedia.getMediaName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sendMediaGroup.getDisableNotification() != null) {
|
||||||
|
builder.addTextBody(SendMediaGroup.DISABLENOTIFICATION_FIELD, sendMediaGroup.getDisableNotification().toString(), TEXT_PLAIN_CONTENT_TYPE);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sendMediaGroup.getReplyToMessageId() != null) {
|
||||||
|
builder.addTextBody(SendMediaGroup.REPLYTOMESSAGEID_FIELD, sendMediaGroup.getReplyToMessageId().toString(), TEXT_PLAIN_CONTENT_TYPE);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
HttpEntity multipart = builder.build();
|
||||||
|
httppost.setEntity(multipart);
|
||||||
|
|
||||||
|
return sendMediaGroup.deserializeResponse(sendHttpPostRequest(httppost));
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new TelegramApiException("Unable to set chat photo", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Boolean addStickerToSet(AddStickerToSet addStickerToSet) throws TelegramApiException {
|
public Boolean addStickerToSet(AddStickerToSet addStickerToSet) throws TelegramApiException {
|
||||||
|
@ -26,6 +26,7 @@ public class DefaultBotOptions implements BotOptions {
|
|||||||
baseUrl = ApiConstants.BASE_URL;
|
baseUrl = ApiConstants.BASE_URL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public String getBaseUrl() {
|
public String getBaseUrl() {
|
||||||
return baseUrl;
|
return baseUrl;
|
||||||
}
|
}
|
||||||
|
@ -24,6 +24,7 @@ import org.telegram.telegrambots.logging.BotLogger;
|
|||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InvalidObjectException;
|
import java.io.InvalidObjectException;
|
||||||
|
import java.net.SocketException;
|
||||||
import java.net.SocketTimeoutException;
|
import java.net.SocketTimeoutException;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.security.InvalidParameterException;
|
import java.security.InvalidParameterException;
|
||||||
@ -259,6 +260,10 @@ public class DefaultBotSession implements BotSession {
|
|||||||
BotLogger.severe(responseContent, LOGTAG, e);
|
BotLogger.severe(responseContent, LOGTAG, e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} catch (SocketException e) {
|
||||||
|
if (!e.getMessage().equals("Socket Closed")) {
|
||||||
|
BotLogger.severe(LOGTAG, e);
|
||||||
|
}
|
||||||
} catch (SocketTimeoutException e) {
|
} catch (SocketTimeoutException e) {
|
||||||
BotLogger.fine(LOGTAG, e);
|
BotLogger.fine(LOGTAG, e);
|
||||||
} catch (InvalidObjectException | TelegramApiRequestException e) {
|
} catch (InvalidObjectException | TelegramApiRequestException e) {
|
||||||
|
Loading…
Reference in New Issue
Block a user