Merge pull request #823 from rubenlagus/dev

Dev
This commit is contained in:
Ruben Bermudez 2020-10-29 00:21:38 +00:00 committed by GitHub
commit 48dea8184c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
47 changed files with 601 additions and 329 deletions

View File

@ -1,5 +1,5 @@
# Telegram Bot Java Library # Telegram Bot Java Library
[![Telegram](http://trellobot.doomdns.org/telegrambadge.svg)](https://telegram.me/JavaBotsApi) [![Telegram](/TelegramBots.svg)](https://telegram.me/JavaBotsApi)
[![Build Status](https://travis-ci.org/rubenlagus/TelegramBots.svg?branch=master)](https://travis-ci.org/rubenlagus/TelegramBots) [![Build Status](https://travis-ci.org/rubenlagus/TelegramBots.svg?branch=master)](https://travis-ci.org/rubenlagus/TelegramBots)
@ -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.1</version> <version>4.9.2</version>
</dependency> </dependency>
``` ```
```gradle ```gradle
compile "org.telegram:telegrambots:4.9.1" compile "org.telegram:telegrambots:4.9.2"
``` ```
2. Using Jitpack from [here](https://jitpack.io/#rubenlagus/TelegramBots/4.9.1) 2. Using Jitpack from [here](https://jitpack.io/#rubenlagus/TelegramBots/4.9.2)
3. Download the jar(including all dependencies) from [here](https://mvnrepository.com/artifact/org.telegram/telegrambots/4.9.1) 3. Download the jar(including all dependencies) from [here](https://mvnrepository.com/artifact/org.telegram/telegrambots/4.9.2)
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`.

22
TelegramBots.svg Normal file
View File

@ -0,0 +1,22 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" width="100" height="20">
<linearGradient id="b" x2="0" y2="100%">
<stop offset="0" stop-color="#bbb" stop-opacity=".1" />
<stop offset="1" stop-opacity=".1" />
</linearGradient>
<mask id="a">
<rect width="100" height="20" rx="3" fill="#fff" />
</mask>
<g mask="url(#a)">
<path fill="#555" d="M0 0h34v20H0z" />
<path fill="#54a9eb" d="M34 0h68v20H34z" />
<path fill="url(#b)" d="M0 0h92v20H0z" />
</g>
<g fill="#fff" text-anchor="middle" font-family="HelveticaNeue-Light,Helvetica Neue Light, Helvetica Light,Helvetica,Arial,Verdana,sans-serif" font-size="11" color="#fff" font-weight="bold">
<text x="16" y="15" fill="#010101" fill-opacity=".3">chat</text>
<text x="16" y="14">chat</text>
<text x="67" y="15" fill="#010101" fill-opacity=".3">on telegram</text>
<text x="67" y="14">on telegram</text>
</g>
</svg>

After

Width:  |  Height:  |  Size: 998 B

View File

@ -1,3 +1,6 @@
### <a id="4.9.2"></a>4.9.2 ###
1. Bug fixing: #792, #801, #804, #810, #812, #813, #820 and #814
### <a id="4.9.1"></a>4.9.1 ### ### <a id="4.9.1"></a>4.9.1 ###
1. Bug fixing: #767, #766, #761, #763, #776, #772, #771, #780 1. Bug fixing: #767, #766, #761, #763, #776, #772, #771, #780

View File

@ -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.1</version> <version>4.9.2</version>
</dependency> </dependency>
``` ```
* With **Gradle**: * With **Gradle**:
```groovy ```groovy
compile group: 'org.telegram', name: 'telegrambots', version: '4.9.1' compile group: 'org.telegram', name: 'telegrambots', version: '4.9.2'
``` ```
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).

View File

@ -38,3 +38,17 @@ public class MrBadGuy implements AbilityExtension {
// Override creatorId // Override creatorId
} }
``` ```
It's also possible to add extensions in the constructor by using the `addExtension()` or `addExtensions()` method:
```java
public class YourAwesomeBot implements AbilityBot {
public YourAwesomeBot() {
super(/* pass required args ... */);
addExtensions(new MrGoodGuy(), new MrBadGuy());
}
// Override creatorId
}
```

View File

@ -65,3 +65,14 @@ Please note that this may cause ability overlap. If multiple abilities can match
if you have two abilities `do` and `do1`, the command `/do1` will trigger the `do1` ability. 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.
## Execute code on bot registration
If you want to execute custom logic to initialize your bot, but you can't do it in the constructor,
you can override the `onRegister()` method:
```
@Override
public void onRegister() {
super.onRegister();
// Execute custom initialize logic here
}
```

View File

@ -104,6 +104,8 @@ public class ExampleBotTest {
public void setUp() { public void setUp() {
// Create your bot // Create your bot
bot = new ExampleBot(); bot = new ExampleBot();
// Call onRegister() to initialize abilities etc.
bot.onRegister();
// Create a new sender as a mock // Create a new sender as a mock
silent = mock(SilentSender.class); silent = mock(SilentSender.class);
// Set your bot silent sender to the mocked sender // Set your bot silent sender to the mocked sender
@ -156,6 +158,7 @@ public class ExampleBotTest {
// Offline instance will get deleted at JVM shutdown // Offline instance will get deleted at JVM shutdown
db = MapDBContext.offlineInstance("test"); db = MapDBContext.offlineInstance("test");
bot = new ExampleBot(db); bot = new ExampleBot(db);
bot.onRegister();
... ...
} }
@ -180,6 +183,7 @@ public class ExampleBotTest {
@Before @Before
public void setUp() { public void setUp() {
bot = new ExampleBot(db); bot = new ExampleBot(db);
bot.onRegister();
sender = mock(MessageSender.class); sender = mock(MessageSender.class);
SilentSender silent = new SilentSender(sender); SilentSender silent = new SilentSender(sender);
// Create setter in your bot // Create setter in your bot

View File

@ -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.1</version> <version>4.9.2</version>
</dependency> </dependency>
``` ```
* **Gradle** * **Gradle**
```groovy ```groovy
implementation group: 'org.telegram', name: 'telegrambots-abilities', version: '4.9.1' implementation group: 'org.telegram', name: 'telegrambots-abilities', version: '4.9.2'
``` ```
* [JitPack](https://jitpack.io/#rubenlagus/TelegramBots) * [JitPack](https://jitpack.io/#rubenlagus/TelegramBots)

View File

@ -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.1</version> <version>4.9.2</version>
<modules> <modules>
<module>telegrambots</module> <module>telegrambots</module>
@ -190,6 +190,7 @@
</executions> </executions>
<configuration> <configuration>
<doclint>none</doclint> <doclint>none</doclint>
<javadocExecutable>${java.home}/bin/javadoc</javadocExecutable>
</configuration> </configuration>
</plugin> </plugin>
<plugin> <plugin>

View File

@ -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.1</version> <version>4.9.2</version>
</dependency> </dependency>
``` ```
**Gradle** **Gradle**
```gradle ```gradle
compile "org.telegram:telegrambots-abilities:4.9.1" compile "org.telegram:telegrambots-abilities:4.9.2"
``` ```
**JitPack** - [JitPack](https://jitpack.io/#rubenlagus/TelegramBots/v4.9.1) **JitPack** - [JitPack](https://jitpack.io/#rubenlagus/TelegramBots/v4.9.2)
**Plain imports** - [Here](https://github.com/rubenlagus/TelegramBots/releases/tag/v4.9.1) **Plain imports** - [Here](https://github.com/rubenlagus/TelegramBots/releases/tag/v4.9.2)
Motivation Motivation
---------- ----------

View File

@ -7,7 +7,7 @@
<parent> <parent>
<groupId>org.telegram</groupId> <groupId>org.telegram</groupId>
<artifactId>Bots</artifactId> <artifactId>Bots</artifactId>
<version>4.9.1</version> <version>4.9.2</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.1</version> <version>4.9.2</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.apache.commons</groupId> <groupId>org.apache.commons</groupId>

View File

@ -106,6 +106,7 @@ public abstract class BaseAbilityBot extends DefaultAbsSender implements Ability
private final String botUsername; private final String botUsername;
// Ability registry // Ability registry
private final List<AbilityExtension> extensions = new ArrayList<>();
private Map<String, Ability> abilities; private Map<String, Ability> abilities;
private Map<String, Stats> stats; private Map<String, Stats> stats;
@ -123,11 +124,34 @@ public abstract class BaseAbilityBot extends DefaultAbsSender implements Ability
this.toggle = toggle; this.toggle = toggle;
this.sender = new DefaultSender(this); this.sender = new DefaultSender(this);
silent = new SilentSender(sender); silent = new SilentSender(sender);
}
public void onRegister() {
registerAbilities(); registerAbilities();
initStats(); initStats();
} }
/**
* @return the database of this bot
*/
public DBContext db() {
return db;
}
/**
* @return the message sender for this bot
*/
public MessageSender sender() {
return sender;
}
/**
* @return the silent sender for this bot
*/
public SilentSender silent() {
return silent;
}
/** /**
* @return the map of <ID,User> * @return the map of <ID,User>
*/ */
@ -272,6 +296,18 @@ public abstract class BaseAbilityBot extends DefaultAbsSender implements Ability
return false; return false;
} }
protected void addExtension(AbilityExtension extension) {
this.extensions.add(extension);
}
protected void addExtensions(AbilityExtension... extensions) {
this.extensions.addAll(Arrays.asList(extensions));
}
protected void addExtensions(Collection<AbilityExtension> extensions) {
this.extensions.addAll(extensions);
}
/** /**
* 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>
@ -280,10 +316,10 @@ public abstract class BaseAbilityBot extends DefaultAbsSender implements Ability
private void registerAbilities() { private void registerAbilities() {
try { try {
// Collect all classes that implement AbilityExtension declared in the bot // Collect all classes that implement AbilityExtension declared in the bot
List<AbilityExtension> extensions = stream(getClass().getMethods()) extensions.addAll(stream(getClass().getMethods())
.filter(checkReturnType(AbilityExtension.class)) .filter(checkReturnType(AbilityExtension.class))
.map(returnExtension(this)) .map(returnExtension(this))
.collect(Collectors.toList()); .collect(Collectors.toList()));
// Add the bot itself as it is an AbilityExtension // Add the bot itself as it is an AbilityExtension
extensions.add(this); extensions.add(this);
@ -437,7 +473,7 @@ public abstract class BaseAbilityBot extends DefaultAbsSender implements Ability
Update update = trio.a(); Update update = trio.a();
User user = AbilityUtils.getUser(update); User user = AbilityUtils.getUser(update);
return Pair.of(newContext(update, user, getChatId(update), trio.c()), trio.b()); return Pair.of(newContext(update, user, getChatId(update), this, trio.c()), trio.b());
} }
boolean checkBlacklist(Update update) { boolean checkBlacklist(Update update) {

View File

@ -17,7 +17,7 @@ import static com.google.common.collect.Lists.newArrayList;
import static java.lang.String.format; import static java.lang.String.format;
import static java.util.Objects.hash; import static java.util.Objects.hash;
import static java.util.Optional.ofNullable; import static java.util.Optional.ofNullable;
import static org.apache.commons.lang3.StringUtils.*; import static org.telegram.abilitybots.api.util.AbilityUtils.isValidCommandName;
/** /**
* An ability is a fully-fledged bot action that contains all the necessary information to process: * An ability is a fully-fledged bot action that contains all the necessary information to process:
@ -50,9 +50,8 @@ public final class Ability {
@SafeVarargs @SafeVarargs
private Ability(String name, String info, Locality locality, Privacy privacy, int argNum, boolean statsEnabled, Consumer<MessageContext> action, Consumer<MessageContext> postAction, List<Reply> replies, Predicate<Update>... flags) { private Ability(String name, String info, Locality locality, Privacy privacy, int argNum, boolean statsEnabled, Consumer<MessageContext> action, Consumer<MessageContext> postAction, List<Reply> replies, Predicate<Update>... flags) {
checkArgument(!isEmpty(name), "Method name cannot be empty"); checkArgument(isValidCommandName(name), "Method name can only contain alpha-numeric characters and underscores," +
checkArgument(!containsWhitespace(name), "Method name cannot contain spaces"); " cannot be longer than 31 characters, empty or null", name);
checkArgument(isAlphanumeric(name), "Method name can only be alpha-numeric", name);
this.name = name; this.name = name;
this.info = info; this.info = info;

View File

@ -2,6 +2,7 @@ package org.telegram.abilitybots.api.objects;
import com.google.common.base.MoreObjects; import com.google.common.base.MoreObjects;
import com.google.common.base.Objects; import com.google.common.base.Objects;
import org.telegram.abilitybots.api.bot.BaseAbilityBot;
import org.telegram.telegrambots.meta.api.objects.Update; import org.telegram.telegrambots.meta.api.objects.Update;
import org.telegram.telegrambots.meta.api.objects.User; import org.telegram.telegrambots.meta.api.objects.User;
@ -19,16 +20,18 @@ public class MessageContext {
private final Long chatId; private final Long chatId;
private final String[] arguments; private final String[] arguments;
private final Update update; private final Update update;
private final BaseAbilityBot bot;
private MessageContext(Update update, User user, Long chatId, String[] arguments) { private MessageContext(Update update, User user, Long chatId, BaseAbilityBot bot, String[] arguments) {
this.user = user; this.user = user;
this.chatId = chatId; this.chatId = chatId;
this.update = update; this.update = update;
this.bot = bot;
this.arguments = arguments; this.arguments = arguments;
} }
public static MessageContext newContext(Update update, User user, Long chatId, String... arguments) { public static MessageContext newContext(Update update, User user, Long chatId, BaseAbilityBot bot, String... arguments) {
return new MessageContext(update, user, chatId, arguments); return new MessageContext(update, user, chatId, bot, arguments);
} }
/** /**
@ -45,6 +48,13 @@ public class MessageContext {
return chatId; return chatId;
} }
/**
* @return the bot in which this message is executed
*/
public BaseAbilityBot bot() {
return bot;
}
/** /**
* If there's no message in the update, then this will an empty array. * If there's no message in the update, then this will an empty array.
* *

View File

@ -269,4 +269,29 @@ public final class AbilityUtils {
public static String escape(String username) { public static String escape(String username) {
return username.replace("_", "\\_"); return username.replace("_", "\\_");
} }
/**
* Checks if the passed string is a valid bot command according to the requirements of Telegram Bot API:
* "A command must always start with the '/' symbol and may not be longer than 32 characters.
* Commands can use latin letters, numbers and underscores."
* (https://core.telegram.org/bots#commands)
*
* @param command String representation of a command to be checked for validity
* @return whether the command is valid
*/
public static boolean isValidCommand(String command){
if (command == null || command.length() > 32) return false;
return command.matches("/[A-Za-z_0-9]+");
}
/**
* Checks if the passed String is a valid command name. Command name is text of a command without leading '/'
*
* @param commandName the command name to be checked for validity
* @return whether the command name is valid
*/
public static boolean isValidCommandName(String commandName){
if (commandName == null || commandName.length() > 31) return false;
return commandName.matches("[A-Za-z_0-9]+");
}
} }

View File

@ -33,6 +33,7 @@ class AbilityBotI18nTest {
void setUp() { void setUp() {
db = offlineInstance("db"); db = offlineInstance("db");
bot = new NoPublicCommandsBot(EMPTY, EMPTY, db); bot = new NoPublicCommandsBot(EMPTY, EMPTY, db);
bot.onRegister();
defaultAbs = new DefaultAbilities(bot); defaultAbs = new DefaultAbilities(bot);
sender = mock(MessageSender.class); sender = mock(MessageSender.class);

View File

@ -71,6 +71,7 @@ public class AbilityBotTest {
void setUp() { void setUp() {
db = offlineInstance("db"); db = offlineInstance("db");
bot = new DefaultBot(EMPTY, EMPTY, db); bot = new DefaultBot(EMPTY, EMPTY, db);
bot.onRegister();
defaultAbs = new DefaultAbilities(bot); defaultAbs = new DefaultAbilities(bot);
sender = mock(MessageSender.class); sender = mock(MessageSender.class);
@ -503,7 +504,7 @@ public class AbilityBotTest {
mockUser(update, message, USER); mockUser(update, message, USER);
Pair<MessageContext, Ability> actualPair = bot.getContext(trio); Pair<MessageContext, Ability> actualPair = bot.getContext(trio);
Pair<MessageContext, Ability> expectedPair = Pair.of(newContext(update, USER, GROUP_ID, TEXT), ability); Pair<MessageContext, Ability> expectedPair = Pair.of(newContext(update, USER, GROUP_ID, bot, TEXT), ability);
assertEquals(expectedPair, actualPair, "Unexpected result when fetching for context"); assertEquals(expectedPair, actualPair, "Unexpected result when fetching for context");
} }
@ -619,7 +620,7 @@ public class AbilityBotTest {
when(update.hasMessage()).thenReturn(true); when(update.hasMessage()).thenReturn(true);
when(update.getMessage()).thenReturn(message); when(update.getMessage()).thenReturn(message);
when(message.hasText()).thenReturn(true); when(message.hasText()).thenReturn(true);
MessageContext creatorCtx = newContext(update, CREATOR, GROUP_ID); MessageContext creatorCtx = newContext(update, CREATOR, GROUP_ID, bot);
defaultAbs.commands().action().accept(creatorCtx); defaultAbs.commands().action().accept(creatorCtx);
@ -636,7 +637,7 @@ public class AbilityBotTest {
when(update.getMessage()).thenReturn(message); when(update.getMessage()).thenReturn(message);
when(message.hasText()).thenReturn(true); when(message.hasText()).thenReturn(true);
MessageContext userCtx = newContext(update, USER, GROUP_ID); MessageContext userCtx = newContext(update, USER, GROUP_ID, bot);
defaultAbs.commands().action().accept(userCtx); defaultAbs.commands().action().accept(userCtx);

View File

@ -33,6 +33,7 @@ public class ContinuousTextTest {
void setUp() { void setUp() {
db = offlineInstance("db"); db = offlineInstance("db");
bot = new ContinuousTextBot(EMPTY, EMPTY, db); bot = new ContinuousTextBot(EMPTY, EMPTY, db);
bot.onRegister();
silent = mock(SilentSender.class); silent = mock(SilentSender.class);
bot.silent = silent; bot.silent = silent;
} }

View File

@ -19,6 +19,7 @@ class ExtensionTest {
@BeforeEach @BeforeEach
void setUp() { void setUp() {
bot = new ExtensionUsingBot(); bot = new ExtensionUsingBot();
bot.onRegister();
} }
@AfterEach @AfterEach
@ -32,6 +33,7 @@ class ExtensionTest {
assertTrue(hasAbilityNamed("direct"), "Failed to find Ability in directly declared in root extension/bot"); assertTrue(hasAbilityNamed("direct"), "Failed to find Ability in directly declared in root extension/bot");
assertTrue(hasAbilityNamed("returningSuperClass0abc"), "Failed to find Ability in directly declared in extension returned by method returning the AbilityExtension class"); assertTrue(hasAbilityNamed("returningSuperClass0abc"), "Failed to find Ability in directly declared in extension returned by method returning the AbilityExtension class");
assertTrue(hasAbilityNamed("returningSubClass0abc"), "Failed to find Ability in directly declared in extension returned by method returning the AbilityExtension subclass"); assertTrue(hasAbilityNamed("returningSubClass0abc"), "Failed to find Ability in directly declared in extension returned by method returning the AbilityExtension subclass");
assertTrue(hasAbilityNamed("addedInConstructor0abc"), "Failed to find Ability in directly declared in extension added in the constructor");
} }
private boolean hasAbilityNamed(String name) { private boolean hasAbilityNamed(String name) {
@ -41,6 +43,7 @@ class ExtensionTest {
public static class ExtensionUsingBot extends AbilityBot { public static class ExtensionUsingBot extends AbilityBot {
ExtensionUsingBot() { ExtensionUsingBot() {
super("", "", offlineInstance("testing")); super("", "", offlineInstance("testing"));
addExtension(new AbilityBotExtension("addedInConstructor"));
} }
@Override @Override

View File

@ -39,6 +39,7 @@ public class ReplyFlowTest {
void setUp() { void setUp() {
db = offlineInstance("db"); db = offlineInstance("db");
bot = new ReplyFlowBot(EMPTY, EMPTY, db); bot = new ReplyFlowBot(EMPTY, EMPTY, db);
bot.onRegister();
sender = mock(MessageSender.class); sender = mock(MessageSender.class);
silent = mock(SilentSender.class); silent = mock(SilentSender.class);

View File

@ -43,6 +43,7 @@ public final class TestUtils {
static MessageContext mockContext(User user, long groupId, String... args) { static MessageContext mockContext(User user, long groupId, String... args) {
Update update = mock(Update.class); Update update = mock(Update.class);
Message message = mock(Message.class); Message message = mock(Message.class);
BaseAbilityBot bot = mock(BaseAbilityBot.class);
when(update.hasMessage()).thenReturn(true); when(update.hasMessage()).thenReturn(true);
when(update.getMessage()).thenReturn(message); when(update.getMessage()).thenReturn(message);
@ -50,7 +51,7 @@ public final class TestUtils {
when(message.getFrom()).thenReturn(user); when(message.getFrom()).thenReturn(user);
when(message.hasText()).thenReturn(true); when(message.hasText()).thenReturn(true);
return newContext(update, user, groupId, args); return newContext(update, user, groupId, bot, args);
} }
@NotNull @NotNull

View File

@ -26,6 +26,7 @@ public class BareboneToggleTest {
db = offlineInstance("db"); db = offlineInstance("db");
toggle = new BareboneToggle(); toggle = new BareboneToggle();
bareboneBot = new DefaultBot(EMPTY, EMPTY, db, toggle); bareboneBot = new DefaultBot(EMPTY, EMPTY, db, toggle);
bareboneBot.onRegister();
defaultAbs = new DefaultAbilities(bareboneBot); defaultAbs = new DefaultAbilities(bareboneBot);
} }

View File

@ -1,7 +1,6 @@
package org.telegram.abilitybots.api.toggle; package org.telegram.abilitybots.api.toggle;
import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Assertions;
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.bot.DefaultAbilities; import org.telegram.abilitybots.api.bot.DefaultAbilities;
@ -18,12 +17,10 @@ class CustomToggleTest {
private DBContext db; private DBContext db;
private AbilityToggle toggle; private AbilityToggle toggle;
private DefaultBot customBot; private DefaultBot customBot;
private DefaultAbilities defaultAbs;
@BeforeEach @BeforeEach
void setUp() { void setUp() {
db = offlineInstance("db"); db = offlineInstance("db");
defaultAbs = new DefaultAbilities(customBot);
} }
@AfterEach @AfterEach
@ -36,6 +33,7 @@ class CustomToggleTest {
public void canTurnOffAbilities() { public void canTurnOffAbilities() {
toggle = new CustomToggle().turnOff(DefaultAbilities.CLAIM); toggle = new CustomToggle().turnOff(DefaultAbilities.CLAIM);
customBot = new DefaultBot(EMPTY, EMPTY, db, toggle); customBot = new DefaultBot(EMPTY, EMPTY, db, toggle);
customBot.onRegister();
assertFalse(customBot.abilities().containsKey(DefaultAbilities.CLAIM)); assertFalse(customBot.abilities().containsKey(DefaultAbilities.CLAIM));
} }
@ -44,6 +42,7 @@ class CustomToggleTest {
String targetName = DefaultAbilities.CLAIM + "1toggle"; String targetName = DefaultAbilities.CLAIM + "1toggle";
toggle = new CustomToggle().toggle(DefaultAbilities.CLAIM, targetName); toggle = new CustomToggle().toggle(DefaultAbilities.CLAIM, targetName);
customBot = new DefaultBot(EMPTY, EMPTY, db, toggle); customBot = new DefaultBot(EMPTY, EMPTY, db, toggle);
customBot.onRegister();
assertTrue(customBot.abilities().containsKey(targetName)); assertTrue(customBot.abilities().containsKey(targetName));
} }

View File

@ -3,7 +3,6 @@ package org.telegram.abilitybots.api.toggle;
import org.junit.jupiter.api.AfterEach; 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.bot.DefaultAbilities;
import org.telegram.abilitybots.api.bot.DefaultBot; import org.telegram.abilitybots.api.bot.DefaultBot;
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;
@ -21,12 +20,10 @@ class DefaultToggleTest {
private DBContext db; private DBContext db;
private AbilityToggle toggle; private AbilityToggle toggle;
private DefaultBot defaultBot; private DefaultBot defaultBot;
private DefaultAbilities defaultAbs;
@BeforeEach @BeforeEach
void setUp() { void setUp() {
db = offlineInstance("db"); db = offlineInstance("db");
defaultAbs = new DefaultAbilities(defaultBot);
} }
@AfterEach @AfterEach
@ -41,6 +38,7 @@ class DefaultToggleTest {
.name("randomsomethingrandom").build(); .name("randomsomethingrandom").build();
toggle = new DefaultToggle(); toggle = new DefaultToggle();
defaultBot = new DefaultBot(EMPTY, EMPTY, db, toggle); defaultBot = new DefaultBot(EMPTY, EMPTY, db, toggle);
defaultBot.onRegister();
assertFalse(toggle.isOff(random)); assertFalse(toggle.isOff(random));
} }
@ -51,6 +49,7 @@ class DefaultToggleTest {
.name("randomsomethingrandom").build(); .name("randomsomethingrandom").build();
toggle = new DefaultToggle(); toggle = new DefaultToggle();
defaultBot = new DefaultBot(EMPTY, EMPTY, db, toggle); defaultBot = new DefaultBot(EMPTY, EMPTY, db, toggle);
defaultBot.onRegister();
assertSame(random, toggle.processAbility(random), "Toggle returned a different ability"); assertSame(random, toggle.processAbility(random), "Toggle returned a different ability");
} }
@ -59,6 +58,7 @@ class DefaultToggleTest {
public void allAbilitiesAreRegistered() { public void allAbilitiesAreRegistered() {
toggle = new DefaultToggle(); toggle = new DefaultToggle();
defaultBot = new DefaultBot(EMPTY, EMPTY, db, toggle); defaultBot = new DefaultBot(EMPTY, EMPTY, db, toggle);
defaultBot.onRegister();
Set<String> defaultNames = newHashSet( Set<String> defaultNames = newHashSet(
CLAIM, BAN, UNBAN, CLAIM, BAN, UNBAN,
PROMOTE, DEMOTE, RECOVER, PROMOTE, DEMOTE, RECOVER,

View File

@ -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.1</version> <version>4.9.2</version>
</dependency> </dependency>
``` ```

View File

@ -7,7 +7,7 @@
<parent> <parent>
<groupId>org.telegram</groupId> <groupId>org.telegram</groupId>
<artifactId>Bots</artifactId> <artifactId>Bots</artifactId>
<version>4.9.1</version> <version>4.9.2</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.1</version> <version>4.9.2</version>
</dependency> </dependency>
<!-- https://mvnrepository.com/artifact/org.apache.shiro/shiro-core --> <!-- https://mvnrepository.com/artifact/org.apache.shiro/shiro-core -->

View File

@ -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.1</version> <version>4.9.2</version>
</dependency> </dependency>
``` ```
2. Using Gradle: 2. Using Gradle:
```gradle ```gradle
compile "org.telegram:telegrambotsextensions:4.9.1" compile "org.telegram:telegrambotsextensions:4.9.2"
``` ```

View File

@ -7,7 +7,7 @@
<parent> <parent>
<groupId>org.telegram</groupId> <groupId>org.telegram</groupId>
<artifactId>Bots</artifactId> <artifactId>Bots</artifactId>
<version>4.9.1</version> <version>4.9.2</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.1</version> <version>4.9.2</version>
</dependency> </dependency>
</dependencies> </dependencies>

View File

@ -53,7 +53,7 @@ public abstract class TelegramLongPollingCommandBot extends TelegramLongPollingB
*/ */
public TelegramLongPollingCommandBot(DefaultBotOptions options, boolean allowCommandsWithUsername) { public TelegramLongPollingCommandBot(DefaultBotOptions options, boolean allowCommandsWithUsername) {
super(options); super(options);
this.commandRegistry = new CommandRegistry(allowCommandsWithUsername, this.getBotUsername()); this.commandRegistry = new CommandRegistry(allowCommandsWithUsername, this::getBotUsername);
} }
@Override @Override

View File

@ -7,7 +7,9 @@ import java.util.Arrays;
import java.util.Collection; import java.util.Collection;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.Objects;
import java.util.function.BiConsumer; import java.util.function.BiConsumer;
import java.util.function.Supplier;
import java.util.regex.Pattern; import java.util.regex.Pattern;
/** /**
@ -19,17 +21,32 @@ public final class CommandRegistry implements ICommandRegistry {
private final Map<String, IBotCommand> commandRegistryMap = new HashMap<>(); private final Map<String, IBotCommand> commandRegistryMap = new HashMap<>();
private final boolean allowCommandsWithUsername; private final boolean allowCommandsWithUsername;
private final String botUsername; private final Supplier<String> botUsernameSupplier;
private BiConsumer<AbsSender, Message> defaultConsumer; private BiConsumer<AbsSender, Message> defaultConsumer;
/** /**
* Creates a Command registry * Creates a Command registry
*
* @param allowCommandsWithUsername True to allow commands with username, false otherwise * @param allowCommandsWithUsername True to allow commands with username, false otherwise
* @param botUsername Bot username * @param botUsername Bot username
* @throws java.lang.NullPointerException if {@code botUsername} is {@code null}
* @deprecated Use {@link #CommandRegistry(boolean, java.util.function.Supplier)} instead
*/ */
@Deprecated
public CommandRegistry(boolean allowCommandsWithUsername, String botUsername) { public CommandRegistry(boolean allowCommandsWithUsername, String botUsername) {
Objects.requireNonNull(botUsername, "Bot username must not be null");
this.allowCommandsWithUsername = allowCommandsWithUsername; this.allowCommandsWithUsername = allowCommandsWithUsername;
this.botUsername = botUsername; this.botUsernameSupplier = () -> botUsername;
}
/**
* Creates a Command registry
* @param allowCommandsWithUsername True to allow commands with username, false otherwise
* @param botUsernameSupplier Bot username supplier
*/
public CommandRegistry(boolean allowCommandsWithUsername, Supplier<String> botUsernameSupplier) {
this.allowCommandsWithUsername = allowCommandsWithUsername;
this.botUsernameSupplier = botUsernameSupplier;
} }
@Override @Override
@ -120,9 +137,12 @@ public final class CommandRegistry implements ICommandRegistry {
* the command * the command
* @param command Command to simplify * @param command Command to simplify
* @return Simplified command * @return Simplified command
* @throws java.lang.NullPointerException if {@code allowCommandsWithUsername} is {@code true}
* and {@code botUsernameSupplier} returns {@code null}
*/ */
private String removeUsernameFromCommandIfNeeded(String command) { private String removeUsernameFromCommandIfNeeded(String command) {
if (allowCommandsWithUsername) { if (allowCommandsWithUsername) {
String botUsername = Objects.requireNonNull(botUsernameSupplier.get(), "Bot username must not be null");
return command.replaceAll("(?i)@" + Pattern.quote(botUsername), "").trim(); return command.replaceAll("(?i)@" + Pattern.quote(botUsername), "").trim();
} }
return command; return command;

View File

@ -0,0 +1,51 @@
package org.telegram.telegrambots.extensions.bots.commandbot.commands;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;
import org.telegram.telegrambots.meta.api.objects.Message;
import org.telegram.telegrambots.meta.bots.AbsSender;
class CommandRegistryTest {
@Test
void should_create_registry() {
CommandRegistry registry = new CommandRegistry(true, "BotUsername");
Assertions.assertNotNull(registry, "CommandRegistry is not created");
NullPointerException exception = Assertions.assertThrows(NullPointerException.class,
() -> new CommandRegistry(true, (String) null));
Assertions.assertEquals("Bot username must not be null", exception.getMessage(), "Invalid exception message");
}
@Test
void should_executes_commandWithBotUsername() {
CommandRegistry registry = new CommandRegistry(true, () -> "BotUsername");
IBotCommand command = Mockito.mock(IBotCommand.class);
Mockito.when(command.getCommandIdentifier()).thenReturn("command");
registry.register(command);
AbsSender absSender = Mockito.mock(AbsSender.class);
Message message = Mockito.mock(Message.class);
Mockito.when(message.hasText()).thenReturn(true);
Mockito.when(message.getText()).thenReturn("/command@BotUsername I'll be test!");
Assertions.assertTrue(registry.executeCommand(absSender, message), "Command must be executed");
Mockito.verify(message).hasText();
Mockito.verify(message).getText();
Mockito.verify(command).processMessage(
Mockito.same(absSender), Mockito.same(message), Mockito.eq(new String[]{"I'll", "be", "test!"}));
}
@Test
void should_throws_NPE_on_executes_commandWithNullableBotUsername() {
CommandRegistry registry = new CommandRegistry(true, () -> null);
IBotCommand command = Mockito.mock(IBotCommand.class);
Mockito.when(command.getCommandIdentifier()).thenReturn("command");
registry.register(command);
AbsSender absSender = Mockito.mock(AbsSender.class);
Message message = Mockito.mock(Message.class);
Mockito.when(message.hasText()).thenReturn(true);
Mockito.when(message.getText()).thenReturn("/command@BotUsername ignore");
NullPointerException exception = Assertions.assertThrows(
NullPointerException.class, () -> registry.executeCommand(absSender, message), "Bot username is null");
Assertions.assertEquals("Bot username must not be null", exception.getMessage(), "Invalid exception message");
}
}

View File

@ -7,7 +7,7 @@
<parent> <parent>
<groupId>org.telegram</groupId> <groupId>org.telegram</groupId>
<artifactId>Bots</artifactId> <artifactId>Bots</artifactId>
<version>4.9.1</version> <version>4.9.2</version>
</parent> </parent>
<artifactId>telegrambots-meta</artifactId> <artifactId>telegrambots-meta</artifactId>

View File

@ -117,6 +117,7 @@ public class TelegramBotsApi {
* @param bot the bot to register * @param bot the bot to register
*/ */
public BotSession registerBot(LongPollingBot bot) throws TelegramApiRequestException { public BotSession registerBot(LongPollingBot bot) throws TelegramApiRequestException {
bot.onRegister();
bot.clearWebhook(); bot.clearWebhook();
BotSession session = ApiContext.getInstance(BotSession.class); BotSession session = ApiContext.getInstance(BotSession.class);
session.setToken(bot.getBotToken()); session.setToken(bot.getBotToken());
@ -132,6 +133,7 @@ public class TelegramBotsApi {
*/ */
public void registerBot(WebhookBot bot) throws TelegramApiRequestException { public void registerBot(WebhookBot bot) throws TelegramApiRequestException {
if (useWebhook) { if (useWebhook) {
bot.onRegister();
webhook.registerWebhook(bot); webhook.registerWebhook(bot);
bot.setWebhook(externalUrl + bot.getBotPath(), pathToCertificate); bot.setWebhook(externalUrl + bot.getBotPath(), pathToCertificate);
} }

View File

@ -11,7 +11,7 @@ import java.util.List;
* @brief Callback to handle updates. * @brief Callback to handle updates.
* @date 20 of June of 2015 * @date 20 of June of 2015
*/ */
public interface LongPollingBot { public interface LongPollingBot extends TelegramBot {
/** /**
* This method is called when receiving updates via GetUpdates method * This method is called when receiving updates via GetUpdates method
* @param update Update received * @param update Update received
@ -27,16 +27,6 @@ public interface LongPollingBot {
updates.forEach(this::onUpdateReceived); updates.forEach(this::onUpdateReceived);
} }
/**
* Return bot username of this bot
*/
String getBotUsername();
/**
* Return bot token to access Telegram API
*/
String getBotToken();
/** /**
* Gets options for current bot * Gets options for current bot
* @return BotOptions object with options information * @return BotOptions object with options information

View File

@ -0,0 +1,24 @@
package org.telegram.telegrambots.meta.generics;
/**
* Main interface for telegram bots.
*/
public interface TelegramBot {
/**
* Return username of this bot
*/
String getBotUsername();
/**
* Return bot token to access Telegram API
*/
String getBotToken();
/**
* Is called when bot gets registered
*/
default void onRegister() {
}
}

View File

@ -10,25 +10,13 @@ import org.telegram.telegrambots.meta.exceptions.TelegramApiRequestException;
* @brief Callback to handle updates. * @brief Callback to handle updates.
* @date 20 of June of 2015 * @date 20 of June of 2015
*/ */
public interface WebhookBot { public interface WebhookBot extends TelegramBot {
/** /**
* This method is called when receiving updates via webhook * This method is called when receiving updates via webhook
* @param update Update received * @param update Update received
*/ */
BotApiMethod onWebhookUpdateReceived(Update update); BotApiMethod onWebhookUpdateReceived(Update update);
/**
* Gets bot username of this bot
* @return Bot username
*/
String getBotUsername();
/**
* Gets bot token to access Telegram API
* @return Bot token
*/
String getBotToken();
/** /**
* Execute setWebhook method to set up the url of the webhook * Execute setWebhook method to set up the url of the webhook
* @param url Url for the webhook * @param url Url for the webhook

View File

@ -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.9.1</version> <version>4.9.2</version>
</dependency> </dependency>
``` ```
**Gradle** **Gradle**
```gradle ```gradle
compile "org.telegram:telegrambots-spring-boot-starter:4.9.1" compile "org.telegram:telegrambots-spring-boot-starter:4.9.2"
``` ```
Motivation Motivation

View File

@ -7,7 +7,7 @@
<parent> <parent>
<groupId>org.telegram</groupId> <groupId>org.telegram</groupId>
<artifactId>Bots</artifactId> <artifactId>Bots</artifactId>
<version>4.9.1</version> <version>4.9.2</version>
</parent> </parent>
<artifactId>telegrambots-spring-boot-starter</artifactId> <artifactId>telegrambots-spring-boot-starter</artifactId>
@ -70,8 +70,21 @@
<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>
<telegrambots.version>4.9.2</telegrambots.version>
<spring-boot.version>2.3.3.RELEASE</spring-boot.version>
<assertj-core.version>3.14.0</assertj-core.version>
<spring-boot.version>2.2.2.RELEASE</spring-boot.version> <maven-gpg-plugin.version>1.6</maven-gpg-plugin.version>
<nexus-staging-maven-plugin.version>1.6.8</nexus-staging-maven-plugin.version>
<maven-clean-plugin.version>3.1.0</maven-clean-plugin.version>
<maven-assembly-plugin.version>3.1.1</maven-assembly-plugin.version>
<maven-source-plugin.version>3.1.0</maven-source-plugin.version>
<maven-javadoc-plugin.version>3.1.0</maven-javadoc-plugin.version>
<jacoco-maven-plugin.version>0.8.4</jacoco-maven-plugin.version>
<maven-enforcer-plugin.version>3.0.0-M2</maven-enforcer-plugin.version>
<maven-dependency-plugin.version>3.1.1</maven-dependency-plugin.version>
<maven-surefire-plugin.version>3.0.0-M3</maven-surefire-plugin.version>
<maven-compiler-plugin.version>3.8.1</maven-compiler-plugin.version>
</properties> </properties>
<dependencies> <dependencies>
@ -79,7 +92,7 @@
<dependency> <dependency>
<groupId>org.telegram</groupId> <groupId>org.telegram</groupId>
<artifactId>telegrambots</artifactId> <artifactId>telegrambots</artifactId>
<version>4.9.1</version> <version>${telegrambots.version}</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
@ -104,7 +117,7 @@
<groupId>org.assertj</groupId> <groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId> <artifactId>assertj-core</artifactId>
<scope>test</scope> <scope>test</scope>
<version>3.14.0</version> <version>${assertj-core.version}</version>
</dependency> </dependency>
</dependencies> </dependencies>
@ -118,7 +131,7 @@
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-gpg-plugin</artifactId> <artifactId>maven-gpg-plugin</artifactId>
<version>1.6</version> <version>${maven-gpg-plugin.version}</version>
<executions> <executions>
<execution> <execution>
<id>sign-artifacts</id> <id>sign-artifacts</id>
@ -132,7 +145,7 @@
<plugin> <plugin>
<groupId>org.sonatype.plugins</groupId> <groupId>org.sonatype.plugins</groupId>
<artifactId>nexus-staging-maven-plugin</artifactId> <artifactId>nexus-staging-maven-plugin</artifactId>
<version>1.6.8</version> <version>${nexus-staging-maven-plugin.version}</version>
<extensions>true</extensions> <extensions>true</extensions>
<configuration> <configuration>
<serverId>ossrh</serverId> <serverId>ossrh</serverId>
@ -142,7 +155,7 @@
</plugin> </plugin>
<plugin> <plugin>
<artifactId>maven-clean-plugin</artifactId> <artifactId>maven-clean-plugin</artifactId>
<version>3.1.0</version> <version>${maven-clean-plugin.version}</version>
<executions> <executions>
<execution> <execution>
<id>clean-project</id> <id>clean-project</id>
@ -155,7 +168,7 @@
</plugin> </plugin>
<plugin> <plugin>
<artifactId>maven-assembly-plugin</artifactId> <artifactId>maven-assembly-plugin</artifactId>
<version>3.1.1</version> <version>${maven-assembly-plugin.version}</version>
<configuration> <configuration>
<descriptorRefs> <descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef> <descriptorRef>jar-with-dependencies</descriptorRef>
@ -174,7 +187,7 @@
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId> <artifactId>maven-source-plugin</artifactId>
<version>3.1.0</version> <version>${maven-source-plugin.version}</version>
<executions> <executions>
<execution> <execution>
<goals> <goals>
@ -186,7 +199,7 @@
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId> <artifactId>maven-javadoc-plugin</artifactId>
<version>3.1.0</version> <version>${maven-javadoc-plugin.version}</version>
<executions> <executions>
<execution> <execution>
<goals> <goals>
@ -201,7 +214,7 @@
<plugin> <plugin>
<groupId>org.jacoco</groupId> <groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId> <artifactId>jacoco-maven-plugin</artifactId>
<version>0.8.4</version> <version>${jacoco-maven-plugin.version}</version>
<executions> <executions>
<execution> <execution>
<goals> <goals>
@ -220,7 +233,7 @@
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-enforcer-plugin</artifactId> <artifactId>maven-enforcer-plugin</artifactId>
<version>3.0.0-M2</version> <version>${maven-enforcer-plugin.version}</version>
<executions> <executions>
<execution> <execution>
<id>enforce-versions</id> <id>enforce-versions</id>
@ -238,7 +251,7 @@
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId> <artifactId>maven-dependency-plugin</artifactId>
<version>3.1.1</version> <version>${maven-dependency-plugin.version}</version>
<executions> <executions>
<execution> <execution>
<id>copy</id> <id>copy</id>
@ -249,7 +262,7 @@
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId> <artifactId>maven-surefire-plugin</artifactId>
<version>3.0.0-M3</version> <version>${maven-surefire-plugin.version}</version>
</plugin> </plugin>
</plugins> </plugins>
<pluginManagement> <pluginManagement>
@ -257,7 +270,7 @@
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId> <artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version> <version>${maven-compiler-plugin.version}</version>
<configuration> <configuration>
<source>${java.version}</source> <source>${java.version}</source>
<target>${java.version}</target> <target>${java.version}</target>

View File

@ -10,15 +10,14 @@ import org.telegram.telegrambots.meta.generics.LongPollingBot;
import org.telegram.telegrambots.meta.generics.WebhookBot; import org.telegram.telegrambots.meta.generics.WebhookBot;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.*;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
class TestTelegramBotStarterConfiguration { class TestTelegramBotStarterConfiguration {
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner() private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
.withConfiguration(AutoConfigurations.of(MockTelegramBotsApi.class, TelegramBotStarterConfiguration.class)); .withAllowBeanDefinitionOverriding(true)
.withConfiguration(AutoConfigurations.of(MockTelegramBotsApi.class,
TelegramBotStarterConfiguration.class));
@Test @Test
void createMockTelegramBotsApiWithDefaultSettings() { void createMockTelegramBotsApiWithDefaultSettings() {
@ -40,7 +39,8 @@ class TestTelegramBotStarterConfiguration {
TelegramBotsApi telegramBotsApi = context.getBean(TelegramBotsApi.class); TelegramBotsApi telegramBotsApi = context.getBean(TelegramBotsApi.class);
verify(telegramBotsApi, times(1)).registerBot( context.getBean(LongPollingBot.class) ); verify(telegramBotsApi,
times(1)).registerBot(context.getBean(LongPollingBot.class));
verifyNoMoreInteractions(telegramBotsApi); verifyNoMoreInteractions(telegramBotsApi);
}); });
} }
@ -54,22 +54,26 @@ class TestTelegramBotStarterConfiguration {
TelegramBotsApi telegramBotsApi = context.getBean(TelegramBotsApi.class); TelegramBotsApi telegramBotsApi = context.getBean(TelegramBotsApi.class);
verify(telegramBotsApi, times(1)).registerBot( context.getBean(WebhookBot.class) ); verify(telegramBotsApi,
times(1)).registerBot(context.getBean(WebhookBot.class));
verifyNoMoreInteractions(telegramBotsApi); verifyNoMoreInteractions(telegramBotsApi);
}); });
} }
@Test @Test
void createLongPoolingBotAndWebhookBot() { void createLongPoolingBotAndWebhookBot() {
this.contextRunner.withUserConfiguration(LongPollingBotConfig.class, WebhookBotConfig.class) this.contextRunner.withUserConfiguration(LongPollingBotConfig.class,
WebhookBotConfig.class)
.run((context) -> { .run((context) -> {
assertThat(context).hasSingleBean(LongPollingBot.class); assertThat(context).hasSingleBean(LongPollingBot.class);
assertThat(context).hasSingleBean(WebhookBot.class); assertThat(context).hasSingleBean(WebhookBot.class);
TelegramBotsApi telegramBotsApi = context.getBean(TelegramBotsApi.class); TelegramBotsApi telegramBotsApi = context.getBean(TelegramBotsApi.class);
verify(telegramBotsApi, times(1)).registerBot( context.getBean(LongPollingBot.class) ); verify(telegramBotsApi,
verify(telegramBotsApi, times(1)).registerBot( context.getBean(WebhookBot.class) ); times(1)).registerBot(context.getBean(LongPollingBot.class));
verify(telegramBotsApi,
times(1)).registerBot(context.getBean(WebhookBot.class));
//verifyNoMoreInteractions(telegramBotsApi); //verifyNoMoreInteractions(telegramBotsApi);
}); });
} }

View File

@ -14,24 +14,19 @@ import org.telegram.telegrambots.meta.generics.LongPollingBot;
import org.telegram.telegrambots.updatesreceivers.DefaultBotSession; import org.telegram.telegrambots.updatesreceivers.DefaultBotSession;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.any; import static org.mockito.Mockito.*;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.when;
class TestTelegramBotStarterRegistrationHooks { class TestTelegramBotStarterRegistrationHooks {
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner() private static final DefaultBotSession someBotSession = new DefaultBotSession();
.withConfiguration(AutoConfigurations.of(MockTelegramBotsApi.class, TelegramBotStarterConfiguration.class)); private static final TelegramBotsApi mockTelegramBotsApi = mock(TelegramBotsApi.class);
// Terrible workaround for mockito loosing annotations on methods // Terrible workaround for mockito loosing annotations on methods
private static boolean hookCalled = false; private static boolean hookCalled = false;
private static boolean hookCalledWithSession = false; private static boolean hookCalledWithSession = false;
private static final DefaultBotSession someBotSession = new DefaultBotSession(); private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
.withAllowBeanDefinitionOverriding(true)
private static final TelegramBotsApi mockTelegramBotsApi = mock(TelegramBotsApi.class); .withConfiguration(AutoConfigurations.of(MockTelegramBotsApi.class,
TelegramBotStarterConfiguration.class));
@Test @Test
void longPollingBotWithAnnotatedMethodshouldBeCalled() throws TelegramApiRequestException { void longPollingBotWithAnnotatedMethodshouldBeCalled() throws TelegramApiRequestException {
@ -47,7 +42,8 @@ class TestTelegramBotStarterRegistrationHooks {
assertThat(hookCalled).isTrue(); assertThat(hookCalled).isTrue();
assertThat(hookCalledWithSession).isTrue(); assertThat(hookCalledWithSession).isTrue();
verify(telegramBotsApi, times(1)).registerBot(bot); verify(telegramBotsApi,
times(1)).registerBot(bot);
verifyNoMoreInteractions(telegramBotsApi); verifyNoMoreInteractions(telegramBotsApi);
}); });
} }
@ -65,19 +61,26 @@ class TestTelegramBotStarterRegistrationHooks {
@Configuration @Configuration
static class LongPollingBotConfig { static class LongPollingBotConfig {
@Bean @Bean
public LongPollingBot longPollingBot() { return new AnnotatedLongPollingBot(); } public LongPollingBot longPollingBot() {
return new AnnotatedLongPollingBot();
}
} }
static class AnnotatedLongPollingBot extends TelegramLongPollingBot { static class AnnotatedLongPollingBot extends TelegramLongPollingBot {
@Override @Override
public void onUpdateReceived(final Update update) {} public void onUpdateReceived(final Update update) {
}
@Override @Override
public String getBotUsername() { return null; } public String getBotUsername() {
return null;
}
@Override @Override
public String getBotToken() { return null; } public String getBotToken() {
return null;
}
@AfterBotRegistration @AfterBotRegistration
public void afterBotHook() { public void afterBotHook() {

View File

@ -7,7 +7,7 @@
<parent> <parent>
<groupId>org.telegram</groupId> <groupId>org.telegram</groupId>
<artifactId>Bots</artifactId> <artifactId>Bots</artifactId>
<version>4.9.1</version> <version>4.9.2</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.1</version> <version>4.9.2</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>com.fasterxml.jackson.core</groupId> <groupId>com.fasterxml.jackson.core</groupId>

View File

@ -26,6 +26,8 @@ public class DefaultBotOptions implements BotOptions {
private ProxyType proxyType; private ProxyType proxyType;
private String proxyHost; private String proxyHost;
private int proxyPort; private int proxyPort;
private int getUpdatesTimeout;
private int getUpdatesLimit;
public enum ProxyType { public enum ProxyType {
NO_PROXY, NO_PROXY,
@ -39,6 +41,8 @@ public class DefaultBotOptions implements BotOptions {
baseUrl = ApiConstants.BASE_URL; baseUrl = ApiConstants.BASE_URL;
httpContext = HttpClientContext.create(); httpContext = HttpClientContext.create();
proxyType = ProxyType.NO_PROXY; proxyType = ProxyType.NO_PROXY;
getUpdatesLimit = ApiConstants.GETUPDATES_TIMEOUT;
getUpdatesLimit = 100;
} }
@Override @Override
@ -129,4 +133,20 @@ public class DefaultBotOptions implements BotOptions {
public void setProxyPort(int proxyPort) { public void setProxyPort(int proxyPort) {
this.proxyPort = proxyPort; this.proxyPort = proxyPort;
} }
public int getGetUpdatesTimeout() {
return getUpdatesTimeout;
}
public void setGetUpdatesTimeout(int getUpdatesTimeout) {
this.getUpdatesTimeout = getUpdatesTimeout;
}
public int getGetUpdatesLimit() {
return getUpdatesLimit;
}
public void setGetUpdatesLimit(int getUpdatesLimit) {
this.getUpdatesLimit = getUpdatesLimit;
}
} }

View File

@ -236,8 +236,8 @@ public class DefaultBotSession implements BotSession {
private List<Update> getUpdatesFromServer() throws IOException { private List<Update> getUpdatesFromServer() throws IOException {
GetUpdates request = new GetUpdates() GetUpdates request = new GetUpdates()
.setLimit(100) .setLimit(options.getGetUpdatesLimit())
.setTimeout(ApiConstants.GETUPDATES_TIMEOUT) .setTimeout(options.getGetUpdatesTimeout())
.setOffset(lastReceivedUpdate + 1); .setOffset(lastReceivedUpdate + 1);
if (options.getAllowedUpdates() != null) { if (options.getAllowedUpdates() != null) {

View File

@ -0,0 +1,23 @@
package org.telegram.telegrambots.updatesreceivers;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.ws.rs.core.Response;
import javax.ws.rs.ext.ExceptionMapper;
/**
* Prints exceptions in webhook bots to stderr
*
* @author Mouamle
* @version 1.0
*/
public class DefaultExceptionMapper implements ExceptionMapper<Throwable> {
private static final Logger log = LoggerFactory.getLogger(DefaultExceptionMapper.class);
@Override
public Response toResponse(Throwable exception) {
log.error("Exception caught: ", exception);
return Response.serverError().build();
}
}

View File

@ -52,6 +52,7 @@ public class DefaultWebhook implements Webhook {
ResourceConfig rc = new ResourceConfig(); ResourceConfig rc = new ResourceConfig();
rc.register(restApi); rc.register(restApi);
rc.register(JacksonFeature.class); rc.register(JacksonFeature.class);
rc.register(DefaultExceptionMapper.class);
final HttpServer grizzlyServer; final HttpServer grizzlyServer;
if (keystoreServerFile != null && keystoreServerPwd != null) { if (keystoreServerFile != null && keystoreServerPwd != null) {