Merge commit '203b26587f771f9b9bf0f97f8df04e18612a5fe5'
This commit is contained in:
commit
73b8f90ee2
@ -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>4.9</version>
|
<version>4.9.1</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
```
|
```
|
||||||
|
|
||||||
```gradle
|
```gradle
|
||||||
compile "org.telegram:telegrambots:4.9"
|
compile "org.telegram:telegrambots:4.9.1"
|
||||||
```
|
```
|
||||||
|
|
||||||
2. Using Jitpack from [here](https://jitpack.io/#rubenlagus/TelegramBots/4.9)
|
2. Using Jitpack from [here](https://jitpack.io/#rubenlagus/TelegramBots/4.9.1)
|
||||||
3. Download the jar(including all dependencies) from [here](https://mvnrepository.com/artifact/org.telegram/telegrambots/4.9)
|
3. Download the jar(including all dependencies) from [here](https://mvnrepository.com/artifact/org.telegram/telegrambots/4.9.1)
|
||||||
|
|
||||||
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,6 @@
|
|||||||
|
### <a id="4.9.1"></a>4.9.1 ###
|
||||||
|
1. Bug fixing: #767, #766, #761, #763, #776, #772, #771, #780
|
||||||
|
|
||||||
### <a id="4.9"></a>4.9 ###
|
### <a id="4.9"></a>4.9 ###
|
||||||
1. Update Api version [4.9](https://core.telegram.org/bots/api-changelog#june-4-2020)
|
1. Update Api version [4.9](https://core.telegram.org/bots/api-changelog#june-4-2020)
|
||||||
2. Bug fixing: #731, #749, #752 and #753
|
2. Bug fixing: #731, #749, #752 and #753
|
||||||
|
@ -243,16 +243,16 @@ This is just one way, how you can compile it (here with maven). The example belo
|
|||||||
Please use ```execute()``` instead.
|
Please use ```execute()``` instead.
|
||||||
Example:
|
Example:
|
||||||
```java
|
```java
|
||||||
SendMessage sn = new SendMessage();
|
SendMessage message = new SendMessage();
|
||||||
//add chat id and text
|
//add chat id and text
|
||||||
execute(sn);
|
execute(message);
|
||||||
```
|
```
|
||||||
|
|
||||||
If you extend ```TelegramLongPollingCommandBot```, then use ```AbsSender.execute()``` instead.
|
If you extend ```TelegramLongPollingCommandBot```, then use ```AbsSender.execute()``` instead.
|
||||||
|
|
||||||
|
|
||||||
## <a id="example_webhook"></a>Is there any example for WebHook? ##
|
## <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)
|
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)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -268,7 +268,7 @@ public class YourApplicationMainClass {
|
|||||||
//Add this line to initialize bots context
|
//Add this line to initialize bots context
|
||||||
ApiContextInitializer.init();
|
ApiContextInitializer.init();
|
||||||
|
|
||||||
SpringApplication.run(MusicUploaderApplication.class, args);
|
SpringApplication.run(YourApplicationMainClass.class, args);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
@ -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>4.9</version>
|
<version>4.9.1</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
```
|
```
|
||||||
* With **Gradle**:
|
* With **Gradle**:
|
||||||
|
|
||||||
```groovy
|
```groovy
|
||||||
compile group: 'org.telegram', name: 'telegrambots', version: '4.9'
|
compile group: 'org.telegram', name: 'telegrambots', version: '4.9.1'
|
||||||
```
|
```
|
||||||
|
|
||||||
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).
|
||||||
|
@ -33,5 +33,35 @@ As an example, if you want to restrict the updates to photos only, then you may
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Custom Command Processing
|
||||||
|
### Command Prefix
|
||||||
|
Customizing the command prefix is as simple as overriding the `getCommandPrefix` method as shown below.
|
||||||
|
```java
|
||||||
|
@Override
|
||||||
|
protected String getCommandPrefix() {
|
||||||
|
return "!";
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Command Regex Split
|
||||||
|
The method that the bot uses to capture command tokens is through the regex splitters. By default, it's set to `" "`. However, this can be customized. For example,
|
||||||
|
if you'd like to split on digits and whitespaces, then you may do the following:
|
||||||
|
```java
|
||||||
|
@Override
|
||||||
|
protected String getCommandRegexSplit() {
|
||||||
|
return "\\s\\d";
|
||||||
|
}
|
||||||
|
```
|
||||||
|
### Commands with Continuous Text
|
||||||
|
Feeling ambitious? You may allow your bot to process tokens that are technically attached to your command. Imagine you have a command
|
||||||
|
`/do` and you'd like users to send commands as `/do1` and still trigger the `do` ability. In order to do that, override the `allowContinuousText` function.
|
||||||
|
```java
|
||||||
|
@Override
|
||||||
|
protected boolean allowContinuousText() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
Please note that this may cause ability overlap. If multiple abilities can match the same command, the longest match will be taken. For example,
|
||||||
|
if you have two abilities `do` and `do1`, the command `/do1` will trigger the `do1` ability.
|
||||||
## Statistics
|
## Statistics
|
||||||
AbilityBot can accrue basic statistics about the usage of your abilities and replies. Simply `enableStats()` on an Ability builder or `enableStats(<name>)` on replies to activate this feature. Once activated, you may call `/stats` and the bot will print a basic list of statistics. At the moment, AbilityBot only tracks hits. In the future, this will be enhanced to track more stats.
|
AbilityBot can accrue basic statistics about the usage of your abilities and replies. Simply `enableStats()` on an Ability builder or `enableStats(<name>)` on replies to activate this feature. Once activated, you may call `/stats` and the bot will print a basic list of statistics. At the moment, AbilityBot only tracks hits. In the future, this will be enhanced to track more stats.
|
@ -9,12 +9,12 @@ As with any Java project, you will need to set your dependencies.
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.telegram</groupId>
|
<groupId>org.telegram</groupId>
|
||||||
<artifactId>telegrambots-abilities</artifactId>
|
<artifactId>telegrambots-abilities</artifactId>
|
||||||
<version>4.9</version>
|
<version>4.9.1</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
```
|
```
|
||||||
* **Gradle**
|
* **Gradle**
|
||||||
```groovy
|
```groovy
|
||||||
implementation group: 'org.telegram', name: 'telegrambots-abilities', version: '4.9'
|
implementation group: 'org.telegram', name: 'telegrambots-abilities', version: '4.9.1'
|
||||||
```
|
```
|
||||||
* [JitPack](https://jitpack.io/#rubenlagus/TelegramBots)
|
* [JitPack](https://jitpack.io/#rubenlagus/TelegramBots)
|
||||||
|
|
||||||
|
2
pom.xml
2
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>4.9</version>
|
<version>4.9.1</version>
|
||||||
|
|
||||||
<modules>
|
<modules>
|
||||||
<module>telegrambots</module>
|
<module>telegrambots</module>
|
||||||
|
@ -18,19 +18,19 @@ Usage
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.telegram</groupId>
|
<groupId>org.telegram</groupId>
|
||||||
<artifactId>telegrambots-abilities</artifactId>
|
<artifactId>telegrambots-abilities</artifactId>
|
||||||
<version>4.9</version>
|
<version>4.9.1</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
```
|
```
|
||||||
|
|
||||||
**Gradle**
|
**Gradle**
|
||||||
|
|
||||||
```gradle
|
```gradle
|
||||||
compile "org.telegram:telegrambots-abilities:4.9"
|
compile "org.telegram:telegrambots-abilities:4.9.1"
|
||||||
```
|
```
|
||||||
|
|
||||||
**JitPack** - [JitPack](https://jitpack.io/#rubenlagus/TelegramBots/v4.9)
|
**JitPack** - [JitPack](https://jitpack.io/#rubenlagus/TelegramBots/v4.9.1)
|
||||||
|
|
||||||
**Plain imports** - [Here](https://github.com/rubenlagus/TelegramBots/releases/tag/v4.9)
|
**Plain imports** - [Here](https://github.com/rubenlagus/TelegramBots/releases/tag/v4.9.1)
|
||||||
|
|
||||||
Motivation
|
Motivation
|
||||||
----------
|
----------
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>org.telegram</groupId>
|
<groupId>org.telegram</groupId>
|
||||||
<artifactId>Bots</artifactId>
|
<artifactId>Bots</artifactId>
|
||||||
<version>4.9</version>
|
<version>4.9.1</version>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
<artifactId>telegrambots-abilities</artifactId>
|
<artifactId>telegrambots-abilities</artifactId>
|
||||||
@ -84,7 +84,7 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.telegram</groupId>
|
<groupId>org.telegram</groupId>
|
||||||
<artifactId>telegrambots</artifactId>
|
<artifactId>telegrambots</artifactId>
|
||||||
<version>4.9</version>
|
<version>4.9.1</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.apache.commons</groupId>
|
<groupId>org.apache.commons</groupId>
|
||||||
|
@ -3,9 +3,9 @@ package org.telegram.abilitybots.api.bot;
|
|||||||
import org.telegram.abilitybots.api.db.DBContext;
|
import org.telegram.abilitybots.api.db.DBContext;
|
||||||
import org.telegram.abilitybots.api.toggle.AbilityToggle;
|
import org.telegram.abilitybots.api.toggle.AbilityToggle;
|
||||||
import org.telegram.abilitybots.api.toggle.DefaultToggle;
|
import org.telegram.abilitybots.api.toggle.DefaultToggle;
|
||||||
|
import org.telegram.telegrambots.bots.DefaultAbsSender;
|
||||||
import org.telegram.telegrambots.meta.api.objects.Update;
|
import org.telegram.telegrambots.meta.api.objects.Update;
|
||||||
import org.telegram.telegrambots.bots.DefaultBotOptions;
|
import org.telegram.telegrambots.bots.DefaultBotOptions;
|
||||||
import org.telegram.telegrambots.bots.TelegramLongPollingBot;
|
|
||||||
import org.telegram.telegrambots.meta.exceptions.TelegramApiRequestException;
|
import org.telegram.telegrambots.meta.exceptions.TelegramApiRequestException;
|
||||||
import org.telegram.telegrambots.meta.generics.LongPollingBot;
|
import org.telegram.telegrambots.meta.generics.LongPollingBot;
|
||||||
import org.telegram.telegrambots.util.WebhookUtils;
|
import org.telegram.telegrambots.util.WebhookUtils;
|
||||||
@ -13,7 +13,7 @@ import org.telegram.telegrambots.util.WebhookUtils;
|
|||||||
import static org.telegram.abilitybots.api.db.MapDBContext.onlineInstance;
|
import static org.telegram.abilitybots.api.db.MapDBContext.onlineInstance;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The default AbilityBot class implements {@link LongPollingBot}. It delegates all updates to a {@link TelegramLongPollingBot} instance.
|
* The default AbilityBot class implements {@link LongPollingBot}. It delegates all updates to a {@link DefaultAbsSender} instance.
|
||||||
*
|
*
|
||||||
* @author Abbas Abou Daya
|
* @author Abbas Abou Daya
|
||||||
*/
|
*/
|
||||||
|
@ -3,7 +3,6 @@ package org.telegram.abilitybots.api.bot;
|
|||||||
import com.google.common.collect.*;
|
import com.google.common.collect.*;
|
||||||
import com.google.common.collect.ImmutableList.Builder;
|
import com.google.common.collect.ImmutableList.Builder;
|
||||||
import com.google.common.collect.ImmutableMap;
|
import com.google.common.collect.ImmutableMap;
|
||||||
import org.jetbrains.annotations.NotNull;
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.telegram.abilitybots.api.db.DBContext;
|
import org.telegram.abilitybots.api.db.DBContext;
|
||||||
@ -18,7 +17,6 @@ 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.bots.DefaultAbsSender;
|
import org.telegram.telegrambots.bots.DefaultAbsSender;
|
||||||
import org.telegram.telegrambots.bots.DefaultBotOptions;
|
import org.telegram.telegrambots.bots.DefaultBotOptions;
|
||||||
import org.telegram.telegrambots.bots.TelegramLongPollingBot;
|
|
||||||
import org.telegram.telegrambots.meta.api.methods.groupadministration.GetChatAdministrators;
|
import org.telegram.telegrambots.meta.api.methods.groupadministration.GetChatAdministrators;
|
||||||
import org.telegram.telegrambots.meta.api.objects.Message;
|
import org.telegram.telegrambots.meta.api.objects.Message;
|
||||||
import org.telegram.telegrambots.meta.api.objects.Update;
|
import org.telegram.telegrambots.meta.api.objects.Update;
|
||||||
@ -27,6 +25,7 @@ import org.telegram.telegrambots.meta.api.objects.User;
|
|||||||
import java.lang.reflect.InvocationTargetException;
|
import java.lang.reflect.InvocationTargetException;
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
import java.util.concurrent.Callable;
|
||||||
import java.util.function.BiFunction;
|
import java.util.function.BiFunction;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
import java.util.function.Predicate;
|
import java.util.function.Predicate;
|
||||||
@ -37,6 +36,8 @@ import static com.google.common.collect.Sets.difference;
|
|||||||
import static java.lang.String.format;
|
import static java.lang.String.format;
|
||||||
import static java.time.ZonedDateTime.now;
|
import static java.time.ZonedDateTime.now;
|
||||||
import static java.util.Arrays.stream;
|
import static java.util.Arrays.stream;
|
||||||
|
import static java.util.Comparator.comparingInt;
|
||||||
|
import static java.util.Objects.isNull;
|
||||||
import static java.util.Optional.ofNullable;
|
import static java.util.Optional.ofNullable;
|
||||||
import static java.util.regex.Pattern.CASE_INSENSITIVE;
|
import static java.util.regex.Pattern.CASE_INSENSITIVE;
|
||||||
import static java.util.regex.Pattern.compile;
|
import static java.util.regex.Pattern.compile;
|
||||||
@ -51,7 +52,7 @@ import static org.telegram.abilitybots.api.util.AbilityUtils.*;
|
|||||||
/**
|
/**
|
||||||
* The <b>father</b> of all ability bots. Bots that need to utilize abilities need to extend this bot.
|
* The <b>father</b> of all ability bots. Bots that need to utilize abilities need to extend this bot.
|
||||||
* <p>
|
* <p>
|
||||||
* It's important to note that this bot strictly extends {@link TelegramLongPollingBot}.
|
* It's important to note that this bot strictly extends {@link DefaultAbsSender}.
|
||||||
* <p>
|
* <p>
|
||||||
* All bots extending the {@link BaseAbilityBot} get implicit abilities:
|
* All bots extending the {@link BaseAbilityBot} get implicit abilities:
|
||||||
* <ul>
|
* <ul>
|
||||||
@ -130,35 +131,35 @@ public abstract class BaseAbilityBot extends DefaultAbsSender implements Ability
|
|||||||
/**
|
/**
|
||||||
* @return the map of <ID,User>
|
* @return the map of <ID,User>
|
||||||
*/
|
*/
|
||||||
protected Map<Integer, User> users() {
|
public Map<Integer, User> users() {
|
||||||
return db.getMap(USERS);
|
return db.getMap(USERS);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the map of <Username,ID>
|
* @return the map of <Username,ID>
|
||||||
*/
|
*/
|
||||||
protected Map<String, Integer> userIds() {
|
public Map<String, Integer> userIds() {
|
||||||
return db.getMap(USER_ID);
|
return db.getMap(USER_ID);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return a blacklist containing all the IDs of the banned users
|
* @return a blacklist containing all the IDs of the banned users
|
||||||
*/
|
*/
|
||||||
protected Set<Integer> blacklist() {
|
public Set<Integer> blacklist() {
|
||||||
return db.getSet(BLACKLIST);
|
return db.getSet(BLACKLIST);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return an admin set of all the IDs of bot administrators
|
* @return an admin set of all the IDs of bot administrators
|
||||||
*/
|
*/
|
||||||
protected Set<Integer> admins() {
|
public Set<Integer> admins() {
|
||||||
return db.getSet(ADMINS);
|
return db.getSet(ADMINS);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return a mapping of ability and reply names to their corresponding statistics
|
* @return a mapping of ability and reply names to their corresponding statistics
|
||||||
*/
|
*/
|
||||||
protected Map<String, Stats> stats() {
|
public Map<String, Stats> stats() {
|
||||||
return stats;
|
return stats;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -221,6 +222,32 @@ public abstract class BaseAbilityBot extends DefaultAbsSender implements Ability
|
|||||||
return botUsername;
|
return botUsername;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Privacy getPrivacy(Update update, int id) {
|
||||||
|
return isCreator(id) ?
|
||||||
|
CREATOR : isAdmin(id) ?
|
||||||
|
ADMIN : (isGroupUpdate(update) || isSuperGroupUpdate(update)) && isGroupAdmin(update, id) ?
|
||||||
|
GROUP_ADMIN : PUBLIC;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isGroupAdmin(Update update, int id) {
|
||||||
|
return isGroupAdmin(getChatId(update), id);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isGroupAdmin(long chatId, int id) {
|
||||||
|
GetChatAdministrators admins = new GetChatAdministrators().setChatId(chatId);
|
||||||
|
return silent.execute(admins)
|
||||||
|
.orElse(new ArrayList<>()).stream()
|
||||||
|
.anyMatch(member -> member.getUser().getId() == id);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isCreator(int id) {
|
||||||
|
return id == creatorId();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isAdmin(Integer id) {
|
||||||
|
return admins().contains(id);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test the update against the provided global flags. The default implementation is a passthrough to all updates.
|
* Test the update against the provided global flags. The default implementation is a passthrough to all updates.
|
||||||
* <p>
|
* <p>
|
||||||
@ -233,6 +260,18 @@ public abstract class BaseAbilityBot extends DefaultAbsSender implements Ability
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected String getCommandPrefix() {
|
||||||
|
return "/";
|
||||||
|
}
|
||||||
|
|
||||||
|
protected String getCommandRegexSplit() {
|
||||||
|
return " ";
|
||||||
|
}
|
||||||
|
|
||||||
|
protected boolean allowContinuousText() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Registers the declared abilities using method reflection. Also, replies are accumulated using the built abilities and standalone methods that return a Reply.
|
* Registers the declared abilities using method reflection. Also, replies are accumulated using the built abilities and standalone methods that return a Reply.
|
||||||
* <p>
|
* <p>
|
||||||
@ -277,7 +316,8 @@ public abstract class BaseAbilityBot extends DefaultAbsSender implements Ability
|
|||||||
|
|
||||||
// Replies can be standalone or attached to abilities, fetch those too
|
// Replies can be standalone or attached to abilities, fetch those too
|
||||||
Stream<Reply> abilityReplies = abilities.values().stream()
|
Stream<Reply> abilityReplies = abilities.values().stream()
|
||||||
.flatMap(ability -> ability.replies().stream());
|
.flatMap(ability -> ability.replies().stream())
|
||||||
|
.flatMap(Reply::stream);
|
||||||
|
|
||||||
// Now create the replies registry (list)
|
// Now create the replies registry (list)
|
||||||
replies = Stream.concat(abilityReplies, extensionReplies).collect(
|
replies = Stream.concat(abilityReplies, extensionReplies).collect(
|
||||||
@ -401,8 +441,12 @@ public abstract class BaseAbilityBot extends DefaultAbsSender implements Ability
|
|||||||
}
|
}
|
||||||
|
|
||||||
boolean checkBlacklist(Update update) {
|
boolean checkBlacklist(Update update) {
|
||||||
Integer id = AbilityUtils.getUser(update).getId();
|
User user = getUser(update);
|
||||||
|
if (isNull(user)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
int id = user.getId();
|
||||||
return id == creatorId() || !blacklist().contains(id);
|
return id == creatorId() || !blacklist().contains(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -458,30 +502,6 @@ public abstract class BaseAbilityBot extends DefaultAbsSender implements Ability
|
|||||||
return isOk;
|
return isOk;
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
|
||||||
Privacy getPrivacy(Update update, int id) {
|
|
||||||
return isCreator(id) ?
|
|
||||||
CREATOR : isAdmin(id) ?
|
|
||||||
ADMIN : (isGroupUpdate(update) || isSuperGroupUpdate(update)) && isGroupAdmin(update, id) ?
|
|
||||||
GROUP_ADMIN : PUBLIC;
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean isGroupAdmin(Update update, int id) {
|
|
||||||
GetChatAdministrators admins = new GetChatAdministrators().setChatId(getChatId(update));
|
|
||||||
|
|
||||||
return silent.execute(admins)
|
|
||||||
.orElse(new ArrayList<>()).stream()
|
|
||||||
.anyMatch(member -> member.getUser().getId() == id);
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean isCreator(int id) {
|
|
||||||
return id == creatorId();
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean isAdmin(Integer id) {
|
|
||||||
return admins().contains(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
boolean validateAbility(Trio<Update, Ability, String[]> trio) {
|
boolean validateAbility(Trio<Update, Ability, String[]> trio) {
|
||||||
return trio.b() != null;
|
return trio.b() != null;
|
||||||
}
|
}
|
||||||
@ -493,17 +513,28 @@ public abstract class BaseAbilityBot extends DefaultAbsSender implements Ability
|
|||||||
if (!update.hasMessage() || !msg.hasText())
|
if (!update.hasMessage() || !msg.hasText())
|
||||||
return Trio.of(update, abilities.get(DEFAULT), new String[]{});
|
return Trio.of(update, abilities.get(DEFAULT), new String[]{});
|
||||||
|
|
||||||
String[] tokens = msg.getText().split(" ");
|
Ability ability;
|
||||||
|
String[] tokens;
|
||||||
if (tokens[0].startsWith("/")) {
|
if (allowContinuousText()) {
|
||||||
String abilityToken = stripBotUsername(tokens[0].substring(1)).toLowerCase();
|
String abName = abilities.keySet().stream()
|
||||||
Ability ability = abilities.get(abilityToken);
|
.filter(name -> msg.getText().startsWith(format("%s%s", getCommandPrefix(), name)))
|
||||||
tokens = Arrays.copyOfRange(tokens, 1, tokens.length);
|
.max(comparingInt(String::length))
|
||||||
return Trio.of(update, ability, tokens);
|
.orElse(DEFAULT);
|
||||||
|
tokens = msg.getText()
|
||||||
|
.replaceFirst(getCommandPrefix() + abName, "")
|
||||||
|
.split(getCommandRegexSplit());
|
||||||
|
ability = abilities.get(abName);
|
||||||
} else {
|
} else {
|
||||||
Ability ability = abilities.get(DEFAULT);
|
tokens = msg.getText().split(getCommandRegexSplit());
|
||||||
return Trio.of(update, ability, tokens);
|
if (tokens[0].startsWith(getCommandPrefix())) {
|
||||||
|
String abilityToken = stripBotUsername(tokens[0].substring(1)).toLowerCase();
|
||||||
|
ability = abilities.get(abilityToken);
|
||||||
|
tokens = Arrays.copyOfRange(tokens, 1, tokens.length);
|
||||||
|
} else {
|
||||||
|
ability = abilities.get(DEFAULT);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
return Trio.of(update, ability, tokens);
|
||||||
}
|
}
|
||||||
|
|
||||||
private String stripBotUsername(String token) {
|
private String stripBotUsername(String token) {
|
||||||
@ -556,15 +587,25 @@ public abstract class BaseAbilityBot extends DefaultAbsSender implements Ability
|
|||||||
|
|
||||||
boolean filterReply(Update update) {
|
boolean filterReply(Update update) {
|
||||||
return replies.stream()
|
return replies.stream()
|
||||||
.filter(reply -> reply.isOkFor(update))
|
.filter(reply -> runSilently(() -> reply.isOkFor(update), reply.name()))
|
||||||
.map(reply -> {
|
.map(reply -> runSilently(() -> {
|
||||||
reply.actOn(update);
|
reply.actOn(update);
|
||||||
updateReplyStats(reply);
|
updateReplyStats(reply);
|
||||||
return false;
|
return false;
|
||||||
})
|
}, reply.name()))
|
||||||
.reduce(true, Boolean::logicalAnd);
|
.reduce(true, Boolean::logicalAnd);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
boolean runSilently(Callable<Boolean> callable, String name) {
|
||||||
|
try {
|
||||||
|
return callable.call();
|
||||||
|
} catch(Exception ex) {
|
||||||
|
log.error(format("Reply [%s] failed to check for conditions. " +
|
||||||
|
"Make sure you're safeguarding against all possible updates.", name));
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
boolean checkMessageFlags(Trio<Update, Ability, String[]> trio) {
|
boolean checkMessageFlags(Trio<Update, Ability, String[]> trio) {
|
||||||
Ability ability = trio.b();
|
Ability ability = trio.b();
|
||||||
Update update = trio.a();
|
Update update = trio.a();
|
||||||
|
@ -2,10 +2,8 @@ package org.telegram.abilitybots.api.objects;
|
|||||||
|
|
||||||
import com.google.common.base.MoreObjects;
|
import com.google.common.base.MoreObjects;
|
||||||
import com.google.common.collect.ImmutableList;
|
import com.google.common.collect.ImmutableList;
|
||||||
import com.google.common.collect.Lists;
|
|
||||||
import org.telegram.telegrambots.meta.api.objects.Update;
|
import org.telegram.telegrambots.meta.api.objects.Update;
|
||||||
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.function.BiFunction;
|
import java.util.function.BiFunction;
|
||||||
@ -14,7 +12,6 @@ import java.util.function.Predicate;
|
|||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
import static com.google.common.collect.Lists.newArrayList;
|
import static com.google.common.collect.Lists.newArrayList;
|
||||||
import static java.util.Arrays.asList;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A reply consists of update conditionals and an action to be applied on the update.
|
* A reply consists of update conditionals and an action to be applied on the update.
|
||||||
@ -37,6 +34,13 @@ public class Reply {
|
|||||||
statsEnabled = false;
|
statsEnabled = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reply(List<Predicate<Update>> conditions, Consumer<Update> action, String name) {
|
||||||
|
this(conditions, action);
|
||||||
|
if (Objects.nonNull(name)) {
|
||||||
|
enableStats(name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static Reply of(Consumer<Update> action, List<Predicate<Update>> conditions) {
|
public static Reply of(Consumer<Update> action, List<Predicate<Update>> conditions) {
|
||||||
return new Reply(conditions, action);
|
return new Reply(conditions, action);
|
||||||
}
|
}
|
||||||
|
@ -20,8 +20,8 @@ public class ReplyFlow extends Reply {
|
|||||||
|
|
||||||
private final Set<Reply> nextReplies;
|
private final Set<Reply> nextReplies;
|
||||||
|
|
||||||
private ReplyFlow(List<Predicate<Update>> conditions, Consumer<Update> action, Set<Reply> nextReplies) {
|
private ReplyFlow(List<Predicate<Update>> conditions, Consumer<Update> action, Set<Reply> nextReplies, String name) {
|
||||||
super(conditions, action);
|
super(conditions, action, name);
|
||||||
this.nextReplies = nextReplies;
|
this.nextReplies = nextReplies;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -50,6 +50,7 @@ public class ReplyFlow extends Reply {
|
|||||||
private List<Predicate<Update>> conds;
|
private List<Predicate<Update>> conds;
|
||||||
private Consumer<Update> action;
|
private Consumer<Update> action;
|
||||||
private Set<Reply> nextReplies;
|
private Set<Reply> nextReplies;
|
||||||
|
private String name;
|
||||||
|
|
||||||
private ReplyFlowBuilder(DBContext db, int id) {
|
private ReplyFlowBuilder(DBContext db, int id) {
|
||||||
conds = new ArrayList<>();
|
conds = new ArrayList<>();
|
||||||
@ -67,6 +68,11 @@ public class ReplyFlow extends Reply {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ReplyFlowBuilder enableStats(String name) {
|
||||||
|
this.name = name;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
public ReplyFlowBuilder onlyIf(Predicate<Update> pred) {
|
public ReplyFlowBuilder onlyIf(Predicate<Update> pred) {
|
||||||
conds.add(pred);
|
conds.add(pred);
|
||||||
return this;
|
return this;
|
||||||
@ -79,7 +85,7 @@ public class ReplyFlow extends Reply {
|
|||||||
db.<Long, Integer>getMap(STATES).remove(chatId);
|
db.<Long, Integer>getMap(STATES).remove(chatId);
|
||||||
});
|
});
|
||||||
|
|
||||||
Reply statefulReply = Reply.of(statefulAction, statefulConditions);
|
Reply statefulReply = new Reply(statefulConditions, statefulAction, nextReply.name());
|
||||||
nextReplies.add(statefulReply);
|
nextReplies.add(statefulReply);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
@ -87,7 +93,7 @@ public class ReplyFlow extends Reply {
|
|||||||
public ReplyFlowBuilder next(ReplyFlow nextReplyFlow) {
|
public ReplyFlowBuilder next(ReplyFlow nextReplyFlow) {
|
||||||
List<Predicate<Update>> statefulConditions = toStateful(nextReplyFlow.conditions());
|
List<Predicate<Update>> statefulConditions = toStateful(nextReplyFlow.conditions());
|
||||||
|
|
||||||
ReplyFlow statefulReplyFlow = new ReplyFlow(statefulConditions, nextReplyFlow.action(), nextReplyFlow.nextReplies());
|
ReplyFlow statefulReplyFlow = new ReplyFlow(statefulConditions, nextReplyFlow.action(), nextReplyFlow.nextReplies(), nextReplyFlow.name());
|
||||||
nextReplies.add(statefulReplyFlow);
|
nextReplies.add(statefulReplyFlow);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
@ -95,12 +101,21 @@ public class ReplyFlow extends Reply {
|
|||||||
public ReplyFlow build() {
|
public ReplyFlow build() {
|
||||||
if (action == null)
|
if (action == null)
|
||||||
action = upd -> {};
|
action = upd -> {};
|
||||||
Consumer<Update> statefulAction = action.andThen(upd -> {
|
|
||||||
Long chatId = AbilityUtils.getChatId(upd);
|
|
||||||
db.<Long, Integer>getMap(STATES).put(chatId, id);
|
|
||||||
});
|
|
||||||
|
|
||||||
return new ReplyFlow(conds, statefulAction, nextReplies);
|
Consumer<Update> statefulAction;
|
||||||
|
if (nextReplies.size() > 0) {
|
||||||
|
statefulAction = action.andThen(upd -> {
|
||||||
|
Long chatId = AbilityUtils.getChatId(upd);
|
||||||
|
db.<Long, Integer>getMap(STATES).put(chatId, id);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
statefulAction = action.andThen(upd -> {
|
||||||
|
Long chatId = AbilityUtils.getChatId(upd);
|
||||||
|
db.<Long, Integer>getMap(STATES).remove(chatId);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return new ReplyFlow(conds, statefulAction, nextReplies, name);
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
|
@ -17,6 +17,7 @@ import java.util.function.Predicate;
|
|||||||
import static java.util.ResourceBundle.Control.FORMAT_PROPERTIES;
|
import static java.util.ResourceBundle.Control.FORMAT_PROPERTIES;
|
||||||
import static java.util.ResourceBundle.Control.getNoFallbackControl;
|
import static java.util.ResourceBundle.Control.getNoFallbackControl;
|
||||||
import static java.util.ResourceBundle.getBundle;
|
import static java.util.ResourceBundle.getBundle;
|
||||||
|
import static org.apache.commons.lang3.ObjectUtils.defaultIfNull;
|
||||||
import static org.apache.commons.lang3.StringUtils.isEmpty;
|
import static org.apache.commons.lang3.StringUtils.isEmpty;
|
||||||
import static org.telegram.abilitybots.api.objects.Flag.*;
|
import static org.telegram.abilitybots.api.objects.Flag.*;
|
||||||
|
|
||||||
@ -57,6 +58,10 @@ public final class AbilityUtils {
|
|||||||
* @throws IllegalStateException if the user could not be found
|
* @throws IllegalStateException if the user could not be found
|
||||||
*/
|
*/
|
||||||
public static User getUser(Update update) {
|
public static User getUser(Update update) {
|
||||||
|
return defaultIfNull(getUserElseThrow(update), EMPTY_USER);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static User getUserElseThrow(Update update) {
|
||||||
if (MESSAGE.test(update)) {
|
if (MESSAGE.test(update)) {
|
||||||
return update.getMessage().getFrom();
|
return update.getMessage().getFrom();
|
||||||
} else if (CALLBACK_QUERY.test(update)) {
|
} else if (CALLBACK_QUERY.test(update)) {
|
||||||
@ -199,16 +204,16 @@ public final class AbilityUtils {
|
|||||||
return update -> update.getMessage().getReplyToMessage().getText().equals(msg);
|
return update -> update.getMessage().getReplyToMessage().getText().equals(msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String getLocalizedMessage(String messageCode, Locale locale, Object...arguments) {
|
public static String getLocalizedMessage(String messageCode, Locale locale, Object... arguments) {
|
||||||
ResourceBundle bundle;
|
ResourceBundle bundle;
|
||||||
if (locale == null) {
|
if (locale == null) {
|
||||||
bundle = getBundle("messages", Locale.ROOT);
|
bundle = getBundle("messages", Locale.ROOT);
|
||||||
} else {
|
} else {
|
||||||
try {
|
try {
|
||||||
bundle = getBundle(
|
bundle = getBundle(
|
||||||
"messages",
|
"messages",
|
||||||
locale,
|
locale,
|
||||||
getNoFallbackControl(FORMAT_PROPERTIES));
|
getNoFallbackControl(FORMAT_PROPERTIES));
|
||||||
} catch (MissingResourceException e) {
|
} catch (MissingResourceException e) {
|
||||||
bundle = getBundle("messages", Locale.ROOT);
|
bundle = getBundle("messages", Locale.ROOT);
|
||||||
}
|
}
|
||||||
@ -217,7 +222,7 @@ public final class AbilityUtils {
|
|||||||
return MessageFormat.format(message, arguments);
|
return MessageFormat.format(message, arguments);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String getLocalizedMessage(String messageCode, String languageCode, Object...arguments){
|
public static String getLocalizedMessage(String messageCode, String languageCode, Object... arguments) {
|
||||||
Locale locale = Strings.isNullOrEmpty(languageCode) ? null : Locale.forLanguageTag(languageCode);
|
Locale locale = Strings.isNullOrEmpty(languageCode) ? null : Locale.forLanguageTag(languageCode);
|
||||||
return getLocalizedMessage(messageCode, locale, arguments);
|
return getLocalizedMessage(messageCode, locale, arguments);
|
||||||
}
|
}
|
||||||
@ -247,8 +252,8 @@ public final class AbilityUtils {
|
|||||||
* The full name is identified as the concatenation of the first and last name, separated by a space.
|
* The full name is identified as the concatenation of the first and last name, separated by a space.
|
||||||
* This method can return an empty name if both first and last name are empty.
|
* This method can return an empty name if both first and last name are empty.
|
||||||
*
|
*
|
||||||
* @return the full name of the user
|
|
||||||
* @param user
|
* @param user
|
||||||
|
* @return the full name of the user
|
||||||
*/
|
*/
|
||||||
public static String fullName(User user) {
|
public static String fullName(User user) {
|
||||||
StringJoiner name = new StringJoiner(" ");
|
StringJoiner name = new StringJoiner(" ");
|
||||||
@ -262,6 +267,6 @@ public final class AbilityUtils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static String escape(String username) {
|
public static String escape(String username) {
|
||||||
return username.replace("_", "\\_");
|
return username.replace("_", "\\_");
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -644,6 +644,21 @@ public class AbilityBotTest {
|
|||||||
verify(silent, times(1)).send(expected, GROUP_ID);
|
verify(silent, times(1)).send(expected, GROUP_ID);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void canProcessChannelPosts() {
|
||||||
|
Update update = mock(Update.class);
|
||||||
|
Message message = mock(Message.class);
|
||||||
|
when(message.getChatId()).thenReturn(1L);
|
||||||
|
|
||||||
|
when(update.getChannelPost()).thenReturn(message);
|
||||||
|
when(update.hasChannelPost()).thenReturn(true);
|
||||||
|
|
||||||
|
bot.onUpdateReceived(update);
|
||||||
|
|
||||||
|
String expected = "test channel post";
|
||||||
|
verify(silent, times(1)).send(expected, 1);
|
||||||
|
}
|
||||||
|
|
||||||
private void handlesAllUpdates(Consumer<Update> utilMethod) {
|
private void handlesAllUpdates(Consumer<Update> utilMethod) {
|
||||||
Arrays.stream(Update.class.getMethods())
|
Arrays.stream(Update.class.getMethods())
|
||||||
// filter to all these methods of hasXXX (hasPoll, hasMessage, etc...)
|
// filter to all these methods of hasXXX (hasPoll, hasMessage, etc...)
|
||||||
|
@ -0,0 +1,102 @@
|
|||||||
|
package org.telegram.abilitybots.api.bot;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.AfterEach;
|
||||||
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.telegram.abilitybots.api.db.DBContext;
|
||||||
|
import org.telegram.abilitybots.api.objects.Ability;
|
||||||
|
import org.telegram.abilitybots.api.sender.SilentSender;
|
||||||
|
import org.telegram.telegrambots.meta.api.objects.Update;
|
||||||
|
import org.telegram.telegrambots.meta.api.objects.User;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
import static org.apache.commons.lang3.StringUtils.EMPTY;
|
||||||
|
import static org.mockito.Mockito.mock;
|
||||||
|
import static org.mockito.Mockito.verify;
|
||||||
|
import static org.mockito.internal.verification.VerificationModeFactory.times;
|
||||||
|
import static org.telegram.abilitybots.api.bot.TestUtils.mockFullUpdate;
|
||||||
|
import static org.telegram.abilitybots.api.db.MapDBContext.offlineInstance;
|
||||||
|
import static org.telegram.abilitybots.api.objects.Ability.builder;
|
||||||
|
import static org.telegram.abilitybots.api.objects.Locality.ALL;
|
||||||
|
import static org.telegram.abilitybots.api.objects.Privacy.PUBLIC;
|
||||||
|
|
||||||
|
public class ContinuousTextTest {
|
||||||
|
private static final User USER = new User(1, "first", false, "last", "username", null);
|
||||||
|
|
||||||
|
private DBContext db;
|
||||||
|
|
||||||
|
private SilentSender silent;
|
||||||
|
private ContinuousTextBot bot;
|
||||||
|
|
||||||
|
@BeforeEach
|
||||||
|
void setUp() {
|
||||||
|
db = offlineInstance("db");
|
||||||
|
bot = new ContinuousTextBot(EMPTY, EMPTY, db);
|
||||||
|
silent = mock(SilentSender.class);
|
||||||
|
bot.silent = silent;
|
||||||
|
}
|
||||||
|
|
||||||
|
@AfterEach
|
||||||
|
void tearDown() throws IOException {
|
||||||
|
db.clear();
|
||||||
|
db.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void processesContinuousText() {
|
||||||
|
Update update = mockFullUpdate(bot, USER, "/do2");
|
||||||
|
|
||||||
|
bot.onUpdateReceived(update);
|
||||||
|
|
||||||
|
verify(silent, times(1))
|
||||||
|
.send("2", USER.getId());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void matchesLongestAbilityName() {
|
||||||
|
Update update = mockFullUpdate(bot, USER, "/do1");
|
||||||
|
|
||||||
|
bot.onUpdateReceived(update);
|
||||||
|
|
||||||
|
verify(silent, times(1))
|
||||||
|
.send("longer ability name", USER.getId());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class ContinuousTextBot extends AbilityBot {
|
||||||
|
|
||||||
|
public ContinuousTextBot(String token, String username, DBContext db) {
|
||||||
|
super(token, username, db);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int creatorId() {
|
||||||
|
return 1337;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean allowContinuousText() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Ability continuousTextAbility() {
|
||||||
|
return builder()
|
||||||
|
.name("do")
|
||||||
|
.privacy(PUBLIC)
|
||||||
|
.locality(ALL)
|
||||||
|
.input(0)
|
||||||
|
.action(ctx -> silent.send(ctx.firstArg(), ctx.chatId()))
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Ability continuousTextSimilarAbility() {
|
||||||
|
return builder()
|
||||||
|
.name("do1")
|
||||||
|
.privacy(PUBLIC)
|
||||||
|
.locality(ALL)
|
||||||
|
.input(0)
|
||||||
|
.action(ctx -> silent.send("longer ability name", ctx.chatId()))
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -3,6 +3,7 @@ package org.telegram.abilitybots.api.bot;
|
|||||||
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.objects.Flag;
|
||||||
import org.telegram.abilitybots.api.objects.Reply;
|
import org.telegram.abilitybots.api.objects.Reply;
|
||||||
import org.telegram.abilitybots.api.toggle.AbilityToggle;
|
import org.telegram.abilitybots.api.toggle.AbilityToggle;
|
||||||
|
|
||||||
@ -72,6 +73,12 @@ public class DefaultBot extends AbilityBot {
|
|||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Reply channelPostReply() {
|
||||||
|
return Reply.of(
|
||||||
|
upd -> silent.send("test channel post", upd.getChannelPost().getChatId()), Flag.CHANNEL_POST
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
public Ability testAbility() {
|
public Ability testAbility() {
|
||||||
return getDefaultBuilder().build();
|
return getDefaultBuilder().build();
|
||||||
}
|
}
|
||||||
|
@ -5,17 +5,18 @@ import org.junit.jupiter.api.AfterEach;
|
|||||||
import org.junit.jupiter.api.BeforeEach;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.telegram.abilitybots.api.db.DBContext;
|
import org.telegram.abilitybots.api.db.DBContext;
|
||||||
import org.telegram.abilitybots.api.objects.Flag;
|
import org.telegram.abilitybots.api.objects.*;
|
||||||
import org.telegram.abilitybots.api.objects.Reply;
|
|
||||||
import org.telegram.abilitybots.api.objects.ReplyFlow;
|
|
||||||
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.sender.SilentSender;
|
||||||
import org.telegram.telegrambots.meta.api.objects.Update;
|
import org.telegram.telegrambots.meta.api.objects.Update;
|
||||||
import org.telegram.telegrambots.meta.api.objects.polls.Poll;
|
import org.telegram.telegrambots.meta.api.objects.polls.Poll;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.util.Set;
|
||||||
import java.util.function.Predicate;
|
import java.util.function.Predicate;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import static com.google.common.collect.Sets.newHashSet;
|
||||||
import static org.apache.commons.lang3.StringUtils.EMPTY;
|
import static org.apache.commons.lang3.StringUtils.EMPTY;
|
||||||
import static org.junit.jupiter.api.Assertions.*;
|
import static org.junit.jupiter.api.Assertions.*;
|
||||||
import static org.mockito.Mockito.*;
|
import static org.mockito.Mockito.*;
|
||||||
@ -122,6 +123,33 @@ public class ReplyFlowTest {
|
|||||||
assertTrue(bot.filterReply(update));
|
assertTrue(bot.filterReply(update));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void replyFlowsAreWorkingWhenDefinedInAbilities() {
|
||||||
|
Update update1 = mockFullUpdate(bot, USER, "one");
|
||||||
|
Update update2 = mockFullUpdate(bot, USER, "two");
|
||||||
|
long chatId = getChatId(update1);
|
||||||
|
|
||||||
|
// Trigger and verify first reply stage
|
||||||
|
assertFalse(bot.filterReply(update1));
|
||||||
|
|
||||||
|
verify(silent, only()).send("First reply", chatId);
|
||||||
|
assertTrue(db.<Long, Integer>getMap(STATES).containsKey(chatId), "User is not in initial state");
|
||||||
|
// Resetting the mock now helps with verification later
|
||||||
|
reset(silent);
|
||||||
|
|
||||||
|
// Trigger and verify second reply stage
|
||||||
|
assertFalse(bot.filterReply(update2));
|
||||||
|
|
||||||
|
verify(silent, only()).send("Second reply", chatId);
|
||||||
|
assertFalse(db.<Long, Integer>getMap(STATES).containsKey(chatId), "User is still in a state");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void replyFlowsPertainNames() {
|
||||||
|
Set<String> replyNames = bot.replies().stream().map(Reply::name).collect(Collectors.toSet());
|
||||||
|
assertTrue(replyNames.containsAll(newHashSet("FIRST", "SECOND")));
|
||||||
|
}
|
||||||
|
|
||||||
public static class ReplyFlowBot extends AbilityBot {
|
public static class ReplyFlowBot extends AbilityBot {
|
||||||
|
|
||||||
private ReplyFlowBot(String botToken, String botUsername, DBContext db) {
|
private ReplyFlowBot(String botToken, String botUsername, DBContext db) {
|
||||||
@ -153,6 +181,43 @@ public class ReplyFlowTest {
|
|||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Reply errantReply() {
|
||||||
|
return Reply.of(
|
||||||
|
upd -> {
|
||||||
|
throw new RuntimeException("Throwing an exception inside the update consumer");
|
||||||
|
},
|
||||||
|
upd -> {
|
||||||
|
throw new RuntimeException("Throwing an exception inside the reply conditions (flags)");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public Ability replyFlowsWithAbility() {
|
||||||
|
Reply replyWithVk = ReplyFlow.builder(db, 2)
|
||||||
|
.enableStats("SECOND")
|
||||||
|
.action(upd -> {
|
||||||
|
silent.send("Second reply", upd.getMessage().getChatId());
|
||||||
|
})
|
||||||
|
.onlyIf(hasMessageWith("two"))
|
||||||
|
.build();
|
||||||
|
|
||||||
|
Reply replyWithNickname = ReplyFlow.builder(db, 1)
|
||||||
|
.enableStats("FIRST")
|
||||||
|
.action(upd -> {
|
||||||
|
silent.send("First reply", upd.getMessage().getChatId());
|
||||||
|
})
|
||||||
|
.onlyIf(hasMessageWith("one"))
|
||||||
|
.next(replyWithVk)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
return Ability.builder()
|
||||||
|
.name("trigger")
|
||||||
|
.privacy(Privacy.PUBLIC)
|
||||||
|
.locality(Locality.ALL)
|
||||||
|
.action(ctx -> silent.send("I'm in an ability", ctx.chatId()))
|
||||||
|
.reply(replyWithNickname)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
private Predicate<Update> hasMessageWith(String msg) {
|
private Predicate<Update> hasMessageWith(String msg) {
|
||||||
return upd -> Flag.MESSAGE.test(upd) && upd.getMessage().getText().equalsIgnoreCase(msg);
|
return upd -> Flag.MESSAGE.test(upd) && upd.getMessage().getText().equalsIgnoreCase(msg);
|
||||||
|
@ -15,7 +15,7 @@ Usage
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.telegram</groupId>
|
<groupId>org.telegram</groupId>
|
||||||
<artifactId>telegrambots-chat-session-bot</artifactId>
|
<artifactId>telegrambots-chat-session-bot</artifactId>
|
||||||
<version>4.9</version>
|
<version>4.9.1</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>org.telegram</groupId>
|
<groupId>org.telegram</groupId>
|
||||||
<artifactId>Bots</artifactId>
|
<artifactId>Bots</artifactId>
|
||||||
<version>4.9</version>
|
<version>4.9.1</version>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
<artifactId>telegrambots-chat-session-bot</artifactId>
|
<artifactId>telegrambots-chat-session-bot</artifactId>
|
||||||
@ -84,7 +84,7 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.telegram</groupId>
|
<groupId>org.telegram</groupId>
|
||||||
<artifactId>telegrambots</artifactId>
|
<artifactId>telegrambots</artifactId>
|
||||||
<version>4.9</version>
|
<version>4.9.1</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<!-- https://mvnrepository.com/artifact/org.apache.shiro/shiro-core -->
|
<!-- https://mvnrepository.com/artifact/org.apache.shiro/shiro-core -->
|
||||||
|
@ -5,6 +5,8 @@ import org.apache.shiro.session.UnknownSessionException;
|
|||||||
import org.apache.shiro.session.mgt.DefaultSessionManager;
|
import org.apache.shiro.session.mgt.DefaultSessionManager;
|
||||||
import org.apache.shiro.session.mgt.SessionContext;
|
import org.apache.shiro.session.mgt.SessionContext;
|
||||||
import org.apache.shiro.session.mgt.eis.AbstractSessionDAO;
|
import org.apache.shiro.session.mgt.eis.AbstractSessionDAO;
|
||||||
|
import org.telegram.telegrambots.bots.DefaultBotOptions;
|
||||||
|
import org.telegram.telegrambots.meta.ApiContext;
|
||||||
import org.telegram.telegrambots.meta.api.objects.Message;
|
import org.telegram.telegrambots.meta.api.objects.Message;
|
||||||
import org.telegram.telegrambots.meta.api.objects.Update;
|
import org.telegram.telegrambots.meta.api.objects.Update;
|
||||||
import org.telegram.telegrambots.bots.TelegramLongPollingBot;
|
import org.telegram.telegrambots.bots.TelegramLongPollingBot;
|
||||||
@ -22,6 +24,10 @@ public abstract class TelegramLongPollingSessionBot extends TelegramLongPollingB
|
|||||||
}
|
}
|
||||||
|
|
||||||
public TelegramLongPollingSessionBot(ChatIdConverter chatIdConverter){
|
public TelegramLongPollingSessionBot(ChatIdConverter chatIdConverter){
|
||||||
|
this(chatIdConverter, ApiContext.getInstance(DefaultBotOptions.class));
|
||||||
|
}
|
||||||
|
|
||||||
|
public TelegramLongPollingSessionBot(ChatIdConverter chatIdConverter, DefaultBotOptions defaultBotOptions){
|
||||||
this.setSessionManager(new DefaultSessionManager());
|
this.setSessionManager(new DefaultSessionManager());
|
||||||
this.setChatIdConverter(chatIdConverter);
|
this.setChatIdConverter(chatIdConverter);
|
||||||
AbstractSessionDAO sessionDAO = (AbstractSessionDAO) sessionManager.getSessionDAO();
|
AbstractSessionDAO sessionDAO = (AbstractSessionDAO) sessionManager.getSessionDAO();
|
||||||
|
@ -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>4.9</version>
|
<version>4.9.1</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
```
|
```
|
||||||
|
|
||||||
2. Using Gradle:
|
2. Using Gradle:
|
||||||
|
|
||||||
```gradle
|
```gradle
|
||||||
compile "org.telegram:telegrambotsextensions:4.9"
|
compile "org.telegram:telegrambotsextensions:4.9.1"
|
||||||
```
|
```
|
@ -7,7 +7,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>org.telegram</groupId>
|
<groupId>org.telegram</groupId>
|
||||||
<artifactId>Bots</artifactId>
|
<artifactId>Bots</artifactId>
|
||||||
<version>4.9</version>
|
<version>4.9.1</version>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
<artifactId>telegrambotsextensions</artifactId>
|
<artifactId>telegrambotsextensions</artifactId>
|
||||||
@ -75,7 +75,7 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.telegram</groupId>
|
<groupId>org.telegram</groupId>
|
||||||
<artifactId>telegrambots</artifactId>
|
<artifactId>telegrambots</artifactId>
|
||||||
<version>4.9</version>
|
<version>4.9.1</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>org.telegram</groupId>
|
<groupId>org.telegram</groupId>
|
||||||
<artifactId>Bots</artifactId>
|
<artifactId>Bots</artifactId>
|
||||||
<version>4.9</version>
|
<version>4.9.1</version>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
<artifactId>telegrambots-meta</artifactId>
|
<artifactId>telegrambots-meta</artifactId>
|
||||||
|
@ -39,11 +39,13 @@ public class SendInvoice extends BotApiMethod<Message> {
|
|||||||
private static final String NEED_PHONE_NUMBER_FIELD = "need_phone_number";
|
private static final String NEED_PHONE_NUMBER_FIELD = "need_phone_number";
|
||||||
private static final String NEED_EMAIL_FIELD = "need_email";
|
private static final String NEED_EMAIL_FIELD = "need_email";
|
||||||
private static final String NEED_SHIPPING_ADDRESS_FIELD = "need_shipping_address";
|
private static final String NEED_SHIPPING_ADDRESS_FIELD = "need_shipping_address";
|
||||||
|
private static final String SEND_PHONE_NUMBER_TO_PROVIDER_FIELD = "send_phone_number_to_provider";
|
||||||
|
private static final String SEND_EMAIL_TO_PROVIDER_FIELD = "send_email_to_provider";
|
||||||
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";
|
private static final String REPLY_MARKUP_FIELD = "reply_markup";
|
||||||
private static final String PRIVIDER_DATA_FIELD = "provider_data";
|
private static final String PROVIDER_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
|
||||||
@ -87,6 +89,11 @@ public class SendInvoice extends BotApiMethod<Message> {
|
|||||||
private Boolean disableNotification; ///< Optional. Sends the message silently. Users will receive a notification with no sound.
|
private Boolean disableNotification; ///< Optional. Sends the message silently. Users will receive a notification with no sound.
|
||||||
@JsonProperty(REPLY_TO_MESSAGE_ID_FIELD)
|
@JsonProperty(REPLY_TO_MESSAGE_ID_FIELD)
|
||||||
private Integer replyToMessageId; ///< Optional. If the message is a reply, ID of the original message
|
private Integer replyToMessageId; ///< Optional. If the message is a reply, ID of the original message
|
||||||
|
|
||||||
|
@JsonProperty(SEND_PHONE_NUMBER_TO_PROVIDER_FIELD)
|
||||||
|
private Boolean sendPhoneNumberToProvider; ///< Optional. Pass True, if user's phone number should be sent to provider
|
||||||
|
@JsonProperty(SEND_EMAIL_TO_PROVIDER_FIELD)
|
||||||
|
private Boolean sendEmailToProvider; ///< Optional. Pass True, if user's email address should be sent to provider
|
||||||
/**
|
/**
|
||||||
* Optional. A JSON-serialized object for an inline keyboard.
|
* Optional. A JSON-serialized object for an inline keyboard.
|
||||||
*
|
*
|
||||||
@ -99,11 +106,10 @@ public class SendInvoice extends BotApiMethod<Message> {
|
|||||||
*
|
*
|
||||||
* @note A detailed description of required fields should be provided by the payment provider.
|
* @note A detailed description of required fields should be provided by the payment provider.
|
||||||
*/
|
*/
|
||||||
@JsonProperty(PRIVIDER_DATA_FIELD)
|
@JsonProperty(PROVIDER_DATA_FIELD)
|
||||||
private String providerData;
|
private String providerData;
|
||||||
|
|
||||||
|
/**
|
||||||
/**
|
|
||||||
* Build an empty SendInvoice object
|
* Build an empty SendInvoice object
|
||||||
*/
|
*/
|
||||||
public SendInvoice() {
|
public SendInvoice() {
|
||||||
@ -277,6 +283,20 @@ public class SendInvoice extends BotApiMethod<Message> {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Boolean getSendPhoneNumberToProvider() { return sendPhoneNumberToProvider; }
|
||||||
|
|
||||||
|
public SendInvoice setSendPhoneNumberToProvider(Boolean sendPhoneNumberToProvider) {
|
||||||
|
this.sendPhoneNumberToProvider = sendPhoneNumberToProvider;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Boolean getSendEmailToProvider() { return sendEmailToProvider; }
|
||||||
|
|
||||||
|
public SendInvoice setSendEmailToProvider(Boolean sendEmailToProvider) {
|
||||||
|
this.sendEmailToProvider = sendEmailToProvider;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
public Boolean getFlexible() {
|
public Boolean getFlexible() {
|
||||||
return isFlexible;
|
return isFlexible;
|
||||||
}
|
}
|
||||||
@ -396,6 +416,8 @@ public class SendInvoice extends BotApiMethod<Message> {
|
|||||||
", needPhoneNumber=" + needPhoneNumber +
|
", needPhoneNumber=" + needPhoneNumber +
|
||||||
", needEmail=" + needEmail +
|
", needEmail=" + needEmail +
|
||||||
", needShippingAddress=" + needShippingAddress +
|
", needShippingAddress=" + needShippingAddress +
|
||||||
|
", sendPhoneNumberToProvider=" + sendPhoneNumberToProvider +
|
||||||
|
", sendEmailToProvider=" + sendEmailToProvider +
|
||||||
", isFlexible=" + isFlexible +
|
", isFlexible=" + isFlexible +
|
||||||
", disableNotification=" + disableNotification +
|
", disableNotification=" + disableNotification +
|
||||||
", replyToMessageId=" + replyToMessageId +
|
", replyToMessageId=" + replyToMessageId +
|
||||||
|
@ -18,14 +18,14 @@ Usage
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.telegram</groupId>
|
<groupId>org.telegram</groupId>
|
||||||
<artifactId>telegrambots-spring-boot-starter</artifactId>
|
<artifactId>telegrambots-spring-boot-starter</artifactId>
|
||||||
<version>4.1.2</version>
|
<version>4.9.1</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
```
|
```
|
||||||
|
|
||||||
**Gradle**
|
**Gradle**
|
||||||
|
|
||||||
```gradle
|
```gradle
|
||||||
compile "org.telegram:telegrambots-spring-boot-starter:4.1.2"
|
compile "org.telegram:telegrambots-spring-boot-starter:4.9.1"
|
||||||
```
|
```
|
||||||
|
|
||||||
Motivation
|
Motivation
|
||||||
@ -45,7 +45,7 @@ public class YourApplicationMainClass {
|
|||||||
//Add this line to initialize bots context
|
//Add this line to initialize bots context
|
||||||
ApiContextInitializer.init();
|
ApiContextInitializer.init();
|
||||||
|
|
||||||
SpringApplication.run(MusicUploaderApplication.class, args);
|
SpringApplication.run(YourApplicationMainClass.class, args);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>org.telegram</groupId>
|
<groupId>org.telegram</groupId>
|
||||||
<artifactId>Bots</artifactId>
|
<artifactId>Bots</artifactId>
|
||||||
<version>4.9</version>
|
<version>4.9.1</version>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
<artifactId>telegrambots-spring-boot-starter</artifactId>
|
<artifactId>telegrambots-spring-boot-starter</artifactId>
|
||||||
@ -79,7 +79,7 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.telegram</groupId>
|
<groupId>org.telegram</groupId>
|
||||||
<artifactId>telegrambots</artifactId>
|
<artifactId>telegrambots</artifactId>
|
||||||
<version>4.9</version>
|
<version>4.9.1</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springframework.boot</groupId>
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>org.telegram</groupId>
|
<groupId>org.telegram</groupId>
|
||||||
<artifactId>Bots</artifactId>
|
<artifactId>Bots</artifactId>
|
||||||
<version>4.9</version>
|
<version>4.9.1</version>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
<artifactId>telegrambots</artifactId>
|
<artifactId>telegrambots</artifactId>
|
||||||
@ -95,7 +95,7 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.telegram</groupId>
|
<groupId>org.telegram</groupId>
|
||||||
<artifactId>telegrambots-meta</artifactId>
|
<artifactId>telegrambots-meta</artifactId>
|
||||||
<version>4.9</version>
|
<version>4.9.1</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.fasterxml.jackson.core</groupId>
|
<groupId>com.fasterxml.jackson.core</groupId>
|
||||||
|
Loading…
Reference in New Issue
Block a user