Merge pull request #11 from rubenlagus/master

Merge Ruben master to my master
This commit is contained in:
Andy Costanza 2020-10-29 10:17:15 +01:00 committed by GitHub
commit 3e4a300318
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
45 changed files with 442 additions and 191 deletions

View File

@ -1,5 +1,5 @@
# 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)
@ -27,16 +27,16 @@ Just import add the library to your project with one of these options:
<dependency>
<groupId>org.telegram</groupId>
<artifactId>telegrambots</artifactId>
<version>4.9.1</version>
<version>4.9.2</version>
</dependency>
```
```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)
3. Download the jar(including all dependencies) from [here](https://mvnrepository.com/artifact/org.telegram/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.2)
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 ###
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>
<groupId>org.telegram</groupId>
<artifactId>telegrambots</artifactId>
<version>4.9.1</version>
<version>4.9.2</version>
</dependency>
```
* With **Gradle**:
```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).

View File

@ -35,6 +35,20 @@ public class MrBadGuy implements AbilityExtension {
return new MrBadGuy();
}
// 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

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

View File

@ -9,12 +9,12 @@ As with any Java project, you will need to set your dependencies.
<dependency>
<groupId>org.telegram</groupId>
<artifactId>telegrambots-abilities</artifactId>
<version>4.9.1</version>
<version>4.9.2</version>
</dependency>
```
* **Gradle**
```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)

View File

@ -7,7 +7,7 @@
<groupId>org.telegram</groupId>
<artifactId>Bots</artifactId>
<packaging>pom</packaging>
<version>4.9.1</version>
<version>4.9.2</version>
<modules>
<module>telegrambots</module>

View File

@ -18,19 +18,19 @@ Usage
<dependency>
<groupId>org.telegram</groupId>
<artifactId>telegrambots-abilities</artifactId>
<version>4.9.1</version>
<version>4.9.2</version>
</dependency>
```
**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
----------

View File

@ -7,7 +7,7 @@
<parent>
<groupId>org.telegram</groupId>
<artifactId>Bots</artifactId>
<version>4.9.1</version>
<version>4.9.2</version>
</parent>
<artifactId>telegrambots-abilities</artifactId>
@ -84,7 +84,7 @@
<dependency>
<groupId>org.telegram</groupId>
<artifactId>telegrambots</artifactId>
<version>4.9.1</version>
<version>4.9.2</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>

View File

@ -18,45 +18,45 @@ import static org.telegram.abilitybots.api.db.MapDBContext.onlineInstance;
* @author Abbas Abou Daya
*/
public abstract class AbilityBot extends BaseAbilityBot implements LongPollingBot {
protected AbilityBot(String botToken, String botUsername, DBContext db, AbilityToggle toggle, DefaultBotOptions botOptions) {
super(botToken, botUsername, db, toggle, botOptions);
}
protected AbilityBot(String botToken, String botUsername, DBContext db, AbilityToggle toggle, DefaultBotOptions botOptions) {
super(botToken, botUsername, db, toggle, botOptions);
}
protected AbilityBot(String botToken, String botUsername, AbilityToggle toggle, DefaultBotOptions options) {
this(botToken, botUsername, onlineInstance(botUsername), toggle, options);
}
protected AbilityBot(String botToken, String botUsername, AbilityToggle toggle, DefaultBotOptions options) {
this(botToken, botUsername, onlineInstance(botUsername), toggle, options);
}
protected AbilityBot(String botToken, String botUsername, DBContext db, AbilityToggle toggle) {
this(botToken, botUsername, db, toggle, new DefaultBotOptions());
}
protected AbilityBot(String botToken, String botUsername, DBContext db, AbilityToggle toggle) {
this(botToken, botUsername, db, toggle, new DefaultBotOptions());
}
protected AbilityBot(String botToken, String botUsername, DBContext db, DefaultBotOptions options) {
this(botToken, botUsername, db, new DefaultToggle(), options);
}
protected AbilityBot(String botToken, String botUsername, DBContext db, DefaultBotOptions options) {
this(botToken, botUsername, db, new DefaultToggle(), options);
}
protected AbilityBot(String botToken, String botUsername, DefaultBotOptions botOptions) {
this(botToken, botUsername, onlineInstance(botUsername), botOptions);
}
protected AbilityBot(String botToken, String botUsername, DefaultBotOptions botOptions) {
this(botToken, botUsername, onlineInstance(botUsername), botOptions);
}
protected AbilityBot(String botToken, String botUsername, AbilityToggle toggle) {
this(botToken, botUsername, onlineInstance(botUsername), toggle);
}
protected AbilityBot(String botToken, String botUsername, AbilityToggle toggle) {
this(botToken, botUsername, onlineInstance(botUsername), toggle);
}
protected AbilityBot(String botToken, String botUsername, DBContext db) {
this(botToken, botUsername, db, new DefaultToggle());
}
protected AbilityBot(String botToken, String botUsername, DBContext db) {
this(botToken, botUsername, db, new DefaultToggle());
}
protected AbilityBot(String botToken, String botUsername) {
this(botToken, botUsername, onlineInstance(botUsername));
}
protected AbilityBot(String botToken, String botUsername) {
this(botToken, botUsername, onlineInstance(botUsername));
}
@Override
public void onUpdateReceived(Update update) {
super.onUpdateReceived(update);
}
@Override
public void onUpdateReceived(Update update) {
super.onUpdateReceived(update);
}
@Override
public void clearWebhook() throws TelegramApiRequestException {
WebhookUtils.clearWebhook(this);
}
@Override
public void clearWebhook() throws TelegramApiRequestException {
WebhookUtils.clearWebhook(this);
}
}

View File

@ -21,54 +21,54 @@ import static org.telegram.abilitybots.api.db.MapDBContext.onlineInstance;
@SuppressWarnings("WeakerAccess")
public abstract class AbilityWebhookBot extends BaseAbilityBot implements WebhookBot {
private final String botPath;
private final String botPath;
protected AbilityWebhookBot(String botToken, String botUsername, String botPath, DBContext db, AbilityToggle toggle, DefaultBotOptions botOptions) {
super(botToken, botUsername, db, toggle, botOptions);
this.botPath = botPath;
}
protected AbilityWebhookBot(String botToken, String botUsername, String botPath, DBContext db, AbilityToggle toggle, DefaultBotOptions botOptions) {
super(botToken, botUsername, db, toggle, botOptions);
this.botPath = botPath;
}
protected AbilityWebhookBot(String botToken, String botUsername, String botPath, AbilityToggle toggle, DefaultBotOptions options) {
this(botToken, botUsername, botPath, onlineInstance(botUsername), toggle, options);
}
protected AbilityWebhookBot(String botToken, String botUsername, String botPath, AbilityToggle toggle, DefaultBotOptions options) {
this(botToken, botUsername, botPath, onlineInstance(botUsername), toggle, options);
}
protected AbilityWebhookBot(String botToken, String botUsername, String botPath, DBContext db, AbilityToggle toggle) {
this(botToken, botUsername, botPath, db, toggle, new DefaultBotOptions());
}
protected AbilityWebhookBot(String botToken, String botUsername, String botPath, DBContext db, AbilityToggle toggle) {
this(botToken, botUsername, botPath, db, toggle, new DefaultBotOptions());
}
protected AbilityWebhookBot(String botToken, String botUsername, String botPath, DBContext db, DefaultBotOptions options) {
this(botToken, botUsername, botPath, db, new DefaultToggle(), options);
}
protected AbilityWebhookBot(String botToken, String botUsername, String botPath, DBContext db, DefaultBotOptions options) {
this(botToken, botUsername, botPath, db, new DefaultToggle(), options);
}
protected AbilityWebhookBot(String botToken, String botUsername, String botPath, DefaultBotOptions botOptions) {
this(botToken, botUsername, botPath, onlineInstance(botUsername), botOptions);
}
protected AbilityWebhookBot(String botToken, String botUsername, String botPath, DefaultBotOptions botOptions) {
this(botToken, botUsername, botPath, onlineInstance(botUsername), botOptions);
}
protected AbilityWebhookBot(String botToken, String botUsername, String botPath, AbilityToggle toggle) {
this(botToken, botUsername, botPath, onlineInstance(botUsername), toggle);
}
protected AbilityWebhookBot(String botToken, String botUsername, String botPath, AbilityToggle toggle) {
this(botToken, botUsername, botPath, onlineInstance(botUsername), toggle);
}
protected AbilityWebhookBot(String botToken, String botUsername, String botPath, DBContext db) {
this(botToken, botUsername, botPath, db, new DefaultToggle());
}
protected AbilityWebhookBot(String botToken, String botUsername, String botPath, DBContext db) {
this(botToken, botUsername, botPath, db, new DefaultToggle());
}
protected AbilityWebhookBot(String botToken, String botUsername, String botPath) {
this(botToken, botUsername, botPath, onlineInstance(botUsername));
}
protected AbilityWebhookBot(String botToken, String botUsername, String botPath) {
this(botToken, botUsername, botPath, onlineInstance(botUsername));
}
@Override
public BotApiMethod onWebhookUpdateReceived(Update update) {
super.onUpdateReceived(update);
return null;
}
@Override
public BotApiMethod onWebhookUpdateReceived(Update update) {
super.onUpdateReceived(update);
return null;
}
@Override
public void setWebhook(String url, String publicCertificatePath) throws TelegramApiRequestException {
WebhookUtils.setWebhook(this, url, publicCertificatePath);
}
@Override
public void setWebhook(String url, String publicCertificatePath) throws TelegramApiRequestException {
WebhookUtils.setWebhook(this, url, publicCertificatePath);
}
@Override
public String getBotPath() {
return botPath;
}
@Override
public String getBotPath() {
return botPath;
}
}

View File

@ -106,6 +106,7 @@ public abstract class BaseAbilityBot extends DefaultAbsSender implements Ability
private final String botUsername;
// Ability registry
private final List<AbilityExtension> extensions = new ArrayList<>();
private Map<String, Ability> abilities;
private Map<String, Stats> stats;
@ -123,11 +124,34 @@ public abstract class BaseAbilityBot extends DefaultAbsSender implements Ability
this.toggle = toggle;
this.sender = new DefaultSender(this);
silent = new SilentSender(sender);
}
public void onRegister() {
registerAbilities();
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>
*/
@ -272,6 +296,18 @@ public abstract class BaseAbilityBot extends DefaultAbsSender implements Ability
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.
* <p>
@ -280,10 +316,10 @@ public abstract class BaseAbilityBot extends DefaultAbsSender implements Ability
private void registerAbilities() {
try {
// 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))
.map(returnExtension(this))
.collect(Collectors.toList());
.collect(Collectors.toList()));
// Add the bot itself as it is an AbilityExtension
extensions.add(this);
@ -437,7 +473,7 @@ public abstract class BaseAbilityBot extends DefaultAbsSender implements Ability
Update update = trio.a();
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) {

View File

@ -17,7 +17,7 @@ import static com.google.common.collect.Lists.newArrayList;
import static java.lang.String.format;
import static java.util.Objects.hash;
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:
@ -50,9 +50,8 @@ public final class Ability {
@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) {
checkArgument(!isEmpty(name), "Method name cannot be empty");
checkArgument(!containsWhitespace(name), "Method name cannot contain spaces");
checkArgument(isAlphanumeric(name), "Method name can only be alpha-numeric", name);
checkArgument(isValidCommandName(name), "Method name can only contain alpha-numeric characters and underscores," +
" cannot be longer than 31 characters, empty or null", name);
this.name = name;
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.Objects;
import org.telegram.abilitybots.api.bot.BaseAbilityBot;
import org.telegram.telegrambots.meta.api.objects.Update;
import org.telegram.telegrambots.meta.api.objects.User;
@ -19,16 +20,18 @@ public class MessageContext {
private final Long chatId;
private final String[] arguments;
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.chatId = chatId;
this.update = update;
this.bot = bot;
this.arguments = arguments;
}
public static MessageContext newContext(Update update, User user, Long chatId, String... arguments) {
return new MessageContext(update, user, chatId, arguments);
public static MessageContext newContext(Update update, User user, Long chatId, BaseAbilityBot bot, String... arguments) {
return new MessageContext(update, user, chatId, bot, arguments);
}
/**
@ -45,6 +48,13 @@ public class MessageContext {
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.
*

View File

@ -269,4 +269,29 @@ public final class AbilityUtils {
public static String escape(String username) {
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() {
db = offlineInstance("db");
bot = new NoPublicCommandsBot(EMPTY, EMPTY, db);
bot.onRegister();
defaultAbs = new DefaultAbilities(bot);
sender = mock(MessageSender.class);

View File

@ -71,6 +71,7 @@ public class AbilityBotTest {
void setUp() {
db = offlineInstance("db");
bot = new DefaultBot(EMPTY, EMPTY, db);
bot.onRegister();
defaultAbs = new DefaultAbilities(bot);
sender = mock(MessageSender.class);
@ -503,7 +504,7 @@ public class AbilityBotTest {
mockUser(update, message, USER);
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");
}
@ -619,7 +620,7 @@ public class AbilityBotTest {
when(update.hasMessage()).thenReturn(true);
when(update.getMessage()).thenReturn(message);
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);
@ -636,7 +637,7 @@ public class AbilityBotTest {
when(update.getMessage()).thenReturn(message);
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);

View File

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

View File

@ -19,6 +19,7 @@ class ExtensionTest {
@BeforeEach
void setUp() {
bot = new ExtensionUsingBot();
bot.onRegister();
}
@AfterEach
@ -32,6 +33,7 @@ class ExtensionTest {
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("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) {
@ -41,6 +43,7 @@ class ExtensionTest {
public static class ExtensionUsingBot extends AbilityBot {
ExtensionUsingBot() {
super("", "", offlineInstance("testing"));
addExtension(new AbilityBotExtension("addedInConstructor"));
}
@Override

View File

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

View File

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

View File

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

View File

@ -1,7 +1,6 @@
package org.telegram.abilitybots.api.toggle;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.telegram.abilitybots.api.bot.DefaultAbilities;
@ -18,12 +17,10 @@ class CustomToggleTest {
private DBContext db;
private AbilityToggle toggle;
private DefaultBot customBot;
private DefaultAbilities defaultAbs;
@BeforeEach
void setUp() {
db = offlineInstance("db");
defaultAbs = new DefaultAbilities(customBot);
}
@AfterEach
@ -36,6 +33,7 @@ class CustomToggleTest {
public void canTurnOffAbilities() {
toggle = new CustomToggle().turnOff(DefaultAbilities.CLAIM);
customBot = new DefaultBot(EMPTY, EMPTY, db, toggle);
customBot.onRegister();
assertFalse(customBot.abilities().containsKey(DefaultAbilities.CLAIM));
}
@ -44,6 +42,7 @@ class CustomToggleTest {
String targetName = DefaultAbilities.CLAIM + "1toggle";
toggle = new CustomToggle().toggle(DefaultAbilities.CLAIM, targetName);
customBot = new DefaultBot(EMPTY, EMPTY, db, toggle);
customBot.onRegister();
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.BeforeEach;
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.db.DBContext;
import org.telegram.abilitybots.api.objects.Ability;
@ -18,52 +17,53 @@ import static org.telegram.abilitybots.api.bot.DefaultAbilities.*;
import static org.telegram.abilitybots.api.db.MapDBContext.offlineInstance;
class DefaultToggleTest {
private DBContext db;
private AbilityToggle toggle;
private DefaultBot defaultBot;
private DefaultAbilities defaultAbs;
private DBContext db;
private AbilityToggle toggle;
private DefaultBot defaultBot;
@BeforeEach
void setUp() {
db = offlineInstance("db");
defaultAbs = new DefaultAbilities(defaultBot);
}
@BeforeEach
void setUp() {
db = offlineInstance("db");
}
@AfterEach
void tearDown() throws IOException {
db.clear();
db.close();
}
@AfterEach
void tearDown() throws IOException {
db.clear();
db.close();
}
@Test
public void claimsEveryAbilityIsOn() {
Ability random = DefaultBot.getDefaultBuilder()
.name("randomsomethingrandom").build();
toggle = new DefaultToggle();
defaultBot = new DefaultBot(EMPTY, EMPTY, db, toggle);
@Test
public void claimsEveryAbilityIsOn() {
Ability random = DefaultBot.getDefaultBuilder()
.name("randomsomethingrandom").build();
toggle = new DefaultToggle();
defaultBot = new DefaultBot(EMPTY, EMPTY, db, toggle);
defaultBot.onRegister();
assertFalse(toggle.isOff(random));
}
assertFalse(toggle.isOff(random));
}
@Test
public void passedSameAbilityRefOnProcess() {
Ability random = DefaultBot.getDefaultBuilder()
.name("randomsomethingrandom").build();
toggle = new DefaultToggle();
defaultBot = new DefaultBot(EMPTY, EMPTY, db, toggle);
@Test
public void passedSameAbilityRefOnProcess() {
Ability random = DefaultBot.getDefaultBuilder()
.name("randomsomethingrandom").build();
toggle = new DefaultToggle();
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");
}
@Test
public void allAbilitiesAreRegistered() {
toggle = new DefaultToggle();
defaultBot = new DefaultBot(EMPTY, EMPTY, db, toggle);
Set<String> defaultNames = newHashSet(
CLAIM, BAN, UNBAN,
PROMOTE, DEMOTE, RECOVER,
BACKUP, REPORT, COMMANDS);
@Test
public void allAbilitiesAreRegistered() {
toggle = new DefaultToggle();
defaultBot = new DefaultBot(EMPTY, EMPTY, db, toggle);
defaultBot.onRegister();
Set<String> defaultNames = newHashSet(
CLAIM, BAN, UNBAN,
PROMOTE, DEMOTE, RECOVER,
BACKUP, REPORT, COMMANDS);
assertTrue(defaultBot.abilities().keySet().containsAll(defaultNames), "Toggle returned a different ability");
}
assertTrue(defaultBot.abilities().keySet().containsAll(defaultNames), "Toggle returned a different ability");
}
}

View File

@ -15,7 +15,7 @@ Usage
<dependency>
<groupId>org.telegram</groupId>
<artifactId>telegrambots-chat-session-bot</artifactId>
<version>4.9.1</version>
<version>4.9.2</version>
</dependency>
```

View File

@ -7,7 +7,7 @@
<parent>
<groupId>org.telegram</groupId>
<artifactId>Bots</artifactId>
<version>4.9.1</version>
<version>4.9.2</version>
</parent>
<artifactId>telegrambots-chat-session-bot</artifactId>
@ -84,7 +84,7 @@
<dependency>
<groupId>org.telegram</groupId>
<artifactId>telegrambots</artifactId>
<version>4.9.1</version>
<version>4.9.2</version>
</dependency>
<!-- 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>
<groupId>org.telegram</groupId>
<artifactId>telegrambotsextensions</artifactId>
<version>4.9.1</version>
<version>4.9.2</version>
</dependency>
```
2. Using Gradle:
```gradle
compile "org.telegram:telegrambotsextensions:4.9.1"
compile "org.telegram:telegrambotsextensions:4.9.2"
```

View File

@ -7,7 +7,7 @@
<parent>
<groupId>org.telegram</groupId>
<artifactId>Bots</artifactId>
<version>4.9.1</version>
<version>4.9.2</version>
</parent>
<artifactId>telegrambotsextensions</artifactId>
@ -75,7 +75,7 @@
<dependency>
<groupId>org.telegram</groupId>
<artifactId>telegrambots</artifactId>
<version>4.9.1</version>
<version>4.9.2</version>
</dependency>
</dependencies>

View File

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

View File

@ -7,7 +7,9 @@ import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.function.BiConsumer;
import java.util.function.Supplier;
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 boolean allowCommandsWithUsername;
private final String botUsername;
private final Supplier<String> botUsernameSupplier;
private BiConsumer<AbsSender, Message> defaultConsumer;
/**
* Creates a Command registry
*
* @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) {
Objects.requireNonNull(botUsername, "Bot username must not be null");
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
@ -120,9 +137,12 @@ public final class CommandRegistry implements ICommandRegistry {
* the command
* @param command Command to simplify
* @return Simplified command
* @throws java.lang.NullPointerException if {@code allowCommandsWithUsername} is {@code true}
* and {@code botUsernameSupplier} returns {@code null}
*/
private String removeUsernameFromCommandIfNeeded(String command) {
if (allowCommandsWithUsername) {
String botUsername = Objects.requireNonNull(botUsernameSupplier.get(), "Bot username must not be null");
return command.replaceAll("(?i)@" + Pattern.quote(botUsername), "").trim();
}
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>
<groupId>org.telegram</groupId>
<artifactId>Bots</artifactId>
<version>4.9.1</version>
<version>4.9.2</version>
</parent>
<artifactId>telegrambots-meta</artifactId>

View File

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

View File

@ -11,7 +11,7 @@ import java.util.List;
* @brief Callback to handle updates.
* @date 20 of June of 2015
*/
public interface LongPollingBot {
public interface LongPollingBot extends TelegramBot {
/**
* This method is called when receiving updates via GetUpdates method
* @param update Update received
@ -27,16 +27,6 @@ public interface LongPollingBot {
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
* @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.
* @date 20 of June of 2015
*/
public interface WebhookBot {
public interface WebhookBot extends TelegramBot {
/**
* This method is called when receiving updates via webhook
* @param update Update received
*/
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
* @param url Url for the webhook

View File

@ -18,14 +18,14 @@ Usage
<dependency>
<groupId>org.telegram</groupId>
<artifactId>telegrambots-spring-boot-starter</artifactId>
<version>4.9.1</version>
<version>4.9.2</version>
</dependency>
```
**Gradle**
```gradle
compile "org.telegram:telegrambots-spring-boot-starter:4.9.1"
compile "org.telegram:telegrambots-spring-boot-starter:4.9.2"
```
Motivation

View File

@ -7,7 +7,7 @@
<parent>
<groupId>org.telegram</groupId>
<artifactId>Bots</artifactId>
<version>4.9.1</version>
<version>4.9.2</version>
</parent>
<artifactId>telegrambots-spring-boot-starter</artifactId>
@ -70,7 +70,7 @@
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<telegrambots.version>4.9.1</telegrambots.version>
<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>

View File

@ -7,7 +7,7 @@
<parent>
<groupId>org.telegram</groupId>
<artifactId>Bots</artifactId>
<version>4.9.1</version>
<version>4.9.2</version>
</parent>
<artifactId>telegrambots</artifactId>
@ -95,7 +95,7 @@
<dependency>
<groupId>org.telegram</groupId>
<artifactId>telegrambots-meta</artifactId>
<version>4.9.1</version>
<version>4.9.2</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>

View File

@ -26,6 +26,8 @@ public class DefaultBotOptions implements BotOptions {
private ProxyType proxyType;
private String proxyHost;
private int proxyPort;
private int getUpdatesTimeout;
private int getUpdatesLimit;
public enum ProxyType {
NO_PROXY,
@ -39,6 +41,8 @@ public class DefaultBotOptions implements BotOptions {
baseUrl = ApiConstants.BASE_URL;
httpContext = HttpClientContext.create();
proxyType = ProxyType.NO_PROXY;
getUpdatesLimit = ApiConstants.GETUPDATES_TIMEOUT;
getUpdatesLimit = 100;
}
@Override
@ -129,4 +133,20 @@ public class DefaultBotOptions implements BotOptions {
public void setProxyPort(int 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 {
GetUpdates request = new GetUpdates()
.setLimit(100)
.setTimeout(ApiConstants.GETUPDATES_TIMEOUT)
.setLimit(options.getGetUpdatesLimit())
.setTimeout(options.getGetUpdatesTimeout())
.setOffset(lastReceivedUpdate + 1);
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();
rc.register(restApi);
rc.register(JacksonFeature.class);
rc.register(DefaultExceptionMapper.class);
final HttpServer grizzlyServer;
if (keystoreServerFile != null && keystoreServerPwd != null) {