Merge pull request #912 from rubenlagus/dev

Dev
This commit is contained in:
Ruben Bermudez 2021-04-26 21:01:34 +01:00 committed by GitHub
commit 02fdbec4cc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
76 changed files with 907 additions and 156 deletions

View File

@ -1,7 +1,7 @@
# Telegram Bot Java Library # Telegram Bot Java Library
[![Telegram](/TelegramBots.svg)](https://telegram.me/JavaBotsApi) [![Telegram](/TelegramBots.svg)](https://telegram.me/JavaBotsApi)
[![Build Status](https://telegrambots.teamcity.com/app/rest/builds/buildType:(id:TelegramBots_TelegramBotsBuild)/statusIcon.svg)](https://telegrambots.teamcity.com/viewType.html?buildTypeId=TelegramBots_TelegramBotsBuild)
[![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)
[![Jitpack](https://jitpack.io/v/rubenlagus/TelegramBots.svg)](https://jitpack.io/#rubenlagus/TelegramBots) [![Jitpack](https://jitpack.io/v/rubenlagus/TelegramBots.svg)](https://jitpack.io/#rubenlagus/TelegramBots)
[![Maven Central](https://maven-badges.herokuapp.com/maven-central/org.telegram/telegrambots/badge.svg)](http://mvnrepository.com/artifact/org.telegram/telegrambots) [![Maven Central](https://maven-badges.herokuapp.com/maven-central/org.telegram/telegrambots/badge.svg)](http://mvnrepository.com/artifact/org.telegram/telegrambots)
@ -27,18 +27,18 @@ 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>5.1.1</version> <version>5.2.0</version>
</dependency> </dependency>
``` ```
2. Using Gradle: 2. Using Gradle:
```gradle ```gradle
implementation 'org.telegram:telegrambots:5.1.1' implementation 'org.telegram:telegrambots:5.2.0'
``` ```
3. Using Jitpack from [here](https://jitpack.io/#rubenlagus/TelegramBots/5.1.1) 3. Using Jitpack from [here](https://jitpack.io/#rubenlagus/TelegramBots/5.2.0)
4. Download the jar(including all dependencies) from [here](https://mvnrepository.com/artifact/org.telegram/telegrambots/5.1.1) 4. Download the jar(including all dependencies) from [here](https://mvnrepository.com/artifact/org.telegram/telegrambots/5.2.0)
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`.

View File

@ -1,3 +1,9 @@
### <a id="5.2.0"></a>5.2.0 ###
1. Update Api version [5.2](https://core.telegram.org/bots/api#april-26-2021)
2. Allow custom BackOff implementations
3. Spring version 2.4.5 in spring module
4. Bug fixing: #869, #888 and #892
### <a id="5.1.1"></a>5.1.1 ### ### <a id="5.1.1"></a>5.1.1 ###
1. Bug fixing: #874 1. Bug fixing: #874

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>5.1.1</version> <version>5.2.0</version>
</dependency> </dependency>
``` ```
* With **Gradle**: * With **Gradle**:
```gradle ```gradle
implementation 'org.telegram:telegrambots:5.1.1' implementation 'org.telegram:telegrambots:5.2.0'
``` ```
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

@ -1,10 +1,10 @@
* [Bot Token Dont's](#bot-token-donts) * [Bot Token Rules](#bot-token-rules)
* [Using Enviroment Variables](#using-environment-variables) * [Using Enviroment Variables](#using-environment-variables)
* [Setting Enviroment Variables](#setting-environment-variables) * [Setting Enviroment Variables](#setting-environment-variables)
* [Accessing Enviroment Variables](#accessing-enviroment-variables) * [Accessing Enviroment Variables](#accessing-enviroment-variables)
* [Using Command Line Arguments](#using-command-line-arguments) * [Using Command Line Arguments](#using-command-line-arguments)
# <a id="bot-token-donts"></a> Bot Token Dont's ## # <a id="bot-token-rules"></a> Bot Token Rules ##
* Tokens should not be hardcoded into the bot code * Tokens should not be hardcoded into the bot code
* Tokens should never be published * Tokens should never be published
* Tokens should not be pushed into Repositorys * Tokens should not be pushed into Repositorys
@ -36,7 +36,7 @@ It can also be set using the Windows GUI
export VARIABLE_NAME = {YOUR_BOT_TOKEN} export VARIABLE_NAME = {YOUR_BOT_TOKEN}
``` ```
* Save the file * Save the file
* Either reboot your system or run the command above in your terminal * Either start a new terminal or run the command above
### IntelliJ ### IntelliJ
* Go to Run->Edit Configuratuions... * Go to Run->Edit Configuratuions...
@ -45,7 +45,7 @@ export VARIABLE_NAME = {YOUR_BOT_TOKEN}
* Click the Plus Icon to add a new Variable * Click the Plus Icon to add a new Variable
* Enter a Name and your Token as the Value * Enter a Name and your Token as the Value
###Heroku Cloud ### Heroku Cloud
* Naviage to your App * Naviage to your App
* In the Settings Tab under Config Vars, click "Reveal Config Vars" * In the Settings Tab under Config Vars, click "Reveal Config Vars"
* Enter a Name and your Token as the Value * Enter a Name and your Token as the Value
@ -65,7 +65,7 @@ String BOT_TOKEN = System.getenv("VARIABLE_NAME");
In Spring the @Value annotation allows you to inject the Value into your class In Spring the @Value annotation allows you to inject the Value into your class
```java ```java
public class Bot extends TelegramLongPollingBot { public class Bot extends TelegramLongPollingBot {
public Bot(@Value("${VARIABLE_NAME") String botToken) { public Bot(@Value("${VARIABLE_NAME}") String botToken) {
this.botToken = botToken; this.botToken = botToken;
} }
} }
@ -85,4 +85,4 @@ public static void main(String[] args) {
You now have to call your jar by using You now have to call your jar by using
``` ```
java -jar myBot.jar [BOT_TOKEN] java -jar myBot.jar [BOT_TOKEN]
``` ```

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>5.1.1</version> <version>5.2.0</version>
</dependency> </dependency>
``` ```
* **Gradle** * **Gradle**
```gradle ```gradle
implementation 'org.telegram:telegrambots-abilities:5.1.1' implementation 'org.telegram:telegrambots-abilities:5.2.0'
``` ```
* [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>5.1.1</version> <version>5.2.0</version>
<modules> <modules>
<module>telegrambots</module> <module>telegrambots</module>

View File

@ -18,14 +18,14 @@ Usage
<dependency> <dependency>
<groupId>org.telegram</groupId> <groupId>org.telegram</groupId>
<artifactId>telegrambots-abilities</artifactId> <artifactId>telegrambots-abilities</artifactId>
<version>5.1.1</version> <version>5.2.0</version>
</dependency> </dependency>
``` ```
**Gradle** **Gradle**
```gradle ```gradle
implementation 'org.telegram:telegrambots-abilities:5.1.1' implementation 'org.telegram:telegrambots-abilities:5.2.0'
``` ```
**JitPack** - [JitPack](https://jitpack.io/#rubenlagus/TelegramBots/v5.0.1) **JitPack** - [JitPack](https://jitpack.io/#rubenlagus/TelegramBots/v5.0.1)

View File

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

View File

@ -200,6 +200,11 @@ public final class Ability {
return this; return this;
} }
public AbilityBuilder setStatsEnabled(boolean statsEnabled) {
this.statsEnabled = statsEnabled;
return this;
}
public AbilityBuilder privacy(Privacy privacy) { public AbilityBuilder privacy(Privacy privacy) {
this.privacy = privacy; this.privacy = privacy;
return this; return this;

View File

@ -5,6 +5,8 @@ import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotEquals; import static org.junit.jupiter.api.Assertions.assertNotEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.telegram.abilitybots.api.bot.DefaultBot.getDefaultBuilder; import static org.telegram.abilitybots.api.bot.DefaultBot.getDefaultBuilder;
class AbilityTest { class AbilityTest {
@ -55,5 +57,17 @@ class AbilityTest {
assertEquals(ability1, ability4, "Abilities should not be equal"); assertEquals(ability1, ability4, "Abilities should not be equal");
assertNotEquals(ability1, ability3, "Abilities should be equal"); assertNotEquals(ability1, ability3, "Abilities should be equal");
} }
@Test
void abilityBuilderSetStatsEnabledTrueTest() {
Ability statsEnabledAbility = getDefaultBuilder().setStatsEnabled(true).build();
assertTrue(statsEnabledAbility.statsEnabled());
}
@Test
void abilityBuilderSetStatsEnabledFalseTest() {
Ability statsDisabledAbility = getDefaultBuilder().setStatsEnabled(false).build();
assertFalse(statsDisabledAbility.statsEnabled());
}
} }

View File

@ -15,14 +15,14 @@ Usage
<dependency> <dependency>
<groupId>org.telegram</groupId> <groupId>org.telegram</groupId>
<artifactId>telegrambots-chat-session-bot</artifactId> <artifactId>telegrambots-chat-session-bot</artifactId>
<version>5.1.1</version> <version>5.2.0</version>
</dependency> </dependency>
``` ```
**Gradle** **Gradle**
```gradle ```gradle
implementation 'org.telegram:telegrambots-chat-session-bot:5.1.1' implementation 'org.telegram:telegrambots-chat-session-bot:5.2.0'
``` ```
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>5.1.1</version> <version>5.2.0</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>5.1.1</version> <version>5.2.0</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>5.1.1</version> <version>5.2.0</version>
</dependency> </dependency>
``` ```
2. Using Gradle: 2. Using Gradle:
```gradle ```gradle
implementation 'org.telegram:telegrambotsextensions:5.1.1' implementation 'org.telegram:telegrambotsextensions:5.2.0'
``` ```

View File

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

View File

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

View File

@ -3,22 +3,31 @@ package org.telegram.telegrambots.meta.api.methods;
/** /**
* @author Ruben Bermudez * @author Ruben Bermudez
* @version 1.0 * @version 1.0
* @brief Types of actions for SendChatAction method. * Types of actions for SendChatAction method.
* @date 20 of June of 2016
*/ */
public enum ActionType { public enum ActionType {
TYPING("typing"), TYPING("typing"),
RECORDVIDEO("record_video"), RECORDVIDEO("record_video"),
RECORDVIDEONOTE("record_video_note"), RECORDVIDEONOTE("record_video_note"),
/**
* @deprecated Use {@link #RECORDVOICE} instead
*/
@Deprecated
RECORDAUDIO("record_audio"), RECORDAUDIO("record_audio"),
RECORDVOICE("record_voice"),
UPLOADPHOTO("upload_photo"), UPLOADPHOTO("upload_photo"),
UPLOADVIDEO("upload_video"), UPLOADVIDEO("upload_video"),
UPLOADVIDEONOTE("upload_video_note"), UPLOADVIDEONOTE("upload_video_note"),
/**
* @deprecated Use {@link #UPLOADVOICE} instead
*/
@Deprecated
UPLOADAUDIO("upload_audio"), UPLOADAUDIO("upload_audio"),
UPLOADVOICE("upload_voice"),
UPLOADDOCUMENT("upload_document"), UPLOADDOCUMENT("upload_document"),
FINDLOCATION("find_location"); FINDLOCATION("find_location");
private String text; private final String text;
ActionType(String text) { ActionType(String text) {
this.text = text; this.text = text;
@ -41,7 +50,8 @@ public enum ActionType {
case "record_video_note": case "record_video_note":
return RECORDVIDEONOTE; return RECORDVIDEONOTE;
case "record_audio": case "record_audio":
return RECORDAUDIO; case "record_voice":
return RECORDVOICE;
case "upload_photo": case "upload_photo":
return UPLOADPHOTO; return UPLOADPHOTO;
case "upload_video": case "upload_video":
@ -49,7 +59,8 @@ public enum ActionType {
case "upload_video_note": case "upload_video_note":
return UPLOADVIDEONOTE; return UPLOADVIDEONOTE;
case "upload_audio": case "upload_audio":
return UPLOADAUDIO; case "upload_voice":
return UPLOADVOICE;
case "upload_document": case "upload_document":
return UPLOADDOCUMENT; return UPLOADDOCUMENT;
case "find_location": case "find_location":

View File

@ -25,8 +25,10 @@ import java.util.List;
/** /**
* @author Ruben Bermudez * @author Ruben Bermudez
* @version 1.0 * @version 1.0
* Use this method to copy messages of any kind. The method is analogous to the method forwardMessages, * Use this method to copy messages of any kind.
* but the copied message doesn't have a link to the original message. * Service messages and invoice messages can't be copied.
*
* The method is analogous to the method forwardMessage, but the copied message doesn't have a link to the original message.
* Returns the MessageId of the sent message on success. * Returns the MessageId of the sent message on success.
*/ */
@SuppressWarnings("unused") @SuppressWarnings("unused")
@ -138,7 +140,7 @@ public class CopyMessage extends BotApiMethod<MessageId> {
@Override @Override
public void validate() throws TelegramApiValidationException { public void validate() throws TelegramApiValidationException {
if (chatId == null) { if (chatId == null || chatId.isEmpty()) {
throw new TelegramApiValidationException("ChatId parameter can't be empty", this); throw new TelegramApiValidationException("ChatId parameter can't be empty", this);
} }
if (fromChatId == null) { if (fromChatId == null) {

View File

@ -21,7 +21,10 @@ import java.io.IOException;
/** /**
* @author Ruben Bermudez * @author Ruben Bermudez
* @version 1.0 * @version 1.0
* Use this method to send text messages. On success, the sent Message is returned. * Use this method to forward messages of any kind.
* Service messages can't be forwarded.
*
* On success, the sent Message is returned.
*/ */
@EqualsAndHashCode(callSuper = false) @EqualsAndHashCode(callSuper = false)
@Getter @Getter

View File

@ -93,7 +93,7 @@ public class StopMessageLiveLocation extends BotApiMethod<Serializable> {
@Override @Override
public void validate() throws TelegramApiValidationException { public void validate() throws TelegramApiValidationException {
if (inlineMessageId == null) { if (inlineMessageId == null) {
if (chatId == null) { if (chatId == null || chatId.isEmpty()) {
throw new TelegramApiValidationException("ChatId parameter can't be empty if inlineMessageId is not present", this); throw new TelegramApiValidationException("ChatId parameter can't be empty if inlineMessageId is not present", this);
} }
if (messageId == null) { if (messageId == null) {

View File

@ -102,7 +102,7 @@ public class GetGameHighScores extends BotApiMethod<ArrayList<GameHighScore>> {
throw new TelegramApiValidationException("UserId parameter can't be empty", this); throw new TelegramApiValidationException("UserId parameter can't be empty", this);
} }
if (inlineMessageId == null) { if (inlineMessageId == null) {
if (chatId == null) { if (chatId == null || chatId.isEmpty()) {
throw new TelegramApiValidationException("ChatId parameter can't be empty if inlineMessageId is not present", this); throw new TelegramApiValidationException("ChatId parameter can't be empty if inlineMessageId is not present", this);
} }
if (messageId == null) { if (messageId == null) {

View File

@ -124,7 +124,7 @@ public class SetGameScore extends BotApiMethod<Serializable> {
throw new TelegramApiValidationException("Score parameter can't be empty", this); throw new TelegramApiValidationException("Score parameter can't be empty", this);
} }
if (inlineMessageId == null) { if (inlineMessageId == null) {
if (chatId == null) { if (chatId == null || chatId.isEmpty()) {
throw new TelegramApiValidationException("ChatId parameter can't be empty if inlineMessageId is not present", this); throw new TelegramApiValidationException("ChatId parameter can't be empty if inlineMessageId is not present", this);
} }
if (messageId == null) { if (messageId == null) {

View File

@ -64,7 +64,7 @@ public class DeleteChatPhoto extends BotApiMethod<Boolean> {
@Override @Override
public void validate() throws TelegramApiValidationException { public void validate() throws TelegramApiValidationException {
if (chatId == null) { if (chatId == null || chatId.isEmpty()) {
throw new TelegramApiValidationException("ChatId can't be null", this); throw new TelegramApiValidationException("ChatId can't be null", this);
} }
} }

View File

@ -137,7 +137,7 @@ public class SendPoll extends BotApiMethod<Message> {
@Override @Override
public void validate() throws TelegramApiValidationException { public void validate() throws TelegramApiValidationException {
if (chatId == null) { if (chatId == null || chatId.isEmpty()) {
throw new TelegramApiValidationException("ChatId parameter can't be empty", this); throw new TelegramApiValidationException("ChatId parameter can't be empty", this);
} }
if (question == null || question.isEmpty()) { if (question == null || question.isEmpty()) {

View File

@ -67,7 +67,7 @@ public class StopPoll extends BotApiMethod<Poll> {
@Override @Override
public void validate() throws TelegramApiValidationException { public void validate() throws TelegramApiValidationException {
if (chatId == null) { if (chatId == null || chatId.isEmpty()) {
throw new TelegramApiValidationException("ChatId parameter can't be empty", this); throw new TelegramApiValidationException("ChatId parameter can't be empty", this);
} }
if (messageId == null || messageId == 0) { if (messageId == null || messageId == 0) {

View File

@ -111,7 +111,7 @@ public class SendAnimation extends PartialBotApiMethod<Message> {
@Override @Override
public void validate() throws TelegramApiValidationException { public void validate() throws TelegramApiValidationException {
if (chatId == null) { if (chatId == null || chatId.isEmpty()) {
throw new TelegramApiValidationException("ChatId parameter can't be empty", this); throw new TelegramApiValidationException("ChatId parameter can't be empty", this);
} }

View File

@ -107,7 +107,7 @@ public class SendAudio extends PartialBotApiMethod<Message> {
@Override @Override
public void validate() throws TelegramApiValidationException { public void validate() throws TelegramApiValidationException {
if (chatId == null) { if (chatId == null || chatId.isEmpty()) {
throw new TelegramApiValidationException("ChatId parameter can't be empty", this); throw new TelegramApiValidationException("ChatId parameter can't be empty", this);
} }

View File

@ -85,7 +85,7 @@ public class SendChatAction extends BotApiMethod<Boolean> {
@Override @Override
public void validate() throws TelegramApiValidationException { public void validate() throws TelegramApiValidationException {
if (chatId == null) { if (chatId == null || chatId.isEmpty()) {
throw new TelegramApiValidationException("ChatId parameter can't be empty", this); throw new TelegramApiValidationException("ChatId parameter can't be empty", this);
} }
if (action == null) { if (action == null) {

View File

@ -99,7 +99,7 @@ public class SendContact extends BotApiMethod<Message> {
@Override @Override
public void validate() throws TelegramApiValidationException { public void validate() throws TelegramApiValidationException {
if (chatId == null) { if (chatId == null || chatId.isEmpty()) {
throw new TelegramApiValidationException("ChatId parameter can't be empty", this); throw new TelegramApiValidationException("ChatId parameter can't be empty", this);
} }
if (phoneNumber == null) { if (phoneNumber == null) {

View File

@ -103,7 +103,7 @@ public class SendDice extends BotApiMethod<Message> {
@Override @Override
public void validate() throws TelegramApiValidationException { public void validate() throws TelegramApiValidationException {
if (chatId == null) { if (chatId == null || chatId.isEmpty()) {
throw new TelegramApiValidationException("ChatId parameter can't be empty", this); throw new TelegramApiValidationException("ChatId parameter can't be empty", this);
} }
if (emoji != null && !VALIDEMOJIS.contains(emoji)) { if (emoji != null && !VALIDEMOJIS.contains(emoji)) {

View File

@ -99,7 +99,7 @@ public class SendDocument extends PartialBotApiMethod<Message> {
@Override @Override
public void validate() throws TelegramApiValidationException { public void validate() throws TelegramApiValidationException {
if (chatId == null) { if (chatId == null || chatId.isEmpty()) {
throw new TelegramApiValidationException("ChatId parameter can't be empty", this); throw new TelegramApiValidationException("ChatId parameter can't be empty", this);
} }

View File

@ -105,7 +105,7 @@ public class SendGame extends BotApiMethod<Message> {
@Override @Override
public void validate() throws TelegramApiValidationException { public void validate() throws TelegramApiValidationException {
if (chatId == null) { if (chatId == null || chatId.isEmpty()) {
throw new TelegramApiValidationException("ChatId parameter can't be empty", this); throw new TelegramApiValidationException("ChatId parameter can't be empty", this);
} }
if (gameShortName == null || gameShortName.isEmpty()) { if (gameShortName == null || gameShortName.isEmpty()) {

View File

@ -2,6 +2,7 @@ package org.telegram.telegrambots.meta.api.methods.send;
import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.core.type.TypeReference;
import com.google.common.base.Strings;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Builder; import lombok.Builder;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
@ -10,6 +11,7 @@ import lombok.NoArgsConstructor;
import lombok.NonNull; import lombok.NonNull;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.Setter; import lombok.Setter;
import lombok.Singular;
import lombok.ToString; import lombok.ToString;
import org.telegram.telegrambots.meta.api.methods.BotApiMethod; import org.telegram.telegrambots.meta.api.methods.BotApiMethod;
import org.telegram.telegrambots.meta.api.objects.ApiResponse; import org.telegram.telegrambots.meta.api.objects.ApiResponse;
@ -62,10 +64,12 @@ public class SendInvoice extends BotApiMethod<Message> {
private static final String REPLY_MARKUP_FIELD = "reply_markup"; private static final String REPLY_MARKUP_FIELD = "reply_markup";
private static final String PROVIDER_DATA_FIELD = "provider_data"; private static final String PROVIDER_DATA_FIELD = "provider_data";
private static final String ALLOWSENDINGWITHOUTREPLY_FIELD = "allow_sending_without_reply"; private static final String ALLOWSENDINGWITHOUTREPLY_FIELD = "allow_sending_without_reply";
private static final String MAXTIPAMOUNT_FIELD = "max_tip_amount";
private static final String SUGGESTEDTIPAMOUNTS_FIELD = "suggested_tip_amounts";
@JsonProperty(CHATID_FIELD) @JsonProperty(CHATID_FIELD)
@NonNull @NonNull
private Integer chatId; ///< Unique identifier for the target private chat private String chatId; ///< Unique identifier for the target chat or username of the target channel (in the format @channelusername)
@JsonProperty(TITLE_FIELD) @JsonProperty(TITLE_FIELD)
@NonNull @NonNull
private String title; ///< Product name private String title; ///< Product name
@ -78,14 +82,22 @@ public class SendInvoice extends BotApiMethod<Message> {
@JsonProperty(PROVIDER_TOKEN_FIELD) @JsonProperty(PROVIDER_TOKEN_FIELD)
@NonNull @NonNull
private String providerToken; ///< Payments provider token, obtained via Botfather private String providerToken; ///< Payments provider token, obtained via Botfather
/**
* Optional
* Unique deep-linking parameter. If left empty, forwarded copies of the sent message will have a Pay button,
* allowing multiple users to pay directly from the forwarded message, using the same invoice.
* If non-empty, forwarded copies of the sent message will have a URL button with a deep link to the bot (instead of a Pay button),
* with the value used as the start parameter
*/
@JsonProperty(START_PARAMETER_FIELD) @JsonProperty(START_PARAMETER_FIELD)
@NonNull @NonNull
private String startParameter; ///< Unique deep-linking parameter that can be used to generate this invoice when used as a start parameter. private String startParameter;
@JsonProperty(CURRENCY_FIELD) @JsonProperty(CURRENCY_FIELD)
@NonNull @NonNull
private String currency; ///< 3-letter ISO 4217 currency code private String currency; ///< 3-letter ISO 4217 currency code
@JsonProperty(PRICES_FIELD) @JsonProperty(PRICES_FIELD)
@NonNull @NonNull
@Singular
private List<LabeledPrice> prices; ///< Price breakdown, a list of components (e.g. product price, tax, discount, delivery cost, delivery tax, bonus, etc.) private List<LabeledPrice> prices; ///< Price breakdown, a list of components (e.g. product price, tax, discount, delivery cost, delivery tax, bonus, etc.)
/** /**
* Optional. URL of the product photo for the invoice. Can be a photo of the goods or a marketing image for a service. * Optional. URL of the product photo for the invoice. Can be a photo of the goods or a marketing image for a service.
@ -134,6 +146,21 @@ public class SendInvoice extends BotApiMethod<Message> {
private String providerData; private String providerData;
@JsonProperty(ALLOWSENDINGWITHOUTREPLY_FIELD) @JsonProperty(ALLOWSENDINGWITHOUTREPLY_FIELD)
private Boolean allowSendingWithoutReply; ///< Optional Pass True, if the message should be sent even if the specified replied-to message is not found private Boolean allowSendingWithoutReply; ///< Optional Pass True, if the message should be sent even if the specified replied-to message is not found
/**
* The maximum accepted amount for tips in the smallest units of the currency (integer, not float/double).
* For example, for a maximum tip of US$ 1.45 pass max_tip_amount = 145.
* Defaults to 0
*/
@JsonProperty(MAXTIPAMOUNT_FIELD)
private Integer maxTipAmount;
/**
* A JSON-serialized array of suggested amounts of tips in the smallest units of the currency (integer, not float/double).
* At most 4 suggested tip amounts can be specified.
* The suggested tip amounts must be positive, passed in a strictly increased order and must not exceed max_tip_amount.
*/
@JsonProperty(SUGGESTEDTIPAMOUNTS_FIELD)
@Singular
private List<Integer> suggestedTipAmounts;
@Override @Override
public String getMethod() { public String getMethod() {
@ -157,25 +184,25 @@ public class SendInvoice extends BotApiMethod<Message> {
@Override @Override
public void validate() throws TelegramApiValidationException { public void validate() throws TelegramApiValidationException {
if (chatId == null) { if (Strings.isNullOrEmpty(chatId)) {
throw new TelegramApiValidationException("ChatId parameter can't be empty", this); throw new TelegramApiValidationException("ChatId parameter can't be empty", this);
} }
if (title == null || title.isEmpty()) { if (Strings.isNullOrEmpty(title)) {
throw new TelegramApiValidationException("Title parameter can't be empty", this); throw new TelegramApiValidationException("Title parameter can't be empty", this);
} }
if (description == null || description.isEmpty()) { if (Strings.isNullOrEmpty(description)) {
throw new TelegramApiValidationException("Description parameter can't be empty", this); throw new TelegramApiValidationException("Description parameter can't be empty", this);
} }
if (payload == null || payload.isEmpty()) { if (Strings.isNullOrEmpty(payload)) {
throw new TelegramApiValidationException("Payload parameter can't be empty", this); throw new TelegramApiValidationException("Payload parameter can't be empty", this);
} }
if (providerToken == null || providerToken.isEmpty()) { if (Strings.isNullOrEmpty(providerToken)) {
throw new TelegramApiValidationException("ProviderToken parameter can't be empty", this); throw new TelegramApiValidationException("ProviderToken parameter can't be empty", this);
} }
if (startParameter == null || startParameter.isEmpty()) { if (Strings.isNullOrEmpty(startParameter)) {
throw new TelegramApiValidationException("StartParameter parameter can't be empty", this); throw new TelegramApiValidationException("StartParameter parameter can't be empty", this);
} }
if (currency == null || currency.isEmpty()) { if (Strings.isNullOrEmpty(currency)) {
throw new TelegramApiValidationException("Currency parameter can't be empty", this); throw new TelegramApiValidationException("Currency parameter can't be empty", this);
} }
if (prices == null || prices.isEmpty()) { if (prices == null || prices.isEmpty()) {
@ -185,6 +212,9 @@ public class SendInvoice extends BotApiMethod<Message> {
price.validate(); price.validate();
} }
} }
if (suggestedTipAmounts != null && !suggestedTipAmounts.isEmpty() && suggestedTipAmounts.size() > 4) {
throw new TelegramApiValidationException("No more that 4 suggested tips allowed", this);
}
if (replyMarkup != null) { if (replyMarkup != null) {
replyMarkup.validate(); replyMarkup.validate();
} }

View File

@ -118,7 +118,7 @@ public class SendLocation extends BotApiMethod<Message> {
@Override @Override
public void validate() throws TelegramApiValidationException { public void validate() throws TelegramApiValidationException {
if (chatId == null) { if (chatId == null || chatId.isEmpty()) {
throw new TelegramApiValidationException("ChatId parameter can't be empty", this); throw new TelegramApiValidationException("ChatId parameter can't be empty", this);
} }
if (latitude == null) { if (latitude == null) {

View File

@ -90,7 +90,7 @@ public class SendMediaGroup extends PartialBotApiMethod<ArrayList<Message>> {
@Override @Override
public void validate() throws TelegramApiValidationException { public void validate() throws TelegramApiValidationException {
if (chatId == null) { if (chatId == null || chatId.isEmpty()) {
throw new TelegramApiValidationException("ChatId parameter can't be empty", this); throw new TelegramApiValidationException("ChatId parameter can't be empty", this);
} }

View File

@ -135,7 +135,7 @@ public class SendMessage extends BotApiMethod<Message> {
@Override @Override
public void validate() throws TelegramApiValidationException { public void validate() throws TelegramApiValidationException {
if (chatId == null) { if (chatId == null || chatId.isEmpty()) {
throw new TelegramApiValidationException("ChatId parameter can't be empty", this); throw new TelegramApiValidationException("ChatId parameter can't be empty", this);
} }
if (text == null || text.isEmpty()) { if (text == null || text.isEmpty()) {

View File

@ -93,7 +93,7 @@ public class SendPhoto extends PartialBotApiMethod<Message> {
@Override @Override
public void validate() throws TelegramApiValidationException { public void validate() throws TelegramApiValidationException {
if (chatId == null) { if (chatId == null || chatId.isEmpty()) {
throw new TelegramApiValidationException("ChatId parameter can't be empty", this); throw new TelegramApiValidationException("ChatId parameter can't be empty", this);
} }

View File

@ -81,7 +81,7 @@ public class SendSticker extends PartialBotApiMethod<Message> {
@Override @Override
public void validate() throws TelegramApiValidationException { public void validate() throws TelegramApiValidationException {
if (chatId == null) { if (chatId == null || chatId.isEmpty()) {
throw new TelegramApiValidationException("ChatId parameter can't be empty", this); throw new TelegramApiValidationException("ChatId parameter can't be empty", this);
} }

View File

@ -113,7 +113,7 @@ public class SendVenue extends BotApiMethod<Message> {
@Override @Override
public void validate() throws TelegramApiValidationException { public void validate() throws TelegramApiValidationException {
if (chatId == null) { if (chatId == null || chatId.isEmpty()) {
throw new TelegramApiValidationException("ChatId parameter can't be empty", this); throw new TelegramApiValidationException("ChatId parameter can't be empty", this);
} }
if (longitude == null) { if (longitude == null) {

View File

@ -106,7 +106,7 @@ public class SendVideo extends PartialBotApiMethod<Message> {
@Override @Override
public void validate() throws TelegramApiValidationException { public void validate() throws TelegramApiValidationException {
if (chatId == null) { if (chatId == null || chatId.isEmpty()) {
throw new TelegramApiValidationException("ChatId parameter can't be empty", this); throw new TelegramApiValidationException("ChatId parameter can't be empty", this);
} }

View File

@ -92,7 +92,7 @@ public class SendVideoNote extends PartialBotApiMethod<Message> {
@Override @Override
public void validate() throws TelegramApiValidationException { public void validate() throws TelegramApiValidationException {
if (chatId == null) { if (chatId == null || chatId.isEmpty()) {
throw new TelegramApiValidationException("ChatId parameter can't be empty", this); throw new TelegramApiValidationException("ChatId parameter can't be empty", this);
} }

View File

@ -91,7 +91,7 @@ public class SendVoice extends PartialBotApiMethod<Message> {
@Override @Override
public void validate() throws TelegramApiValidationException { public void validate() throws TelegramApiValidationException {
if (chatId == null) { if (chatId == null || chatId.isEmpty()) {
throw new TelegramApiValidationException("ChatId parameter can't be empty", this); throw new TelegramApiValidationException("ChatId parameter can't be empty", this);
} }

View File

@ -79,7 +79,7 @@ public class DeleteMessage extends BotApiMethod<Boolean> {
@Override @Override
public void validate() throws TelegramApiValidationException { public void validate() throws TelegramApiValidationException {
if (chatId == null) { if (chatId == null || chatId.isEmpty()) {
throw new TelegramApiValidationException("ChatId parameter can't be empty", this); throw new TelegramApiValidationException("ChatId parameter can't be empty", this);
} }
if (messageId == null) { if (messageId == null) {

View File

@ -106,7 +106,7 @@ public class EditMessageCaption extends BotApiMethod<Serializable> {
@Override @Override
public void validate() throws TelegramApiValidationException { public void validate() throws TelegramApiValidationException {
if (inlineMessageId == null) { if (inlineMessageId == null) {
if (chatId == null) { if (chatId == null || chatId.isEmpty()) {
throw new TelegramApiValidationException("ChatId parameter can't be empty if inlineMessageId is not present", this); throw new TelegramApiValidationException("ChatId parameter can't be empty if inlineMessageId is not present", this);
} }
if (messageId == null) { if (messageId == null) {

View File

@ -127,7 +127,7 @@ public class EditMessageLiveLocation extends BotApiMethod<Serializable> {
@Override @Override
public void validate() throws TelegramApiValidationException { public void validate() throws TelegramApiValidationException {
if (inlineMessageId == null) { if (inlineMessageId == null) {
if (chatId == null) { if (chatId == null || chatId.isEmpty()) {
throw new TelegramApiValidationException("ChatId parameter can't be empty if inlineMessageId is not present", this); throw new TelegramApiValidationException("ChatId parameter can't be empty if inlineMessageId is not present", this);
} }
if (messageId == null) { if (messageId == null) {

View File

@ -104,7 +104,7 @@ public class EditMessageMedia extends PartialBotApiMethod<Serializable> {
@Override @Override
public void validate() throws TelegramApiValidationException { public void validate() throws TelegramApiValidationException {
if (inlineMessageId == null) { if (inlineMessageId == null) {
if (chatId == null) { if (chatId == null || chatId.isEmpty()) {
throw new TelegramApiValidationException("ChatId parameter can't be empty if inlineMessageId is not present", this); throw new TelegramApiValidationException("ChatId parameter can't be empty if inlineMessageId is not present", this);
} }
if (messageId == null) { if (messageId == null) {

View File

@ -94,7 +94,7 @@ public class EditMessageReplyMarkup extends BotApiMethod<Serializable> {
@Override @Override
public void validate() throws TelegramApiValidationException { public void validate() throws TelegramApiValidationException {
if (inlineMessageId == null) { if (inlineMessageId == null) {
if (chatId == null) { if (chatId == null || chatId.isEmpty()) {
throw new TelegramApiValidationException("ChatId parameter can't be empty if inlineMessageId is not present", this); throw new TelegramApiValidationException("ChatId parameter can't be empty if inlineMessageId is not present", this);
} }
if (messageId == null) { if (messageId == null) {

View File

@ -144,7 +144,7 @@ public class EditMessageText extends BotApiMethod<Serializable> {
@Override @Override
public void validate() throws TelegramApiValidationException { public void validate() throws TelegramApiValidationException {
if (inlineMessageId == null) { if (inlineMessageId == null) {
if (chatId == null) { if (chatId == null || chatId.isEmpty()) {
throw new TelegramApiValidationException("ChatId parameter can't be empty if inlineMessageId is not present", this); throw new TelegramApiValidationException("ChatId parameter can't be empty if inlineMessageId is not present", this);
} }
if (messageId == null) { if (messageId == null) {

View File

@ -19,6 +19,7 @@ import org.telegram.telegrambots.meta.api.objects.replykeyboard.InlineKeyboardMa
import org.telegram.telegrambots.meta.api.objects.stickers.Sticker; import org.telegram.telegrambots.meta.api.objects.stickers.Sticker;
import org.telegram.telegrambots.meta.api.objects.voicechat.VoiceChatEnded; import org.telegram.telegrambots.meta.api.objects.voicechat.VoiceChatEnded;
import org.telegram.telegrambots.meta.api.objects.voicechat.VoiceChatParticipantsInvited; import org.telegram.telegrambots.meta.api.objects.voicechat.VoiceChatParticipantsInvited;
import org.telegram.telegrambots.meta.api.objects.voicechat.VoiceChatScheduled;
import org.telegram.telegrambots.meta.api.objects.voicechat.VoiceChatStarted; import org.telegram.telegrambots.meta.api.objects.voicechat.VoiceChatStarted;
import java.util.ArrayList; import java.util.ArrayList;
@ -87,10 +88,11 @@ public class Message implements BotApiObject {
private static final String VIABOT_FIELD = "via_bot"; private static final String VIABOT_FIELD = "via_bot";
private static final String SENDERCHAT_FIELD = "sender_chat"; private static final String SENDERCHAT_FIELD = "sender_chat";
private static final String PROXIMITYALERTTRIGGERED_FIELD = "proximity_alert_triggered"; private static final String PROXIMITYALERTTRIGGERED_FIELD = "proximity_alert_triggered";
private static final String MESSAGEAUTODELETETIMERCHANGED_FIELD = "message_auto_delete_timer_changed\t"; private static final String MESSAGEAUTODELETETIMERCHANGED_FIELD = "message_auto_delete_timer_changed";
private static final String VOICECHATSTARTED_FIELD = "voice_chat_started"; private static final String VOICECHATSTARTED_FIELD = "voice_chat_started";
private static final String VOICECHATENDED_FIELD = "voice_chat_ended"; private static final String VOICECHATENDED_FIELD = "voice_chat_ended";
private static final String VOICECHATPARTICIPANTSINVITED_FIELD = "voice_chat_participants_invited"; private static final String VOICECHATPARTICIPANTSINVITED_FIELD = "voice_chat_participants_invited";
private static final String VOICECHATSCHEDULED_FIELD = "voice_chat_scheduled";
@JsonProperty(MESSAGEID_FIELD) @JsonProperty(MESSAGEID_FIELD)
private Integer messageId; ///< Integer Unique message identifier private Integer messageId; ///< Integer Unique message identifier
@ -266,7 +268,8 @@ public class Message implements BotApiObject {
private VoiceChatEnded voiceChatEnded; ///< Optional. Service message: voice chat ended private VoiceChatEnded voiceChatEnded; ///< Optional. Service message: voice chat ended
@JsonProperty(VOICECHATPARTICIPANTSINVITED_FIELD) @JsonProperty(VOICECHATPARTICIPANTSINVITED_FIELD)
private VoiceChatParticipantsInvited voiceChatParticipantsInvited; ///< Optional. Service message: new members invited to a voice chat private VoiceChatParticipantsInvited voiceChatParticipantsInvited; ///< Optional. Service message: new members invited to a voice chat
@JsonProperty(VOICECHATSCHEDULED_FIELD)
private VoiceChatScheduled voiceChatScheduled; ///< Optional. Service message: voice chat scheduled
public List<MessageEntity> getEntities() { public List<MessageEntity> getEntities() {
if (entities != null) { if (entities != null) {
@ -445,6 +448,11 @@ public class Message implements BotApiObject {
return voiceChatEnded != null; return voiceChatEnded != null;
} }
@JsonIgnore
private boolean hasVoiceChatScheduled() {
return voiceChatScheduled != null;
}
@JsonIgnore @JsonIgnore
private boolean hasVoiceChatParticipantsInvited() { private boolean hasVoiceChatParticipantsInvited() {
return voiceChatParticipantsInvited != null; return voiceChatParticipantsInvited != null;

View File

@ -34,6 +34,7 @@ public class InlineQuery implements BotApiObject {
private static final String LOCATION_FIELD = "location"; private static final String LOCATION_FIELD = "location";
private static final String QUERY_FIELD = "query"; private static final String QUERY_FIELD = "query";
private static final String OFFSET_FIELD = "offset"; private static final String OFFSET_FIELD = "offset";
private static final String CHATTYPE_FIELD = "chat_type";
@JsonProperty(ID_FIELD) @JsonProperty(ID_FIELD)
@NonNull @NonNull
@ -49,5 +50,13 @@ public class InlineQuery implements BotApiObject {
@JsonProperty(OFFSET_FIELD) @JsonProperty(OFFSET_FIELD)
@NonNull @NonNull
private String offset; ///< Offset of the results to be returned, can be controlled by the bot private String offset; ///< Offset of the results to be returned, can be controlled by the bot
/**
* Optional. Type of the chat, from which the inline query was sent.
* Can be either sender for a private chat with the inline query sender, private, group, supergroup, or channel.
* The chat type should be always known for requests sent from official clients and most third-party clients,
* unless the request was sent from a secret chat
*/
@JsonProperty(CHATTYPE_FIELD)
private String chatType;
} }

View File

@ -0,0 +1,165 @@
package org.telegram.telegrambots.meta.api.objects.inlinequery.inputmessagecontent;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.google.common.base.Strings;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.NonNull;
import lombok.RequiredArgsConstructor;
import lombok.Setter;
import lombok.Singular;
import lombok.ToString;
import org.telegram.telegrambots.meta.api.objects.payments.LabeledPrice;
import org.telegram.telegrambots.meta.exceptions.TelegramApiValidationException;
import java.util.List;
/**
* @author Ruben Bermudez
* @version 1.0
* Represents the content of a text message to be sent as the result of an inline query.
*/
@JsonDeserialize
@EqualsAndHashCode(callSuper = false)
@Getter
@Setter
@ToString
@RequiredArgsConstructor
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class InputInvoiceMessageContent implements InputMessageContent {
private static final String TITLE_FIELD = "title";
private static final String DESCRIPTION_FIELD = "description";
private static final String PAYLOAD_FIELD = "payload";
private static final String PROVIDERTOKEN_FIELD = "provider_token";
private static final String CURRENCY_FIELD = "currency";
private static final String PRICES_FIELD = "prices";
private static final String MAXTIPAMOUNT_FIELD = "max_tip_amount";
private static final String SUGGESTEDTIPAMOUNTS_FIELD = "suggested_tip_amounts";
private static final String PROVIDERDATA_FIELD = "provider_data";
private static final String PHOTOURL_FIELD = "photo_url";
private static final String PHOTOSIZE_FIELD = "photo_size";
private static final String PHOTOWIDTH_FIELD = "photo_width";
private static final String PHOTOHEIGHT_FIELD = "photo_height";
private static final String NEEDNAME_FIELD = "need_name";
private static final String NEEDPHONENUMBER_FIELD = "need_phone_number";
private static final String NEEDEMAIL_FIELD = "need_email";
private static final String NEEDSHIPPINGADDRESS_FIELD = "need_shipping_address";
private static final String SENDPHONENUMBERTOPROVIDER_FIELD = "send_phone_number_to_provider";
private static final String SENDEMAILTOPROVIDER_FIELD = "send_email_to_provider";
private static final String ISFLEXIBLE_FIELD = "is_flexible";
@JsonProperty(TITLE_FIELD)
@NonNull
private String title; ///< Product name, 1-32 characters
@JsonProperty(DESCRIPTION_FIELD)
@NonNull
private String description; ///< Product description, 1-255 characters
/**
* Bot-defined invoice payload, 1-128 bytes.
* This will not be displayed to the user, use for your internal processes.
*/
@JsonProperty(PAYLOAD_FIELD)
@NonNull
private String payload;
@JsonProperty(PROVIDERTOKEN_FIELD)
@NonNull
private String providerToken; ///< Payment provider token, obtained via Botfather
@JsonProperty(CURRENCY_FIELD)
@NonNull
private String currency; ///< Three-letter ISO 4217 currency code, see more on currencies
/**
* Price breakdown, a JSON-serialized list of components
* (e.g. product price, tax, discount, delivery cost, delivery tax, bonus, etc.)
*/
@JsonProperty(PRICES_FIELD)
@NonNull
@Singular
private List<LabeledPrice> prices;
/**
* Optional.
* The maximum accepted amount for tips in the smallest units of the currency (integer, not float/double).
* For example, for a maximum tip of US$ 1.45 pass max_tip_amount = 145.
* Defaults to 0
*/
@JsonProperty(MAXTIPAMOUNT_FIELD)
private Integer maxTipAmount;
/**
* Optional.
* A JSON-serialized array of suggested amounts of tip in the smallest units of the currency (integer, not float/double).
* At most 4 suggested tip amounts can be specified.
* The suggested tip amounts must be positive, passed in a strictly increased order and must not exceed max_tip_amount.
*/
@JsonProperty(SUGGESTEDTIPAMOUNTS_FIELD)
@Singular
private List<Integer> suggestedTipAmounts;
/**
* Optional.
* A JSON-serialized object for data about the invoice, which will be shared with the payment provider.
* A detailed description of the required fields should be provided by the payment provider.
*/
@JsonProperty(PROVIDERDATA_FIELD)
private String providerData;
/**
* Optional.
* URL of the product photo for the invoice.
* Can be a photo of the goods or a marketing image for a service.
* People like it better when they see what they are paying for.
*/
@JsonProperty(PHOTOURL_FIELD)
private String photoUrl;
@JsonProperty(PHOTOSIZE_FIELD)
private Integer photoSize; ///< Optional. Photo size
@JsonProperty(PHOTOWIDTH_FIELD)
private Integer photoWidth; ///< Optional. Photo width
@JsonProperty(PHOTOHEIGHT_FIELD)
private Integer photoHeight; ///< Optional. Photo height
@JsonProperty(NEEDNAME_FIELD)
private Boolean needName; ///< Optional. Pass True, if you require the user's full name to complete the order
@JsonProperty(NEEDPHONENUMBER_FIELD)
private Boolean needPhoneNumber; ///< Optional. Pass True, if you require the user's phone number to complete the order
@JsonProperty(NEEDEMAIL_FIELD)
private Boolean needEmail; ///< Optional. Pass True, if you require the user's email address to complete the order
@JsonProperty(NEEDSHIPPINGADDRESS_FIELD)
private Boolean needShippingAddress; ///< Optional. Pass True, if you require the user's shipping address to complete the order
@JsonProperty(SENDPHONENUMBERTOPROVIDER_FIELD)
private Boolean sendPhoneNumberToProvider; ///< Optional. Pass True, if user's phone number should be sent to provider
@JsonProperty(SENDEMAILTOPROVIDER_FIELD)
private Boolean sendEmailToProvider; ///< Optional. Pass True, if user's email address should be sent to provider
@JsonProperty(ISFLEXIBLE_FIELD)
private Boolean isFlexible; ///< Optional. Pass True, if the final price depends on the shipping method
@Override
public void validate() throws TelegramApiValidationException {
if (Strings.isNullOrEmpty(title) || title.length() > 32) {
throw new TelegramApiValidationException("Title parameter must be between 1 and 32 characters", this);
}
if (Strings.isNullOrEmpty(description) || description.length() > 32) {
throw new TelegramApiValidationException("Description parameter must be between 1 and 255 characters", this);
}
if (Strings.isNullOrEmpty(payload) || payload.length() > 32) {
throw new TelegramApiValidationException("Payload parameter must be between 1 and 128 characters", this);
}
if (Strings.isNullOrEmpty(providerToken)) {
throw new TelegramApiValidationException("ProviderToken parameter must not be empty", this);
}
if (Strings.isNullOrEmpty(currency)) {
throw new TelegramApiValidationException("Currency parameter must not be empty", this);
}
if (prices == null || prices.isEmpty()) {
throw new TelegramApiValidationException("Prices parameter must not be empty", this);
}
for (LabeledPrice price : prices) {
price.validate();
}
if (suggestedTipAmounts != null && !suggestedTipAmounts.isEmpty() && suggestedTipAmounts.size() > 4) {
throw new TelegramApiValidationException("Only up to 4 suggested tip amounts are allowed", this);
}
}
}

View File

@ -52,6 +52,11 @@ public class InputMessageContentDeserializer extends StdDeserializer<InputMessag
new com.fasterxml.jackson.core.type.TypeReference<InputContactMessageContent>(){}); new com.fasterxml.jackson.core.type.TypeReference<InputContactMessageContent>(){});
} }
if (node.has("provider_token")) {
return objectMapper.readValue(node.toString(),
new com.fasterxml.jackson.core.type.TypeReference<InputInvoiceMessageContent>(){});
}
return null; return null;
} }
} }

View File

@ -34,8 +34,11 @@ public class Invoice implements BotApiObject {
private String title; ///< Product name private String title; ///< Product name
@JsonProperty(DESCRIPTION_FIELD) @JsonProperty(DESCRIPTION_FIELD)
private String description; ///< Product description private String description; ///< Product description
/**
* Unique bot deep-linking parameter that can be used to generate this invoice; may be empty
*/
@JsonProperty(START_PARAMETER_FIELD) @JsonProperty(START_PARAMETER_FIELD)
private String startParameter; ///< Unique bot deep-linking parameter for generation of this invoice private String startParameter;
@JsonProperty(CURRENCY_FIELD) @JsonProperty(CURRENCY_FIELD)
private String currency; ///< Three-letter ISO 4217 currency code private String currency; ///< Three-letter ISO 4217 currency code
/** /**

View File

@ -2,9 +2,11 @@ package org.telegram.telegrambots.meta.api.objects.payments;
import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import lombok.Getter; import lombok.Getter;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import lombok.NonNull;
import lombok.Setter; import lombok.Setter;
import lombok.ToString; import lombok.ToString;
import org.telegram.telegrambots.meta.api.interfaces.BotApiObject; import org.telegram.telegrambots.meta.api.interfaces.BotApiObject;
@ -22,17 +24,20 @@ import org.telegram.telegrambots.meta.exceptions.TelegramApiValidationException;
@ToString @ToString
@NoArgsConstructor @NoArgsConstructor
@AllArgsConstructor @AllArgsConstructor
@Builder
public class LabeledPrice implements Validable, BotApiObject { public class LabeledPrice implements Validable, BotApiObject {
private static final String LABEL_FIELD = "label"; private static final String LABEL_FIELD = "label";
private static final String AMOUNT_FIELD = "amount"; private static final String AMOUNT_FIELD = "amount";
@JsonProperty(LABEL_FIELD) @JsonProperty(LABEL_FIELD)
@NonNull
private String label; ///< Portion label private String label; ///< Portion label
/** /**
* Price of the product in the smallest units of the currency (integer, not float/double). * Price of the product in the smallest units of the currency (integer, not float/double).
* For example, for a price of US$ 1.45 pass amount = 145. * For example, for a price of US$ 1.45 pass amount = 145.
*/ */
@JsonProperty(AMOUNT_FIELD) @JsonProperty(AMOUNT_FIELD)
@NonNull
private Integer amount; private Integer amount;
@Override @Override

View File

@ -0,0 +1,31 @@
package org.telegram.telegrambots.meta.api.objects.voicechat;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.AllArgsConstructor;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.NonNull;
import lombok.Setter;
import lombok.ToString;
import org.telegram.telegrambots.meta.api.interfaces.BotApiObject;
/**
* @author Ruben Bermudez
* @version 5.2
*
* This object represents a service message about a voice chat scheduled in the chat.
*/
@EqualsAndHashCode(callSuper = false)
@Getter
@Setter
@ToString
@NoArgsConstructor
@AllArgsConstructor
public class VoiceChatScheduled implements BotApiObject {
private static final String STARTDATE_FIELD = "start_date";
@JsonProperty(STARTDATE_FIELD)
@NonNull
private Integer startDate; ///< Point in time (Unix timestamp) when the voice chat is supposed to be started by a chat administrator
}

View File

@ -84,14 +84,30 @@ public class TelegramApiRequestException extends TelegramApiException {
return parameters; return parameters;
} }
/**
* More detailed error description.
*
* @return assembled response code and reason
*/
@Override @Override
public String toString() { public String getMessage() {
if (apiResponse == null) { if (apiResponse == null) {
return super.toString(); return super.getMessage();
} else if (errorCode == null) { } else if (errorCode == null) {
return super.toString() + ": " + apiResponse; return super.getMessage() + ": " + apiResponse;
} else { } else {
return super.toString() + ": [" + errorCode + "] " + apiResponse; return super.getMessage() + ": [" + errorCode + "] " + apiResponse;
} }
} }
/**
* Just left as backward compatibility if anybody used this in version 5.2.0 or older.
*
* @return the getMessage string
*/
@Override
public String toString() {
return getMessage();
}
} }

View File

@ -0,0 +1,19 @@
package org.telegram.telegrambots.meta.generics;
/**
* @author Calvin
* @version 1.0
* Interface for backoff retries
*/
public interface BackOff {
/**
* Should be able to reset to the starting
*/
void reset();
/**
* specify the next backoff interval in milliseconds
*/
long nextBackOffMillis();
}

View File

@ -0,0 +1,19 @@
package org.telegram.telegrambots.meta;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import java.util.Arrays;
/**
* @author Ruben Bermudez
* @version 1.0
*/
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class TestUtils {
public static String getTextOfSize(int n) {
char[] text = new char[33];
Arrays.fill(text, 'A');
return new String(text);
}
}

View File

@ -0,0 +1,138 @@
package org.telegram.telegrambots.meta.api.methods.send;
import org.junit.jupiter.api.Test;
import org.telegram.telegrambots.meta.api.objects.payments.LabeledPrice;
import org.telegram.telegrambots.meta.api.objects.replykeyboard.InlineKeyboardMarkup;
import org.telegram.telegrambots.meta.api.objects.replykeyboard.buttons.InlineKeyboardButton;
import org.telegram.telegrambots.meta.exceptions.TelegramApiValidationException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
/**
* @author Ruben Bermudez
* @version 5.2
*/
public class SendInvoiceTest {
@Test
public void validObjectMustNotThrow() {
SendInvoice sendInvoice = createSendInvoiceObject();
assertDoesNotThrow(sendInvoice::validate);
sendInvoice.setSuggestedTipAmounts(new ArrayList<>());
assertDoesNotThrow(sendInvoice::validate);
}
@Test
public void chatIdCantBeEmpty() {
SendInvoice sendInvoice = createSendInvoiceObject();
sendInvoice.setChatId("");
Throwable thrown = assertThrows(TelegramApiValidationException.class, sendInvoice::validate);
assertEquals("ChatId parameter can't be empty", thrown.getMessage());
}
@Test
public void titleCantBeEmpty() {
SendInvoice sendInvoice = createSendInvoiceObject();
sendInvoice.setTitle("");
Throwable thrown = assertThrows(TelegramApiValidationException.class, sendInvoice::validate);
assertEquals("Title parameter can't be empty", thrown.getMessage());
}
@Test
public void descriptionCantBeEmpty() {
SendInvoice sendInvoice = createSendInvoiceObject();
sendInvoice.setDescription("");
Throwable thrown = assertThrows(TelegramApiValidationException.class, sendInvoice::validate);
assertEquals("Description parameter can't be empty", thrown.getMessage());
}
@Test
public void payloadCantBeEmpty() {
SendInvoice sendInvoice = createSendInvoiceObject();
sendInvoice.setPayload("");
Throwable thrown = assertThrows(TelegramApiValidationException.class, sendInvoice::validate);
assertEquals("Payload parameter can't be empty", thrown.getMessage());
}
@Test
public void providerTokenCantBeEmpty() {
SendInvoice sendInvoice = createSendInvoiceObject();
sendInvoice.setProviderToken("");
Throwable thrown = assertThrows(TelegramApiValidationException.class, sendInvoice::validate);
assertEquals("ProviderToken parameter can't be empty", thrown.getMessage());
}
@Test
public void startParameterCantBeEmpty() {
SendInvoice sendInvoice = createSendInvoiceObject();
sendInvoice.setStartParameter("");
Throwable thrown = assertThrows(TelegramApiValidationException.class, sendInvoice::validate);
assertEquals("StartParameter parameter can't be empty", thrown.getMessage());
}
@Test
public void currencyCantBeEmpty() {
SendInvoice sendInvoice = createSendInvoiceObject();
sendInvoice.setCurrency("");
Throwable thrown = assertThrows(TelegramApiValidationException.class, sendInvoice::validate);
assertEquals("Currency parameter can't be empty", thrown.getMessage());
}
@Test
public void pricesMustBeValidated() {
SendInvoice sendInvoice = createSendInvoiceObject();
sendInvoice.setPrices(Collections.singletonList(LabeledPrice.builder().label("").amount(1).build()));
Throwable thrown = assertThrows(TelegramApiValidationException.class, sendInvoice::validate);
assertEquals("Label parameter can't be empty", thrown.getMessage());
}
@Test
public void pricesCantBeEmpty() {
SendInvoice sendInvoice = createSendInvoiceObject();
sendInvoice.setPrices(new ArrayList<>());
Throwable thrown = assertThrows(TelegramApiValidationException.class, sendInvoice::validate);
assertEquals("Prices parameter can't be empty", thrown.getMessage());
sendInvoice.setPrices(Collections.singletonList(LabeledPrice.builder().label("").amount(1).build()));
thrown = assertThrows(TelegramApiValidationException.class, sendInvoice::validate);
assertEquals("Label parameter can't be empty", thrown.getMessage());
}
@Test
public void suggestedTipAmountsMustNotHaveMoreThan4Elements() {
SendInvoice sendInvoice = createSendInvoiceObject();
sendInvoice.setSuggestedTipAmounts(Arrays.asList(1,2,3,4,5));
Throwable thrown = assertThrows(TelegramApiValidationException.class, sendInvoice::validate);
assertEquals("No more that 4 suggested tips allowed", thrown.getMessage());
}
@Test
public void replyMarkupMustBeValidated() {
SendInvoice sendInvoice = createSendInvoiceObject();
sendInvoice.setReplyMarkup(InlineKeyboardMarkup.builder().keyboardRow(Collections.singletonList(InlineKeyboardButton.builder().text("").build())).build());
Throwable thrown = assertThrows(TelegramApiValidationException.class, sendInvoice::validate);
assertEquals("Text parameter can't be empty", thrown.getMessage());
}
private SendInvoice createSendInvoiceObject() {
return SendInvoice.builder()
.chatId("123456")
.title("Title")
.description("Description")
.payload("Payload")
.providerToken("ProviderToken")
.startParameter("StartParameter")
.currency("Currency")
.price(LabeledPrice.builder().label("Label").amount(1).build())
.suggestedTipAmount(1)
.suggestedTipAmount(2)
.suggestedTipAmount(3)
.suggestedTipAmount(4)
.replyMarkup(InlineKeyboardMarkup.builder().keyboardRow(Collections.singletonList(InlineKeyboardButton.builder().text("Hello").build())).build())
.build();
}
}

View File

@ -0,0 +1,133 @@
package org.telegram.telegrambots.meta.api.objects.inlinequery.inputmessagecontent;
import org.junit.jupiter.api.Test;
import org.telegram.telegrambots.meta.TestUtils;
import org.telegram.telegrambots.meta.api.objects.payments.LabeledPrice;
import org.telegram.telegrambots.meta.exceptions.TelegramApiValidationException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
/**
* @author Ruben Bermudez
* @version 1.0
*/
public class InputInvoiceMessageContentTest {
@Test
public void validObjectMustNotThrow() {
InputInvoiceMessageContent sendInvoice = createSendInvoiceObject();
assertDoesNotThrow(sendInvoice::validate);
}
@Test
public void titleCantBeEmpty() {
InputInvoiceMessageContent sendInvoice = createSendInvoiceObject();
sendInvoice.setTitle("");
Throwable thrown = assertThrows(TelegramApiValidationException.class, sendInvoice::validate);
assertEquals("Title parameter must be between 1 and 32 characters", thrown.getMessage());
}
@Test
public void titleCantBeLongerThan32() {
InputInvoiceMessageContent sendInvoice = createSendInvoiceObject();
sendInvoice.setTitle(TestUtils.getTextOfSize(33));
Throwable thrown = assertThrows(TelegramApiValidationException.class, sendInvoice::validate);
assertEquals("Title parameter must be between 1 and 32 characters", thrown.getMessage());
}
@Test
public void descriptionCantBeEmpty() {
InputInvoiceMessageContent sendInvoice = createSendInvoiceObject();
sendInvoice.setDescription("");
Throwable thrown = assertThrows(TelegramApiValidationException.class, sendInvoice::validate);
assertEquals("Description parameter must be between 1 and 255 characters", thrown.getMessage());
}
@Test
public void descriptionCantBeLongerThan255() {
InputInvoiceMessageContent sendInvoice = createSendInvoiceObject();
sendInvoice.setDescription(TestUtils.getTextOfSize(256));
Throwable thrown = assertThrows(TelegramApiValidationException.class, sendInvoice::validate);
assertEquals("Description parameter must be between 1 and 255 characters", thrown.getMessage());
}
@Test
public void payloadCantBeEmpty() {
InputInvoiceMessageContent sendInvoice = createSendInvoiceObject();
sendInvoice.setPayload("");
Throwable thrown = assertThrows(TelegramApiValidationException.class, sendInvoice::validate);
assertEquals("Payload parameter must be between 1 and 128 characters", thrown.getMessage());
}
@Test
public void payloadCantBeLongerThan128() {
InputInvoiceMessageContent sendInvoice = createSendInvoiceObject();
sendInvoice.setPayload(TestUtils.getTextOfSize(129));
Throwable thrown = assertThrows(TelegramApiValidationException.class, sendInvoice::validate);
assertEquals("Payload parameter must be between 1 and 128 characters", thrown.getMessage());
}
@Test
public void providerTokenCantBeEmpty() {
InputInvoiceMessageContent sendInvoice = createSendInvoiceObject();
sendInvoice.setProviderToken("");
Throwable thrown = assertThrows(TelegramApiValidationException.class, sendInvoice::validate);
assertEquals("ProviderToken parameter must not be empty", thrown.getMessage());
}
@Test
public void currencyCantBeEmpty() {
InputInvoiceMessageContent sendInvoice = createSendInvoiceObject();
sendInvoice.setCurrency("");
Throwable thrown = assertThrows(TelegramApiValidationException.class, sendInvoice::validate);
assertEquals("Currency parameter must not be empty", thrown.getMessage());
}
@Test
public void pricesMustBeValidated() {
InputInvoiceMessageContent sendInvoice = createSendInvoiceObject();
sendInvoice.setPrices(Collections.singletonList(LabeledPrice.builder().label("").amount(1).build()));
Throwable thrown = assertThrows(TelegramApiValidationException.class, sendInvoice::validate);
assertEquals("Label parameter can't be empty", thrown.getMessage());
}
@Test
public void pricesCantBeEmpty() {
InputInvoiceMessageContent sendInvoice = createSendInvoiceObject();
sendInvoice.setPrices(new ArrayList<>());
Throwable thrown = assertThrows(TelegramApiValidationException.class, sendInvoice::validate);
assertEquals("Prices parameter must not be empty", thrown.getMessage());
sendInvoice.setPrices(Collections.singletonList(LabeledPrice.builder().label("").amount(1).build()));
thrown = assertThrows(TelegramApiValidationException.class, sendInvoice::validate);
assertEquals("Label parameter can't be empty", thrown.getMessage());
}
@Test
public void suggestedTipAmountsMustNotHaveMoreThan4Elements() {
InputInvoiceMessageContent sendInvoice = createSendInvoiceObject();
sendInvoice.setSuggestedTipAmounts(Arrays.asList(1,2,3,4,5));
Throwable thrown = assertThrows(TelegramApiValidationException.class, sendInvoice::validate);
assertEquals("Only up to 4 suggested tip amounts are allowed", thrown.getMessage());
}
private InputInvoiceMessageContent createSendInvoiceObject() {
return InputInvoiceMessageContent.builder()
.title("Title")
.description("Description")
.payload("Payload")
.providerToken("ProviderToken")
.currency("Currency")
.price(LabeledPrice.builder().label("Label").amount(1).build())
.suggestedTipAmount(1)
.suggestedTipAmount(2)
.suggestedTipAmount(3)
.suggestedTipAmount(4)
.build();
}
}

View File

@ -185,6 +185,10 @@ public final class TelegramBotsHelper {
return "{\"ok\": false,\"error_code\": 400,\"description\": \"Error descriptions\",\"parameters\": {\"migrate_to_chat_id\": 12345,\"retry_after\": 12}}"; return "{\"ok\": false,\"error_code\": 400,\"description\": \"Error descriptions\",\"parameters\": {\"migrate_to_chat_id\": 12345,\"retry_after\": 12}}";
} }
public static String getResponseWithError409() {
return "{\"ok\": false,\"error_code\": 409,\"description\": \"Conflict: terminated by other getUpdates request; make sure that only one bot instance is running\"}";
}
public static String GetSetGameScoreBooleanResponse() { public static String GetSetGameScoreBooleanResponse() {
return "{\"ok\": true,\"result\": true}"; return "{\"ok\": true,\"result\": true}";
} }

View File

@ -51,7 +51,7 @@ class TestDeserialization {
} }
@Test @Test
void TestListUpdates() throws Exception { void testListUpdates() throws Exception {
String updateText = "{\"ok\":true,\"result\":[{\"update_id\":79995144,\n" + String updateText = "{\"ok\":true,\"result\":[{\"update_id\":79995144,\n" +
"\"message\":{\"message_id\":90,\"from\":{\"id\":1234567,\"is_bot\":false,\"first_name\":\"MyFirstName\",\"username\":\"MyUsername\",\"language_code\":\"en\"},\"chat\":{\"id\":1234567,\"first_name\":\"MyFirstName\",\"username\":\"MyUsername\",\"type\":\"private\"},\"date\":1604154223,\"text\":\"/start\",\"entities\":[{\"offset\":0,\"length\":6,\"type\":\"bot_command\"}]}},{\"update_id\":79995145,\n" + "\"message\":{\"message_id\":90,\"from\":{\"id\":1234567,\"is_bot\":false,\"first_name\":\"MyFirstName\",\"username\":\"MyUsername\",\"language_code\":\"en\"},\"chat\":{\"id\":1234567,\"first_name\":\"MyFirstName\",\"username\":\"MyUsername\",\"type\":\"private\"},\"date\":1604154223,\"text\":\"/start\",\"entities\":[{\"offset\":0,\"length\":6,\"type\":\"bot_command\"}]}},{\"update_id\":79995145,\n" +
"\"message\":{\"message_id\":91,\"from\":{\"id\":12345678,\"is_bot\":false,\"first_name\":\"MyFirstName\",\"username\":\"MyUsername\",\"language_code\":\"it\"},\"chat\":{\"id\":12345678,\"first_name\":\"MyFirstName\",\"username\":\"MyUsername\",\"type\":\"private\"},\"date\":1604154306,\"text\":\"/start\",\"entities\":[{\"offset\":0,\"length\":6,\"type\":\"bot_command\"}]}},{\"update_id\":79995146,\n" + "\"message\":{\"message_id\":91,\"from\":{\"id\":12345678,\"is_bot\":false,\"first_name\":\"MyFirstName\",\"username\":\"MyUsername\",\"language_code\":\"it\"},\"chat\":{\"id\":12345678,\"first_name\":\"MyFirstName\",\"username\":\"MyUsername\",\"type\":\"private\"},\"date\":1604154306,\"text\":\"/start\",\"entities\":[{\"offset\":0,\"length\":6,\"type\":\"bot_command\"}]}},{\"update_id\":79995146,\n" +
@ -89,7 +89,7 @@ class TestDeserialization {
} }
@Test @Test
void TestListUpdates2() throws Exception { void testListUpdates2() throws Exception {
String updateText = "{\"ok\":true,\"result\":[{\"update_id\":259894298,\n" + String updateText = "{\"ok\":true,\"result\":[{\"update_id\":259894298,\n" +
"\"message\":{\"message_id\":101,\"from\":{\"id\":12345678,\"is_bot\":false,\"first_name\":\"FistName\",\"last_name\":\"LastName\",\"username\":\"username\"},\"chat\":{\"id\":12345678,\"first_name\":\"FistName\",\"last_name\":\"LastName\",\"username\":\"username\",\"type\":\"private\"},\"date\":1604171814,\"text\":\"/start\",\"entities\":[{\"offset\":0,\"length\":6,\"type\":\"bot_command\"}]}},{\"update_id\":259894299,\n" + "\"message\":{\"message_id\":101,\"from\":{\"id\":12345678,\"is_bot\":false,\"first_name\":\"FistName\",\"last_name\":\"LastName\",\"username\":\"username\"},\"chat\":{\"id\":12345678,\"first_name\":\"FistName\",\"last_name\":\"LastName\",\"username\":\"username\",\"type\":\"private\"},\"date\":1604171814,\"text\":\"/start\",\"entities\":[{\"offset\":0,\"length\":6,\"type\":\"bot_command\"}]}},{\"update_id\":259894299,\n" +
"\"message\":{\"message_id\":102,\"from\":{\"id\":12345678,\"is_bot\":false,\"first_name\":\"FistName\",\"last_name\":\"LastName\",\"username\":\"username\",\"language_code\":\"en\"},\"chat\":{\"id\":12345678,\"first_name\":\"FistName\",\"last_name\":\"LastName\",\"username\":\"username\",\"type\":\"private\"},\"date\":1604188661,\"text\":\"/start\",\"entities\":[{\"offset\":0,\"length\":6,\"type\":\"bot_command\"}]}},{\"update_id\":259894300,\n" + "\"message\":{\"message_id\":102,\"from\":{\"id\":12345678,\"is_bot\":false,\"first_name\":\"FistName\",\"last_name\":\"LastName\",\"username\":\"username\",\"language_code\":\"en\"},\"chat\":{\"id\":12345678,\"first_name\":\"FistName\",\"last_name\":\"LastName\",\"username\":\"username\",\"type\":\"private\"},\"date\":1604188661,\"text\":\"/start\",\"entities\":[{\"offset\":0,\"length\":6,\"type\":\"bot_command\"}]}},{\"update_id\":259894300,\n" +
@ -106,7 +106,7 @@ class TestDeserialization {
} }
@Test @Test
void TestListUpdates3() throws Exception { void testListUpdates3() throws Exception {
String updateText = "{\"ok\":true,\"result\":[{\"update_id\":259894302,\n" + String updateText = "{\"ok\":true,\"result\":[{\"update_id\":259894302,\n" +
"\"message\":{\"message_id\":105,\"from\":{\"id\":12345678,\"is_bot\":false,\"first_name\":\"FirstName\",\"username\":\"Username\"},\"chat\":{\"id\":12345678,\"first_name\":\"FirstName\",\"username\":\"Username\",\"type\":\"private\"},\"date\":1604226451,\"text\":\"/start\",\"entities\":[{\"offset\":0,\"length\":6,\"type\":\"bot_command\"}]}},{\"update_id\":259894303,\n" + "\"message\":{\"message_id\":105,\"from\":{\"id\":12345678,\"is_bot\":false,\"first_name\":\"FirstName\",\"username\":\"Username\"},\"chat\":{\"id\":12345678,\"first_name\":\"FirstName\",\"username\":\"Username\",\"type\":\"private\"},\"date\":1604226451,\"text\":\"/start\",\"entities\":[{\"offset\":0,\"length\":6,\"type\":\"bot_command\"}]}},{\"update_id\":259894303,\n" +
"\"message\":{\"message_id\":106,\"from\":{\"id\":12345678,\"is_bot\":false,\"first_name\":\"FirstName\",\"username\":\"Username\",\"language_code\":\"en\"},\"chat\":{\"id\":12345678,\"first_name\":\"FirstName\",\"username\":\"Username\",\"type\":\"private\"},\"date\":1604226480,\"document\":{\"file_name\":\"aaa.txt\",\"mime_type\":\"text/plain\",\"file_id\":\"FILEID\",\"file_unique_id\":\"AgADiQEAAjTe-VQ\",\"file_size\":2}}},{\"update_id\":259894304,\n" + "\"message\":{\"message_id\":106,\"from\":{\"id\":12345678,\"is_bot\":false,\"first_name\":\"FirstName\",\"username\":\"Username\",\"language_code\":\"en\"},\"chat\":{\"id\":12345678,\"first_name\":\"FirstName\",\"username\":\"Username\",\"type\":\"private\"},\"date\":1604226480,\"document\":{\"file_name\":\"aaa.txt\",\"mime_type\":\"text/plain\",\"file_id\":\"FILEID\",\"file_unique_id\":\"AgADiQEAAjTe-VQ\",\"file_size\":2}}},{\"update_id\":259894304,\n" +
@ -165,7 +165,7 @@ class TestDeserialization {
} }
@Test @Test
void TestListUpdatesVoiceChat() throws Exception { void testListUpdatesVoiceChat() throws Exception {
String updateText = "{\n" + String updateText = "{\n" +
" \"ok\": true,\n" + " \"ok\": true,\n" +
" \"result\": [\n" + " \"result\": [\n" +
@ -289,7 +289,7 @@ class TestDeserialization {
} }
@Test @Test
void TestDeserializationCloseMethod() throws Exception { void testDeserializationCloseMethod() throws Exception {
String updateText = "{\"ok\":true,\"result\": true}"; String updateText = "{\"ok\":true,\"result\": true}";
Boolean response = new Close().deserializeResponse(updateText); Boolean response = new Close().deserializeResponse(updateText);
@ -298,7 +298,7 @@ class TestDeserialization {
} }
@Test @Test
void TestDeserializationChatMember() throws Exception { void testDeserializationChatMember() throws Exception {
String updateText = "{\n" + String updateText = "{\n" +
" \"ok\": true,\n" + " \"ok\": true,\n" +
" \"result\": {\n" + " \"result\": {\n" +
@ -344,7 +344,50 @@ class TestDeserialization {
} }
@Test @Test
void TestDeserializationLogoutMethod() throws Exception { void testDeserializationMessageAutodeleteChanged() throws Exception {
String updateText = "{\n" +
" \"ok\": true,\n" +
" \"result\": [\n" +
" {\n" +
" \"update_id\": 259894298,\n" +
" \"message\": {\n" +
" \"message_id\": 101,\n" +
" \"from\": {\n" +
" \"id\": 12345678,\n" +
" \"is_bot\": false,\n" +
" \"first_name\": \"FistName\",\n" +
" \"last_name\": \"LastName\",\n" +
" \"username\": \"username\"\n" +
" },\n" +
" \"chat\": {\n" +
" \"id\": 12345678,\n" +
" \"first_name\": \"FistName\",\n" +
" \"last_name\": \"LastName\",\n" +
" \"username\": \"username\",\n" +
" \"type\": \"private\"\n" +
" },\n" +
" \"date\": 1604171814,\n" +
" \"message_auto_delete_timer_changed\": {\n" +
" \"message_auto_delete_time\": 100\n" +
" }\n" +
" \n" +
" }\n" +
" }\n" +
" ]\n" +
"}";
ArrayList<Update> response = new GetUpdates().deserializeResponse(updateText);
assertNotNull(response);
assertEquals(1, response.size());
assertNotNull(response.get(0));
assertNotNull(response.get(0).getMessage());
assertNotNull(response.get(0).getMessage().getMessageAutoDeleteTimerChanged());
assertEquals(100, response.get(0).getMessage().getMessageAutoDeleteTimerChanged().getMessageAutoDeleteTime());
}
@Test
void testDeserializationLogoutMethod() throws Exception {
String updateText = "{\"ok\":true,\"result\": true}"; String updateText = "{\"ok\":true,\"result\": true}";
Boolean response = new LogOut().deserializeResponse(updateText); Boolean response = new LogOut().deserializeResponse(updateText);
@ -353,7 +396,7 @@ class TestDeserialization {
} }
@Test @Test
void TestDeserializationGetMyCommandsMethod() throws Exception { void testDeserializationGetMyCommandsMethod() throws Exception {
String updateText = "{\n" + String updateText = "{\n" +
" \"ok\": true,\n" + " \"ok\": true,\n" +
" \"result\": [\n" + " \"result\": [\n" +

View File

@ -28,7 +28,7 @@ class TestTelegramApi {
} }
@Test @Test
void TestTelegramApiMustBeInitializableForLongPolling() { void testTelegramApiMustBeInitializableForLongPolling() {
try { try {
new TelegramBotsApi(BotSession.class); new TelegramBotsApi(BotSession.class);
} catch (TelegramApiException e) { } catch (TelegramApiException e) {
@ -37,7 +37,7 @@ class TestTelegramApi {
} }
@Test @Test
void TestTelegramApiMustBeInitializableForWebhook() { void testTelegramApiMustBeInitializableForWebhook() {
try { try {
new TelegramBotsApi(BotSession.class, webhook); new TelegramBotsApi(BotSession.class, webhook);
} catch (TelegramApiException e) { } catch (TelegramApiException e) {
@ -46,7 +46,7 @@ class TestTelegramApi {
} }
@Test @Test
void TestTelegramApiMustBeThrowIfNotCreatedForWebhook() { void testTelegramApiMustBeThrowIfNotCreatedForWebhook() {
try { try {
TelegramBotsApi telegramBotsApi = new TelegramBotsApi(BotSession.class, null); TelegramBotsApi telegramBotsApi = new TelegramBotsApi(BotSession.class, null);
telegramBotsApi.registerBot(new WebhookBot() { telegramBotsApi.registerBot(new WebhookBot() {

View File

@ -22,7 +22,7 @@ class TestAnswerInlineQuery {
} }
@Test @Test
void TestInlineQueryIdMustBePresent() { void testInlineQueryIdMustBePresent() {
try { try {
answerInlineQuery.validate(); answerInlineQuery.validate();
} catch (TelegramApiValidationException e) { } catch (TelegramApiValidationException e) {
@ -31,7 +31,7 @@ class TestAnswerInlineQuery {
} }
@Test @Test
void TestInlineQueryIdCanNotBeEmpty() { void testInlineQueryIdCanNotBeEmpty() {
answerInlineQuery.setInlineQueryId(""); answerInlineQuery.setInlineQueryId("");
try { try {
answerInlineQuery.validate(); answerInlineQuery.validate();
@ -41,7 +41,7 @@ class TestAnswerInlineQuery {
} }
@Test @Test
void TestResultsMustBePresent() { void testResultsMustBePresent() {
answerInlineQuery.setInlineQueryId("RANDOMEID"); answerInlineQuery.setInlineQueryId("RANDOMEID");
try { try {
answerInlineQuery.validate(); answerInlineQuery.validate();
@ -51,7 +51,7 @@ class TestAnswerInlineQuery {
} }
@Test @Test
void TestSwitchPmTextCanNotBeEmpty() { void testSwitchPmTextCanNotBeEmpty() {
answerInlineQuery.setInlineQueryId("RANDOMEID"); answerInlineQuery.setInlineQueryId("RANDOMEID");
answerInlineQuery.setResults(new ArrayList<>()); answerInlineQuery.setResults(new ArrayList<>());
answerInlineQuery.setSwitchPmText(""); answerInlineQuery.setSwitchPmText("");
@ -64,7 +64,7 @@ class TestAnswerInlineQuery {
} }
@Test @Test
void TestSwitchPmParameterIsMandatoryIfSwitchPmTextIsPresent() { void testSwitchPmParameterIsMandatoryIfSwitchPmTextIsPresent() {
answerInlineQuery.setInlineQueryId("RANDOMEID"); answerInlineQuery.setInlineQueryId("RANDOMEID");
answerInlineQuery.setResults(new ArrayList<>()); answerInlineQuery.setResults(new ArrayList<>());
answerInlineQuery.setSwitchPmText("Test Text"); answerInlineQuery.setSwitchPmText("Test Text");
@ -77,7 +77,7 @@ class TestAnswerInlineQuery {
} }
@Test @Test
void TestSwitchPmParameterCanNotBeEmptyIfSwitchPmTextIsPresent() { void testSwitchPmParameterCanNotBeEmptyIfSwitchPmTextIsPresent() {
answerInlineQuery.setInlineQueryId("RANDOMEID"); answerInlineQuery.setInlineQueryId("RANDOMEID");
answerInlineQuery.setResults(new ArrayList<>()); answerInlineQuery.setResults(new ArrayList<>());
answerInlineQuery.setSwitchPmText("Test Text"); answerInlineQuery.setSwitchPmText("Test Text");
@ -91,7 +91,7 @@ class TestAnswerInlineQuery {
} }
@Test @Test
void TestSwitchPmParameterContainsUpTo64Chars() { void testSwitchPmParameterContainsUpTo64Chars() {
answerInlineQuery.setInlineQueryId("RANDOMEID"); answerInlineQuery.setInlineQueryId("RANDOMEID");
answerInlineQuery.setResults(new ArrayList<>()); answerInlineQuery.setResults(new ArrayList<>());
answerInlineQuery.setSwitchPmText("Test Text"); answerInlineQuery.setSwitchPmText("Test Text");
@ -105,7 +105,7 @@ class TestAnswerInlineQuery {
} }
@Test @Test
void TestSwitchPmParameterOnlyContainsAcceptedCharacters() { void testSwitchPmParameterOnlyContainsAcceptedCharacters() {
answerInlineQuery.setInlineQueryId("RANDOMEID"); answerInlineQuery.setInlineQueryId("RANDOMEID");
answerInlineQuery.setResults(new ArrayList<>()); answerInlineQuery.setResults(new ArrayList<>());
answerInlineQuery.setSwitchPmText("Test Text"); answerInlineQuery.setSwitchPmText("Test Text");

View File

@ -11,8 +11,7 @@ import org.telegram.telegrambots.meta.test.TelegramBotsHelper;
import java.util.ArrayList; import java.util.ArrayList;
import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.*;
import static org.junit.jupiter.api.Assertions.assertNotNull;
/** /**
* @author Ruben Bermudez * @author Ruben Bermudez
@ -32,14 +31,14 @@ class TestGetUpdates {
} }
@Test @Test
void TestGetUpdatesMustBeSerializable() throws Exception { void testGetUpdatesMustBeSerializable() throws Exception {
String json = mapper.writeValueAsString(getUpdates); String json = mapper.writeValueAsString(getUpdates);
assertNotNull(json); assertNotNull(json);
assertEquals("{\"offset\":15,\"limit\":100,\"timeout\":50,\"method\":\"getupdates\"}", json); assertEquals("{\"offset\":15,\"limit\":100,\"timeout\":50,\"method\":\"getupdates\"}", json);
} }
@Test @Test
void TestGetUpdatesMustDeserializeCorrectResponse() throws Exception { void testGetUpdatesMustDeserializeCorrectResponse() throws Exception {
ArrayList<Update> result = ArrayList<Update> result =
getUpdates.deserializeResponse(TelegramBotsHelper.GetResponseWithoutError()); getUpdates.deserializeResponse(TelegramBotsHelper.GetResponseWithoutError());
assertNotNull(result); assertNotNull(result);
@ -47,7 +46,7 @@ class TestGetUpdates {
} }
@Test @Test
void TestGetUpdatesMustThrowAnExceptionForInCorrectResponse() { void testGetUpdatesMustThrowAnExceptionForInCorrectResponse() {
try { try {
getUpdates.deserializeResponse(TelegramBotsHelper.GetResponseWithError()); getUpdates.deserializeResponse(TelegramBotsHelper.GetResponseWithError());
} catch (TelegramApiRequestException e) { } catch (TelegramApiRequestException e) {
@ -56,4 +55,15 @@ class TestGetUpdates {
assertEquals("Error descriptions", e.getApiResponse()); assertEquals("Error descriptions", e.getApiResponse());
} }
} }
@Test
void testGetUpdatesMustThrowAnExceptionForInCorrectResponse409() {
try {
getUpdates.deserializeResponse(TelegramBotsHelper.getResponseWithError409());
} catch (TelegramApiRequestException e) {
assertNull(e.getParameters());
assertEquals(Integer.valueOf(409), e.getErrorCode());
assertEquals("Conflict: terminated by other getUpdates request; make sure that only one bot instance is running", e.getApiResponse());
}
}
} }

View File

@ -18,9 +18,4 @@
}, },
"text": "Original" "text": "Original"
} }
}
{
"ok": true,
"result": true
} }

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>5.1.1</version> <version>5.2.0</version>
</dependency> </dependency>
``` ```
**Gradle** **Gradle**
```gradle ```gradle
implementation 'org.telegram:telegrambots-spring-boot-starter:5.1.1' implementation 'org.telegram:telegrambots-spring-boot-starter:5.2.0'
``` ```
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>5.1.1</version> <version>5.2.0</version>
</parent> </parent>
<artifactId>telegrambots-spring-boot-starter</artifactId> <artifactId>telegrambots-spring-boot-starter</artifactId>
@ -70,8 +70,8 @@
<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>5.1.1</telegrambots.version> <telegrambots.version>5.2.0</telegrambots.version>
<spring-boot.version>2.4.3</spring-boot.version> <spring-boot.version>2.4.5</spring-boot.version>
<maven-gpg-plugin.version>1.6</maven-gpg-plugin.version> <maven-gpg-plugin.version>1.6</maven-gpg-plugin.version>
<nexus-staging-maven-plugin.version>1.6.8</nexus-staging-maven-plugin.version> <nexus-staging-maven-plugin.version>1.6.8</nexus-staging-maven-plugin.version>

View File

@ -7,7 +7,7 @@
<parent> <parent>
<groupId>org.telegram</groupId> <groupId>org.telegram</groupId>
<artifactId>Bots</artifactId> <artifactId>Bots</artifactId>
<version>5.1.1</version> <version>5.2.0</version>
</parent> </parent>
<artifactId>telegrambots</artifactId> <artifactId>telegrambots</artifactId>
@ -92,7 +92,7 @@
<dependency> <dependency>
<groupId>org.telegram</groupId> <groupId>org.telegram</groupId>
<artifactId>telegrambots-meta</artifactId> <artifactId>telegrambots-meta</artifactId>
<version>5.1.1</version> <version>5.2.0</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.projectlombok</groupId> <groupId>org.projectlombok</groupId>

View File

@ -5,7 +5,7 @@ import org.apache.http.client.protocol.HttpClientContext;
import org.apache.http.protocol.HttpContext; import org.apache.http.protocol.HttpContext;
import org.telegram.telegrambots.meta.ApiConstants; import org.telegram.telegrambots.meta.ApiConstants;
import org.telegram.telegrambots.meta.generics.BotOptions; import org.telegram.telegrambots.meta.generics.BotOptions;
import org.telegram.telegrambots.updatesreceivers.ExponentialBackOff; import org.telegram.telegrambots.meta.generics.BackOff;
import java.util.List; import java.util.List;
@ -19,7 +19,7 @@ public class DefaultBotOptions implements BotOptions {
private int maxThreads; ///< Max number of threads used for async methods executions (default 1) private int maxThreads; ///< Max number of threads used for async methods executions (default 1)
private RequestConfig requestConfig; private RequestConfig requestConfig;
private volatile HttpContext httpContext; private volatile HttpContext httpContext;
private ExponentialBackOff exponentialBackOff; private BackOff backOff;
private Integer maxWebhookConnections; private Integer maxWebhookConnections;
private String baseUrl; private String baseUrl;
private List<String> allowedUpdates; private List<String> allowedUpdates;
@ -91,23 +91,23 @@ public class DefaultBotOptions implements BotOptions {
} }
/** /**
* @implSpec Default implementation assumes no proxy is needed and sets a 75secs timoute
* @param requestConfig Request config to be used in all Http requests * @param requestConfig Request config to be used in all Http requests
* @implSpec Default implementation assumes no proxy is needed and sets a 75secs timoute
*/ */
public void setRequestConfig(RequestConfig requestConfig) { public void setRequestConfig(RequestConfig requestConfig) {
this.requestConfig = requestConfig; this.requestConfig = requestConfig;
} }
public ExponentialBackOff getExponentialBackOff() { public BackOff getBackOff() {
return exponentialBackOff; return backOff;
} }
/** /**
* @param BackOff backOff to be used when long polling fails
* @implSpec Default implementation assumes starting at 500ms and max time of 60 minutes * @implSpec Default implementation assumes starting at 500ms and max time of 60 minutes
* @param exponentialBackOff ExponentialBackOff to be used when long polling fails
*/ */
public void setExponentialBackOff(ExponentialBackOff exponentialBackOff) { public void setBackOff(BackOff BackOff) {
this.exponentialBackOff = exponentialBackOff; this.backOff = BackOff;
} }
public ProxyType getProxyType() { public ProxyType getProxyType() {

View File

@ -16,11 +16,7 @@ import org.telegram.telegrambots.facilities.TelegramHttpClientBuilder;
import org.telegram.telegrambots.meta.api.methods.updates.GetUpdates; import org.telegram.telegrambots.meta.api.methods.updates.GetUpdates;
import org.telegram.telegrambots.meta.api.objects.Update; import org.telegram.telegrambots.meta.api.objects.Update;
import org.telegram.telegrambots.meta.exceptions.TelegramApiRequestException; import org.telegram.telegrambots.meta.exceptions.TelegramApiRequestException;
import org.telegram.telegrambots.meta.generics.BotOptions; import org.telegram.telegrambots.meta.generics.*;
import org.telegram.telegrambots.meta.generics.BotSession;
import org.telegram.telegrambots.meta.generics.LongPollingBot;
import org.telegram.telegrambots.meta.generics.UpdatesHandler;
import org.telegram.telegrambots.meta.generics.UpdatesReader;
import java.io.IOException; import java.io.IOException;
import java.io.InvalidObjectException; import java.io.InvalidObjectException;
@ -142,7 +138,7 @@ public class DefaultBotSession implements BotSession {
private final UpdatesSupplier updatesSupplier; private final UpdatesSupplier updatesSupplier;
private final Object lock; private final Object lock;
private CloseableHttpClient httpclient; private CloseableHttpClient httpclient;
private ExponentialBackOff exponentialBackOff; private BackOff backOff;
private RequestConfig requestConfig; private RequestConfig requestConfig;
public ReaderThread(UpdatesSupplier updatesSupplier, Object lock) { public ReaderThread(UpdatesSupplier updatesSupplier, Object lock) {
@ -154,10 +150,11 @@ public class DefaultBotSession implements BotSession {
public synchronized void start() { public synchronized void start() {
httpclient = TelegramHttpClientBuilder.build(options); httpclient = TelegramHttpClientBuilder.build(options);
requestConfig = options.getRequestConfig(); requestConfig = options.getRequestConfig();
exponentialBackOff = options.getExponentialBackOff(); backOff = options.getBackOff();
if (exponentialBackOff == null) { // fall back to default exponential backoff strategy if no backoff specified
exponentialBackOff = new ExponentialBackOff(); if (backOff == null) {
backOff = new ExponentialBackOff();
} }
if (requestConfig == null) { if (requestConfig == null) {
@ -215,7 +212,7 @@ public class DefaultBotSession implements BotSession {
log.error(global.getLocalizedMessage(), global); log.error(global.getLocalizedMessage(), global);
try { try {
synchronized (lock) { synchronized (lock) {
lock.wait(exponentialBackOff.nextBackOffMillis()); lock.wait(backOff.nextBackOffMillis());
} }
} catch (InterruptedException e) { } catch (InterruptedException e) {
if (!running.get()) { if (!running.get()) {
@ -261,7 +258,7 @@ public class DefaultBotSession implements BotSession {
} else { } else {
try { try {
List<Update> updates = request.deserializeResponse(responseContent); List<Update> updates = request.deserializeResponse(responseContent);
exponentialBackOff.reset(); backOff.reset();
return updates; return updates;
} catch (JSONException e) { } catch (JSONException e) {
log.error("Error deserializing update: " + responseContent, e); log.error("Error deserializing update: " + responseContent, e);

View File

@ -14,6 +14,7 @@
package org.telegram.telegrambots.updatesreceivers; package org.telegram.telegrambots.updatesreceivers;
import com.google.common.base.Preconditions; import com.google.common.base.Preconditions;
import org.telegram.telegrambots.meta.generics.BackOff;
/** /**
* Implementation of BackOff that increases the back off period for each retry attempt using * Implementation of BackOff that increases the back off period for each retry attempt using
@ -68,7 +69,7 @@ import com.google.common.base.Preconditions;
* @since 1.15 * @since 1.15
* @author Ravi Mistry * @author Ravi Mistry
*/ */
public class ExponentialBackOff { public class ExponentialBackOff implements BackOff {
/** The default initial interval value in milliseconds (0.5 seconds). */ /** The default initial interval value in milliseconds (0.5 seconds). */
private static final int DEFAULT_INITIAL_INTERVAL_MILLIS = 500; private static final int DEFAULT_INITIAL_INTERVAL_MILLIS = 500;
@ -82,7 +83,7 @@ public class ExponentialBackOff {
private static final double DEFAULT_MULTIPLIER = 1.5; private static final double DEFAULT_MULTIPLIER = 1.5;
/** The default maximum back off time in milliseconds (15 minutes). */ /** The default maximum back off time in milliseconds (15 minutes). */
private static final int DEFAULT_MAX_INTERVAL_MILLIS = 30000; private static final int DEFAULT_MAX_INTERVAL_MILLIS = 900000;
/** The default maximum elapsed time in milliseconds (60 minutes). */ /** The default maximum elapsed time in milliseconds (60 minutes). */
private static final int DEFAULT_MAX_ELAPSED_TIME_MILLIS = 3600000; private static final int DEFAULT_MAX_ELAPSED_TIME_MILLIS = 3600000;
@ -161,7 +162,8 @@ public class ExponentialBackOff {
} }
/** Sets the interval back to the initial retry interval and restarts the timer. */ /** Sets the interval back to the initial retry interval and restarts the timer. */
final void reset() { @Override
public void reset() {
currentIntervalMillis = initialIntervalMillis; currentIntervalMillis = initialIntervalMillis;
startTimeNanos = nanoTime(); startTimeNanos = nanoTime();
} }
@ -178,7 +180,8 @@ public class ExponentialBackOff {
* Subclasses may override if a different algorithm is required. * Subclasses may override if a different algorithm is required.
* </p> * </p>
*/ */
long nextBackOffMillis() { @Override
public long nextBackOffMillis() {
// Make sure we have not gone over the maximum elapsed time. // Make sure we have not gone over the maximum elapsed time.
if (getElapsedTimeMillis() > maxElapsedTimeMillis) { if (getElapsedTimeMillis() > maxElapsedTimeMillis) {
return maxElapsedTimeMillis; return maxElapsedTimeMillis;
@ -274,7 +277,32 @@ public class ExponentialBackOff {
*/ */
int maxElapsedTimeMillis = DEFAULT_MAX_ELAPSED_TIME_MILLIS; int maxElapsedTimeMillis = DEFAULT_MAX_ELAPSED_TIME_MILLIS;
Builder() { public Builder() {
}
public Builder setInitialIntervalMillis(int initialIntervalMillis) {
this.initialIntervalMillis = initialIntervalMillis;
return this;
}
public Builder setRandomizationFactor(double randomizationFactor) {
this.randomizationFactor = randomizationFactor;
return this;
}
public Builder setMultiplier(double multiplier) {
this.multiplier = multiplier;
return this;
}
public Builder setMaxIntervalMillis(int maxIntervalMillis) {
this.maxIntervalMillis = maxIntervalMillis;
return this;
}
public Builder setMaxElapsedTimeMillis(int maxElapsedTimeMillis) {
this.maxElapsedTimeMillis = maxElapsedTimeMillis;
return this;
} }
/** Builds a new instance of {@link ExponentialBackOff}. */ /** Builds a new instance of {@link ExponentialBackOff}. */

View File

@ -1,7 +1,6 @@
package org.telegram.telegrambots.updatesreceivers; package org.telegram.telegrambots.updatesreceivers;
import org.slf4j.Logger; import lombok.extern.slf4j.Slf4j;
import org.slf4j.LoggerFactory;
import org.telegram.telegrambots.Constants; import org.telegram.telegrambots.Constants;
import org.telegram.telegrambots.meta.api.methods.BotApiMethod; import org.telegram.telegrambots.meta.api.methods.BotApiMethod;
import org.telegram.telegrambots.meta.api.objects.Update; import org.telegram.telegrambots.meta.api.objects.Update;
@ -24,9 +23,8 @@ import java.util.concurrent.ConcurrentHashMap;
* Rest api to for webhook callback function * Rest api to for webhook callback function
*/ */
@Path(Constants.WEBHOOK_URL_PATH) @Path(Constants.WEBHOOK_URL_PATH)
@Slf4j
public class RestApi { public class RestApi {
private static final Logger log = LoggerFactory.getLogger(RestApi.class);
private final ConcurrentHashMap<String, WebhookBot> callbacks = new ConcurrentHashMap<>(); private final ConcurrentHashMap<String, WebhookBot> callbacks = new ConcurrentHashMap<>();
public RestApi() { public RestApi() {

View File

@ -71,7 +71,7 @@ public final class BotApiMethodHelperFactory {
.text("Hithere") .text("Hithere")
.replyToMessageId(12) .replyToMessageId(12)
.parseMode(ParseMode.HTML) .parseMode(ParseMode.HTML)
.replyMarkup(new ForceReplyKeyboard()) .replyMarkup(ForceReplyKeyboard.builder().forceReply(true).build())
.build(); .build();
} }
@ -362,12 +362,16 @@ public final class BotApiMethodHelperFactory {
return SendInvoice return SendInvoice
.builder() .builder()
.chatId(12345) .chatId("12345")
.title("Random title") .title("Random title")
.description("Random description") .description("Random description")
.payload("Random Payload") .payload("Random Payload")
.providerToken("Random provider token") .providerToken("Random provider token")
.startParameter("STARTPARAM") .startParameter("STARTPARAM")
.maxTipAmount(100)
.suggestedTipAmount(10)
.suggestedTipAmount(50)
.suggestedTipAmount(75)
.currency("EUR") .currency("EUR")
.prices(prices) .prices(prices)
.build(); .build();

View File

@ -22,7 +22,9 @@ public class TelegramLongPollingBotTest {
TelegramLongPollingBot bot = Mockito.mock(TelegramLongPollingBot.class); TelegramLongPollingBot bot = Mockito.mock(TelegramLongPollingBot.class);
Mockito.doCallRealMethod().when(bot).onUpdatesReceived(any()); Mockito.doCallRealMethod().when(bot).onUpdatesReceived(any());
Update update1 = new Update(); Update update1 = new Update();
update1.setUpdateId(1);
Update update2 = new Update(); Update update2 = new Update();
update2.setUpdateId(2);
bot.onUpdatesReceived(asList(update1, update2)); bot.onUpdatesReceived(asList(update1, update2));
Mockito.verify(bot).onUpdateReceived(update1); Mockito.verify(bot).onUpdateReceived(update1);
Mockito.verify(bot).onUpdateReceived(update2); Mockito.verify(bot).onUpdateReceived(update2);

View File

@ -15,9 +15,11 @@ import org.mockito.Mockito;
import org.telegram.telegrambots.bots.DefaultBotOptions; import org.telegram.telegrambots.bots.DefaultBotOptions;
import org.telegram.telegrambots.meta.TelegramBotsApi; import org.telegram.telegrambots.meta.TelegramBotsApi;
import org.telegram.telegrambots.meta.api.objects.Update; import org.telegram.telegrambots.meta.api.objects.Update;
import org.telegram.telegrambots.meta.generics.BackOff;
import org.telegram.telegrambots.meta.generics.LongPollingBot; import org.telegram.telegrambots.meta.generics.LongPollingBot;
import org.telegram.telegrambots.test.Fakes.FakeLongPollingBot; import org.telegram.telegrambots.test.Fakes.FakeLongPollingBot;
import org.telegram.telegrambots.updatesreceivers.DefaultBotSession; import org.telegram.telegrambots.updatesreceivers.DefaultBotSession;
import org.telegram.telegrambots.updatesreceivers.ExponentialBackOff;
import java.io.IOException; import java.io.IOException;
import java.util.Arrays; import java.util.Arrays;
@ -139,6 +141,30 @@ public class TestDefaultBotSession {
session.stop(); session.stop();
} }
@Test
public void testDefaultBotSessionWithCustomExponentialBackOff() {
ExponentialBackOff ex = new ExponentialBackOff.Builder()
.setInitialIntervalMillis(500)
.setRandomizationFactor(0.5)
.setMultiplier(1.5)
.setMaxIntervalMillis(900000)
.setMaxElapsedTimeMillis(3600000)
.build();
DefaultBotOptions options = new DefaultBotOptions();
options.setBackOff(ex);
DefaultBotSession session = new DefaultBotSession();
session.setOptions(options);
}
@Test
public void testDefaultBotSessionWithCustomConstantBackOff() {
DefaultBotOptions options = new DefaultBotOptions();
ConstantBackOff backOff = new ConstantBackOff(3000);
options.setBackOff(backOff);
DefaultBotSession session = new DefaultBotSession();
session.setOptions(options);
}
private Update[] createFakeUpdates(int count) { private Update[] createFakeUpdates(int count) {
return IntStream.range(0, count).mapToObj(x -> { return IntStream.range(0, count).mapToObj(x -> {
Update mock = Mockito.mock(Update.class); Update mock = Mockito.mock(Update.class);
@ -178,4 +204,26 @@ public class TestDefaultBotSession {
session.setOptions(new DefaultBotOptions()); session.setOptions(new DefaultBotOptions());
return session; return session;
} }
private static class ConstantBackOff implements BackOff {
private long backOffMillis;
ConstantBackOff() {
new ConstantBackOff(3000);
}
ConstantBackOff(long millis) {
this.backOffMillis = millis;
}
@Override
public void reset() {
}
@Override
public long nextBackOffMillis() {
return backOffMillis;
}
}
} }

View File

@ -113,7 +113,8 @@ public class TestRestApi extends JerseyTest {
.request(MediaType.APPLICATION_JSON) .request(MediaType.APPLICATION_JSON)
.post(entity, AnswerInlineQuery.class); .post(entity, AnswerInlineQuery.class);
assertEquals("{\"personal\":true,\"inline_query_id\":\"id\",\"results\":[{\"type\":\"article\",\"id\":\"0\",\"title\":\"Title\",\"input_message_content\":{\"message_text\":\"Text\",\"parse_mode\":\"Markdown\"},\"reply_markup\":{\"inline_keyboard\":[[{\"text\":\"Button1\",\"callback_data\":\"Callback\"}]]},\"url\":\"Url\",\"hide_url\":false,\"description\":\"Description\",\"thumb_url\":\"ThumbUrl\",\"thumb_width\":10,\"thumb_height\":20},{\"type\":\"photo\",\"id\":\"1\",\"photo_url\":\"PhotoUrl\",\"mime_type\":\"image/jpg\",\"photo_width\":10,\"photo_height\":20,\"thumb_url\":\"ThumbUrl\",\"title\":\"Title\",\"description\":\"Description\",\"caption\":\"Caption\",\"input_message_content\":{\"message_text\":\"Text\",\"parse_mode\":\"Markdown\"},\"reply_markup\":{\"inline_keyboard\":[[{\"text\":\"Button1\",\"callback_data\":\"Callback\"}]]}}],\"cache_time\":100,\"is_personal\":true,\"next_offset\":\"3\",\"switch_pm_text\":\"pmText\",\"switch_pm_parameter\":\"PmParameter\",\"method\":\"answerInlineQuery\"}", map(result)); assertEquals("{\"inline_query_id\":\"id\",\"results\":[{\"type\":\"article\",\"id\":\"0\",\"title\":\"Title\",\"input_message_content\":{\"message_text\":\"Text\",\"parse_mode\":\"Markdown\"},\"reply_markup\":{\"inline_keyboard\":[[{\"text\":\"Button1\",\"callback_data\":\"Callback\"}]]},\"url\":\"Url\",\"hide_url\":false,\"description\":\"Description\",\"thumb_url\":\"ThumbUrl\",\"thumb_width\":10,\"thumb_height\":20},{\"type\":\"photo\",\"id\":\"1\",\"photo_url\":\"PhotoUrl\",\"mime_type\":\"image/jpg\",\"photo_width\":10,\"photo_height\":20,\"thumb_url\":\"ThumbUrl\",\"title\":\"Title\",\"description\":\"Description\",\"caption\":\"Caption\",\"input_message_content\":{\"message_text\":\"Text\",\"parse_mode\":\"Markdown\"},\"reply_markup\":{\"inline_keyboard\":[[{\"text\":\"Button1\",\"callback_data\":\"Callback\"}]]},\"caption_entities\":[]}],\"cache_time\":100,\"is_personal\":true,\"next_offset\":\"3\",\"switch_pm_text\":\"pmText\",\"switch_pm_parameter\":\"PmParameter\",\"method\":\"answerInlineQuery\"}",
map(result));
} }
@Test @Test
@ -127,9 +128,8 @@ public class TestRestApi extends JerseyTest {
.post(entity, EditMessageCaption.class); .post(entity, EditMessageCaption.class);
assertEquals("{\"chat_id\":\"ChatId\",\"message_id\":1,\"caption\":\"Caption\"," + assertEquals("{\"chat_id\":\"ChatId\",\"message_id\":1,\"caption\":\"Caption\"," +
"\"reply_markup\":{\"inline_keyboard\":[[{" + "\"reply_markup\":{\"inline_keyboard\":[[{\"text\":\"Button1\",\"callback_data\":\"Callback\"}]]}," +
"\"text\":\"Button1\",\"callback_data\":\"Callback\"}]]},\"method\":" + "\"caption_entities\":[],\"method\":\"editmessagecaption\"}", map(result));
"\"editmessagecaption\"}", map(result));
} }
@Test @Test
@ -422,10 +422,10 @@ public class TestRestApi extends JerseyTest {
.request(MediaType.APPLICATION_JSON) .request(MediaType.APPLICATION_JSON)
.post(entity, SendInvoice.class); .post(entity, SendInvoice.class);
assertEquals("{\"chat_id\":12345,\"title\":\"Random title\",\"description\":\"Random description\"" + assertEquals("{\"chat_id\":\"12345\",\"title\":\"Random title\",\"description\":\"Random description\"," +
",\"payload\":\"Random Payload\",\"provider_token\":\"Random provider token\",\"start_parameter\":" + "\"payload\":\"Random Payload\",\"provider_token\":\"Random provider token\",\"start_parameter\":\"STARTPARAM\"," +
"\"STARTPARAM\",\"currency\":\"EUR\",\"prices\":[{\"label\":\"LABEL\"," + "\"currency\":\"EUR\",\"prices\":[{\"label\":\"LABEL\",\"amount\":1000}],\"max_tip_amount\":100," +
"\"amount\":1000}],\"method\":\"sendinvoice\"}", map(result)); "\"suggested_tip_amounts\":[10,50,75],\"method\":\"sendinvoice\"}", map(result));
} }
private Update getUpdate() { private Update getUpdate() {