Merge remote-tracking branch 'github/dev'

This commit is contained in:
Andrea Cavalli 2022-09-09 22:43:14 +02:00
commit a1cab968c6
17 changed files with 190 additions and 54 deletions

View File

@ -1,7 +1,7 @@
So, you just wanna program your own Telegram bot with TelegramBots? Let's see the fast version.
So, youd like to create your own Telegram bot with TelegramBots? Then Let's get You started quickly.
## Grab the library
First you need ot get the library and add it to your project. There are few possibilities for this:
First you need to acquire the library and add it to your project. There are several ways to do this:
1. If you use [Maven](https://maven.apache.org/), [Gradle](https://gradle.org/), etc; you should be able to import the dependency directly from [Maven Central Repository](http://mvnrepository.com/artifact/org.telegram/telegrambots). For example:
@ -20,14 +20,14 @@ First you need ot get the library and add it to your project. There are few poss
implementation 'org.telegram:telegrambots:6.1.0'
```
2. Don't like **Maven Central Repository**? It can also be taken from [Jitpack](https://jitpack.io/#rubenlagus/TelegramBots).
3. Import the library *.jar* direclty to your project. You can find it [here](https://github.com/rubenlagus/TelegramBots/releases), don't forget to take last version, it usually is a good idea. Depending on the IDE you are using, the process to add a library is different, here is a video that may help with [Intellij](https://www.youtube.com/watch?v=NZaH4tjwMYg) or [Eclipse](https://www.youtube.com/watch?v=VWnfHkBgO1I)
2. Don't like the **Maven Central Repository**? It can also be grabbed from [Jitpack](https://jitpack.io/#rubenlagus/TelegramBots).
3. Import the library *.jar* direclty to your project. You can find it [here](https://github.com/rubenlagus/TelegramBots/releases), don't forget to fetch the latest version, it usually is a good idea. Depending on the IDE you are using, the process to add a library is different, here is a video that may help with [Intellij](https://www.youtube.com/watch?v=NZaH4tjwMYg) or [Eclipse](https://www.youtube.com/watch?v=VWnfHkBgO1I)
## Build our first bot
Now that we have the library, we can start coding. There are few steps to follow, in this tutorial (for the sake of simplicity), we are going to build a [Long Polling Bot](http://en.wikipedia.org/wiki/Push_technology#Long_polling):
## Building your first bot
Now that you have the library, you can start coding. There are few steps to follow, in this tutorial (for the sake of simplicity), we are going to build a [Long Polling Bot](http://en.wikipedia.org/wiki/Push_technology#Long_polling):
1. **Create your actual bot:**
1. **Creating your actual bot:**
The class must extends `TelegramLongPollingBot` and implement necessary methods:
```java
@ -99,7 +99,7 @@ Now that we have the library, we can start coding. There are few steps to follow
```
2. **Instantiate `TelegramBotsApi` and register our new bot:**
For this part, we need to actually perform 2 steps: _Instantiate Telegram Api_ and _Register our Bot_. In this tutorial, we are going to make it in our `main` method:
For this part, we need to actually perform 2 steps: _Instantiate Telegram Api_ and _Register our Bot_. In this tutorial, we are going to do it in our `main` method:
```java

View File

@ -78,7 +78,7 @@
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<shiro.version>1.9.0</shiro.version>
<shiro.version>1.9.1</shiro.version>
</properties>
<dependencies>

View File

@ -25,7 +25,7 @@ import java.util.List;
* @version 1.0
* Use this method to copy messages of any kind.
* Service messages and invoice messages can't be copied.
*
* A quiz poll can be copied only if the value of the field correct_option_id is known to the bot.
* 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.
*/

View File

@ -64,11 +64,11 @@ public class GetGameHighScores extends BotApiMethod<ArrayList<GameHighScore>> {
private static final String USER_ID_FIELD = "user_id";
@JsonProperty(CHATID_FIELD)
private String chatId; ///< Optional Required if inline_message_id is not specified. Unique identifier for the target chat (or username of the target channel in the format @channelusername)
private String chatId; ///< Optional. Required if inline_message_id is not specified. Unique identifier for the target chat (or username of the target channel in the format @channelusername)
@JsonProperty(MESSAGEID_FIELD)
private Integer messageId; ///< Optional Required if inline_message_id is not specified. Unique identifier of the sent message
private Integer messageId; ///< Optional. Required if inline_message_id is not specified. Unique identifier of the sent message
@JsonProperty(INLINE_MESSAGE_ID_FIELD)
private String inlineMessageId; ///< Optional Required if chat_id and message_id are not specified. Identifier of the inline message
private String inlineMessageId; ///< Optional. Required if chat_id and message_id are not specified. Identifier of the inline message
@JsonProperty(USER_ID_FIELD)
@NonNull
private Long userId; ///<Target user id

View File

@ -14,6 +14,7 @@ import lombok.Setter;
import lombok.Singular;
import lombok.ToString;
import org.telegram.telegrambots.meta.api.methods.BotApiMethod;
import org.telegram.telegrambots.meta.api.methods.botapimethods.BotApiMethodMessage;
import org.telegram.telegrambots.meta.api.objects.ApiResponse;
import org.telegram.telegrambots.meta.api.objects.Message;
import org.telegram.telegrambots.meta.api.objects.payments.LabeledPrice;
@ -36,7 +37,7 @@ import java.util.List;
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class CreateInvoiceLink extends BotApiMethod<Message> {
public class CreateInvoiceLink extends BotApiMethodMessage {
public static final String PATH = "createInvoiceLink";
public static final String TITLE_FIELD = "title";
@ -135,21 +136,6 @@ public class CreateInvoiceLink extends BotApiMethod<Message> {
return PATH;
}
@Override
public Message deserializeResponse(String answer) throws TelegramApiRequestException {
try {
ApiResponse<Message> result = OBJECT_MAPPER.readValue(answer,
new TypeReference<ApiResponse<Message>>(){});
if (result.getOk()) {
return result.getResult();
} else {
throw new TelegramApiRequestException("Error sending invoice", result);
}
} catch (IOException e) {
throw new TelegramApiRequestException("Unable to deserialize response", e);
}
}
@Override
public void validate() throws TelegramApiValidationException {
if (Strings.isNullOrEmpty(title) || title.length() > 32) {

View File

@ -15,6 +15,7 @@ import lombok.Singular;
import lombok.ToString;
import lombok.experimental.Tolerate;
import org.telegram.telegrambots.meta.api.methods.BotApiMethod;
import org.telegram.telegrambots.meta.api.methods.botapimethods.BotApiMethodMessage;
import org.telegram.telegrambots.meta.api.objects.ApiResponse;
import org.telegram.telegrambots.meta.api.objects.Message;
import org.telegram.telegrambots.meta.api.objects.payments.LabeledPrice;
@ -38,7 +39,7 @@ import java.util.List;
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class SendInvoice extends BotApiMethod<Message> {
public class SendInvoice extends BotApiMethodMessage {
public static final String PATH = "sendinvoice";
private static final String CHATID_FIELD = "chat_id";
@ -176,21 +177,6 @@ public class SendInvoice extends BotApiMethod<Message> {
return PATH;
}
@Override
public Message deserializeResponse(String answer) throws TelegramApiRequestException {
try {
ApiResponse<Message> result = OBJECT_MAPPER.readValue(answer,
new TypeReference<ApiResponse<Message>>(){});
if (result.getOk()) {
return result.getResult();
} else {
throw new TelegramApiRequestException("Error sending invoice", result);
}
} catch (IOException e) {
throw new TelegramApiRequestException("Unable to deserialize response", e);
}
}
@Override
public void validate() throws TelegramApiValidationException {
if (Strings.isNullOrEmpty(chatId)) {

View File

@ -9,12 +9,17 @@ import lombok.NonNull;
import lombok.RequiredArgsConstructor;
import lombok.Setter;
import lombok.ToString;
import lombok.experimental.Tolerate;
import org.telegram.telegrambots.meta.api.methods.CopyMessage;
import org.telegram.telegrambots.meta.api.methods.PartialBotApiMethod;
import org.telegram.telegrambots.meta.api.objects.InputFile;
import org.telegram.telegrambots.meta.api.objects.stickers.MaskPosition;
import org.telegram.telegrambots.meta.exceptions.TelegramApiRequestException;
import org.telegram.telegrambots.meta.exceptions.TelegramApiValidationException;
import java.util.Arrays;
import java.util.List;
/**
* @author Ruben Bermudez
* @version 1.0
@ -36,6 +41,8 @@ public class CreateNewStickerSet extends PartialBotApiMethod<Boolean> {
public static final String USERID_FIELD = "user_id";
public static final String NAME_FIELD = "name";
public static final String STICKERTYPE_FIELD = "sticker_type";
public static final String TITLE_FIELD = "title";
public static final String PNGSTICKER_FIELD = "png_sticker";
public static final String TGSSTICKER_FIELD = "tgs_sticker";
@ -46,6 +53,13 @@ public class CreateNewStickerSet extends PartialBotApiMethod<Boolean> {
@NonNull
private Long userId; ///< User identifier of created sticker set owner
/**
* Type of stickers in the set, pass regular or mask.
* Custom emoji sticker sets can't be created via the Bot API at the moment.
* By default, a regular sticker set is created.
*/
@Builder.Default
private String stickerType = "regular";
/**
* Name of sticker set, to be used in t.me/addstickers/<name> URLs.
* Can contain only english letters, digits and underscores.
@ -58,7 +72,6 @@ public class CreateNewStickerSet extends PartialBotApiMethod<Boolean> {
private String title; ///< User identifier of created sticker set owner
@NonNull
private String emojis; ///< One or more emoji corresponding to the sticker
private Boolean containsMasks; ///< Optional. Pass True, if a set of mask stickers should be created
private MaskPosition maskPosition; ///< Optional. Position where the mask should be placed on faces
/**
* Optional.
@ -84,6 +97,33 @@ public class CreateNewStickerSet extends PartialBotApiMethod<Boolean> {
*/
private InputFile webmSticker;
/**
* @deprecated Use {@link #setStickerType(String)}
*/
@Deprecated
public void setContainsMasks(boolean containsMasks) {
if (containsMasks) {
this.stickerType = "mask";
} else {
this.stickerType = "regular";
}
}
/**
* @deprecated Use {@link #getStickerType()} or {@link #isMask()}
*/
@Deprecated
public Boolean getContainsMasks() {
return isMask();
}
public boolean isRegularSticker() {
return "regular".equals(stickerType);
}
public boolean isMask() {
return "mask".equals(stickerType);
}
@Override
public Boolean deserializeResponse(String answer) throws TelegramApiRequestException {
return deserializeResponse(answer, Boolean.class);
@ -94,6 +134,9 @@ public class CreateNewStickerSet extends PartialBotApiMethod<Boolean> {
if (userId <= 0) {
throw new TelegramApiValidationException("userId can't be empty", this);
}
if (!Arrays.asList("regular", "mask").contains(stickerType)) {
throw new TelegramApiValidationException("Stickertype must be 'regular' or 'mask'", this);
}
if (name.isEmpty()) {
throw new TelegramApiValidationException("name can't be empty", this);
}
@ -129,4 +172,20 @@ public class CreateNewStickerSet extends PartialBotApiMethod<Boolean> {
maskPosition.validate();
}
}
public static class CreateNewStickerSetBuilder {
/**
* @deprecated Use {@link #stickerType(String)} or {@link #setStickerType(String)}
*/
@Tolerate
@Deprecated
public CreateNewStickerSet.CreateNewStickerSetBuilder containsMasks(@NonNull Boolean containsMasks) {
if (containsMasks) {
this.stickerType("mask");
} else {
this.stickerType("regular");
}
return this;
}
}
}

View File

@ -0,0 +1,57 @@
package org.telegram.telegrambots.meta.api.methods.stickers;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.*;
import org.telegram.telegrambots.meta.api.methods.BotApiMethod;
import org.telegram.telegrambots.meta.api.methods.botapimethods.BotApiMethodBoolean;
import org.telegram.telegrambots.meta.api.objects.games.GameHighScore;
import org.telegram.telegrambots.meta.api.objects.stickers.Sticker;
import org.telegram.telegrambots.meta.exceptions.TelegramApiRequestException;
import org.telegram.telegrambots.meta.exceptions.TelegramApiValidationException;
import java.util.ArrayList;
import java.util.List;
/**
* @author Ruben Bermudez
* @version 6.2
* Use this method to get information about emoji stickers by their identifiers.
* Returns an Array of Sticker on success.
*/
@EqualsAndHashCode(callSuper = false)
@Getter
@Setter
@ToString
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class GetCustomEmojiStickers extends BotApiMethod<ArrayList<Sticker>> {
private static final String PATH = "getCustomEmojiStickers";
private static final String CUSTOMEMOJIID_FIELD = "custom_emoji_ids";
/**
* List of custom emoji identifiers.
* At most 200 custom emoji identifiers can be specified.
*/
@Singular
@JsonProperty(CUSTOMEMOJIID_FIELD)
private List<String> customEmojiIds;
@Override
public void validate() throws TelegramApiValidationException {
if (customEmojiIds == null || customEmojiIds.isEmpty() || customEmojiIds.size() > 200) {
throw new TelegramApiValidationException("CustomEmojiIds must be between 1 and 200", this);
}
}
@Override
public String getMethod() {
return PATH;
}
@Override
public ArrayList<Sticker> deserializeResponse(String answer) throws TelegramApiRequestException {
return deserializeResponseArray(answer, Sticker.class);
}
}

View File

@ -49,6 +49,7 @@ public class Chat implements BotApiObject {
private static final String HASPROTECTEDCONTENT_FIELD = "has_protected_content";
private static final String JOINTOSENDMESSAGES_FIELD = "join_to_send_messages";
private static final String JOINBYREQUEST_FIELD = "join_by_request";
private static final String HASRESTRICTEDVOICEANDVIDEOMESSAGES_FIELD = "has_restricted_voice_and_video_messages";
private static final String USERCHATTYPE = "private";
private static final String GROUPCHATTYPE = "group";
@ -152,6 +153,13 @@ public class Chat implements BotApiObject {
*/
@JsonProperty(JOINBYREQUEST_FIELD)
private Boolean joinByRequest;
/**
* Optional.
* True, if the privacy settings of the other party restrict sending voice and video note messages in the private chat.
* Returned only in getChat.
*/
@JsonProperty(HASRESTRICTEDVOICEANDVIDEOMESSAGES_FIELD)
private Boolean hasRestrictedVoiceAndVideoMessages;
@JsonProperty(IS_VERIFIED_FIELD)
private Boolean isVerified; ///< Optional. Extra.

View File

@ -42,6 +42,7 @@ public class MessageEntity implements BotApiObject {
private static final String URL_FIELD = "url";
private static final String USER_FIELD = "user";
private static final String LANGUAGE_FIELD = "language";
private static final String CUSTOMEMOJI_FIELD = "custom_emoji_id";
/**
* Type of the entity.
* Currently, can be:
@ -61,6 +62,7 @@ public class MessageEntity implements BotApiObject {
* - pre (monowidth block)
* - text_link (for clickable text URLs)
* - text_mention (for users without usernames)
* - "custom_emoji" (for inline custom emoji stickers)
*/
@JsonProperty(TYPE_FIELD)
@NonNull
@ -77,6 +79,13 @@ public class MessageEntity implements BotApiObject {
private User user; ///< Optional. For text_mention only, the mentioned user
@JsonProperty(LANGUAGE_FIELD)
private String language; ///< Optional. For pre only, the programming language of the entity text
/**
* Optional.
* For custom_emoji only, unique identifier of the custom emoji.
* Use getCustomEmojiStickers to get full information about the sticker
*/
@JsonProperty(CUSTOMEMOJI_FIELD)
private String customEmojiId;
@Setter(AccessLevel.NONE)
@JsonIgnore
private MemoizedUTF16Substring text; ///< Text present in the entity. Computed from offset and length

View File

@ -26,6 +26,7 @@ public class Sticker implements BotApiObject {
private static final String FILEID_FIELD = "file_id";
private static final String FILEUNIQUEID_FIELD = "file_unique_id";
private static final String TYPE_FIELD = "type";
private static final String WIDTH_FIELD = "width";
private static final String HEIGHT_FIELD = "height";
private static final String THUMB_FIELD = "thumb";
@ -36,6 +37,7 @@ public class Sticker implements BotApiObject {
private static final String ISANIMATED_FIELD = "is_animated";
private static final String ISVIDEO_FIELD = "is_video";
private static final String PREMIUMANIMATION_FIELD = "premium_animation";
private static final String CUSTOMEMOJIID_FIELD = "custom_emoji_id";
@JsonProperty(FILEID_FIELD)
private String fileId; ///< Identifier for this file, which can be used to download or reuse the file
@ -45,6 +47,12 @@ public class Sticker implements BotApiObject {
*/
@JsonProperty(FILEUNIQUEID_FIELD)
private String fileUniqueId;
/**
* Type of the sticker, currently one of regular, mask, custom_emoji.
* The type of the sticker is independent of its format, which is determined by the fields is_animated and is_video.
*/
@JsonProperty(TYPE_FIELD)
private String type;
@JsonProperty(WIDTH_FIELD)
private Integer width; ///< Sticker width
@JsonProperty(HEIGHT_FIELD)
@ -65,4 +73,7 @@ public class Sticker implements BotApiObject {
private Boolean isVideo; ///< True, if the sticker is a video sticker
@JsonProperty(PREMIUMANIMATION_FIELD)
private File premiumAnimation; ///< Optional. Premium animation for the sticker, if the sticker is premium
@JsonProperty(CUSTOMEMOJIID_FIELD)
private String customEmojiId; ///< Optional. For custom emoji stickers, unique identifier of the custom emoji
}

View File

@ -24,6 +24,7 @@ import java.util.List;
@NoArgsConstructor
@AllArgsConstructor
public class StickerSet implements BotApiObject {
private static final String STICKERTYPE_FIELD = "sticker_type";
private static final String NAME_FIELD = "name";
private static final String TITLE_FIELD = "title";
private static final String CONTAINSMASKS_FIELD = "contains_masks";
@ -32,12 +33,20 @@ public class StickerSet implements BotApiObject {
private static final String ISVIDEO_FIELD = "is_video";
private static final String THUMB_FIELD = "thumb";
@JsonProperty(STICKERS_FIELD)
private String stickerType; ///< Type of stickers in the set, currently one of regular, mask, custom_emoji
@JsonProperty(NAME_FIELD)
private String name; ///< Sticker set name
@JsonProperty(TITLE_FIELD)
private String title; ///< Sticker set title
/**
* True, if the sticker set contains animated stickers
*
* @deprecated Use {@link #getStickerType()} or {@link #isMask()}
*/
@JsonProperty(CONTAINSMASKS_FIELD)
private Boolean containsMasks; ///< True, if the sticker set contains animated stickers
@Deprecated
private Boolean containsMasks;
@JsonProperty(STICKERS_FIELD)
private List<Sticker> stickers; ///< True, if the sticker set contains masks
@JsonProperty(ISANIMATED_FIELD)
@ -46,4 +55,15 @@ public class StickerSet implements BotApiObject {
private Boolean isVideo; ///< True, if the sticker set contains video stickers
@JsonProperty(THUMB_FIELD)
private PhotoSize thumb; ///< Optional. Sticker set thumbnail in the .WEBP, .TGS, or .WEBM format
public boolean isRegularSticker() {
return "regular".equals(stickerType);
}
public boolean isMask() {
return "mask".equals(stickerType);
}
public boolean isCustomEmoji() {
return "custom_emoji".equals(stickerType);
}
}

View File

@ -673,7 +673,7 @@ public abstract class DefaultAbsSender extends AbsSender {
builder.addTextBody(CreateNewStickerSet.NAME_FIELD, createNewStickerSet.getName(), TEXT_PLAIN_CONTENT_TYPE);
builder.addTextBody(CreateNewStickerSet.TITLE_FIELD, createNewStickerSet.getTitle(), TEXT_PLAIN_CONTENT_TYPE);
builder.addTextBody(CreateNewStickerSet.EMOJIS_FIELD, createNewStickerSet.getEmojis(), TEXT_PLAIN_CONTENT_TYPE);
builder.addTextBody(CreateNewStickerSet.CONTAINSMASKS_FIELD, createNewStickerSet.getContainsMasks().toString(), TEXT_PLAIN_CONTENT_TYPE);
builder.addTextBody(CreateNewStickerSet.STICKERTYPE_FIELD, createNewStickerSet.getStickerType(), TEXT_PLAIN_CONTENT_TYPE);
if (createNewStickerSet.getPngSticker() != null) {
addInputFile(builder, createNewStickerSet.getPngSticker(), CreateNewStickerSet.PNGSTICKER_FIELD, true);
} else if (createNewStickerSet.getTgsSticker() != null) {

View File

@ -18,10 +18,10 @@ import org.telegram.telegrambots.meta.api.methods.groupadministration.GetChatMem
import org.telegram.telegrambots.meta.api.methods.groupadministration.GetChatMemberCount;
import org.telegram.telegrambots.meta.api.methods.groupadministration.LeaveChat;
import org.telegram.telegrambots.meta.api.methods.groupadministration.UnbanChatMember;
import org.telegram.telegrambots.meta.api.methods.invoices.SendInvoice;
import org.telegram.telegrambots.meta.api.methods.send.SendChatAction;
import org.telegram.telegrambots.meta.api.methods.send.SendContact;
import org.telegram.telegrambots.meta.api.methods.send.SendGame;
import org.telegram.telegrambots.meta.api.methods.send.SendInvoice;
import org.telegram.telegrambots.meta.api.methods.send.SendLocation;
import org.telegram.telegrambots.meta.api.methods.send.SendMessage;
import org.telegram.telegrambots.meta.api.methods.send.SendVenue;

View File

@ -26,9 +26,9 @@ import static java.nio.charset.Charset.defaultCharset;
import static org.apache.commons.io.FileUtils.readFileToString;
import static org.apache.commons.io.IOUtils.toInputStream;
import static org.apache.http.HttpVersion.HTTP_1_1;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.core.IsInstanceOf.instanceOf;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThat;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.timeout;
import static org.mockito.Mockito.verify;

View File

@ -12,7 +12,7 @@ import java.util.concurrent.TimeUnit;
import static java.util.Arrays.asList;
import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertThat;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.mockito.ArgumentMatchers.any;
public class TelegramLongPollingBotTest {

View File

@ -23,10 +23,10 @@ import org.telegram.telegrambots.meta.api.methods.groupadministration.GetChatMem
import org.telegram.telegrambots.meta.api.methods.groupadministration.GetChatMemberCount;
import org.telegram.telegrambots.meta.api.methods.groupadministration.LeaveChat;
import org.telegram.telegrambots.meta.api.methods.groupadministration.UnbanChatMember;
import org.telegram.telegrambots.meta.api.methods.invoices.SendInvoice;
import org.telegram.telegrambots.meta.api.methods.send.SendChatAction;
import org.telegram.telegrambots.meta.api.methods.send.SendContact;
import org.telegram.telegrambots.meta.api.methods.send.SendGame;
import org.telegram.telegrambots.meta.api.methods.send.SendInvoice;
import org.telegram.telegrambots.meta.api.methods.send.SendLocation;
import org.telegram.telegrambots.meta.api.methods.send.SendMessage;
import org.telegram.telegrambots.meta.api.methods.send.SendVenue;
@ -62,7 +62,7 @@ import static org.junit.Assert.fail;
*/
public class TestRestApi extends JerseyTest {
private FakeWebhook webhookBot = new FakeWebhook();
private final FakeWebhook webhookBot = new FakeWebhook();
private RestApi restApi;
@Override