diff --git a/.travis.yml b/.travis.yml index 81b32439..168ea153 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,11 +1,18 @@ language: java jdk: - - oraclejdk8 -install: mvn install -Dgpg.skip -script: mvn clean compile test + - oraclejdk11 + - oraclejdk-ea + - openjdk11 + - openjdk-ea +install: mvn -q install -Dgpg.skip +script: mvn -q clean compile test after_success: - bash <(curl -s https://codecov.io/bash) notifications: webhooks: secure: "jC7dK/x67ONWQoeLZg4HfW0mHhcjDerJjsLLkrbcpltiqAbw2p7XfY8Pk4zHoD72a+5o6WKu5WvYvZ4OdldnjP8Y6ZUbliQ5RG3olg3gFDoe0+sc3geeb4HRYVcdI20O0z4Bup/qO0ZihxPBc0D5IpHmFxlaqlZG0WeST4CicU8PNnBh6aX9/VMrwXhkMb2vfzmjmIhMbx/uK5+93bnk/vR5Uwu00/Yd2cTAAWMaqK1MRdtR0WLbxlUNsprEfCjYiH3n9XZnlKXs6cLC8EOU436Wx7aepiAszW0wWFMe/7nVqOqztrQiKNvL0qXYwlQf0BLechJdt458EopL9QCu687TNDFYvg1yERAmCRiaayYZcX3PbUSMr6H5Q+Odntjs3XKyzfgSqqlkgf/SAND5jny1/1uteVoplZmFXuZFIiK4H8Rl2ezy1/8pnbp+JD3YEfiA2NuRjlou1BZXyMhiqqVXbrJqk/tXF6yZSkDlYJfNsWzRCGfra4B6JjEvUP927chIFm1ii3dgNstXDo1evV46+OQQO4HKvMPdtU2FPvWpPlkTxnmpZRZjB+bjmybluJdWT3E+e1C3wm7YbRe3vporhpfNPlnod6M0G10y9CKzl9Fbcku6X1FtM+IoPO/aqZ8S4/CBZoYEuR/Nk6bcvsYouxtyIl6PSuF9E8YjpJE=" email: false +matrix: + allow_failures: + - jdk: openjdk-ea + - jdk: oraclejdk-ea \ No newline at end of file diff --git a/Bots.ipr b/Bots.ipr index 242d28a4..48a1815b 100644 --- a/Bots.ipr +++ b/Bots.ipr @@ -12,6 +12,12 @@ + + + + + + @@ -23,21 +29,15 @@ - - - - - - - - - - - - - + + + + + + + @@ -757,7 +757,7 @@ - - + @@ -898,15 +898,15 @@ - + - + - + - + @@ -931,6 +931,17 @@ + + + + + + + + + + + @@ -975,26 +986,48 @@ - + - + - + - + - + - + - + - + + + + + + + + + + + + + + + + + + + + + + + @@ -1008,15 +1041,26 @@ - + - + - + - + + + + + + + + + + + + @@ -1030,15 +1074,15 @@ - + - + - + - + @@ -1052,15 +1096,15 @@ - + - + - + - + @@ -1074,15 +1118,59 @@ - + - + - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -1096,48 +1184,15 @@ - + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + @@ -1151,15 +1206,26 @@ - + - + - + - + + + + + + + + + + + + @@ -1173,466 +1239,499 @@ - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -1646,37 +1745,48 @@ - + - + - + - + - + - + - + - + - + - + - + - + + + + + + + + + + + + @@ -1690,6 +1800,50 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -1701,26 +1855,59 @@ - + - + - + - + - + - + - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -1734,103 +1921,103 @@ - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + diff --git a/README.md b/README.md index b6402570..5d45b712 100644 --- a/README.md +++ b/README.md @@ -27,16 +27,16 @@ Just import add the library to your project with one of these options: org.telegram telegrambots - 4.3.1 + 4.4.0 ``` ```gradle - compile "org.telegram:telegrambots:4.3.1" + compile "org.telegram:telegrambots:4.4.0" ``` - 2. Using Jitpack from [here](https://jitpack.io/#rubenlagus/TelegramBots/4.3.1) - 3. Download the jar(including all dependencies) from [here](https://mvnrepository.com/artifact/org.telegram/telegrambots/4.3.1) + 2. Using Jitpack from [here](https://jitpack.io/#rubenlagus/TelegramBots/4.4.0) + 3. Download the jar(including all dependencies) from [here](https://mvnrepository.com/artifact/org.telegram/telegrambots/4.4.0) In order to use Long Polling mode, just create your own bot extending `org.telegram.telegrambots.bots.TelegramLongPollingBot`. diff --git a/TelegramBots.wiki/Changelog.md b/TelegramBots.wiki/Changelog.md index 27d9a2e6..d234ab7c 100644 --- a/TelegramBots.wiki/Changelog.md +++ b/TelegramBots.wiki/Changelog.md @@ -1,3 +1,11 @@ +### 4.4.0 ### +1. Update Api version [4.4](https://core.telegram.org/bots/api-changelog#july-29-2019) +2. Removed BotLogger, replaced with [log4j2](https://logging.apache.org/log4j/2.x/) +3. Library is now built using [Java11](https://www.oracle.com/technetwork/java/javase/overview/index.html) +4. Updated dependencies to use last versions +5. Files can be downloaded into a stream. Allowing it to be processed immediately. +6. A java.io.File can be passed into the methods. The downloaded file is copied into that file instead of a temp file then (does not work with the async methods) + ### 4.3.1 ### 1. Fix bug #625 2. Moved ApiResponse to different package, deprecated old one (will be removed in next mayor version) diff --git a/TelegramBots.wiki/Getting-Started.md b/TelegramBots.wiki/Getting-Started.md index 9bcfeb7d..e0878bbe 100644 --- a/TelegramBots.wiki/Getting-Started.md +++ b/TelegramBots.wiki/Getting-Started.md @@ -11,13 +11,13 @@ First you need ot get the library and add it to your project. There are few poss org.telegram telegrambots - 4.3.1 + 4.4.0 ``` * With **Gradle**: ```groovy - compile group: 'org.telegram', name: 'telegrambots', version: '4.3.1' + compile group: 'org.telegram', name: 'telegrambots', version: '4.4.0' ``` 2. Don't like **Maven Central Repository**? It can also be taken from [Jitpack](https://jitpack.io/#rubenlagus/TelegramBots). diff --git a/TelegramBots.wiki/abilities/Simple-Example.md b/TelegramBots.wiki/abilities/Simple-Example.md index b5986964..3aa89b8a 100644 --- a/TelegramBots.wiki/abilities/Simple-Example.md +++ b/TelegramBots.wiki/abilities/Simple-Example.md @@ -9,12 +9,12 @@ As with any Java project, you will need to set your dependencies. org.telegram telegrambots-abilities - 4.3.1 + 4.4.0 ``` * **Gradle** ```groovy - compile group: 'org.telegram', name: 'telegrambots-abilities', version: '4.3.1' + compile group: 'org.telegram', name: 'telegrambots-abilities', version: 'permissions' ``` * [JitPack](https://jitpack.io/#rubenlagus/TelegramBots) diff --git a/pom.xml b/pom.xml index ad35c9ed..37193d47 100644 --- a/pom.xml +++ b/pom.xml @@ -7,7 +7,7 @@ org.telegram Bots pom - 4.3.1 + 4.4.0 telegrambots @@ -27,6 +27,90 @@ + 11 + 8 + ${java.version} + ${java.version} + true + + 5.5.1 + 3.0.0 + 3.0.0 + 2.9.9 + 2.9.9.1 + 2.12.0 + + + + + org.junit.jupiter + junit-jupiter-api + ${junit.version} + test + + + org.mockito + mockito-core + ${mockito.version} + test + + + org.mockito + mockito-junit-jupiter + ${mockito.version} + test + + + com.fasterxml.jackson.core + jackson-annotations + ${jacksonbase.version} + + + com.fasterxml.jackson.module + jackson-module-jaxb-annotations + ${jacksonbase.version} + + + com.fasterxml.jackson.core + jackson-databind + ${jackson.version} + + + org.apache.logging.log4j + log4j-core + ${log4j.version} + + + + + + + org.mockito + mockito-core + ${mockito.version} + test + + + + org.mockito + mockito-junit-jupiter + ${mockitojupiter.version} + test + + + + org.junit.jupiter + junit-jupiter-engine + ${junit.version} + test + + + + org.apache.logging.log4j + log4j-core + ${log4j.version} + + \ No newline at end of file diff --git a/telegrambots-abilities/README.md b/telegrambots-abilities/README.md index 520481c2..d43fa96c 100644 --- a/telegrambots-abilities/README.md +++ b/telegrambots-abilities/README.md @@ -18,19 +18,19 @@ Usage org.telegram telegrambots-abilities - 4.3.1 + 4.4.0 ``` **Gradle** ```gradle - compile "org.telegram:telegrambots-abilities:4.3.1" + compile "org.telegram:telegrambots-abilities:4.4.0" ``` -**JitPack** - [JitPack](https://jitpack.io/#rubenlagus/TelegramBots/v4.3.1) +**JitPack** - [JitPack](https://jitpack.io/#rubenlagus/TelegramBots/v4.4.0) -**Plain imports** - [Here](https://github.com/rubenlagus/TelegramBots/releases/tag/v4.3.1) +**Plain imports** - [Here](https://github.com/rubenlagus/TelegramBots/releases/tag/v4.4.0) Motivation ---------- diff --git a/telegrambots-abilities/pom.xml b/telegrambots-abilities/pom.xml index f8e1194b..9f8dc9b5 100644 --- a/telegrambots-abilities/pom.xml +++ b/telegrambots-abilities/pom.xml @@ -3,9 +3,14 @@ xmlns="http://maven.apache.org/POM/4.0.0" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 - org.telegram + + + org.telegram + Bots + 4.4.0 + + telegrambots-abilities - 4.3.1 jar Telegram Ability Bot @@ -63,17 +68,23 @@ + 11 + 8 + ${java.version} + ${java.version} + UTF-8 UTF-8 - 3.5 - 3.0.4 + + 3.9 + 3.0.7 org.telegram telegrambots - 4.3.1 + 4.4.0 org.apache.commons @@ -91,18 +102,6 @@ - - org.mockito - mockito-all - 2.0.2-beta - test - - - junit - junit - 4.11 - test - @@ -112,10 +111,15 @@ ${project.build.directory}/test-classes ${project.basedir}/src/main/java + + org.apache.maven.plugins + maven-surefire-plugin + 3.0.0-M3 + org.apache.maven.plugins maven-gpg-plugin - 1.5 + 1.6 sign-artifacts @@ -129,7 +133,7 @@ org.sonatype.plugins nexus-staging-maven-plugin - 1.6.3 + 1.6.8 true ossrh @@ -139,7 +143,7 @@ maven-clean-plugin - 3.0.0 + 3.1.0 clean-project @@ -152,7 +156,7 @@ maven-assembly-plugin - 2.6 + 3.1.1 jar-with-dependencies @@ -171,7 +175,7 @@ org.apache.maven.plugins maven-source-plugin - 3.0.0 + 3.1.0 @@ -183,14 +187,14 @@ org.apache.maven.plugins maven-javadoc-plugin - 2.10.3 + 3.1.0 jar - -Xdoclint:none + none @@ -198,7 +202,7 @@ org.jacoco jacoco-maven-plugin - 0.7.7.201606060606 + 0.8.4 @@ -217,7 +221,7 @@ org.apache.maven.plugins maven-enforcer-plugin - 1.4.1 + 3.0.0-M2 enforce-versions @@ -235,7 +239,7 @@ org.apache.maven.plugins maven-dependency-plugin - 2.4 + 3.1.1 copy @@ -249,9 +253,10 @@ org.apache.maven.plugins maven-compiler-plugin + 3.8.1 - 1.8 - 1.8 + ${java.version} + ${java.version} UTF-8 diff --git a/telegrambots-abilities/src/main/java/org/telegram/abilitybots/api/bot/BaseAbilityBot.java b/telegrambots-abilities/src/main/java/org/telegram/abilitybots/api/bot/BaseAbilityBot.java index 301f2eab..d5f9c0ef 100644 --- a/telegrambots-abilities/src/main/java/org/telegram/abilitybots/api/bot/BaseAbilityBot.java +++ b/telegrambots-abilities/src/main/java/org/telegram/abilitybots/api/bot/BaseAbilityBot.java @@ -6,9 +6,15 @@ import com.google.common.collect.ImmutableMap; import com.google.common.collect.ListMultimap; import com.google.common.collect.Multimap; import org.apache.commons.io.IOUtils; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; import org.jetbrains.annotations.NotNull; import org.telegram.abilitybots.api.db.DBContext; -import org.telegram.abilitybots.api.objects.*; +import org.telegram.abilitybots.api.objects.Ability; +import org.telegram.abilitybots.api.objects.Locality; +import org.telegram.abilitybots.api.objects.MessageContext; +import org.telegram.abilitybots.api.objects.Privacy; +import org.telegram.abilitybots.api.objects.Reply; import org.telegram.abilitybots.api.sender.DefaultSender; import org.telegram.abilitybots.api.sender.MessageSender; import org.telegram.abilitybots.api.sender.SilentSender; @@ -26,7 +32,6 @@ import org.telegram.telegrambots.meta.api.objects.Message; import org.telegram.telegrambots.meta.api.objects.Update; import org.telegram.telegrambots.meta.api.objects.User; import org.telegram.telegrambots.meta.exceptions.TelegramApiException; -import org.telegram.telegrambots.meta.logging.BotLogger; import java.io.File; import java.io.FileNotFoundException; @@ -34,8 +39,13 @@ import java.io.FileReader; import java.io.PrintStream; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; -import java.util.*; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Map; import java.util.Map.Entry; +import java.util.Optional; +import java.util.Set; import java.util.function.BiFunction; import java.util.function.Function; import java.util.function.Predicate; @@ -53,15 +63,47 @@ import static java.util.Optional.ofNullable; import static java.util.regex.Pattern.CASE_INSENSITIVE; import static java.util.regex.Pattern.compile; import static java.util.stream.Collectors.joining; -import static jersey.repackaged.com.google.common.base.Throwables.propagate; import static org.apache.commons.lang3.StringUtils.isEmpty; import static org.telegram.abilitybots.api.objects.Ability.builder; -import static org.telegram.abilitybots.api.objects.Flag.*; -import static org.telegram.abilitybots.api.objects.Locality.*; +import static org.telegram.abilitybots.api.objects.Flag.DOCUMENT; +import static org.telegram.abilitybots.api.objects.Flag.MESSAGE; +import static org.telegram.abilitybots.api.objects.Flag.REPLY; +import static org.telegram.abilitybots.api.objects.Locality.ALL; +import static org.telegram.abilitybots.api.objects.Locality.GROUP; +import static org.telegram.abilitybots.api.objects.Locality.USER; import static org.telegram.abilitybots.api.objects.MessageContext.newContext; -import static org.telegram.abilitybots.api.objects.Privacy.*; -import static org.telegram.abilitybots.api.util.AbilityMessageCodes.*; -import static org.telegram.abilitybots.api.util.AbilityUtils.*; +import static org.telegram.abilitybots.api.objects.Privacy.ADMIN; +import static org.telegram.abilitybots.api.objects.Privacy.CREATOR; +import static org.telegram.abilitybots.api.objects.Privacy.GROUP_ADMIN; +import static org.telegram.abilitybots.api.objects.Privacy.PUBLIC; +import static org.telegram.abilitybots.api.util.AbilityMessageCodes.ABILITY_BAN_FAIL; +import static org.telegram.abilitybots.api.util.AbilityMessageCodes.ABILITY_BAN_SUCCESS; +import static org.telegram.abilitybots.api.util.AbilityMessageCodes.ABILITY_CLAIM_FAIL; +import static org.telegram.abilitybots.api.util.AbilityMessageCodes.ABILITY_CLAIM_SUCCESS; +import static org.telegram.abilitybots.api.util.AbilityMessageCodes.ABILITY_COMMANDS_NOT_FOUND; +import static org.telegram.abilitybots.api.util.AbilityMessageCodes.ABILITY_DEMOTE_FAIL; +import static org.telegram.abilitybots.api.util.AbilityMessageCodes.ABILITY_DEMOTE_SUCCESS; +import static org.telegram.abilitybots.api.util.AbilityMessageCodes.ABILITY_PROMOTE_FAIL; +import static org.telegram.abilitybots.api.util.AbilityMessageCodes.ABILITY_PROMOTE_SUCCESS; +import static org.telegram.abilitybots.api.util.AbilityMessageCodes.ABILITY_RECOVER_ERROR; +import static org.telegram.abilitybots.api.util.AbilityMessageCodes.ABILITY_RECOVER_FAIL; +import static org.telegram.abilitybots.api.util.AbilityMessageCodes.ABILITY_RECOVER_MESSAGE; +import static org.telegram.abilitybots.api.util.AbilityMessageCodes.ABILITY_RECOVER_SUCCESS; +import static org.telegram.abilitybots.api.util.AbilityMessageCodes.ABILITY_UNBAN_FAIL; +import static org.telegram.abilitybots.api.util.AbilityMessageCodes.ABILITY_UNBAN_SUCCESS; +import static org.telegram.abilitybots.api.util.AbilityMessageCodes.CHECK_INPUT_FAIL; +import static org.telegram.abilitybots.api.util.AbilityMessageCodes.CHECK_LOCALITY_FAIL; +import static org.telegram.abilitybots.api.util.AbilityMessageCodes.CHECK_PRIVACY_FAIL; +import static org.telegram.abilitybots.api.util.AbilityMessageCodes.USER_NOT_FOUND; +import static org.telegram.abilitybots.api.util.AbilityUtils.addTag; +import static org.telegram.abilitybots.api.util.AbilityUtils.commitTo; +import static org.telegram.abilitybots.api.util.AbilityUtils.getChatId; +import static org.telegram.abilitybots.api.util.AbilityUtils.getLocalizedMessage; +import static org.telegram.abilitybots.api.util.AbilityUtils.isGroupUpdate; +import static org.telegram.abilitybots.api.util.AbilityUtils.isSuperGroupUpdate; +import static org.telegram.abilitybots.api.util.AbilityUtils.isUserMessage; +import static org.telegram.abilitybots.api.util.AbilityUtils.shortName; +import static org.telegram.abilitybots.api.util.AbilityUtils.stripTag; /** * The father of all ability bots. Bots that need to utilize abilities need to extend this bot. @@ -97,812 +139,812 @@ import static org.telegram.abilitybots.api.util.AbilityUtils.*; */ @SuppressWarnings({"ConfusingArgumentToVarargsMethod", "UnusedReturnValue", "WeakerAccess", "unused", "ConstantConditions"}) public abstract class BaseAbilityBot extends DefaultAbsSender implements AbilityExtension { - private static final String TAG = BaseAbilityBot.class.getSimpleName(); + private static final Logger log = LogManager.getLogger(BaseAbilityBot.class); - // DB objects - public static final String ADMINS = "ADMINS"; - public static final String USERS = "USERS"; - public static final String USER_ID = "USER_ID"; - public static final String BLACKLIST = "BLACKLIST"; + // DB objects + public static final String ADMINS = "ADMINS"; + public static final String USERS = "USERS"; + public static final String USER_ID = "USER_ID"; + public static final String BLACKLIST = "BLACKLIST"; - // Factory commands - protected static final String DEFAULT = "default"; - protected static final String CLAIM = "claim"; - protected static final String BAN = "ban"; - protected static final String PROMOTE = "promote"; - protected static final String DEMOTE = "demote"; - protected static final String UNBAN = "unban"; - protected static final String BACKUP = "backup"; - protected static final String RECOVER = "recover"; - protected static final String COMMANDS = "commands"; - protected static final String REPORT = "report"; + // Factory commands + protected static final String DEFAULT = "default"; + protected static final String CLAIM = "claim"; + protected static final String BAN = "ban"; + protected static final String PROMOTE = "promote"; + protected static final String DEMOTE = "demote"; + protected static final String UNBAN = "unban"; + protected static final String BACKUP = "backup"; + protected static final String RECOVER = "recover"; + protected static final String COMMANDS = "commands"; + protected static final String REPORT = "report"; - // DB and sender - protected final DBContext db; - protected MessageSender sender; - protected SilentSender silent; + // DB and sender + protected final DBContext db; + protected MessageSender sender; + protected SilentSender silent; - // Bot token and username - private final String botToken; - private final String botUsername; + // Bot token and username + private final String botToken; + private final String botUsername; - // Ability registry - private Map abilities; + // Ability registry + private Map abilities; - // Reply registry - private List replies; + // Reply registry + private List replies; - public abstract int creatorId(); + public abstract int creatorId(); - protected BaseAbilityBot(String botToken, String botUsername, DBContext db, DefaultBotOptions botOptions) { - super(botOptions); + protected BaseAbilityBot(String botToken, String botUsername, DBContext db, DefaultBotOptions botOptions) { + super(botOptions); - this.botToken = botToken; - this.botUsername = botUsername; - this.db = db; - this.sender = new DefaultSender(this); - silent = new SilentSender(sender); + this.botToken = botToken; + this.botUsername = botUsername; + this.db = db; + this.sender = new DefaultSender(this); + silent = new SilentSender(sender); - registerAbilities(); - } - - /** - * @return the map of ID -> User - */ - protected Map users() { - return db.getMap(USERS); - } - - /** - * @return the map of Username -> ID - */ - protected Map userIds() { - return db.getMap(USER_ID); - } - - /** - * @return a blacklist containing all the IDs of the banned users - */ - protected Set blacklist() { - return db.getSet(BLACKLIST); - } - - /** - * @return an admin set of all the IDs of bot administrators - */ - protected Set admins() { - return db.getSet(ADMINS); - } - - /** - * @return the immutable map of String -> Ability - */ - public Map abilities() { - return abilities; - } - - /** - * @return the immutable list carrying the embedded replies - */ - public List replies() { - return replies; - } - - /** - * This method contains the stream of actions that are applied on any update. - *

- * It will correctly handle addition of users into the DB and the execution of abilities and replies. - * - * @param update the update received by Telegram's API - */ - public void onUpdateReceived(Update update) { - BotLogger.info(format("New update [%s] received at %s", update.getUpdateId(), now()), format("%s - %s", TAG, botUsername)); - BotLogger.info(update.toString(), TAG); - long millisStarted = System.currentTimeMillis(); - - Stream.of(update) - .filter(this::checkGlobalFlags) - .filter(this::checkBlacklist) - .map(this::addUser) - .filter(this::filterReply) - .map(this::getAbility) - .filter(this::validateAbility) - .filter(this::checkPrivacy) - .filter(this::checkLocality) - .filter(this::checkInput) - .filter(this::checkMessageFlags) - .map(this::getContext) - .map(this::consumeUpdate) - .forEach(this::postConsumption); - - long processingTime = System.currentTimeMillis() - millisStarted; - BotLogger.info(format("Processing of update [%s] ended at %s%n---> Processing time: [%d ms] <---%n", update.getUpdateId(), now(), processingTime), format("%s - %s", TAG, botUsername)); - } - - public String getBotToken() { - return botToken; - } - - public String getBotUsername() { - return botUsername; - } - - /** - * Test the update against the provided global flags. The default implementation is a passthrough to all updates. - *

- * This method should be overridden if the user wants to restrict bot usage to only certain updates. - * - * @param update a Telegram {@link Update} - * @return true if the update satisfies the global flags - */ - protected boolean checkGlobalFlags(Update update) { - return true; - } - - /** - * Gets the user with the specified username. - * - * @param username the username of the required user - * @return the user - */ - protected User getUser(String username) { - Integer id = userIds().get(username.toLowerCase()); - if (id == null) { - throw new IllegalStateException(format("Could not find ID corresponding to username [%s]", username)); + registerAbilities(); } - return getUser(id); - } - - /** - * Gets the user with the specified ID. - * - * @param id the id of the required user - * @return the user - */ - protected User getUser(int id) { - User user = users().get(id); - if (user == null) { - throw new IllegalStateException(format("Could not find user corresponding to id [%d]", id)); + /** + * @return the map of + */ + protected Map users() { + return db.getMap(USERS); } - return user; - } - - /** - * Gets the user with the specified username. If user was not found, the bot will send a message on Telegram. - * - * @param username the username of the required user - * @param ctx the message context with the originating user - * @return the id of the user - */ - protected int getUserIdSendError(String username, MessageContext ctx) { - try { - return getUser(username).getId(); - } catch (IllegalStateException ex) { - silent.send(getLocalizedMessage(USER_NOT_FOUND, ctx.user().getLanguageCode(), username), ctx.chatId()); - throw propagate(ex); + /** + * @return the map of + */ + protected Map userIds() { + return db.getMap(USER_ID); } - } - /** - *

- * Format of the report: - *

- * [command1] - [description1] - *

- * [command2] - [description2] - *

- * ... - *

- * Once you invoke it, the bot will send the available commands to the chat. This is a public ability so anyone can invoke it. - *

- * Usage: /commands - * - * @return the ability to report commands defined by the child bot. - */ - public Ability reportCommands() { - return builder() - .name(REPORT) - .locality(ALL) - .privacy(CREATOR) - .input(0) - .action(ctx -> { - String commands = abilities.entrySet().stream() - .filter(entry -> nonNull(entry.getValue().info())) - .map(entry -> { - String name = entry.getValue().name(); - String info = entry.getValue().info(); - return format("%s - %s", name, info); - }) - .sorted() - .reduce((a, b) -> format("%s%n%s", a, b)) - .orElse(getLocalizedMessage(ABILITY_COMMANDS_NOT_FOUND, ctx.user().getLanguageCode())); + /** + * @return a blacklist containing all the IDs of the banned users + */ + protected Set blacklist() { + return db.getSet(BLACKLIST); + } - silent.send(commands, ctx.chatId()); - }) - .build(); - } + /** + * @return an admin set of all the IDs of bot administrators + */ + protected Set admins() { + return db.getSet(ADMINS); + } - /** - * Default format: - *

- * PUBLIC - *

- * [command1] - [description1] - *

- * [command2] - [description2] - *

- * GROUP_ADMIN - *

- * [command1] - [description1] - *

- * ... - * - * @return the ability to print commands based on the privacy of the requesting user - */ - public Ability commands() { - return builder() - .name(COMMANDS) - .locality(USER) - .privacy(PUBLIC) - .input(0) - .action(ctx -> { - Privacy privacy = getPrivacy(ctx.update(), ctx.user().getId()); + /** + * @return the immutable map of + */ + public Map abilities() { + return abilities; + } - ListMultimap abilitiesPerPrivacy = abilities.entrySet().stream() - .map(entry -> { - String name = entry.getValue().name(); - String info = entry.getValue().info(); + /** + * @return the immutable list carrying the embedded replies + */ + public List replies() { + return replies; + } - if (!isEmpty(info)) - return Pair.of(entry.getValue().privacy(), format("/%s - %s", name, info)); - return Pair.of(entry.getValue().privacy(), format("/%s", name)); - }) - .sorted(comparing(Pair::b)) - .collect(() -> hashKeys().arrayListValues().build(), - (map, pair) -> map.put(pair.a(), pair.b()), - Multimap::putAll); + /** + * This method contains the stream of actions that are applied on any update. + *

+ * It will correctly handle addition of users into the DB and the execution of abilities and replies. + * + * @param update the update received by Telegram's API + */ + public void onUpdateReceived(Update update) { + log.info(format("[%s] New update [%s] received at %s", botUsername, update.getUpdateId(), now())); + log.info(update.toString()); + long millisStarted = System.currentTimeMillis(); - String commands = abilitiesPerPrivacy.asMap().entrySet().stream() - .filter(entry -> privacy.compareTo(entry.getKey()) >= 0) - .sorted(comparing(Entry::getKey)) - .map(entry -> - entry.getValue().stream() - .reduce(entry.getKey().toString(), (a, b) -> format("%s\n%s", a, b)) - ) - .collect(joining("\n")); + Stream.of(update) + .filter(this::checkGlobalFlags) + .filter(this::checkBlacklist) + .map(this::addUser) + .filter(this::filterReply) + .map(this::getAbility) + .filter(this::validateAbility) + .filter(this::checkPrivacy) + .filter(this::checkLocality) + .filter(this::checkInput) + .filter(this::checkMessageFlags) + .map(this::getContext) + .map(this::consumeUpdate) + .forEach(this::postConsumption); - if (commands.isEmpty()) - commands = getLocalizedMessage(ABILITY_COMMANDS_NOT_FOUND, ctx.user().getLanguageCode()); + long processingTime = System.currentTimeMillis() - millisStarted; + log.info(format("[%s] Processing of update [%s] ended at %s%n---> Processing time: [%d ms] <---%n", botUsername, update.getUpdateId(), now(), processingTime)); + } - silent.send(commands, ctx.chatId()); - }) - .build(); - } + public String getBotToken() { + return botToken; + } - /** - * This backup ability returns the object defined by {@link DBContext#backup()} as a message document. - *

- * This is a high-profile ability and is restricted to the CREATOR only. - *

- * Usage: /backup - * - * @return the ability to back-up the database of the bot - */ - public Ability backupDB() { - return builder() - .name(BACKUP) - .locality(USER) - .privacy(CREATOR) - .input(0) - .action(ctx -> { - File backup = new File("backup.json"); + public String getBotUsername() { + return botUsername; + } - try (PrintStream printStream = new PrintStream(backup)) { - printStream.print(db.backup()); - sender.sendDocument(new SendDocument() - .setDocument(backup) - .setChatId(ctx.chatId()) - ); - } catch (FileNotFoundException e) { - BotLogger.error("Error while fetching backup", TAG, e); - } catch (TelegramApiException e) { - BotLogger.error("Error while sending document/backup file", TAG, e); - } - }) - .build(); - } + /** + * Test the update against the provided global flags. The default implementation is a passthrough to all updates. + *

+ * This method should be overridden if the user wants to restrict bot usage to only certain updates. + * + * @param update a Telegram {@link Update} + * @return true if the update satisfies the global flags + */ + protected boolean checkGlobalFlags(Update update) { + return true; + } - /** - * Recovers the bot database using {@link DBContext#recover(Object)}. - *

- * The bot recovery process hugely depends on the implementation of the recovery method of {@link DBContext}. - *

- * Usage: /recover - * - * @return the ability to recover the database of the bot - */ - public Ability recoverDB() { - return builder() - .name(RECOVER) - .locality(USER) - .privacy(CREATOR) - .input(0) - .action(ctx -> silent.forceReply( - getLocalizedMessage(ABILITY_RECOVER_MESSAGE, ctx.user().getLanguageCode()), ctx.chatId())) - .reply(update -> { - String replyToMsg = update.getMessage().getReplyToMessage().getText(); - String recoverMessage = getLocalizedMessage(ABILITY_RECOVER_MESSAGE, AbilityUtils.getUser(update).getLanguageCode()); - if (!replyToMsg.equals(recoverMessage)) - return; + /** + * Gets the user with the specified username. + * + * @param username the username of the required user + * @return the user + */ + protected User getUser(String username) { + Integer id = userIds().get(username.toLowerCase()); + if (id == null) { + throw new IllegalStateException(format("Could not find ID corresponding to username [%s]", username)); + } - String fileId = update.getMessage().getDocument().getFileId(); - try (FileReader reader = new FileReader(downloadFileWithId(fileId))) { - String backupData = IOUtils.toString(reader); - if (db.recover(backupData)) { - send(ABILITY_RECOVER_SUCCESS, update); - } else { - send(ABILITY_RECOVER_FAIL, update); + return getUser(id); + } + + /** + * Gets the user with the specified ID. + * + * @param id the id of the required user + * @return the user + */ + protected User getUser(int id) { + User user = users().get(id); + if (user == null) { + throw new IllegalStateException(format("Could not find user corresponding to id [%d]", id)); + } + + return user; + } + + /** + * Gets the user with the specified username. If user was not found, the bot will send a message on Telegram. + * + * @param username the username of the required user + * @param ctx the message context with the originating user + * @return the id of the user + */ + protected int getUserIdSendError(String username, MessageContext ctx) { + try { + return getUser(username).getId(); + } catch (IllegalStateException ex) { + silent.send(getLocalizedMessage(USER_NOT_FOUND, ctx.user().getLanguageCode(), username), ctx.chatId()); + throw ex; + } + } + + /** + *

+ * Format of the report: + *

+ * [command1] - [description1] + *

+ * [command2] - [description2] + *

+ * ... + *

+ * Once you invoke it, the bot will send the available commands to the chat. This is a public ability so anyone can invoke it. + *

+ * Usage: /commands + * + * @return the ability to report commands defined by the child bot. + */ + public Ability reportCommands() { + return builder() + .name(REPORT) + .locality(ALL) + .privacy(CREATOR) + .input(0) + .action(ctx -> { + String commands = abilities.values().stream() + .filter(ability -> nonNull(ability.info())) + .map(ability -> { + String name = ability.name(); + String info = ability.info(); + return format("%s - %s", name, info); + }) + .sorted() + .reduce((a, b) -> format("%s%n%s", a, b)) + .orElse(getLocalizedMessage(ABILITY_COMMANDS_NOT_FOUND, ctx.user().getLanguageCode())); + + silent.send(commands, ctx.chatId()); + }) + .build(); + } + + /** + * Default format: + *

+ * PUBLIC + *

+ * [command1] - [description1] + *

+ * [command2] - [description2] + *

+ * GROUP_ADMIN + *

+ * [command1] - [description1] + *

+ * ... + * + * @return the ability to print commands based on the privacy of the requesting user + */ + public Ability commands() { + return builder() + .name(COMMANDS) + .locality(USER) + .privacy(PUBLIC) + .input(0) + .action(ctx -> { + Privacy privacy = getPrivacy(ctx.update(), ctx.user().getId()); + + ListMultimap abilitiesPerPrivacy = abilities.values().stream() + .map(ability -> { + String name = ability.name(); + String info = ability.info(); + + if (!isEmpty(info)) + return Pair.of(ability.privacy(), format("/%s - %s", name, info)); + return Pair.of(ability.privacy(), format("/%s", name)); + }) + .sorted(comparing(Pair::b)) + .collect(() -> hashKeys().arrayListValues().build(), + (map, pair) -> map.put(pair.a(), pair.b()), + Multimap::putAll); + + String commands = abilitiesPerPrivacy.asMap().entrySet().stream() + .filter(entry -> privacy.compareTo(entry.getKey()) >= 0) + .sorted(comparing(Entry::getKey)) + .map(entry -> + entry.getValue().stream() + .reduce(entry.getKey().toString(), (a, b) -> format("%s\n%s", a, b)) + ) + .collect(joining("\n")); + + if (commands.isEmpty()) + commands = getLocalizedMessage(ABILITY_COMMANDS_NOT_FOUND, ctx.user().getLanguageCode()); + + silent.send(commands, ctx.chatId()); + }) + .build(); + } + + /** + * This backup ability returns the object defined by {@link DBContext#backup()} as a message document. + *

+ * This is a high-profile ability and is restricted to the CREATOR only. + *

+ * Usage: /backup + * + * @return the ability to back-up the database of the bot + */ + public Ability backupDB() { + return builder() + .name(BACKUP) + .locality(USER) + .privacy(CREATOR) + .input(0) + .action(ctx -> { + File backup = new File("backup.json"); + + try (PrintStream printStream = new PrintStream(backup)) { + printStream.print(db.backup()); + sender.sendDocument(new SendDocument() + .setDocument(backup) + .setChatId(ctx.chatId()) + ); + } catch (FileNotFoundException e) { + log.error("Error while fetching backup", e); + } catch (TelegramApiException e) { + log.error("Error while sending document/backup file", e); + } + }) + .build(); + } + + /** + * Recovers the bot database using {@link DBContext#recover(Object)}. + *

+ * The bot recovery process hugely depends on the implementation of the recovery method of {@link DBContext}. + *

+ * Usage: /recover + * + * @return the ability to recover the database of the bot + */ + public Ability recoverDB() { + return builder() + .name(RECOVER) + .locality(USER) + .privacy(CREATOR) + .input(0) + .action(ctx -> silent.forceReply( + getLocalizedMessage(ABILITY_RECOVER_MESSAGE, ctx.user().getLanguageCode()), ctx.chatId())) + .reply(update -> { + String replyToMsg = update.getMessage().getReplyToMessage().getText(); + String recoverMessage = getLocalizedMessage(ABILITY_RECOVER_MESSAGE, AbilityUtils.getUser(update).getLanguageCode()); + if (!replyToMsg.equals(recoverMessage)) + return; + + String fileId = update.getMessage().getDocument().getFileId(); + try (FileReader reader = new FileReader(downloadFileWithId(fileId))) { + String backupData = IOUtils.toString(reader); + if (db.recover(backupData)) { + send(ABILITY_RECOVER_SUCCESS, update); + } else { + send(ABILITY_RECOVER_FAIL, update); + } + } catch (Exception e) { + log.error("Could not recover DB from backup", e); + send(ABILITY_RECOVER_ERROR, update); + } + }, MESSAGE, DOCUMENT, REPLY) + .build(); + } + + /** + * Banned users are accumulated in the blacklist. Use {@link DBContext#getSet(String)} with name specified by {@link BaseAbilityBot#BLACKLIST}. + *

+ * Usage: /ban @username + *

+ * Note that admins who try to ban the creator, get banned. + * + * @return the ability to ban the user from any kind of bot interaction + */ + public Ability banUser() { + return builder() + .name(BAN) + .locality(ALL) + .privacy(ADMIN) + .input(1) + .action(ctx -> { + String username = stripTag(ctx.firstArg()); + int userId = getUserIdSendError(username, ctx); + String bannedUser; + + // Protection from abuse + if (userId == creatorId()) { + userId = ctx.user().getId(); + bannedUser = isNullOrEmpty(ctx.user().getUserName()) ? addTag(ctx.user().getUserName()) : shortName(ctx.user()); + } else { + bannedUser = addTag(username); + } + + Set blacklist = blacklist(); + if (blacklist.contains(userId)) + sendMd(ABILITY_BAN_FAIL, ctx, escape(bannedUser)); + else { + blacklist.add(userId); + sendMd(ABILITY_BAN_SUCCESS, ctx, escape(bannedUser)); + } + }) + .post(commitTo(db)) + .build(); + } + + /** + * Usage: /unban @username + * + * @return the ability to unban a user + */ + public Ability unbanUser() { + return builder() + .name(UNBAN) + .locality(ALL) + .privacy(ADMIN) + .input(1) + .action(ctx -> { + String username = stripTag(ctx.firstArg()); + Integer userId = getUserIdSendError(username, ctx); + + Set blacklist = blacklist(); + + if (!blacklist.remove(userId)) + silent.sendMd(getLocalizedMessage(ABILITY_UNBAN_FAIL, ctx.user().getLanguageCode(), escape(username)), ctx.chatId()); + else { + silent.sendMd(getLocalizedMessage(ABILITY_UNBAN_SUCCESS, ctx.user().getLanguageCode(), escape(username)), ctx.chatId()); + } + }) + .post(commitTo(db)) + .build(); + } + + /** + * @return the ability to promote a user to a bot admin + */ + public Ability promoteAdmin() { + return builder() + .name(PROMOTE) + .locality(ALL) + .privacy(ADMIN) + .input(1) + .action(ctx -> { + String username = stripTag(ctx.firstArg()); + Integer userId = getUserIdSendError(username, ctx); + + Set admins = admins(); + if (admins.contains(userId)) + sendMd(ABILITY_PROMOTE_FAIL, ctx, escape(username)); + else { + admins.add(userId); + sendMd(ABILITY_PROMOTE_SUCCESS, ctx, escape(username)); + } + }).post(commitTo(db)) + .build(); + } + + /** + * @return the ability to demote an admin to a user + */ + public Ability demoteAdmin() { + return builder() + .name(DEMOTE) + .locality(ALL) + .privacy(ADMIN) + .input(1) + .action(ctx -> { + String username = stripTag(ctx.firstArg()); + Integer userId = getUserIdSendError(username, ctx); + + Set admins = admins(); + if (admins.remove(userId)) { + sendMd(ABILITY_DEMOTE_SUCCESS, ctx, escape(username)); + } else { + sendMd(ABILITY_DEMOTE_FAIL, ctx, escape(username)); + } + }) + .post(commitTo(db)) + .build(); + } + + /** + * Regular users and admins who try to claim the bot will get banned. + * + * @return the ability to claim yourself as the master and creator of the bot + */ + public Ability claimCreator() { + return builder() + .name(CLAIM) + .locality(ALL) + .privacy(CREATOR) + .input(0) + .action(ctx -> { + Set admins = admins(); + int id = creatorId(); + + if (admins.contains(id)) + send(ABILITY_CLAIM_FAIL, ctx); + else { + admins.add(id); + send(ABILITY_CLAIM_SUCCESS, ctx); + } + }) + .post(commitTo(db)) + .build(); + } + + private Optional send(String message, MessageContext ctx, String... args) { + return silent.send(getLocalizedMessage(message, ctx.user().getLanguageCode(), args), ctx.chatId()); + } + + private Optional sendMd(String message, MessageContext ctx, String... args) { + return silent.sendMd(getLocalizedMessage(message, ctx.user().getLanguageCode(), args), ctx.chatId()); + } + + private Optional send(String message, Update upd) { + Long chatId = upd.getMessage().getChatId(); + return silent.send(getLocalizedMessage(message, AbilityUtils.getUser(upd).getLanguageCode()), chatId); + } + + /** + * Registers the declared abilities using method reflection. Also, replies are accumulated using the built abilities and standalone methods that return a Reply. + *

+ * Only abilities and replies with the public accessor are registered! + */ + private void registerAbilities() { + try { + // Collect all classes that implement AbilityExtension declared in the bot + List extensions = stream(getClass().getMethods()) + .filter(checkReturnType(AbilityExtension.class)) + .map(returnExtension(this)) + .collect(Collectors.toList()); + + // Add the bot itself as it is an AbilityExtension + extensions.add(this); + + // Extract all abilities from every single extension instance + abilities = extensions.stream() + .flatMap(ext -> stream(ext.getClass().getMethods()) + .filter(checkReturnType(Ability.class)) + .map(returnAbility(ext))) + // Abilities are immutable, build it respectively + .collect(ImmutableMap::builder, + (b, a) -> b.put(a.name(), a), + (b1, b2) -> b1.putAll(b2.build())) + .build(); + + // Extract all replies from every single extension instance + Stream extensionReplies = extensions.stream() + .flatMap(ext -> stream(ext.getClass().getMethods()) + .filter(checkReturnType(Reply.class)) + .map(returnReply(ext))); + + // Replies can be standalone or attached to abilities, fetch those too + Stream abilityReplies = abilities.values().stream() + .flatMap(ability -> ability.replies().stream()); + + // Now create the replies registry (list) + replies = Stream.concat(abilityReplies, extensionReplies).collect( + ImmutableList::builder, + Builder::add, + (b1, b2) -> b1.addAll(b2.build())) + .build(); + } catch (IllegalStateException e) { + log.error("Duplicate names found while registering abilities. Make sure that the abilities declared don't clash with the reserved ones.", e); + throw new RuntimeException(e); + } + } + + /** + * @param clazz the type to be tested + * @return a predicate testing the return type of the method corresponding to the class parameter + */ + private Predicate checkReturnType(Class clazz) { + return method -> clazz.isAssignableFrom(method.getReturnType()); + } + + /** + * Invokes the method and retrieves its return {@link Reply}. + * + * @param obj an bot or extension that this method is invoked with + * @return a {@link Function} which returns the {@link Reply} returned by the given method + */ + private Function returnExtension(Object obj) { + return method -> { + try { + return (AbilityExtension) method.invoke(obj); + } catch (IllegalAccessException | InvocationTargetException e) { + log.error("Could not add ability extension", e); + throw new RuntimeException(e); } - } catch (Exception e) { - BotLogger.error("Could not recover DB from backup", TAG, e); - send(ABILITY_RECOVER_ERROR, update); - } - }, MESSAGE, DOCUMENT, REPLY) - .build(); - } - - /** - * Banned users are accumulated in the blacklist. Use {@link DBContext#getSet(String)} with name specified by {@link BaseAbilityBot#BLACKLIST}. - *

- * Usage: /ban @username - *

- * Note that admins who try to ban the creator, get banned. - * - * @return the ability to ban the user from any kind of bot interaction - */ - public Ability banUser() { - return builder() - .name(BAN) - .locality(ALL) - .privacy(ADMIN) - .input(1) - .action(ctx -> { - String username = stripTag(ctx.firstArg()); - int userId = getUserIdSendError(username, ctx); - String bannedUser; - - // Protection from abuse - if (userId == creatorId()) { - userId = ctx.user().getId(); - bannedUser = isNullOrEmpty(ctx.user().getUserName()) ? addTag(ctx.user().getUserName()) : shortName(ctx.user()); - } else { - bannedUser = addTag(username); - } - - Set blacklist = blacklist(); - if (blacklist.contains(userId)) - sendMd(ABILITY_BAN_FAIL, ctx, escape(bannedUser)); - else { - blacklist.add(userId); - sendMd(ABILITY_BAN_SUCCESS, ctx, escape(bannedUser)); - } - }) - .post(commitTo(db)) - .build(); - } - - /** - * Usage: /unban @username - * - * @return the ability to unban a user - */ - public Ability unbanUser() { - return builder() - .name(UNBAN) - .locality(ALL) - .privacy(ADMIN) - .input(1) - .action(ctx -> { - String username = stripTag(ctx.firstArg()); - Integer userId = getUserIdSendError(username, ctx); - - Set blacklist = blacklist(); - - if (!blacklist.remove(userId)) - silent.sendMd(getLocalizedMessage(ABILITY_UNBAN_FAIL, ctx.user().getLanguageCode(), escape(username)), ctx.chatId()); - else { - silent.sendMd(getLocalizedMessage(ABILITY_UNBAN_SUCCESS, ctx.user().getLanguageCode(), escape(username)), ctx.chatId()); - } - }) - .post(commitTo(db)) - .build(); - } - - /** - * @return the ability to promote a user to a bot admin - */ - public Ability promoteAdmin() { - return builder() - .name(PROMOTE) - .locality(ALL) - .privacy(ADMIN) - .input(1) - .action(ctx -> { - String username = stripTag(ctx.firstArg()); - Integer userId = getUserIdSendError(username, ctx); - - Set admins = admins(); - if (admins.contains(userId)) - sendMd(ABILITY_PROMOTE_FAIL, ctx, escape(username)); - else { - admins.add(userId); - sendMd(ABILITY_PROMOTE_SUCCESS, ctx, escape(username)); - } - }).post(commitTo(db)) - .build(); - } - - /** - * @return the ability to demote an admin to a user - */ - public Ability demoteAdmin() { - return builder() - .name(DEMOTE) - .locality(ALL) - .privacy(ADMIN) - .input(1) - .action(ctx -> { - String username = stripTag(ctx.firstArg()); - Integer userId = getUserIdSendError(username, ctx); - - Set admins = admins(); - if (admins.remove(userId)) { - sendMd(ABILITY_DEMOTE_SUCCESS, ctx, escape(username)); - } else { - sendMd(ABILITY_DEMOTE_FAIL, ctx, escape(username)); - } - }) - .post(commitTo(db)) - .build(); - } - - /** - * Regular users and admins who try to claim the bot will get banned. - * - * @return the ability to claim yourself as the master and creator of the bot - */ - public Ability claimCreator() { - return builder() - .name(CLAIM) - .locality(ALL) - .privacy(CREATOR) - .input(0) - .action(ctx -> { - Set admins = admins(); - int id = creatorId(); - - if (admins.contains(id)) - send(ABILITY_CLAIM_FAIL, ctx); - else { - admins.add(id); - send(ABILITY_CLAIM_SUCCESS, ctx); - } - }) - .post(commitTo(db)) - .build(); - } - - private Optional send(String message, MessageContext ctx, String... args) { - return silent.send(getLocalizedMessage(message, ctx.user().getLanguageCode(), args), ctx.chatId()); - } - - private Optional sendMd(String message, MessageContext ctx, String... args) { - return silent.sendMd(getLocalizedMessage(message, ctx.user().getLanguageCode(), args), ctx.chatId()); - } - - private Optional send(String message, Update upd) { - Long chatId = upd.getMessage().getChatId(); - return silent.send(getLocalizedMessage(message, AbilityUtils.getUser(upd).getLanguageCode()), chatId); - } - - /** - * Registers the declared abilities using method reflection. Also, replies are accumulated using the built abilities and standalone methods that return a Reply. - *

- * Only abilities and replies with the public accessor are registered! - */ - private void registerAbilities() { - try { - // Collect all classes that implement AbilityExtension declared in the bot - List extensions = stream(getClass().getMethods()) - .filter(checkReturnType(AbilityExtension.class)) - .map(returnExtension(this)) - .collect(Collectors.toList()); - - // Add the bot itself as it is an AbilityExtension - extensions.add(this); - - // Extract all abilities from every single extension instance - abilities = extensions.stream() - .flatMap(ext -> stream(ext.getClass().getMethods()) - .filter(checkReturnType(Ability.class)) - .map(returnAbility(ext))) - // Abilities are immutable, build it respectively - .collect(ImmutableMap::builder, - (b, a) -> b.put(a.name(), a), - (b1, b2) -> b1.putAll(b2.build())) - .build(); - - // Extract all replies from every single extension instance - Stream extensionReplies = extensions.stream() - .flatMap(ext -> stream(ext.getClass().getMethods()) - .filter(checkReturnType(Reply.class)) - .map(returnReply(ext))); - - // Replies can be standalone or attached to abilities, fetch those too - Stream abilityReplies = abilities.values().stream() - .flatMap(ability -> ability.replies().stream()); - - // Now create the replies registry (list) - replies = Stream.concat(abilityReplies, extensionReplies).collect( - ImmutableList::builder, - Builder::add, - (b1, b2) -> b1.addAll(b2.build())) - .build(); - } catch (IllegalStateException e) { - BotLogger.error(TAG, "Duplicate names found while registering abilities. Make sure that the abilities declared don't clash with the reserved ones.", e); - throw propagate(e); - } - } - - /** - * @param clazz the type to be tested - * @return a predicate testing the return type of the method corresponding to the class parameter - */ - private Predicate checkReturnType(Class clazz) { - return method -> clazz.isAssignableFrom(method.getReturnType()); - } - - /** - * Invokes the method and retrieves its return {@link Reply}. - * - * @param obj an bot or extension that this method is invoked with - * @return a {@link Function} which returns the {@link Reply} returned by the given method - */ - private Function returnExtension(Object obj) { - return method -> { - try { - return (AbilityExtension) method.invoke(obj); - } catch (IllegalAccessException | InvocationTargetException e) { - BotLogger.error("Could not add ability extension", TAG, e); - throw propagate(e); - } - }; - } - - /** - * Invokes the method and retrieves its return {@link Ability}. - * - * @param obj an bot or extension that this method is invoked with - * @return a {@link Function} which returns the {@link Ability} returned by the given method - */ - private Function returnAbility(Object obj) { - return method -> { - try { - return (Ability) method.invoke(obj); - } catch (IllegalAccessException | InvocationTargetException e) { - BotLogger.error("Could not add ability", TAG, e); - throw propagate(e); - } - }; - } - - /** - * Invokes the method and retrieves its return {@link Reply}. - * - * @param obj an bot or extension that this method is invoked with - * @return a {@link Function} which returns the {@link Reply} returned by the given method - */ - private Function returnReply(Object obj) { - return method -> { - try { - return (Reply) method.invoke(obj); - } catch (IllegalAccessException | InvocationTargetException e) { - BotLogger.error("Could not add reply", TAG, e); - throw propagate(e); - } - }; - } - - private void postConsumption(Pair pair) { - ofNullable(pair.b().postAction()) - .ifPresent(consumer -> consumer.accept(pair.a())); - } - - Pair consumeUpdate(Pair pair) { - pair.b().action().accept(pair.a()); - return pair; - } - - Pair getContext(Trio trio) { - Update update = trio.a(); - User user = AbilityUtils.getUser(update); - - return Pair.of(newContext(update, user, getChatId(update), trio.c()), trio.b()); - } - - boolean checkBlacklist(Update update) { - Integer id = AbilityUtils.getUser(update).getId(); - - return id == creatorId() || !blacklist().contains(id); - } - - boolean checkInput(Trio trio) { - String[] tokens = trio.c(); - int abilityTokens = trio.b().tokens(); - - boolean isOk = abilityTokens == 0 || (tokens.length > 0 && tokens.length == abilityTokens); - - if (!isOk) - silent.send( - getLocalizedMessage( - CHECK_INPUT_FAIL, - AbilityUtils.getUser(trio.a()).getLanguageCode(), - abilityTokens, abilityTokens == 1 ? "input" : "inputs"), - getChatId(trio.a())); - return isOk; - } - - boolean checkLocality(Trio trio) { - Update update = trio.a(); - Locality locality = isUserMessage(update) ? USER : GROUP; - Locality abilityLocality = trio.b().locality(); - - boolean isOk = abilityLocality == ALL || locality == abilityLocality; - - if (!isOk) - silent.send( - getLocalizedMessage( - CHECK_LOCALITY_FAIL, - AbilityUtils.getUser(trio.a()).getLanguageCode(), - abilityLocality.toString().toLowerCase()), - getChatId(trio.a())); - return isOk; - } - - boolean checkPrivacy(Trio trio) { - Update update = trio.a(); - User user = AbilityUtils.getUser(update); - Privacy privacy; - int id = user.getId(); - - privacy = getPrivacy(update, id); - - boolean isOk = privacy.compareTo(trio.b().privacy()) >= 0; - - if (!isOk) - silent.send( - getLocalizedMessage( - CHECK_PRIVACY_FAIL, - AbilityUtils.getUser(trio.a()).getLanguageCode()), - getChatId(trio.a())); - return isOk; - } - - @NotNull - private Privacy getPrivacy(Update update, int id) { - return isCreator(id) ? - CREATOR : isAdmin(id) ? - ADMIN : (isGroupUpdate(update) || isSuperGroupUpdate(update)) && isGroupAdmin(update, id) ? - GROUP_ADMIN : PUBLIC; - } - - private boolean isGroupAdmin(Update update, int id) { - GetChatAdministrators admins = new GetChatAdministrators().setChatId(getChatId(update)); - - return silent.execute(admins) - .orElse(new ArrayList<>()).stream() - .anyMatch(member -> member.getUser().getId() == id); - } - - private boolean isCreator(int id) { - return id == creatorId(); - } - - private boolean isAdmin(Integer id) { - return admins().contains(id); - } - - boolean validateAbility(Trio trio) { - return trio.b() != null; - } - - Trio getAbility(Update update) { - // Handle updates without messages - // Passing through this function means that the global flags have passed - Message msg = update.getMessage(); - if (!update.hasMessage() || !msg.hasText()) - return Trio.of(update, abilities.get(DEFAULT), new String[]{}); - - String[] tokens = msg.getText().split(" "); - - if (tokens[0].startsWith("/")) { - String abilityToken = stripBotUsername(tokens[0].substring(1)).toLowerCase(); - Ability ability = abilities.get(abilityToken); - tokens = Arrays.copyOfRange(tokens, 1, tokens.length); - return Trio.of(update, ability, tokens); - } else { - Ability ability = abilities.get(DEFAULT); - return Trio.of(update, ability, tokens); - } - } - - private String stripBotUsername(String token) { - return compile(format("@%s", botUsername), CASE_INSENSITIVE) - .matcher(token) - .replaceAll(""); - } - - Update addUser(Update update) { - User endUser = AbilityUtils.getUser(update); - - users().compute(endUser.getId(), (id, user) -> { - if (user == null) { - updateUserId(user, endUser); - return endUser; - } - - if (!user.equals(endUser)) { - updateUserId(user, endUser); - return endUser; - } - - return user; - }); - - db.commit(); - return update; - } - - private void updateUserId(User oldUser, User newUser) { - if (oldUser != null && oldUser.getUserName() != null) { - // Remove old username -> ID - userIds().remove(oldUser.getUserName()); + }; } - if (newUser.getUserName() != null) { - // Add new mapping with the new username - userIds().put(newUser.getUserName().toLowerCase(), newUser.getId()); + /** + * Invokes the method and retrieves its return {@link Ability}. + * + * @param obj an bot or extension that this method is invoked with + * @return a {@link Function} which returns the {@link Ability} returned by the given method + */ + private Function returnAbility(Object obj) { + return method -> { + try { + return (Ability) method.invoke(obj); + } catch (IllegalAccessException | InvocationTargetException e) { + log.error("Could not add ability", e); + throw new RuntimeException(e); + } + }; } - } - boolean filterReply(Update update) { - return replies.stream() - .filter(reply -> reply.isOkFor(update)) - .map(reply -> { - reply.actOn(update); - return false; - }) - .reduce(true, Boolean::logicalAnd); - } + /** + * Invokes the method and retrieves its return {@link Reply}. + * + * @param obj an bot or extension that this method is invoked with + * @return a {@link Function} which returns the {@link Reply} returned by the given method + */ + private Function returnReply(Object obj) { + return method -> { + try { + return (Reply) method.invoke(obj); + } catch (IllegalAccessException | InvocationTargetException e) { + log.error("Could not add reply", e); + throw new RuntimeException(e); + } + }; + } - boolean checkMessageFlags(Trio trio) { - Ability ability = trio.b(); - Update update = trio.a(); + private void postConsumption(Pair pair) { + ofNullable(pair.b().postAction()) + .ifPresent(consumer -> consumer.accept(pair.a())); + } - // The following variable is required to avoid bug #JDK-8044546 - BiFunction, Boolean> flagAnd = (flag, nextFlag) -> flag && nextFlag.test(update); - return ability.flags().stream() - .reduce(true, flagAnd, Boolean::logicalAnd); - } + Pair consumeUpdate(Pair pair) { + pair.b().action().accept(pair.a()); + return pair; + } - private File downloadFileWithId(String fileId) throws TelegramApiException { - return sender.downloadFile(sender.execute(new GetFile().setFileId(fileId))); - } + Pair getContext(Trio trio) { + Update update = trio.a(); + User user = AbilityUtils.getUser(update); + + return Pair.of(newContext(update, user, getChatId(update), trio.c()), trio.b()); + } + + boolean checkBlacklist(Update update) { + Integer id = AbilityUtils.getUser(update).getId(); + + return id == creatorId() || !blacklist().contains(id); + } + + boolean checkInput(Trio trio) { + String[] tokens = trio.c(); + int abilityTokens = trio.b().tokens(); + + boolean isOk = abilityTokens == 0 || (tokens.length > 0 && tokens.length == abilityTokens); + + if (!isOk) + silent.send( + getLocalizedMessage( + CHECK_INPUT_FAIL, + AbilityUtils.getUser(trio.a()).getLanguageCode(), + abilityTokens, abilityTokens == 1 ? "input" : "inputs"), + getChatId(trio.a())); + return isOk; + } + + boolean checkLocality(Trio trio) { + Update update = trio.a(); + Locality locality = isUserMessage(update) ? USER : GROUP; + Locality abilityLocality = trio.b().locality(); + + boolean isOk = abilityLocality == ALL || locality == abilityLocality; + + if (!isOk) + silent.send( + getLocalizedMessage( + CHECK_LOCALITY_FAIL, + AbilityUtils.getUser(trio.a()).getLanguageCode(), + abilityLocality.toString().toLowerCase()), + getChatId(trio.a())); + return isOk; + } + + boolean checkPrivacy(Trio trio) { + Update update = trio.a(); + User user = AbilityUtils.getUser(update); + Privacy privacy; + int id = user.getId(); + + privacy = getPrivacy(update, id); + + boolean isOk = privacy.compareTo(trio.b().privacy()) >= 0; + + if (!isOk) + silent.send( + getLocalizedMessage( + CHECK_PRIVACY_FAIL, + AbilityUtils.getUser(trio.a()).getLanguageCode()), + getChatId(trio.a())); + return isOk; + } + + @NotNull + private Privacy getPrivacy(Update update, int id) { + return isCreator(id) ? + CREATOR : isAdmin(id) ? + ADMIN : (isGroupUpdate(update) || isSuperGroupUpdate(update)) && isGroupAdmin(update, id) ? + GROUP_ADMIN : PUBLIC; + } + + private boolean isGroupAdmin(Update update, int id) { + GetChatAdministrators admins = new GetChatAdministrators().setChatId(getChatId(update)); + + return silent.execute(admins) + .orElse(new ArrayList<>()).stream() + .anyMatch(member -> member.getUser().getId() == id); + } + + private boolean isCreator(int id) { + return id == creatorId(); + } + + private boolean isAdmin(Integer id) { + return admins().contains(id); + } + + boolean validateAbility(Trio trio) { + return trio.b() != null; + } + + Trio getAbility(Update update) { + // Handle updates without messages + // Passing through this function means that the global flags have passed + Message msg = update.getMessage(); + if (!update.hasMessage() || !msg.hasText()) + return Trio.of(update, abilities.get(DEFAULT), new String[]{}); + + String[] tokens = msg.getText().split(" "); + + if (tokens[0].startsWith("/")) { + String abilityToken = stripBotUsername(tokens[0].substring(1)).toLowerCase(); + Ability ability = abilities.get(abilityToken); + tokens = Arrays.copyOfRange(tokens, 1, tokens.length); + return Trio.of(update, ability, tokens); + } else { + Ability ability = abilities.get(DEFAULT); + return Trio.of(update, ability, tokens); + } + } + + private String stripBotUsername(String token) { + return compile(format("@%s", botUsername), CASE_INSENSITIVE) + .matcher(token) + .replaceAll(""); + } + + Update addUser(Update update) { + User endUser = AbilityUtils.getUser(update); + + users().compute(endUser.getId(), (id, user) -> { + if (user == null) { + updateUserId(user, endUser); + return endUser; + } + + if (!user.equals(endUser)) { + updateUserId(user, endUser); + return endUser; + } + + return user; + }); + + db.commit(); + return update; + } + + private void updateUserId(User oldUser, User newUser) { + if (oldUser != null && oldUser.getUserName() != null) { + // Remove old username -> ID + userIds().remove(oldUser.getUserName()); + } + + if (newUser.getUserName() != null) { + // Add new mapping with the new username + userIds().put(newUser.getUserName().toLowerCase(), newUser.getId()); + } + } + + boolean filterReply(Update update) { + return replies.stream() + .filter(reply -> reply.isOkFor(update)) + .map(reply -> { + reply.actOn(update); + return false; + }) + .reduce(true, Boolean::logicalAnd); + } + + boolean checkMessageFlags(Trio trio) { + Ability ability = trio.b(); + Update update = trio.a(); + + // The following variable is required to avoid bug #JDK-8044546 + BiFunction, Boolean> flagAnd = (flag, nextFlag) -> flag && nextFlag.test(update); + return ability.flags().stream() + .reduce(true, flagAnd, Boolean::logicalAnd); + } + + private File downloadFileWithId(String fileId) throws TelegramApiException { + return sender.downloadFile(sender.execute(new GetFile().setFileId(fileId))); + } - private String escape(String username) { - return username.replace("_", "\\_"); - } + private String escape(String username) { + return username.replace("_", "\\_"); + } } \ No newline at end of file diff --git a/telegrambots-abilities/src/main/java/org/telegram/abilitybots/api/db/DBContext.java b/telegrambots-abilities/src/main/java/org/telegram/abilitybots/api/db/DBContext.java index 9fce2c8a..bb33ec22 100644 --- a/telegrambots-abilities/src/main/java/org/telegram/abilitybots/api/db/DBContext.java +++ b/telegrambots-abilities/src/main/java/org/telegram/abilitybots/api/db/DBContext.java @@ -11,7 +11,7 @@ import java.util.Set; /** * This interface represents the high-level methods exposed to the user when handling an {@link Update}. * Example usage: - *

Ability.builder().action(ctx -> {db.getSet(USERS); doSomething();})*

+ *

Ability.builder().action(ctx -> {db.getSet(USERS); doSomething();})

* {@link BaseAbilityBot} contains a handle on the db that the user can use inside his declared abilities. * * @author Abbas Abou Daya diff --git a/telegrambots-abilities/src/main/java/org/telegram/abilitybots/api/db/MapDBContext.java b/telegrambots-abilities/src/main/java/org/telegram/abilitybots/api/db/MapDBContext.java index 781d5b87..a6977917 100644 --- a/telegrambots-abilities/src/main/java/org/telegram/abilitybots/api/db/MapDBContext.java +++ b/telegrambots-abilities/src/main/java/org/telegram/abilitybots/api/db/MapDBContext.java @@ -3,25 +3,29 @@ package org.telegram.abilitybots.api.db; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.ObjectMapper; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; import org.mapdb.Atomic; import org.mapdb.DB; import org.mapdb.DBMaker; import org.mapdb.Serializer; import org.telegram.abilitybots.api.util.Pair; -import org.telegram.telegrambots.meta.logging.BotLogger; import java.io.IOException; -import java.util.*; +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.StringJoiner; import static com.google.common.collect.Lists.newArrayList; -import static com.google.common.collect.Maps.newHashMap; import static com.google.common.collect.Sets.newHashSet; import static java.lang.String.format; import static java.util.Objects.isNull; import static java.util.stream.Collectors.toMap; import static java.util.stream.StreamSupport.stream; import static org.mapdb.Serializer.JAVA; -import static org.telegram.abilitybots.api.bot.BaseAbilityBot.USERS; /** * An implementation of {@link DBContext} that relies on a {@link DB}. @@ -31,7 +35,7 @@ import static org.telegram.abilitybots.api.bot.BaseAbilityBot.USERS; */ @SuppressWarnings({"unchecked", "WeakerAccess"}) public class MapDBContext implements DBContext { - private static final String TAG = DBContext.class.getSimpleName(); + private static final Logger log = LogManager.getLogger(MapDBContext.class); private final DB db; private final ObjectMapper objectMapper; @@ -71,7 +75,6 @@ public class MapDBContext implements DBContext { .fileDB(name) .fileMmapEnableIfSupported() .closeOnJvmShutdown() - .cleanerHackEnable() .transactionEnable() .fileDeleteAfterClose() .make(); @@ -123,7 +126,7 @@ public class MapDBContext implements DBContext { doRecover(backupData); return true; } catch (IOException e) { - BotLogger.error(format("Could not recover DB data from file with String representation %s", backup), TAG, e); + log.error(format("Could not recover DB data from file with String representation %s", backup), e); // Attempt to fallback to data snapshot before recovery doRecover(snapshot); return false; @@ -204,7 +207,7 @@ public class MapDBContext implements DBContext { List entryList = (List) value; getList(name).addAll(entryList); } else { - BotLogger.error(TAG, format("Unable to identify object type during DB recovery, entry name: %s", name)); + log.error(format("Unable to identify object type during DB recovery, entry name: %s", name)); } }); commit(); @@ -214,7 +217,7 @@ public class MapDBContext implements DBContext { try { return objectMapper.writeValueAsString(obj); } catch (JsonProcessingException e) { - BotLogger.info(format("Failed to read the JSON representation of object: %s", obj), TAG, e); + log.info(format("Failed to read the JSON representation of object: %s", obj), e); return "Error reading required data..."; } } diff --git a/telegrambots-abilities/src/main/java/org/telegram/abilitybots/api/objects/Ability.java b/telegrambots-abilities/src/main/java/org/telegram/abilitybots/api/objects/Ability.java index 75259dc3..c3004c8b 100644 --- a/telegrambots-abilities/src/main/java/org/telegram/abilitybots/api/objects/Ability.java +++ b/telegrambots-abilities/src/main/java/org/telegram/abilitybots/api/objects/Ability.java @@ -2,8 +2,9 @@ package org.telegram.abilitybots.api.objects; import com.google.common.base.MoreObjects; import com.google.common.base.Objects; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; import org.telegram.telegrambots.meta.api.objects.Update; -import org.telegram.telegrambots.meta.logging.BotLogger; import java.util.Arrays; import java.util.List; @@ -34,7 +35,7 @@ import static org.apache.commons.lang3.StringUtils.*; * @author Abbas Abou Daya */ public final class Ability { - private static final String TAG = Ability.class.getSimpleName(); + private static final Logger log = LogManager.getLogger(Ability.class); private final String name; private final String info; @@ -63,7 +64,7 @@ public final class Ability { this.action = checkNotNull(action, "Method action can't be empty. Please assign a function by using .action() method"); if (postAction == null) - BotLogger.info(TAG, format("No post action was detected for method with name [%s]", name)); + log.info(format("No post action was detected for method with name [%s]", name)); this.flags = ofNullable(flags).map(Arrays::asList).orElse(newArrayList()); diff --git a/telegrambots-abilities/src/main/java/org/telegram/abilitybots/api/sender/SilentSender.java b/telegrambots-abilities/src/main/java/org/telegram/abilitybots/api/sender/SilentSender.java index a6cb37f9..b5d48bfb 100644 --- a/telegrambots-abilities/src/main/java/org/telegram/abilitybots/api/sender/SilentSender.java +++ b/telegrambots-abilities/src/main/java/org/telegram/abilitybots/api/sender/SilentSender.java @@ -1,11 +1,12 @@ package org.telegram.abilitybots.api.sender; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; import org.telegram.telegrambots.meta.api.methods.BotApiMethod; import org.telegram.telegrambots.meta.api.methods.send.SendMessage; import org.telegram.telegrambots.meta.api.objects.Message; import org.telegram.telegrambots.meta.api.objects.replykeyboard.ForceReplyKeyboard; import org.telegram.telegrambots.meta.exceptions.TelegramApiException; -import org.telegram.telegrambots.meta.logging.BotLogger; import java.io.Serializable; import java.util.Optional; @@ -17,7 +18,7 @@ import java.util.Optional; * @author Abbas Abou Daya */ public class SilentSender { - private static final String TAG = SilentSender.class.getSimpleName(); + private static final Logger log = LogManager.getLogger(SilentSender.class); private final MessageSender sender; @@ -46,7 +47,7 @@ public class SilentSender { try { return Optional.ofNullable(sender.execute(method)); } catch (TelegramApiException e) { - BotLogger.error("Could not execute bot API method", TAG, e); + log.error("Could not execute bot API method", e); return Optional.empty(); } } @@ -55,7 +56,7 @@ public class SilentSender { try { return Optional.ofNullable(sender.execute(method)); } catch (TelegramApiException e) { - BotLogger.error("Could not execute bot API method", TAG, e); + log.error("Could not execute bot API method", e); return Optional.empty(); } } diff --git a/telegrambots-abilities/src/test/java/org/telegram/abilitybots/api/bot/AbilityBotI18nTest.java b/telegrambots-abilities/src/test/java/org/telegram/abilitybots/api/bot/AbilityBotI18nTest.java index 456a2424..5494c595 100644 --- a/telegrambots-abilities/src/test/java/org/telegram/abilitybots/api/bot/AbilityBotI18nTest.java +++ b/telegrambots-abilities/src/test/java/org/telegram/abilitybots/api/bot/AbilityBotI18nTest.java @@ -1,8 +1,8 @@ package org.telegram.abilitybots.api.bot; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import org.telegram.abilitybots.api.db.DBContext; import org.telegram.abilitybots.api.objects.MessageContext; import org.telegram.abilitybots.api.sender.MessageSender; @@ -18,7 +18,7 @@ import static org.mockito.internal.verification.VerificationModeFactory.times; import static org.telegram.abilitybots.api.bot.AbilityBotTest.mockContext; import static org.telegram.abilitybots.api.db.MapDBContext.offlineInstance; -public class AbilityBotI18nTest { +class AbilityBotI18nTest { private static final User NO_LANGUAGE_USER = new User(1, "first", false, "last", "username", null); private static final User ITALIAN_USER = new User(2, "first", false, "last", "username", "it-IT"); @@ -28,8 +28,8 @@ public class AbilityBotI18nTest { private MessageSender sender; private SilentSender silent; - @Before - public void setUp() { + @BeforeEach + void setUp() { db = offlineInstance("db"); bot = new NoPublicCommandsBot(EMPTY, EMPTY, db); @@ -38,11 +38,16 @@ public class AbilityBotI18nTest { bot.sender = sender; bot.silent = silent; + } + @AfterEach + void tearDown() throws IOException { + db.clear(); + db.close(); } @Test - public void missingPublicCommandsLocalizedInEnglishByDefault() { + void missingPublicCommandsLocalizedInEnglishByDefault() { MessageContext context = mockContext(NO_LANGUAGE_USER); bot.reportCommands().action().accept(context); @@ -52,7 +57,7 @@ public class AbilityBotI18nTest { } @Test - public void missingPublicCommandsLocalizedInItalian() { + void missingPublicCommandsLocalizedInItalian() { MessageContext context = mockContext(ITALIAN_USER); bot.reportCommands().action().accept(context); @@ -61,15 +66,9 @@ public class AbilityBotI18nTest { .send("Non sono presenti comandi disponibile.", ITALIAN_USER.getId()); } - @After - public void tearDown() throws IOException { - db.clear(); - db.close(); - } - public static class NoPublicCommandsBot extends AbilityBot { - protected NoPublicCommandsBot(String botToken, String botUsername, DBContext db) { + NoPublicCommandsBot(String botToken, String botUsername, DBContext db) { super(botToken, botUsername, db); } diff --git a/telegrambots-abilities/src/test/java/org/telegram/abilitybots/api/bot/AbilityBotTest.java b/telegrambots-abilities/src/test/java/org/telegram/abilitybots/api/bot/AbilityBotTest.java index 7ad96030..a1c5e8a5 100644 --- a/telegrambots-abilities/src/test/java/org/telegram/abilitybots/api/bot/AbilityBotTest.java +++ b/telegrambots-abilities/src/test/java/org/telegram/abilitybots/api/bot/AbilityBotTest.java @@ -3,9 +3,11 @@ package org.telegram.abilitybots.api.bot; import com.google.common.collect.ImmutableMap; import com.google.common.io.Files; import org.jetbrains.annotations.NotNull; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.ArgumentMatchers; import org.telegram.abilitybots.api.db.DBContext; import org.telegram.abilitybots.api.objects.*; import org.telegram.abilitybots.api.sender.MessageSender; @@ -13,7 +15,12 @@ import org.telegram.abilitybots.api.sender.SilentSender; import org.telegram.abilitybots.api.util.Pair; import org.telegram.abilitybots.api.util.Trio; import org.telegram.telegrambots.meta.api.methods.groupadministration.GetChatAdministrators; -import org.telegram.telegrambots.meta.api.objects.*; +import org.telegram.telegrambots.meta.api.objects.ChatMember; +import org.telegram.telegrambots.meta.api.objects.Document; +import org.telegram.telegrambots.meta.api.objects.File; +import org.telegram.telegrambots.meta.api.objects.Message; +import org.telegram.telegrambots.meta.api.objects.Update; +import org.telegram.telegrambots.meta.api.objects.User; import org.telegram.telegrambots.meta.exceptions.TelegramApiException; import java.io.BufferedWriter; @@ -32,9 +39,13 @@ import static java.util.Optional.empty; import static org.apache.commons.io.FileUtils.deleteQuietly; import static org.apache.commons.lang3.ArrayUtils.addAll; import static org.apache.commons.lang3.StringUtils.EMPTY; -import static org.junit.Assert.*; -import static org.mockito.Matchers.any; -import static org.mockito.Mockito.*; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.Mockito.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; import static org.mockito.internal.verification.VerificationModeFactory.times; import static org.telegram.abilitybots.api.bot.DefaultBot.getDefaultBuilder; import static org.telegram.abilitybots.api.db.MapDBContext.offlineInstance; @@ -62,8 +73,8 @@ public class AbilityBotTest { private MessageSender sender; private SilentSender silent; - @Before - public void setUp() { + @BeforeEach + void setUp() { db = offlineInstance("db"); bot = new DefaultBot(EMPTY, EMPTY, db); @@ -74,8 +85,14 @@ public class AbilityBotTest { bot.silent = silent; } + @AfterEach + void tearDown() throws IOException { + db.clear(); + db.close(); + } + @Test - public void sendsPrivacyViolation() { + void sendsPrivacyViolation() { Update update = mockFullUpdate(USER, "/admin"); bot.onUpdateReceived(update); @@ -84,7 +101,7 @@ public class AbilityBotTest { } @Test - public void sendsLocalityViolation() { + void sendsLocalityViolation() { Update update = mockFullUpdate(USER, "/group"); bot.onUpdateReceived(update); @@ -94,7 +111,7 @@ public class AbilityBotTest { } @Test - public void sendsInputArgsViolation() { + void sendsInputArgsViolation() { Update update = mockFullUpdate(USER, "/count 1 2 3"); bot.onUpdateReceived(update); @@ -103,7 +120,7 @@ public class AbilityBotTest { } @Test - public void canProcessRepliesIfSatisfyRequirements() { + void canProcessRepliesIfSatisfyRequirements() { Update update = mockFullUpdate(USER, "must reply"); // False means the update was not pushed down the stream since it has been consumed by the reply @@ -112,7 +129,7 @@ public class AbilityBotTest { } @Test - public void canBackupDB() throws TelegramApiException { + void canBackupDB() throws TelegramApiException { MessageContext context = defaultContext(); bot.backupDB().action().accept(context); @@ -122,21 +139,23 @@ public class AbilityBotTest { } @Test - public void canRecoverDB() throws TelegramApiException, IOException { + void canRecoverDB() throws TelegramApiException, IOException { Update update = mockBackupUpdate(); Object backup = getDbBackup(); java.io.File backupFile = createBackupFile(backup); - when(sender.downloadFile(any(File.class))).thenReturn(backupFile); + // Support for null parameter matching since due to mocking API changes + when(sender.downloadFile(ArgumentMatchers.isNull())).thenReturn(backupFile); + bot.recoverDB().replies().get(0).actOn(update); verify(silent, times(1)).send(RECOVER_SUCCESS, GROUP_ID); - assertEquals("Bot recovered but the DB is still not in sync", db.getSet(TEST), newHashSet(TEST)); - assertTrue("Could not delete backup file", backupFile.delete()); + assertEquals(db.getSet(TEST), newHashSet(TEST), "Bot recovered but the DB is still not in sync"); + assertTrue(backupFile.delete(), "Could not delete backup file"); } @Test - public void canFilterOutReplies() { + void canFilterOutReplies() { Update update = mock(Update.class); when(update.hasMessage()).thenReturn(false); @@ -144,7 +163,7 @@ public class AbilityBotTest { } @Test - public void canDemote() { + void canDemote() { addUsers(USER); bot.admins().add(USER.getId()); @@ -154,11 +173,11 @@ public class AbilityBotTest { Set actual = bot.admins(); Set expected = emptySet(); - assertEquals("Could not sudont super-admin", expected, actual); + assertEquals(expected, actual, "Could not sudont super-admin"); } @Test - public void canPromote() { + void canPromote() { addUsers(USER); MessageContext context = defaultContext(); @@ -167,11 +186,11 @@ public class AbilityBotTest { Set actual = bot.admins(); Set expected = newHashSet(USER.getId()); - assertEquals("Could not sudo user", expected, actual); + assertEquals(expected, actual, "Could not sudo user"); } @Test - public void canBanUser() { + void canBanUser() { addUsers(USER); MessageContext context = defaultContext(); @@ -179,11 +198,11 @@ public class AbilityBotTest { Set actual = bot.blacklist(); Set expected = newHashSet(USER.getId()); - assertEquals("The ban was not emplaced", expected, actual); + assertEquals(expected, actual, "The ban was not emplaced"); } @Test - public void canUnbanUser() { + void canUnbanUser() { addUsers(USER); bot.blacklist().add(USER.getId()); @@ -193,7 +212,7 @@ public class AbilityBotTest { Set actual = bot.blacklist(); Set expected = newHashSet(); - assertEquals("The ban was not lifted", expected, actual); + assertEquals(expected, actual, "The ban was not lifted"); } @NotNull @@ -202,7 +221,7 @@ public class AbilityBotTest { } @Test - public void cannotBanCreator() { + void cannotBanCreator() { addUsers(USER, CREATOR); MessageContext context = mockContext(USER, GROUP_ID, CREATOR.getUserName()); @@ -210,7 +229,7 @@ public class AbilityBotTest { Set actual = bot.blacklist(); Set expected = newHashSet(USER.getId()); - assertEquals("Impostor was not added to the blacklist", expected, actual); + assertEquals(expected, actual, "Impostor was not added to the blacklist"); } private void addUsers(User... users) { @@ -221,18 +240,18 @@ public class AbilityBotTest { } @Test - public void creatorCanClaimBot() { + void creatorCanClaimBot() { MessageContext context = mockContext(CREATOR, GROUP_ID); bot.claimCreator().action().accept(context); Set actual = bot.admins(); Set expected = newHashSet(CREATOR.getId()); - assertEquals("Creator was not properly added to the super admins set", expected, actual); + assertEquals(expected, actual, "Creator was not properly added to the super admins set"); } @Test - public void bannedCreatorPassesBlacklistCheck() { + void bannedCreatorPassesBlacklistCheck() { bot.blacklist().add(CREATOR.getId()); Update update = mock(Update.class); Message message = mock(Message.class); @@ -241,11 +260,11 @@ public class AbilityBotTest { mockUser(update, message, user); boolean notBanned = bot.checkBlacklist(update); - assertTrue("Creator is banned", notBanned); + assertTrue(notBanned, "Creator is banned"); } @Test - public void canAddUser() { + void canAddUser() { Update update = mock(Update.class); Message message = mock(Message.class); @@ -255,12 +274,12 @@ public class AbilityBotTest { Map expectedUserIds = ImmutableMap.of(USER.getUserName(), USER.getId()); Map expectedUsers = ImmutableMap.of(USER.getId(), USER); - assertEquals("User was not added", expectedUserIds, bot.userIds()); - assertEquals("User was not added", expectedUsers, bot.users()); + assertEquals(expectedUserIds, bot.userIds(), "User was not added"); + assertEquals(expectedUsers, bot.users(), "User was not added"); } @Test - public void canEditUser() { + void canEditUser() { addUsers(USER); Update update = mock(Update.class); Message message = mock(Message.class); @@ -277,22 +296,22 @@ public class AbilityBotTest { Map expectedUserIds = ImmutableMap.of(changedUser.getUserName(), changedUser.getId()); Map expectedUsers = ImmutableMap.of(changedUser.getId(), changedUser); - assertEquals("User was not properly edited", bot.userIds(), expectedUserIds); - assertEquals("User was not properly edited", expectedUsers, expectedUsers); + assertEquals(bot.userIds(), expectedUserIds, "User was not properly edited"); + assertEquals(expectedUsers, expectedUsers, "User was not properly edited"); } @Test - public void canValidateAbility() { + void canValidateAbility() { Trio invalidPair = Trio.of(null, null, null); Ability validAbility = getDefaultBuilder().build(); Trio validPair = Trio.of(null, validAbility, null); - assertFalse("Bot can't validate ability properly", bot.validateAbility(invalidPair)); - assertTrue("Bot can't validate ability properly", bot.validateAbility(validPair)); + assertFalse(bot.validateAbility(invalidPair), "Bot can't validate ability properly"); + assertTrue(bot.validateAbility(validPair), "Bot can't validate ability properly"); } @Test - public void canCheckInput() { + void canCheckInput() { Update update = mockFullUpdate(USER, "/something"); Ability abilityWithOneInput = getDefaultBuilder() .build(); @@ -303,19 +322,19 @@ public class AbilityBotTest { Trio trioOneArg = Trio.of(update, abilityWithOneInput, TEXT); Trio trioZeroArg = Trio.of(update, abilityWithZeroInput, TEXT); - assertTrue("Unexpected result when applying token filter", bot.checkInput(trioOneArg)); + assertTrue(bot.checkInput(trioOneArg), "Unexpected result when applying token filter"); trioOneArg = Trio.of(update, abilityWithOneInput, addAll(TEXT, TEXT)); - assertFalse("Unexpected result when applying token filter", bot.checkInput(trioOneArg)); + assertFalse(bot.checkInput(trioOneArg), "Unexpected result when applying token filter"); - assertTrue("Unexpected result when applying token filter", bot.checkInput(trioZeroArg)); + assertTrue(bot.checkInput(trioZeroArg), "Unexpected result when applying token filter"); trioZeroArg = Trio.of(update, abilityWithZeroInput, EMPTY_ARRAY); - assertTrue("Unexpected result when applying token filter", bot.checkInput(trioZeroArg)); + assertTrue(bot.checkInput(trioZeroArg), "Unexpected result when applying token filter"); } @Test - public void canCheckPrivacy() { + void canCheckPrivacy() { Update update = mock(Update.class); Message message = mock(Message.class); User user = mock(User.class); @@ -331,14 +350,14 @@ public class AbilityBotTest { mockUser(update, message, user); - assertTrue("Unexpected result when checking for privacy", bot.checkPrivacy(publicTrio)); - assertFalse("Unexpected result when checking for privacy", bot.checkPrivacy(groupAdminTrio)); - assertFalse("Unexpected result when checking for privacy", bot.checkPrivacy(adminTrio)); - assertFalse("Unexpected result when checking for privacy", bot.checkPrivacy(creatorTrio)); + assertTrue(bot.checkPrivacy(publicTrio), "Unexpected result when checking for privacy"); + assertFalse(bot.checkPrivacy(groupAdminTrio), "Unexpected result when checking for privacy"); + assertFalse(bot.checkPrivacy(adminTrio), "Unexpected result when checking for privacy"); + assertFalse(bot.checkPrivacy(creatorTrio), "Unexpected result when checking for privacy"); } @Test - public void canValidateGroupAdminPrivacy() { + void canValidateGroupAdminPrivacy() { Update update = mock(Update.class); Message message = mock(Message.class); User user = mock(User.class); @@ -355,11 +374,11 @@ public class AbilityBotTest { when(silent.execute(any(GetChatAdministrators.class))).thenReturn(Optional.of(newArrayList(member))); - assertTrue("Unexpected result when checking for privacy", bot.checkPrivacy(groupAdminTrio)); + assertTrue(bot.checkPrivacy(groupAdminTrio), "Unexpected result when checking for privacy"); } @Test - public void canRestrictNormalUsersFromGroupAdminAbilities() { + void canRestrictNormalUsersFromGroupAdminAbilities() { Update update = mock(Update.class); Message message = mock(Message.class); User user = mock(User.class); @@ -372,11 +391,11 @@ public class AbilityBotTest { when(silent.execute(any(GetChatAdministrators.class))).thenReturn(empty()); - assertFalse("Unexpected result when checking for privacy", bot.checkPrivacy(groupAdminTrio)); + assertFalse(bot.checkPrivacy(groupAdminTrio), "Unexpected result when checking for privacy"); } @Test - public void canBlockAdminsFromCreatorAbilities() { + void canBlockAdminsFromCreatorAbilities() { Update update = mock(Update.class); Message message = mock(Message.class); User user = mock(User.class); @@ -387,11 +406,11 @@ public class AbilityBotTest { bot.admins().add(USER.getId()); mockUser(update, message, user); - assertFalse("Unexpected result when checking for privacy", bot.checkPrivacy(creatorTrio)); + assertFalse(bot.checkPrivacy(creatorTrio), "Unexpected result when checking for privacy"); } @Test - public void canCheckLocality() { + void canCheckLocality() { Update update = mock(Update.class); Message message = mock(Message.class); User user = mock(User.class); @@ -406,13 +425,13 @@ public class AbilityBotTest { mockUser(update, message, user); when(message.isUserMessage()).thenReturn(true); - assertTrue("Unexpected result when checking for locality", bot.checkLocality(publicTrio)); - assertTrue("Unexpected result when checking for locality", bot.checkLocality(userTrio)); - assertFalse("Unexpected result when checking for locality", bot.checkLocality(groupTrio)); + assertTrue(bot.checkLocality(publicTrio), "Unexpected result when checking for locality"); + assertTrue(bot.checkLocality(userTrio), "Unexpected result when checking for locality"); + assertFalse(bot.checkLocality(groupTrio), "Unexpected result when checking for locality"); } @Test - public void canRetrieveContext() { + void canRetrieveContext() { Update update = mock(Update.class); Message message = mock(Message.class); Ability ability = getDefaultBuilder().build(); @@ -424,17 +443,17 @@ public class AbilityBotTest { Pair actualPair = bot.getContext(trio); Pair expectedPair = Pair.of(newContext(update, USER, GROUP_ID, TEXT), ability); - assertEquals("Unexpected result when fetching for context", expectedPair, actualPair); + assertEquals(expectedPair, actualPair, "Unexpected result when fetching for context"); } @Test - public void defaultGlobalFlagIsTrue() { + void defaultGlobalFlagIsTrue() { Update update = mock(Update.class); - assertTrue("Unexpected result when checking for the default global flags", bot.checkGlobalFlags(update)); + assertTrue(bot.checkGlobalFlags(update), "Unexpected result when checking for the default global flags"); } - @Test(expected = ArithmeticException.class) - public void canConsumeUpdate() { + @Test + void canConsumeUpdate() { Ability ability = getDefaultBuilder() .action((context) -> { int x = 1 / 0; @@ -443,11 +462,11 @@ public class AbilityBotTest { Pair pair = Pair.of(context, ability); - bot.consumeUpdate(pair); + Assertions.assertThrows(ArithmeticException.class, () -> bot.consumeUpdate(pair)); } @Test - public void canFetchAbility() { + void canFetchAbility() { Update update = mock(Update.class); Message message = mock(Message.class); @@ -462,11 +481,11 @@ public class AbilityBotTest { Ability expected = bot.testAbility(); Ability actual = trio.b(); - assertEquals("Wrong ability was fetched", expected, actual); + assertEquals(expected, actual, "Wrong ability was fetched"); } @Test - public void canFetchAbilityCaseInsensitive() { + void canFetchAbilityCaseInsensitive() { Update update = mock(Update.class); Message message = mock(Message.class); @@ -481,11 +500,11 @@ public class AbilityBotTest { Ability expected = bot.testAbility(); Ability actual = trio.b(); - assertEquals("Wrong ability was fetched", expected, actual); + assertEquals(expected, actual, "Wrong ability was fetched"); } @Test - public void canFetchDefaultAbility() { + void canFetchDefaultAbility() { Update update = mock(Update.class); Message message = mock(Message.class); @@ -498,11 +517,11 @@ public class AbilityBotTest { Ability expected = bot.defaultAbility(); Ability actual = trio.b(); - assertEquals("Wrong ability was fetched", expected, actual); + assertEquals(expected, actual, "Wrong ability was fetched"); } @Test - public void canCheckAbilityFlags() { + void canCheckAbilityFlags() { Update update = mock(Update.class); Message message = mock(Message.class); @@ -517,12 +536,12 @@ public class AbilityBotTest { Trio docTrio = Trio.of(update, documentAbility, TEXT); Trio textTrio = Trio.of(update, textAbility, TEXT); - assertFalse("Unexpected result when checking for message flags", bot.checkMessageFlags(docTrio)); - assertTrue("Unexpected result when checking for message flags", bot.checkMessageFlags(textTrio)); + assertFalse(bot.checkMessageFlags(docTrio), "Unexpected result when checking for message flags"); + assertTrue(bot.checkMessageFlags(textTrio), "Unexpected result when checking for message flags"); } @Test - public void canReportCommands() { + void canReportCommands() { MessageContext context = mockContext(USER, GROUP_ID); bot.reportCommands().action().accept(context); @@ -531,12 +550,12 @@ public class AbilityBotTest { } @NotNull - public static MessageContext mockContext(User user) { + static MessageContext mockContext(User user) { return mockContext(user, user.getId()); } @NotNull - public static MessageContext mockContext(User user, long groupId, String... args) { + static MessageContext mockContext(User user, long groupId, String... args) { Update update = mock(Update.class); Message message = mock(Message.class); @@ -550,7 +569,7 @@ public class AbilityBotTest { } @Test - public void canPrintCommandsBasedOnPrivacy() { + void canPrintCommandsBasedOnPrivacy() { Update update = mock(Update.class); Message message = mock(Message.class); @@ -566,7 +585,7 @@ public class AbilityBotTest { } @Test - public void printsOnlyPublicCommandsForNormalUser() { + void printsOnlyPublicCommandsForNormalUser() { Update update = mock(Update.class); Message message = mock(Message.class); @@ -582,12 +601,6 @@ public class AbilityBotTest { verify(silent, times(1)).send(expected, GROUP_ID); } - @After - public void tearDown() throws IOException { - db.clear(); - db.close(); - } - @NotNull private Update mockFullUpdate(User user, String args) { bot.users().put(USER.getId(), USER); diff --git a/telegrambots-abilities/src/test/java/org/telegram/abilitybots/api/bot/ExtensionTest.java b/telegrambots-abilities/src/test/java/org/telegram/abilitybots/api/bot/ExtensionTest.java index 43bb8da5..8be53c13 100644 --- a/telegrambots-abilities/src/test/java/org/telegram/abilitybots/api/bot/ExtensionTest.java +++ b/telegrambots-abilities/src/test/java/org/telegram/abilitybots/api/bot/ExtensionTest.java @@ -1,45 +1,45 @@ package org.telegram.abilitybots.api.bot; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import org.telegram.abilitybots.api.objects.Ability; import org.telegram.abilitybots.api.util.AbilityExtension; import java.io.IOException; -import static junit.framework.TestCase.assertTrue; +import static org.junit.jupiter.api.Assertions.assertTrue; import static org.telegram.abilitybots.api.db.MapDBContext.offlineInstance; import static org.telegram.abilitybots.api.objects.Locality.ALL; import static org.telegram.abilitybots.api.objects.Privacy.PUBLIC; -public class ExtensionTest { +class ExtensionTest { private ExtensionUsingBot bot; - @Before - public void setUp() { + @BeforeEach + void setUp() { bot = new ExtensionUsingBot(); } - @Test - public void methodReturningAbilities() { - assertTrue("Failed to find Ability in directly declared in root extension/bot", hasAbilityNamed("direct")); - assertTrue("Failed to find Ability in directly declared in extension returned by method returning the AbilityExtension class", hasAbilityNamed("returningSuperClass0abc")); - assertTrue("Failed to find Ability in directly declared in extension returned by method returning the AbilityExtension subclass", hasAbilityNamed("returningSubClass0abc")); - } - - @After - public void tearDown() throws IOException { + @AfterEach + void tearDown() throws IOException { bot.db.clear(); bot.db.close(); } + @Test + void methodReturningAbilities() { + assertTrue(hasAbilityNamed("direct"), "Failed to find Ability in directly declared in root extension/bot"); + assertTrue(hasAbilityNamed("returningSuperClass0abc"), "Failed to find Ability in directly declared in extension returned by method returning the AbilityExtension class"); + assertTrue(hasAbilityNamed("returningSubClass0abc"), "Failed to find Ability in directly declared in extension returned by method returning the AbilityExtension subclass"); + } + private boolean hasAbilityNamed(String name) { return bot.abilities().values().stream().map(Ability::name).anyMatch(name::equals); } public static class ExtensionUsingBot extends AbilityBot { - public ExtensionUsingBot() { + ExtensionUsingBot() { super("", "", offlineInstance("testing")); } @@ -71,7 +71,7 @@ public class ExtensionTest { public static class AbilityBotExtension implements AbilityExtension { private String name; - public AbilityBotExtension(String name) { + AbilityBotExtension(String name) { this.name = name; } diff --git a/telegrambots-abilities/src/test/java/org/telegram/abilitybots/api/db/MapDBContextTest.java b/telegrambots-abilities/src/test/java/org/telegram/abilitybots/api/db/MapDBContextTest.java index 5a835e77..267450fd 100644 --- a/telegrambots-abilities/src/test/java/org/telegram/abilitybots/api/db/MapDBContextTest.java +++ b/telegrambots-abilities/src/test/java/org/telegram/abilitybots/api/db/MapDBContextTest.java @@ -1,8 +1,9 @@ package org.telegram.abilitybots.api.db; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import org.telegram.telegrambots.meta.api.objects.User; import java.io.IOException; @@ -12,25 +13,33 @@ import java.util.Set; import static com.google.common.collect.Maps.newHashMap; import static com.google.common.collect.Sets.newHashSet; import static java.lang.String.format; -import static org.junit.Assert.*; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; import static org.telegram.abilitybots.api.bot.AbilityBotTest.CREATOR; import static org.telegram.abilitybots.api.bot.AbilityBotTest.USER; import static org.telegram.abilitybots.api.db.MapDBContext.offlineInstance; -public class MapDBContextTest { +class MapDBContextTest { private static final String USERS = "USERS"; private static final String USER_ID = "USER_ID"; private static final String TEST = "TEST"; private DBContext db; - @Before - public void setUp() { + @BeforeEach + void setUp() { db = offlineInstance("db"); } + @AfterEach + void tearDown() throws IOException { + db.clear(); + db.close(); + } + @Test - public void canRecoverDB() { + void canRecoverDB() { Map users = db.getMap(USERS); Map userIds = db.getMap(USER_ID); users.put(CREATOR.getId(), CREATOR); @@ -49,30 +58,30 @@ public class MapDBContextTest { Map recoveredUsers = db.getMap(USERS); String afterRecoveryInfo = db.info(USERS); - assertTrue("Could not recover database successfully", recovered); - assertEquals("Map info before and after recovery is different", beforeBackupInfo, afterRecoveryInfo); - assertEquals("Map before and after recovery are not equal", originalUsers, recoveredUsers); + assertTrue(recovered, "Could not recover database successfully"); + assertEquals(beforeBackupInfo, afterRecoveryInfo, "Map info before and after recovery is different"); + assertEquals(originalUsers, recoveredUsers, "Map before and after recovery are not equal"); } @Test - public void canFallbackDBIfRecoveryFails() { + void canFallbackDBIfRecoveryFails() { Set users = db.getSet(USERS); users.add(CREATOR); users.add(USER); Set originalSet = newHashSet(users); Object jsonBackup = db.backup(); - String corruptBackup = "!@#$" + String.valueOf(jsonBackup); + String corruptBackup = "!@#$" + jsonBackup; boolean recovered = db.recover(corruptBackup); Set recoveredSet = db.getSet(USERS); - assertFalse("Recovery was successful from a CORRUPT backup", recovered); - assertEquals("Set before and after corrupt recovery are not equal", originalSet, recoveredSet); + assertFalse(recovered, "Recovery was successful from a CORRUPT backup"); + assertEquals(originalSet, recoveredSet, "Set before and after corrupt recovery are not equal"); } @Test - public void canGetSummary() { + void canGetSummary() { String anotherTest = TEST + 1; db.getSet(TEST).add(TEST); db.getSet(anotherTest).add(anotherTest); @@ -81,27 +90,27 @@ public class MapDBContextTest { // Name - Type - Number of "rows" String expectedSummary = format("%s - Set - 1\n%s - Set - 1", TEST, anotherTest); - assertEquals("Actual DB summary does not match that of the expected", expectedSummary, actualSummary); + assertEquals(expectedSummary, actualSummary, "Actual DB summary does not match that of the expected"); } @Test - public void canGetInfo() { + void canGetInfo() { db.getSet(TEST).add(TEST); String actualInfo = db.info(TEST); // JSON String expectedInfo = "TEST - Set - 1"; - assertEquals("Actual DB structure info does not match that of the expected", expectedInfo, actualInfo); - } - - @Test(expected = IllegalStateException.class) - public void cantGetInfoFromNonexistentDBStructureName() { - db.info(TEST); + assertEquals(expectedInfo, actualInfo, "Actual DB structure info does not match that of the expected"); } @Test - public void canGetAndSetVariables() { + void cantGetInfoFromNonexistentDBStructureName() { + Assertions.assertThrows(IllegalStateException.class, () -> db.info(TEST)); + } + + @Test + void canGetAndSetVariables() { String varName = "somevar"; Var var = db.getVar(varName); var.set(CREATOR); @@ -116,10 +125,4 @@ public class MapDBContextTest { Var changedVar = db.getVar(varName); assertEquals(changedVar.get(), USER); } - - @After - public void tearDown() throws IOException { - db.clear(); - db.close(); - } } diff --git a/telegrambots-abilities/src/test/java/org/telegram/abilitybots/api/objects/AbilityTest.java b/telegrambots-abilities/src/test/java/org/telegram/abilitybots/api/objects/AbilityTest.java index 5778dab3..91cca733 100644 --- a/telegrambots-abilities/src/test/java/org/telegram/abilitybots/api/objects/AbilityTest.java +++ b/telegrambots-abilities/src/test/java/org/telegram/abilitybots/api/objects/AbilityTest.java @@ -1,58 +1,59 @@ package org.telegram.abilitybots.api.objects; -import org.junit.Test; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotEquals; import static org.telegram.abilitybots.api.bot.DefaultBot.getDefaultBuilder; -public class AbilityTest { - @Test(expected = IllegalArgumentException.class) - public void argumentsCannotBeNegative() { - getDefaultBuilder().input(-4).build(); - } - - @Test(expected = IllegalArgumentException.class) - public void nameCannotBeEmpty() { - getDefaultBuilder().name("").build(); - } - - @Test(expected = IllegalArgumentException.class) - public void nameCannotBeNull() { - getDefaultBuilder().name(null).build(); - } - - @Test(expected = NullPointerException.class) - public void consumerCannotBeNull() { - getDefaultBuilder().action(null).build(); - } - - @Test(expected = NullPointerException.class) - public void localityCannotBeNull() { - getDefaultBuilder().locality(null).build(); - } - - @Test(expected = NullPointerException.class) - public void privacyCannotBeNull() { - getDefaultBuilder().privacy(null).build(); - } - - @Test(expected = IllegalArgumentException.class) - public void nameCannotContainSpaces() { - getDefaultBuilder().name("test test").build(); +class AbilityTest { + @Test + void argumentsCannotBeNegative() { + Assertions.assertThrows(IllegalArgumentException.class, () -> getDefaultBuilder().input(-4).build()); } @Test - public void abilityEqualsMethod() { + void nameCannotBeEmpty() { + Assertions.assertThrows(IllegalArgumentException.class, () -> getDefaultBuilder().name("").build()); + } + + @Test + void nameCannotBeNull() { + Assertions.assertThrows(IllegalArgumentException.class, () -> getDefaultBuilder().name(null).build()); + } + + @Test + void consumerCannotBeNull() { + Assertions.assertThrows(NullPointerException.class, () -> getDefaultBuilder().action(null).build()); + } + + @Test + void localityCannotBeNull() { + Assertions.assertThrows(NullPointerException.class, () -> getDefaultBuilder().locality(null).build()); + } + + @Test + void privacyCannotBeNull() { + Assertions.assertThrows(NullPointerException.class, () -> getDefaultBuilder().privacy(null).build()); + } + + @Test + void nameCannotContainSpaces() { + Assertions.assertThrows(IllegalArgumentException.class, () -> getDefaultBuilder().name("test test").build()); + } + + @Test + void abilityEqualsMethod() { Ability ability1 = getDefaultBuilder().build(); Ability ability2 = getDefaultBuilder().build(); Ability ability3 = getDefaultBuilder().name("anotherconsumer").build(); Ability ability4 = getDefaultBuilder().action((context) -> { }).build(); - assertEquals("Abilities should not be equal", ability1, ability2); - assertEquals("Abilities should not be equal", ability1, ability4); - assertNotEquals("Abilities should be equal", ability1, ability3); + assertEquals(ability1, ability2, "Abilities should not be equal"); + assertEquals(ability1, ability4, "Abilities should not be equal"); + assertNotEquals(ability1, ability3, "Abilities should be equal"); } } diff --git a/telegrambots-abilities/src/test/java/org/telegram/abilitybots/api/sender/SilentSenderTest.java b/telegrambots-abilities/src/test/java/org/telegram/abilitybots/api/sender/SilentSenderTest.java index 3b33ab36..96da662c 100644 --- a/telegrambots-abilities/src/test/java/org/telegram/abilitybots/api/sender/SilentSenderTest.java +++ b/telegrambots-abilities/src/test/java/org/telegram/abilitybots/api/sender/SilentSenderTest.java @@ -1,43 +1,43 @@ package org.telegram.abilitybots.api.sender; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import org.telegram.telegrambots.meta.exceptions.TelegramApiException; import java.util.Optional; -import static junit.framework.TestCase.assertEquals; -import static junit.framework.TestCase.assertFalse; -import static org.mockito.Matchers.any; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; -public class SilentSenderTest { +class SilentSenderTest { private SilentSender silent; private MessageSender sender; - @Before - public void setUp() { + @BeforeEach + void setUp() { sender = mock(MessageSender.class); silent = new SilentSender(sender); } @Test - public void returnsEmptyOnError() throws TelegramApiException { + void returnsEmptyOnError() throws TelegramApiException { when(sender.execute(any())).thenThrow(TelegramApiException.class); Optional execute = silent.execute(null); - assertFalse("Execution of a bot API method with execption results in a nonempty optional", execute.isPresent()); + assertFalse(execute.isPresent(), "Execution of a bot API method with execption results in a nonempty optional"); } @Test - public void returnOptionalOnSuccess() throws TelegramApiException { + void returnOptionalOnSuccess() throws TelegramApiException { String data = "data"; when(sender.execute(any())).thenReturn(data); Optional execute = silent.execute(null); - assertEquals("Silent execution resulted in a different object", data, execute.get()); + assertEquals(data, execute.get(), "Silent execution resulted in a different object"); } } \ No newline at end of file diff --git a/telegrambots-chat-session-bot/README.md b/telegrambots-chat-session-bot/README.md index 6cee2c9d..212ceb0a 100644 --- a/telegrambots-chat-session-bot/README.md +++ b/telegrambots-chat-session-bot/README.md @@ -15,7 +15,7 @@ Usage org.telegram telegrambots-chat-session-bot - 4.3.1 + 4.4.0 ``` diff --git a/telegrambots-chat-session-bot/pom.xml b/telegrambots-chat-session-bot/pom.xml index 058b2f00..3765c8f4 100644 --- a/telegrambots-chat-session-bot/pom.xml +++ b/telegrambots-chat-session-bot/pom.xml @@ -3,9 +3,14 @@ xmlns="http://maven.apache.org/POM/4.0.0" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 - org.telegram + + + org.telegram + Bots + 4.4.0 + + telegrambots-chat-session-bot - 4.3.1 jar Telegram Bots Chat Session Bot @@ -63,9 +68,15 @@ + 11 + 8 + ${java.version} + ${java.version} + UTF-8 UTF-8 - 1.4.0 + + 1.4.1 @@ -73,7 +84,7 @@ org.telegram telegrambots - 4.3.1 + 4.4.0 @@ -82,19 +93,6 @@ shiro-core ${shiro.version} - - - org.mockito - mockito-all - 2.0.2-beta - test - - - junit - junit - 4.11 - test - @@ -104,10 +102,15 @@ ${project.build.directory}/test-classes ${project.basedir}/src/main/java + + org.apache.maven.plugins + maven-surefire-plugin + 3.0.0-M3 + org.apache.maven.plugins maven-gpg-plugin - 1.5 + 1.6 sign-artifacts @@ -121,7 +124,7 @@ org.sonatype.plugins nexus-staging-maven-plugin - 1.6.3 + 1.6.8 true ossrh @@ -131,7 +134,7 @@ maven-clean-plugin - 3.0.0 + 3.1.0 clean-project @@ -144,7 +147,7 @@ maven-assembly-plugin - 2.6 + 3.1.1 jar-with-dependencies @@ -163,7 +166,7 @@ org.apache.maven.plugins maven-source-plugin - 3.0.0 + 3.1.0 @@ -175,14 +178,14 @@ org.apache.maven.plugins maven-javadoc-plugin - 2.10.3 + 3.1.0 jar - -Xdoclint:none + none @@ -190,7 +193,7 @@ org.jacoco jacoco-maven-plugin - 0.7.7.201606060606 + 0.8.4 @@ -209,7 +212,7 @@ org.apache.maven.plugins maven-enforcer-plugin - 1.4.1 + 3.0.0-M2 enforce-versions @@ -227,7 +230,7 @@ org.apache.maven.plugins maven-dependency-plugin - 2.4 + 3.1.1 copy @@ -241,9 +244,10 @@ org.apache.maven.plugins maven-compiler-plugin + 3.8.1 - 1.8 - 1.8 + ${java.version} + ${java.version} UTF-8 diff --git a/telegrambots-extensions/README.md b/telegrambots-extensions/README.md index 8b1d55c3..6e1d2173 100644 --- a/telegrambots-extensions/README.md +++ b/telegrambots-extensions/README.md @@ -16,12 +16,12 @@ Just import add the library to your project with one of these options: org.telegram telegrambotsextensions - 4.3.1 + 4.4.0 ``` 2. Using Gradle: ```gradle - compile "org.telegram:telegrambotsextensions:4.3.1" + compile "org.telegram:telegrambotsextensions:4.4.0" ``` \ No newline at end of file diff --git a/telegrambots-extensions/pom.xml b/telegrambots-extensions/pom.xml index 92863d35..b5990489 100644 --- a/telegrambots-extensions/pom.xml +++ b/telegrambots-extensions/pom.xml @@ -3,9 +3,14 @@ xmlns="http://maven.apache.org/POM/4.0.0" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 - org.telegram + + + org.telegram + Bots + 4.4.0 + + telegrambotsextensions - 4.3.1 jar Telegram Bots Extensions @@ -57,6 +62,11 @@ + 11 + 8 + ${java.version} + ${java.version} + UTF-8 UTF-8 @@ -65,7 +75,7 @@ org.telegram telegrambots - 4.3.1 + 4.4.0 @@ -76,10 +86,15 @@ ${project.build.directory}/test-classes ${project.basedir}/src/main/java + + org.apache.maven.plugins + maven-surefire-plugin + 3.0.0-M3 + org.apache.maven.plugins maven-gpg-plugin - 1.5 + 1.6 sign-artifacts @@ -93,7 +108,7 @@ org.sonatype.plugins nexus-staging-maven-plugin - 1.6.3 + 1.6.8 true ossrh @@ -103,7 +118,7 @@ maven-clean-plugin - 3.0.0 + 3.1.0 clean-project @@ -116,7 +131,7 @@ maven-assembly-plugin - 2.6 + 3.1.1 jar-with-dependencies @@ -135,7 +150,7 @@ org.apache.maven.plugins maven-source-plugin - 3.0.0 + 3.1.0 @@ -147,14 +162,14 @@ org.apache.maven.plugins maven-javadoc-plugin - 2.10.3 + 3.1.0 jar - -Xdoclint:none + none @@ -162,7 +177,7 @@ org.jacoco jacoco-maven-plugin - 0.7.7.201606060606 + 0.8.4 @@ -181,7 +196,7 @@ org.apache.maven.plugins maven-enforcer-plugin - 1.4.1 + 3.0.0-M2 enforce-versions @@ -199,7 +214,7 @@ org.apache.maven.plugins maven-dependency-plugin - 2.4 + 3.1.1 copy @@ -213,9 +228,10 @@ org.apache.maven.plugins maven-compiler-plugin + 3.8.1 - 1.8 - 1.8 + ${java.version} + ${java.version} UTF-8 diff --git a/telegrambots-extensions/src/main/java/org/telegram/telegrambots/extensions/bots/timedbot/TimedSendLongPollingBot.java b/telegrambots-extensions/src/main/java/org/telegram/telegrambots/extensions/bots/timedbot/TimedSendLongPollingBot.java index 7de54f7e..00a240a3 100644 --- a/telegrambots-extensions/src/main/java/org/telegram/telegrambots/extensions/bots/timedbot/TimedSendLongPollingBot.java +++ b/telegrambots-extensions/src/main/java/org/telegram/telegrambots/extensions/bots/timedbot/TimedSendLongPollingBot.java @@ -11,9 +11,9 @@ import java.util.concurrent.atomic.AtomicBoolean; * Created by Daniil Nikanov aka JetCoder */ +@SuppressWarnings("unused") public abstract class TimedSendLongPollingBot extends TelegramLongPollingBot { - private static final long MANY_CHATS_SEND_INTERVAL = 33; private static final long ONE_CHAT_SEND_INTERVAL = 1000; private static final long CHAT_INACTIVE_INTERVAL = 1000 * 60 * 10; private final Timer mSendTimer = new Timer(true); @@ -21,88 +21,29 @@ public abstract class TimedSendLongPollingBot extends TelegramLongPollingBot private final ArrayList mSendQueues = new ArrayList<>(); private final AtomicBoolean mSendRequested = new AtomicBoolean(false); - private final class MessageSenderTask extends TimerTask - { - @Override - public void run() - { - //mSendRequested used for optimisation to not traverse all mMessagesMap 30 times per second all the time - if (!mSendRequested.getAndSet(false)) - return; - - long currentTime = System.currentTimeMillis(); - mSendQueues.clear(); - boolean processNext = false; - - //First step - find all chats in which already allowed to send message (passed more than 1000 ms from previuos send) - Iterator> it = mMessagesMap.entrySet().iterator(); - while (it.hasNext()) - { - MessageQueue queue = it.next().getValue(); - int state = queue.getCurrentState(currentTime); //Actual check here - if (state == MessageQueue.GET_MESSAGE) - { - mSendQueues.add(queue); - processNext = true; - } - else if (state == MessageQueue.WAIT) - { - processNext = true; - } - else if (state == MessageQueue.DELETE) - { - it.remove(); - } - } - - //If any of chats are in state WAIT or GET_MESSAGE, request another iteration - if (processNext) - mSendRequested.set(true); - - //Second step - find oldest waiting queue and peek it's message - MessageQueue sendQueue = null; - long oldestPutTime = Long.MAX_VALUE; - for (int i = 0; i < mSendQueues.size(); i++) - { - MessageQueue queue = mSendQueues.get(i); - long putTime = queue.getPutTime(); - if (putTime < oldestPutTime) - { - oldestPutTime = putTime; - sendQueue = queue; - } - } - if (sendQueue == null) //Possible if on first step wasn't found any chats in state GET_MESSAGE - return; - - //Invoke the send callback. ChatId is passed for possible additional processing - sendMessageCallback(sendQueue.getChatId(), sendQueue.getMessage(currentTime)); - } - } - private static class MessageQueue { - public static final int EMPTY = 0; //Queue is empty - public static final int WAIT = 1; //Queue has message(s) but not yet allowed to send - public static final int DELETE = 2; //No one message of given queue was sent longer than CHAT_INACTIVE_INTERVAL, delete for optimisation - public static final int GET_MESSAGE = 3; //Queue has message(s) and ready to send + static final int EMPTY = 0; //Queue is empty + static final int WAIT = 1; //Queue has message(s) but not yet allowed to send + static final int DELETE = 2; //No one message of given queue was sent longer than CHAT_INACTIVE_INTERVAL, delete for optimisation + static final int GET_MESSAGE = 3; //Queue has message(s) and ready to send private final ConcurrentLinkedQueue mQueue = new ConcurrentLinkedQueue<>(); private final Long mChatId; private long mLastSendTime; //Time of last peek from queue private volatile long mLastPutTime; //Time of last put into queue - public MessageQueue(Long chatId) + MessageQueue(Long chatId) { mChatId = chatId; } - public synchronized void putMessage(Object msg) + synchronized void putMessage(Object msg) { mQueue.add(msg); mLastPutTime = System.currentTimeMillis(); } - public synchronized int getCurrentState(long currentTime) + synchronized int getCurrentState(long currentTime) { //currentTime is passed as parameter for optimisation to do not recall currentTimeMillis() many times long interval = currentTime - mLastSendTime; @@ -117,29 +58,23 @@ public abstract class TimedSendLongPollingBot extends TelegramLongPollingBot return WAIT; } - public synchronized Object getMessage(long currentTime) + synchronized Object getMessage(long currentTime) { mLastSendTime = currentTime; return mQueue.poll(); } - public long getPutTime() + long getPutTime() { return mLastPutTime; } - public Long getChatId() + Long getChatId() { return mChatId; } } - //Constructor - protected TimedSendLongPollingBot() - { - mSendTimer.schedule(new MessageSenderTask(), MANY_CHATS_SEND_INTERVAL, MANY_CHATS_SEND_INTERVAL); - } - //Something like destructor public void finish() { @@ -214,5 +149,5 @@ public abstract class TimedSendLongPollingBot extends TelegramLongPollingBot } } */ - public abstract void sendMessageCallback(Long chatId, Object messageRequest); + abstract void sendMessageCallback(Long chatId, Object messageRequest); } diff --git a/telegrambots-meta/pom.xml b/telegrambots-meta/pom.xml index 5162dd71..c2eb4616 100644 --- a/telegrambots-meta/pom.xml +++ b/telegrambots-meta/pom.xml @@ -3,9 +3,14 @@ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 - org.telegram + + + org.telegram + Bots + 4.4.0 + + telegrambots-meta - 4.3.1 jar Telegram Bots Meta @@ -57,14 +62,18 @@ + 11 + 8 + ${java.version} + ${java.version} + UTF-8 UTF-8 4.2.2 2.9.9 - 2.9.0 + 2.9.9 20180813 - 4.12 - 25.1-jre + 28.0-jre @@ -105,12 +114,6 @@ json ${json.version} - - junit - junit - ${junit.version} - test - @@ -123,7 +126,7 @@ org.apache.maven.plugins maven-gpg-plugin - 1.5 + 1.6 sign-artifacts @@ -137,7 +140,7 @@ org.sonatype.plugins nexus-staging-maven-plugin - 1.6.3 + 1.6.8 true ossrh @@ -147,7 +150,7 @@ maven-clean-plugin - 3.0.0 + 3.1.0 clean-project @@ -160,7 +163,7 @@ maven-assembly-plugin - 2.6 + 3.1.1 jar-with-dependencies @@ -179,7 +182,7 @@ org.apache.maven.plugins maven-source-plugin - 3.0.0 + 3.1.0 @@ -191,14 +194,14 @@ org.apache.maven.plugins maven-javadoc-plugin - 2.10.3 + 3.1.0 jar - -Xdoclint:none + none @@ -206,7 +209,7 @@ org.jacoco jacoco-maven-plugin - 0.7.7.201606060606 + 0.8.4 @@ -225,7 +228,7 @@ org.apache.maven.plugins maven-enforcer-plugin - 1.4.1 + 3.0.0-M2 enforce @@ -243,7 +246,7 @@ org.apache.maven.plugins maven-dependency-plugin - 2.4 + 3.1.1 copy @@ -251,15 +254,21 @@ + + org.apache.maven.plugins + maven-surefire-plugin + 3.0.0-M3 + org.apache.maven.plugins maven-compiler-plugin + 3.8.1 - 1.8 - 1.8 + ${java.version} + ${java.version} UTF-8 diff --git a/telegrambots-meta/src/main/java/org/telegram/telegrambots/meta/ApiContext.java b/telegrambots-meta/src/main/java/org/telegram/telegrambots/meta/ApiContext.java index fe783e65..a5a2e0ce 100644 --- a/telegrambots-meta/src/main/java/org/telegram/telegrambots/meta/ApiContext.java +++ b/telegrambots-meta/src/main/java/org/telegram/telegrambots/meta/ApiContext.java @@ -4,8 +4,8 @@ import com.google.inject.AbstractModule; import com.google.inject.Guice; import com.google.inject.Injector; import com.google.inject.Singleton; - -import org.telegram.telegrambots.meta.logging.BotLogger; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; import java.text.MessageFormat; import java.util.HashMap; @@ -16,6 +16,8 @@ import java.util.Map; * @version 1.0 */ public class ApiContext { + private static final Logger log = LogManager.getLogger(ApiContext.class); + private static final Object lock = new Object(); private static Injector INJECTOR; private static Map bindings = new HashMap<>(); @@ -27,14 +29,14 @@ public class ApiContext { public static void register(Class type, Class implementation) { if (bindings.containsKey(type)) { - BotLogger.debug("ApiContext", MessageFormat.format("Class {0} already registered", type.getName())); + log.debug(MessageFormat.format("Class {0} already registered", type.getName())); } bindings.put(type, implementation); } public static void registerSingleton(Class type, Class implementation) { if (singletonBindings.containsKey(type)) { - BotLogger.debug("ApiContext", MessageFormat.format("Class {0} already registered", type.getName())); + log.debug(MessageFormat.format("Class {0} already registered", type.getName())); } singletonBindings.put(type, implementation); } diff --git a/telegrambots-meta/src/main/java/org/telegram/telegrambots/meta/api/methods/groupadministration/RestrictChatMember.java b/telegrambots-meta/src/main/java/org/telegram/telegrambots/meta/api/methods/groupadministration/RestrictChatMember.java index 7a1424f0..b68e417b 100644 --- a/telegrambots-meta/src/main/java/org/telegram/telegrambots/meta/api/methods/groupadministration/RestrictChatMember.java +++ b/telegrambots-meta/src/main/java/org/telegram/telegrambots/meta/api/methods/groupadministration/RestrictChatMember.java @@ -5,6 +5,7 @@ import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.core.type.TypeReference; import org.telegram.telegrambots.meta.api.methods.BotApiMethod; import org.telegram.telegrambots.meta.api.objects.ApiResponse; +import org.telegram.telegrambots.meta.api.objects.ChatPermissions; import org.telegram.telegrambots.meta.exceptions.TelegramApiRequestException; import org.telegram.telegrambots.meta.exceptions.TelegramApiValidationException; @@ -24,6 +25,7 @@ import static com.google.common.base.Preconditions.checkNotNull; * Pass True for all boolean parameters to lift restrictions from a user. Returns True on success. * */ +@SuppressWarnings("WeakerAccess") public class RestrictChatMember extends BotApiMethod { public static final String PATH = "restrictchatmember"; @@ -34,6 +36,7 @@ public class RestrictChatMember extends BotApiMethod { private static final String CANSENDMEDIAMESSAGES_FIELD = "can_send_media_messages"; private static final String CANSENDOTHERMESSAGES_FIELD = "can_send_other_messages"; private static final String CANADDWEBPAGEPREVIEWS_FIELD = "can_add_web_page_previews"; + private static final String PERMISSIONS_FIELD = "permissions"; @JsonProperty(CHATID_FIELD) private String chatId; ///< Required. Unique identifier for the chat to send the message to (Or username for channels) @@ -49,7 +52,14 @@ public class RestrictChatMember extends BotApiMethod { private Boolean canSendOtherMessages; ///< Pass True, if the user can send animations, games, stickers and use inline bots, implies can_send_media_messages @JsonProperty(CANADDWEBPAGEPREVIEWS_FIELD) private Boolean canAddWebPagePreviews; ///< Pass True, if the user may add web page previews to their messages, implies can_send_messages - + /** + * Optional + * Date when restrictions will be lifted for the user, unix time. + * If user is restricted for more than 366 days or less than 30 seconds + * from the current time, they are considered to be restricted forever + */ + @JsonProperty(PERMISSIONS_FIELD) + private ChatPermissions permissions; public RestrictChatMember() { super(); @@ -108,46 +118,87 @@ public class RestrictChatMember extends BotApiMethod { return setUntilDate(date.toInstant()); } + @JsonIgnore public RestrictChatMember forTimePeriod(Duration duration) { return setUntilDate(Instant.now().plusMillis(duration.toMillis())); } + /** + * @deprecated Use {@link #getPermissions()} instead + */ + @Deprecated public Boolean getCanSendMessages() { return canSendMessages; } + /** + * @deprecated Use {@link #setPermissions(ChatPermissions)} instead + */ + @Deprecated public RestrictChatMember setCanSendMessages(Boolean canSendMessages) { this.canSendMessages = canSendMessages; return this; } + /** + * @deprecated Use {@link #getPermissions()} instead + */ + @Deprecated public Boolean getCanSendMediaMessages() { return canSendMediaMessages; } + /** + * @deprecated Use {@link #setPermissions(ChatPermissions)} instead + */ + @Deprecated public RestrictChatMember setCanSendMediaMessages(Boolean canSendMediaMessages) { this.canSendMediaMessages = canSendMediaMessages; return this; } + /** + * @deprecated Use {@link #getPermissions()} instead + */ + @Deprecated public Boolean getCanSendOtherMessages() { return canSendOtherMessages; } + /** + * @deprecated Use {@link #setPermissions(ChatPermissions)} instead + */ + @Deprecated public RestrictChatMember setCanSendOtherMessages(Boolean canSendOtherMessages) { this.canSendOtherMessages = canSendOtherMessages; return this; } + /** + * @deprecated Use {@link #getPermissions()} instead + */ + @Deprecated public Boolean getCanAddWebPagePreviews() { return canAddWebPagePreviews; } + /** + * @deprecated Use {@link #setPermissions(ChatPermissions)} instead + */ + @Deprecated public RestrictChatMember setCanAddWebPagePreviews(Boolean canAddWebPagePreviews) { this.canAddWebPagePreviews = canAddWebPagePreviews; return this; } + public ChatPermissions getPermissions() { + return permissions; + } + + public void setPermissions(ChatPermissions permissions) { + this.permissions = permissions; + } + @Override public String getMethod() { return PATH; @@ -176,6 +227,9 @@ public class RestrictChatMember extends BotApiMethod { if (userId == null) { throw new TelegramApiValidationException("UserId can't be empty", this); } + if (permissions == null) { + throw new TelegramApiValidationException("Permissions can't be empty", this); + } } @Override @@ -188,6 +242,7 @@ public class RestrictChatMember extends BotApiMethod { ", canSendMediaMessages=" + canSendMediaMessages + ", canSendOtherMessages=" + canSendOtherMessages + ", canAddWebPagePreviews=" + canAddWebPagePreviews + + ", permissions=" + permissions + '}'; } } diff --git a/telegrambots-meta/src/main/java/org/telegram/telegrambots/meta/api/methods/groupadministration/SetChatPermissions.java b/telegrambots-meta/src/main/java/org/telegram/telegrambots/meta/api/methods/groupadministration/SetChatPermissions.java new file mode 100644 index 00000000..790c172d --- /dev/null +++ b/telegrambots-meta/src/main/java/org/telegram/telegrambots/meta/api/methods/groupadministration/SetChatPermissions.java @@ -0,0 +1,112 @@ +package org.telegram.telegrambots.meta.api.methods.groupadministration; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.core.type.TypeReference; +import org.telegram.telegrambots.meta.api.methods.BotApiMethod; +import org.telegram.telegrambots.meta.api.objects.ApiResponse; +import org.telegram.telegrambots.meta.api.objects.ChatPermissions; +import org.telegram.telegrambots.meta.exceptions.TelegramApiRequestException; +import org.telegram.telegrambots.meta.exceptions.TelegramApiValidationException; + +import java.io.IOException; +import java.util.Objects; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * @author Ruben Bermudez + * @version 4.4 + * Use this method to set default chat permissions for all members. + * The bot must be an administrator in the group or a supergroup + * for this to work and must have the can_restrict_members admin rights. + */ +public class SetChatPermissions extends BotApiMethod { + public static final String PATH = "setChatPermissions"; + + private static final String CHAT_ID_FIELD = "chat_id"; + private static final String PERMISSIONS_FIELD = "permissions"; + + @JsonProperty(CHAT_ID_FIELD) + private String chatId; ///< Unique identifier for the target chat or username of the target supergroup (in the format @supergroupusername) + @JsonProperty(PERMISSIONS_FIELD) + private ChatPermissions permissions; ///< New default chat permissions + + public SetChatPermissions() { + super(); + } + + public SetChatPermissions(String chatId, ChatPermissions permissions) { + super(); + this.chatId = checkNotNull(chatId); + this.permissions = checkNotNull(permissions); + } + + public SetChatPermissions(Long chatId, ChatPermissions permissions) { + super(); + this.chatId = checkNotNull(chatId).toString(); + this.permissions = checkNotNull(permissions); + } + + public String getChatId() { + return chatId; + } + + public SetChatPermissions setChatId(String chatId) { + this.chatId = chatId; + return this; + } + + public SetChatPermissions setChatId(Long chatId) { + Objects.requireNonNull(chatId); + this.chatId = chatId.toString(); + return this; + } + + public ChatPermissions getPermissions() { + return permissions; + } + + public SetChatPermissions setPermissions(ChatPermissions permissions) { + Objects.requireNonNull(permissions); + this.permissions = permissions; + return this; + } + + @Override + public String getMethod() { + return PATH; + } + + @Override + public Boolean deserializeResponse(String answer) throws TelegramApiRequestException { + try { + ApiResponse result = OBJECT_MAPPER.readValue(answer, + new TypeReference>(){}); + if (result.getOk()) { + return result.getResult(); + } else { + throw new TelegramApiRequestException("Error setting chat description", result); + } + } catch (IOException e) { + throw new TelegramApiRequestException("Unable to deserialize response", e); + } + } + + @Override + public void validate() throws TelegramApiValidationException { + if (chatId == null || chatId.isEmpty()) { + throw new TelegramApiValidationException("ChatId can't be empty", this); + } + if (permissions == null) { + throw new TelegramApiValidationException("Permissions can't be null", this); + } + } + + @Override + public String toString() { + return "SetChatPermissions{" + + "chatId='" + chatId + '\'' + + ", permissions=" + permissions + + '}'; + } +} diff --git a/telegrambots-meta/src/main/java/org/telegram/telegrambots/meta/api/objects/Chat.java b/telegrambots-meta/src/main/java/org/telegram/telegrambots/meta/api/objects/Chat.java index ffc7cea1..b543e3a0 100644 --- a/telegrambots-meta/src/main/java/org/telegram/telegrambots/meta/api/objects/Chat.java +++ b/telegrambots-meta/src/main/java/org/telegram/telegrambots/meta/api/objects/Chat.java @@ -25,6 +25,7 @@ public class Chat implements BotApiObject { private static final String PINNEDMESSAGE_FIELD = "pinned_message"; private static final String STICKERSETNAME_FIELD = "sticker_set_name"; private static final String CANSETSTICKERSET_FIELD = "can_set_sticker_set"; + private static final String PERMISSIONS_FIELD = "permissions"; private static final String USERCHATTYPE = "private"; private static final String GROUPCHATTYPE = "group"; @@ -57,15 +58,23 @@ public class Chat implements BotApiObject { @JsonProperty(PHOTO_FIELD) private ChatPhoto photo; ///< Optional. Chat photo. Returned only in getChat. @JsonProperty(DESCRIPTION_FIELD) - private String description; ///< Optional. Description, for supergroups and channel chats. Returned only in getChat. + private String description; ///< Optional. Description, for groups, supergroups and channel chats. Returned only in getChat. + /** + * Optional. Chat invite link, for groups, supergroups and channel chats. + * Each administrator in a chat generates their own invite links, so the bot must first generate the link using + * exportChatInviteLink. + * Each Returned only in getChat. + */ @JsonProperty(INVITELINK_FIELD) - private String inviteLink; ///< Optional. Chat invite link, for supergroups and channel chats. Returned only in getChat. + private String inviteLink; @JsonProperty(PINNEDMESSAGE_FIELD) private Message pinnedMessage; ///< Optional. Pinned message, for groups, supergroups and channels. Returned only in getChat. @JsonProperty(STICKERSETNAME_FIELD) private String stickerSetName; ///< Optional. For supergroups, name of Group sticker set. Returned only in getChat. @JsonProperty(CANSETSTICKERSET_FIELD) private Boolean canSetStickerSet; ///< Optional. True, if the bot can change group the sticker set. Returned only in getChat. + @JsonProperty(PERMISSIONS_FIELD) + private ChatPermissions permissions; ///< Optional. Default chat member permissions, for groups and supergroups. Returned only in getChat. public Chat() { super(); @@ -107,6 +116,14 @@ public class Chat implements BotApiObject { return userName; } + public ChatPermissions getPermissions() { + return permissions; + } + + /** + * @deprecated Use {@link #getPermissions()} instead + */ + @Deprecated public Boolean getAllMembersAreAdministrators() { return allMembersAreAdministrators; } @@ -151,6 +168,7 @@ public class Chat implements BotApiObject { ", pinnedMessage=" + pinnedMessage + ", stickerSetName='" + stickerSetName + '\'' + ", canSetStickerSet=" + canSetStickerSet + + ", permissions=" + permissions + '}'; } } diff --git a/telegrambots-meta/src/main/java/org/telegram/telegrambots/meta/api/objects/ChatMember.java b/telegrambots-meta/src/main/java/org/telegram/telegrambots/meta/api/objects/ChatMember.java index 842f3459..2afcf800 100644 --- a/telegrambots-meta/src/main/java/org/telegram/telegrambots/meta/api/objects/ChatMember.java +++ b/telegrambots-meta/src/main/java/org/telegram/telegrambots/meta/api/objects/ChatMember.java @@ -9,8 +9,7 @@ import java.time.Instant; /** * @author Ruben Bermudez * @version 1.0 - * @brief This object contains information about one member of the chat. - * @date 20 of May of 2016 + * This object contains information about one member of the chat. */ public class ChatMember implements BotApiObject { private static final String USER_FIELD = "user"; @@ -29,18 +28,19 @@ public class ChatMember implements BotApiObject { private static final String CANSENDMEDIAMESSAGES_FIELD = "can_send_media_messages"; private static final String CANSENDOTHERMESSAGES_FIELD = "can_send_other_messages"; private static final String CANADDWEBPAGEPREVIEWS_FIELD = "can_add_web_page_previews"; + private static final String CAN_SEND_POLLS_FIELD = "can_send_polls"; private static final String ISMEMBER_FIELD = "is_member"; @JsonProperty(USER_FIELD) private User user; ///< Information about the user @JsonProperty(STATUS_FIELD) - private String status; ///< The member's status in the chat. Can be “creator”, “administrator”, “member”, “restricted”, “left” or “kicked” + private String status; ///< The member's status in the chat. Can be “creator”, “administrator”, “member”, “restricted”, “left” or “kicked” @JsonProperty(UNTILDATE_FIELD) private Integer untilDate; ///< Optional. Restricted and kicked only. Date when restrictions will be lifted for this user, unix time @JsonProperty(CANBEEDITED_FIELD) private Boolean canBeEdited; ///< Optional. Administrators only. True, if the bot is allowed to edit administrator privileges of that user @JsonProperty(CANCHANGEINFORMATION_FIELD) - private Boolean canChangeInformation; ///< Optional. Administrators only. True, if the administrator can change the chat title, photo and other settings + private Boolean canChangeInformation; ///< Optional. Administrators and restricted only. True, if the administrator can change the chat title, photo and other settings @JsonProperty(CANPOSTMESSAGES_FIELD) private Boolean canPostMessages; ///< Optional. Administrators only. True, if the administrator can post in the channel, channels only @JsonProperty(CANEDITMESSAGES_FIELD) @@ -48,21 +48,23 @@ public class ChatMember implements BotApiObject { @JsonProperty(CANDELETEMESSAGES_FIELD) private Boolean canDeleteMessages; ///< Optional. Administrators only. True, if the administrator can delete messages of other users @JsonProperty(CANINVITEUSERS_FIELD) - private Boolean canInviteUsers; ///< Optional. Administrators only. True, if the administrator can invite new users to the chat + private Boolean canInviteUsers; ///< Optional. Administrators and restricted only. True, if the administrator can invite new users to the chat @JsonProperty(CANRESTRICTUSERS_FIELD) private Boolean canRestrictUsers; ///< Optional. Administrators only. True, if the administrator can restrict, ban or unban chat members @JsonProperty(CANPINMESSAGES_FIELD) - private Boolean canPinMessages; ///< Optional. Administrators only. True, if the administrator can pin messages, groups and supergroups only + private Boolean canPinMessages; ///< Optional. Administrators and restricted only. True, if the administrator can pin messages, groups and supergroups only @JsonProperty(CANPROMOTEMEMBERS_FIELD) private Boolean canPromoteMembers; ///< Optional. Administrators only. True, if the administrator can add new administrators with a subset of his own privileges or demote administrators that it has promoted, directly or indirectly (promoted by administrators that were appointed by the bot) @JsonProperty(CANSENDMESSAGES_FIELD) - private Boolean canSendMessages; ///< Optional. Restricted only. True, if the user can send text messages, contacts, locations and venues + private Boolean canSendMessages; ///< Optional. Restricted only. True, if the user is allowed to send text messages, contacts, locations and venues @JsonProperty(CANSENDMEDIAMESSAGES_FIELD) - private Boolean canSendMediaMessages; ///< Optional. Restricted only. True, if the user can send audios, documents, photos, videos, video notes and voice notes, implies can_send_messages + private Boolean canSendMediaMessages; ///< Optional. Restricted only. True, if the user is allowed to send audios, documents, photos, videos, video notes and voice notes, implies can_send_messages @JsonProperty(CANSENDOTHERMESSAGES_FIELD) - private Boolean canSendOtherMessages; ///< Optional. Restricted only. True, if the user can send animations, games, stickers and use inline bots, implies can_send_media_messages + private Boolean canSendOtherMessages; ///< Optional. Restricted only. True, if the user is allowed to send animations, games, stickers and use inline bots, implies can_send_media_messages @JsonProperty(CANADDWEBPAGEPREVIEWS_FIELD) - private Boolean canAddWebPagePreviews; ///< Optional. Restricted only. True, if user may add web page previews Э to his messages, implies can_send_messages + private Boolean canAddWebPagePreviews; ///< Optional. Restricted only. True, if the user is allowed to add web page previews to his messages + @JsonProperty(CAN_SEND_POLLS_FIELD) + private Boolean canSendPolls; ///< Optional. Restricted only. True, if the user is allowed to send polls. @JsonProperty(ISMEMBER_FIELD) private Boolean isMemberField; ///< True, if the user is a member of the chat at the moment of the request. For example, it can be false for the chat creator or for a restricted user. @@ -141,6 +143,14 @@ public class ChatMember implements BotApiObject { return canAddWebPagePreviews; } + public Boolean getCanSendPolls() { + return canSendPolls; + } + + public Boolean getMemberField() { + return isMemberField; + } + @Override public String toString() { return "ChatMember{" + @@ -160,6 +170,8 @@ public class ChatMember implements BotApiObject { ", canSendMediaMessages=" + canSendMediaMessages + ", canSendOtherMessages=" + canSendOtherMessages + ", canAddWebPagePreviews=" + canAddWebPagePreviews + + ", canSendPolls=" + canSendPolls + + ", isMemberField=" + isMemberField + '}'; } } diff --git a/telegrambots-meta/src/main/java/org/telegram/telegrambots/meta/api/objects/ChatPermissions.java b/telegrambots-meta/src/main/java/org/telegram/telegrambots/meta/api/objects/ChatPermissions.java new file mode 100644 index 00000000..7a42bd41 --- /dev/null +++ b/telegrambots-meta/src/main/java/org/telegram/telegrambots/meta/api/objects/ChatPermissions.java @@ -0,0 +1,89 @@ +package org.telegram.telegrambots.meta.api.objects; + +import com.fasterxml.jackson.annotation.JsonProperty; +import org.telegram.telegrambots.meta.api.interfaces.BotApiObject; + +/** + * @author Ruben Bermudez + * @version 4.4 + * Use this method to change the description of a group, supergroup or channel. + * The bot must be an administrator in the chat for this to work and must have the appropriate admin rights. + * Returns True on success. + */ +public class ChatPermissions implements BotApiObject { + private static final String CAN_SEND_MESSAGES_FIELD = "can_send_messages"; + private static final String CAN_SEND_MEDIA_MESSAGES_FIELD = "can_send_media_messages"; + private static final String CAN_SEND_POLLS_FIELD = "can_send_polls"; + private static final String CAN_SEND_OTHER_MESSAGES_FIELD = "can_send_other_messages"; + private static final String CAN_ADD_WEB_PAGE_PREVIEWS_FIELD = "can_add_web_page_previews"; + private static final String CAN_CHANGE_INFO_FIELD = "can_change_info"; + private static final String CAN_INVITE_USERS_FIELD = "can_invite_users"; + private static final String CAN_PIN_MESSAGES_FIELD = "can_pin_messages"; + + @JsonProperty(CAN_SEND_MESSAGES_FIELD) + private Boolean canSendMessages; ///< Optional. True, if the user is allowed to send text messages, contacts, locations and venues + @JsonProperty(CAN_SEND_MEDIA_MESSAGES_FIELD) + private Boolean getCanSendMediaMessages; ///< Optional. True, if the user is allowed to send audios, documents, photos, videos, video notes and voice notes, implies can_send_messages + @JsonProperty(CAN_SEND_POLLS_FIELD) + private Boolean canSendPolls; ///< Optional. True, if the user is allowed to send polls, implies can_send_messages + @JsonProperty(CAN_SEND_OTHER_MESSAGES_FIELD) + private Boolean canSendOtherMessages; ///< Optional. True, if the user is allowed to send animations, games, stickers and use inline bots, implies can_send_media_messages + @JsonProperty(CAN_ADD_WEB_PAGE_PREVIEWS_FIELD) + private Boolean canAddWebPagePreviews; ///< Optional. True, if the user is allowed to add web page previews to their messages, implies can_send_media_messages + @JsonProperty(CAN_CHANGE_INFO_FIELD) + private Boolean canChangeInfo; ///< Optional. True, if the user is allowed to change the chat title, photo and other settings. Ignored in public supergroups + @JsonProperty(CAN_INVITE_USERS_FIELD) + private Boolean canInviteUsers; ///< Optional. True, if the user is allowed to invite new users to the chat + @JsonProperty(CAN_PIN_MESSAGES_FIELD) + private Boolean canPinMessages; ///< Optional. True, if the user is allowed to pin messages. Ignored in public supergroups + + public ChatPermissions() { + super(); + } + + public Boolean getCanSendMessages() { + return canSendMessages; + } + + public Boolean getGetCanSendMediaMessages() { + return getCanSendMediaMessages; + } + + public Boolean getCanSendPolls() { + return canSendPolls; + } + + public Boolean getCanSendOtherMessages() { + return canSendOtherMessages; + } + + public Boolean getCanAddWebPagePreviews() { + return canAddWebPagePreviews; + } + + public Boolean getCanChangeInfo() { + return canChangeInfo; + } + + public Boolean getCanInviteUsers() { + return canInviteUsers; + } + + public Boolean getCanPinMessages() { + return canPinMessages; + } + + @Override + public String toString() { + return "ChatPermissions{" + + "canSendMessages=" + canSendMessages + + ", getCanSendMediaMessages=" + getCanSendMediaMessages + + ", canSendPolls=" + canSendPolls + + ", canSendOtherMessages=" + canSendOtherMessages + + ", canAddWebPagePreviews=" + canAddWebPagePreviews + + ", canChangeInfo=" + canChangeInfo + + ", canInviteUsers=" + canInviteUsers + + ", canPinMessages=" + canPinMessages + + '}'; + } +} diff --git a/telegrambots-meta/src/main/java/org/telegram/telegrambots/meta/api/objects/ChatPhoto.java b/telegrambots-meta/src/main/java/org/telegram/telegrambots/meta/api/objects/ChatPhoto.java index 74785e13..d12f2e84 100644 --- a/telegrambots-meta/src/main/java/org/telegram/telegrambots/meta/api/objects/ChatPhoto.java +++ b/telegrambots-meta/src/main/java/org/telegram/telegrambots/meta/api/objects/ChatPhoto.java @@ -6,16 +6,24 @@ import org.telegram.telegrambots.meta.api.interfaces.BotApiObject; /** * @author Ruben Bermudez * @version 1.0 - * This object represents a chat photo. + * This object represents a chat photo (profile picture of a user, group or channel) */ public class ChatPhoto implements BotApiObject { private static final String SMALLFILEID_FIELD = "small_file_id"; private static final String BIGFILEID_FIELD = "big_file_id"; + /** + * Unique file identifier of a small chat photo (160x160). + * This file_id can be used only for photo download and only for as long as the photo is not changed. + */ @JsonProperty(SMALLFILEID_FIELD) - private String smallFileId; ///< Unique file identifier of small (160x160) chat photo. This file_id can be used only for photo download. + private String smallFileId; + /** + * Unique file identifier of a big chat photo (640x640). + * This file_id can be used only for photo download and only for as long as the photo is not changed. + */ @JsonProperty(BIGFILEID_FIELD) - private String bigFileId; ///< Unique file identifier of big (640x640) chat photo. This file_id can be used only for photo download. + private String bigFileId; public ChatPhoto() { super(); diff --git a/telegrambots-meta/src/main/java/org/telegram/telegrambots/meta/api/objects/inlinequery/result/chached/package-info.java b/telegrambots-meta/src/main/java/org/telegram/telegrambots/meta/api/objects/inlinequery/result/chached/package-info.java deleted file mode 100644 index 96d11b44..00000000 --- a/telegrambots-meta/src/main/java/org/telegram/telegrambots/meta/api/objects/inlinequery/result/chached/package-info.java +++ /dev/null @@ -1,4 +0,0 @@ -/** - * @deprecated Replaced by {@link org.telegram.telegrambots.meta.api.objects.inlinequery.result.cached} - */ -package org.telegram.telegrambots.meta.api.objects.inlinequery.result.chached; \ No newline at end of file diff --git a/telegrambots-meta/src/main/java/org/telegram/telegrambots/meta/api/objects/stickers/Sticker.java b/telegrambots-meta/src/main/java/org/telegram/telegrambots/meta/api/objects/stickers/Sticker.java index f33033b1..ea243e43 100644 --- a/telegrambots-meta/src/main/java/org/telegram/telegrambots/meta/api/objects/stickers/Sticker.java +++ b/telegrambots-meta/src/main/java/org/telegram/telegrambots/meta/api/objects/stickers/Sticker.java @@ -8,7 +8,7 @@ import org.telegram.telegrambots.meta.api.objects.PhotoSize; /** * @author Ruben Bermudez * @version 1.0 - * @brief This object represents a sticker. + * This object represents a sticker. */ public class Sticker implements BotApiObject { @@ -20,6 +20,7 @@ public class Sticker implements BotApiObject { private static final String EMOJI_FIELD = "emoji"; private static final String SETNAME_FIELD = "set_name"; private static final String MASKPOSITON_FIELD = "mask_position"; + private static final String ISANIMATED_FIELD = "is_animated"; @JsonProperty(FILEID_FIELD) private String fileId; ///< Unique identifier for this file @@ -37,6 +38,8 @@ public class Sticker implements BotApiObject { private String setName; ///< Optional. Name of the sticker set to which the sticker belongs @JsonProperty(MASKPOSITON_FIELD) private MaskPosition maskPosition; ///< Optional. For mask stickers, the position where the mask should be placed + @JsonProperty(ISANIMATED_FIELD) + private Boolean isAnimated; ///< True, if the sticker is animated public Sticker() { super(); @@ -74,6 +77,10 @@ public class Sticker implements BotApiObject { return maskPosition; } + public Boolean getAnimated() { + return isAnimated; + } + @Override public String toString() { return "Sticker{" + @@ -85,6 +92,7 @@ public class Sticker implements BotApiObject { ", emoji='" + emoji + '\'' + ", setName='" + setName + '\'' + ", maskPosition=" + maskPosition + + ", isAnimated=" + isAnimated + '}'; } } diff --git a/telegrambots-meta/src/main/java/org/telegram/telegrambots/meta/api/objects/stickers/StickerSet.java b/telegrambots-meta/src/main/java/org/telegram/telegrambots/meta/api/objects/stickers/StickerSet.java index a70f9241..ba053d29 100644 --- a/telegrambots-meta/src/main/java/org/telegram/telegrambots/meta/api/objects/stickers/StickerSet.java +++ b/telegrambots-meta/src/main/java/org/telegram/telegrambots/meta/api/objects/stickers/StickerSet.java @@ -15,6 +15,7 @@ public class StickerSet implements BotApiObject { private static final String TITLE_FIELD = "title"; private static final String CONTAINSMASKS_FIELD = "contains_masks"; private static final String STICKERS_FIELD = "stickers"; + private static final String ISANIMATED_FIELD = "is_animated"; @JsonProperty(NAME_FIELD) private String name; @@ -24,6 +25,8 @@ public class StickerSet implements BotApiObject { private Boolean containsMasks; @JsonProperty(STICKERS_FIELD) private List stickers; + @JsonProperty(ISANIMATED_FIELD) + private Boolean isAnimated; public StickerSet() { super(); @@ -45,6 +48,10 @@ public class StickerSet implements BotApiObject { return stickers; } + public Boolean getAnimated() { + return isAnimated; + } + @Override public String toString() { return "StickerSet{" + @@ -52,6 +59,7 @@ public class StickerSet implements BotApiObject { ", title='" + title + '\'' + ", containsMasks=" + containsMasks + ", stickers=" + stickers + + ", isAnimated=" + isAnimated + '}'; } } diff --git a/telegrambots-meta/src/main/java/org/telegram/telegrambots/meta/exceptions/TelegramApiRequestException.java b/telegrambots-meta/src/main/java/org/telegram/telegrambots/meta/exceptions/TelegramApiRequestException.java index 4d39bcfd..01d52b38 100644 --- a/telegrambots-meta/src/main/java/org/telegram/telegrambots/meta/exceptions/TelegramApiRequestException.java +++ b/telegrambots-meta/src/main/java/org/telegram/telegrambots/meta/exceptions/TelegramApiRequestException.java @@ -18,11 +18,11 @@ package org.telegram.telegrambots.meta.exceptions; import com.fasterxml.jackson.databind.ObjectMapper; - +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; import org.json.JSONObject; -import org.telegram.telegrambots.meta.api.objects.ResponseParameters; import org.telegram.telegrambots.meta.api.objects.ApiResponse; -import org.telegram.telegrambots.meta.logging.BotLogger; +import org.telegram.telegrambots.meta.api.objects.ResponseParameters; import java.io.IOException; @@ -33,6 +33,8 @@ import java.io.IOException; * Exception thrown when something goes wrong in the api */ public class TelegramApiRequestException extends TelegramApiException { + private static final Logger log = LogManager.getLogger(TelegramApiRequestException.class); + private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper(); private static final String ERRORDESCRIPTIONFIELD = "description"; private static final String ERRORCODEFIELD = "error_code"; @@ -54,7 +56,7 @@ public class TelegramApiRequestException extends TelegramApiException { try { parameters = OBJECT_MAPPER.readValue(object.getJSONObject(PARAMETERSFIELD).toString(), ResponseParameters.class); } catch (IOException e) { - BotLogger.severe("APIEXCEPTION", e); + log.fatal(e.getLocalizedMessage(), e); } } } diff --git a/telegrambots-meta/src/main/java/org/telegram/telegrambots/meta/logging/BotLogger.java b/telegrambots-meta/src/main/java/org/telegram/telegrambots/meta/logging/BotLogger.java deleted file mode 100644 index cb8b3bce..00000000 --- a/telegrambots-meta/src/main/java/org/telegram/telegrambots/meta/logging/BotLogger.java +++ /dev/null @@ -1,171 +0,0 @@ -package org.telegram.telegrambots.meta.logging; - -import java.util.logging.Handler; -import java.util.logging.Level; -import java.util.logging.Logger; - -/** - * @author Ruben Bermudez - * @version 2.0 - * @brief Logger to file - * @date 21/01/15 - */ -public class BotLogger { - private static final Logger logger = Logger.getLogger("Telegram Bots Api"); - - public static void setLevel(Level level) { - logger.setLevel(level); - } - - public static Level getLevel() { - return logger.getLevel(); - } - - public static void registerLogger(Handler handler) { - logger.addHandler(handler); - } - - public static void log(Level level, String tag, String msg) { - logger.log(level, String.format("%s - %s", tag, msg)); - } - - public static void severe(String tag, String msg) { - logger.severe(String.format("%s - %s", tag, msg)); - } - - public static void warn(String tag, String msg) { - warning(tag, msg); - } - - public static void debug(String tag, String msg) { - fine(tag, msg); - } - - public static void error(String tag, String msg) { - severe(tag, msg); - } - - public static void trace(String tag, String msg) { - finer(tag, msg); - } - - public static void warning(String tag, String msg) { - logger.warning(String.format("%s - %s", tag, msg)); - } - - public static void info(String tag, String msg) { - logger.info(String.format("%s - %s", tag, msg)); - } - - public static void config(String tag, String msg) { - logger.config(String.format("%s - %s", tag, msg)); - } - - public static void fine(String tag, String msg) { - logger.fine(String.format("%s - %s", tag, msg)); - } - - public static void finer(String tag, String msg) { - logger.finer(String.format("%s - %s", tag, msg)); - } - - public static void finest(String tag, String msg) { - logger.finest(String.format("%s - %s", tag, msg)); - } - - public static void log(Level level, String tag, Throwable throwable) { - logger.log(level, tag, throwable); - } - - public static void log(Level level, String tag, String msg, Throwable thrown) { - logger.log(level, String.format("%s - %s", tag, msg), thrown); - } - - public static void severe(String tag, Throwable throwable) { - logger.log(Level.SEVERE, tag, throwable); - } - - public static void warning(String tag, Throwable throwable) { - logger.log(Level.WARNING, tag, throwable); - } - - public static void info(String tag, Throwable throwable) { - logger.log(Level.INFO, tag, throwable); - } - - public static void config(String tag, Throwable throwable) { - logger.log(Level.CONFIG, tag, throwable); - } - - public static void fine(String tag, Throwable throwable) { - logger.log(Level.FINE, tag, throwable); - } - - public static void finer(String tag, Throwable throwable) { - logger.log(Level.FINER, tag, throwable); - } - - public static void finest(String tag, Throwable throwable) { - logger.log(Level.FINEST, tag, throwable); - } - - public static void warn(String tag, Throwable throwable) { - warning(tag, throwable); - } - - public static void debug(String tag, Throwable throwable) { - fine(tag, throwable); - } - - public static void error(String tag, Throwable throwable) { - severe(tag, throwable); - } - - public static void trace(String tag, Throwable throwable) { - finer(tag, throwable); - } - - public static void severe(String msg, String tag, Throwable throwable) { - log(Level.SEVERE, tag, msg, throwable); - } - - public static void warning(String msg, String tag, Throwable throwable) { - log(Level.WARNING, tag, msg, throwable); - } - - public static void info(String msg, String tag, Throwable throwable) { - log(Level.INFO, tag, msg, throwable); - } - - public static void config(String msg, String tag, Throwable throwable) { - log(Level.CONFIG, tag, msg, throwable); - } - - public static void fine(String msg, String tag, Throwable throwable) { - log(Level.FINE, tag, msg, throwable); - } - - public static void finer(String msg, String tag, Throwable throwable) { - log(Level.FINER, tag, msg, throwable); - } - - public static void finest(String msg, String tag, Throwable throwable) { - log(Level.FINEST, tag, msg, throwable); - } - - public static void warn(String msg, String tag, Throwable throwable) { - log(Level.WARNING, tag, msg, throwable); - } - - public static void debug(String msg, String tag, Throwable throwable) { - log(Level.FINE, tag, msg, throwable); - } - - public static void error(String msg, String tag, Throwable throwable) { - log(Level.SEVERE, tag, msg, throwable); - } - - public static void trace(String msg, String tag, Throwable throwable) { - log(Level.FINER, tag, msg, throwable); - } -} diff --git a/telegrambots-meta/src/main/java/org/telegram/telegrambots/meta/logging/BotsFileHandler.java b/telegrambots-meta/src/main/java/org/telegram/telegrambots/meta/logging/BotsFileHandler.java deleted file mode 100644 index 0da14c3f..00000000 --- a/telegrambots-meta/src/main/java/org/telegram/telegrambots/meta/logging/BotsFileHandler.java +++ /dev/null @@ -1,45 +0,0 @@ -package org.telegram.telegrambots.meta.logging; - -import java.io.IOException; -import java.util.logging.FileHandler; - -/** - * @author Ruben Bermudez - * @version 1.0 - * @brief Handler to use a file as logs destination with {@link BotLogger} - * @date 19 of May of 2016 - */ -public class BotsFileHandler extends FileHandler { - private static final String filePattern = "./TelegramBots%g.%u.log"; - - public BotsFileHandler() throws IOException, SecurityException { - super(filePattern, 1024 * 1024 * 10, 50, true); - setFormatter(new FileFormatter()); - } - - public BotsFileHandler(int limit, int count) throws IOException, SecurityException { - super(filePattern, limit, count); - setFormatter(new FileFormatter()); - } - - public BotsFileHandler(String pattern) throws IOException, SecurityException { - super(pattern); - setFormatter(new FileFormatter()); - } - - public BotsFileHandler(String pattern, boolean append) throws IOException, SecurityException { - super(pattern, append); - setFormatter(new FileFormatter()); - } - - public BotsFileHandler(String pattern, int limit, int count) throws IOException, SecurityException { - super(pattern, limit, count); - setFormatter(new FileFormatter()); - } - - public BotsFileHandler(String pattern, int limit, int count, boolean append) throws IOException, SecurityException { - super(pattern, limit, count, append); - setFormatter(new FileFormatter()); - } - -} diff --git a/telegrambots-meta/src/main/java/org/telegram/telegrambots/meta/logging/FileFormatter.java b/telegrambots-meta/src/main/java/org/telegram/telegrambots/meta/logging/FileFormatter.java deleted file mode 100644 index ca6a1e4b..00000000 --- a/telegrambots-meta/src/main/java/org/telegram/telegrambots/meta/logging/FileFormatter.java +++ /dev/null @@ -1,52 +0,0 @@ -package org.telegram.telegrambots.meta.logging; - -import java.time.LocalDateTime; -import java.util.logging.Formatter; -import java.util.logging.Level; -import java.util.logging.LogRecord; - -/** - * @author Ruben Bermudez - * @version 1.0 - * @brief Formatter for {@link BotsFileHandler} - * @date 19 of May of 2016 - */ -class FileFormatter extends Formatter { - - @Override - public String format(LogRecord record) { - final LocalDateTime currentDate = LocalDateTime.now(); - final String dateForLog = dateFormatterForLogs(currentDate); - String result; - if (record.getThrown() == null) { - result = logMsgToFile(record.getLevel(), record.getMessage(), dateForLog); - } else { - result = logThrowableToFile(record.getLevel(), record.getMessage(), record.getThrown(), dateForLog); - } - return result; - } - - private static String dateFormatterForLogs(LocalDateTime dateTime) { - String dateString = "["; - dateString += dateTime.getDayOfMonth() + "_"; - dateString += dateTime.getMonthValue() + "_"; - dateString += dateTime.getYear() + "_"; - dateString += dateTime.getHour() + ":"; - dateString += dateTime.getMinute() + ":"; - dateString += dateTime.getSecond(); - dateString += "] "; - return dateString; - } - - private static String logMsgToFile(Level level, String msg, String dateForLog) { - return String.format("%s{%s} %s\n", dateForLog, level.toString(), msg); - } - - private static String logThrowableToFile(Level level, String message, Throwable throwable, String dateForLog) { - String throwableLog = String.format("%s{%s} %s - %s\n", dateForLog, level.toString(), message, throwable.toString()); - for (StackTraceElement element : throwable.getStackTrace()) { - throwableLog += "\tat " + element + "\n"; - } - return throwableLog; - } -} diff --git a/telegrambots-meta/src/test/java/org/telegram/telegrambots/meta/api/methods/send/SendMessageTest.java b/telegrambots-meta/src/test/java/org/telegram/telegrambots/meta/api/methods/send/SendMessageTest.java index a56a4350..f6dc3a7f 100644 --- a/telegrambots-meta/src/test/java/org/telegram/telegrambots/meta/api/methods/send/SendMessageTest.java +++ b/telegrambots-meta/src/test/java/org/telegram/telegrambots/meta/api/methods/send/SendMessageTest.java @@ -1,25 +1,26 @@ package org.telegram.telegrambots.meta.api.methods.send; -import org.junit.Test; +import org.junit.jupiter.api.Test; -import static org.junit.Assert.*; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotEquals; -public class SendMessageTest { +class SendMessageTest { @Test - public void comparison() throws Exception { + void comparison() { SendMessage sm1 = new SendMessage().setChatId(1L).setText("Hello World"); SendMessage sm2 = new SendMessage().setChatId(1L).setText("Hello World"); SendMessage noMessage = new SendMessage().setChatId(1L); SendMessage disabledNotification = new SendMessage().setChatId(1L).setText("Hello World").disableNotification(); - assertTrue(sm1.equals(sm2)); - assertFalse(sm1.equals(noMessage)); - assertFalse(sm1.equals(disabledNotification)); + assertEquals(sm1, sm2); + assertNotEquals(sm1, noMessage); + assertNotEquals(sm1, disabledNotification); - assertTrue(sm1.hashCode() == sm2.hashCode()); - assertFalse(sm1.hashCode() == noMessage.hashCode()); - assertFalse(sm1.hashCode() == disabledNotification.hashCode()); + assertEquals(sm1.hashCode(), sm2.hashCode()); + assertNotEquals(sm1.hashCode(), noMessage.hashCode()); + assertNotEquals(sm1.hashCode(), disabledNotification.hashCode()); } } \ No newline at end of file diff --git a/telegrambots-meta/src/test/java/org/telegram/telegrambots/meta/api/objects/replykeyboard/buttons/KeyboardRowTest.java b/telegrambots-meta/src/test/java/org/telegram/telegrambots/meta/api/objects/replykeyboard/buttons/KeyboardRowTest.java index 3e4f87f6..ac702503 100644 --- a/telegrambots-meta/src/test/java/org/telegram/telegrambots/meta/api/objects/replykeyboard/buttons/KeyboardRowTest.java +++ b/telegrambots-meta/src/test/java/org/telegram/telegrambots/meta/api/objects/replykeyboard/buttons/KeyboardRowTest.java @@ -1,31 +1,30 @@ package org.telegram.telegrambots.meta.api.objects.replykeyboard.buttons; -import org.junit.Test; + +import org.junit.jupiter.api.Test; import java.util.ArrayList; -import java.util.Collections; import java.util.List; import static java.util.Arrays.asList; -import static org.hamcrest.core.Is.is; -import static org.junit.Assert.assertThat; -import static org.junit.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; -public class KeyboardRowTest { +class KeyboardRowTest { private static final List BUTTON_NAMES = asList("Carlotta Valdes", "Jimmy Stewart"); @Test - public void shouldAddAllButtons() { + void shouldAddAllButtons() { final KeyboardRow keyboardRow = new KeyboardRow(); keyboardRow.addAll(BUTTON_NAMES); - assertThat(keyboardRow.size(), is(2)); - assertThat(keyboardRow.get(0).getText(), is("Carlotta Valdes")); - assertThat(keyboardRow.get(1).getText(), is("Jimmy Stewart")); + assertEquals(2, keyboardRow.size()); + assertEquals("Carlotta Valdes", keyboardRow.get(0).getText()); + assertEquals("Jimmy Stewart", keyboardRow.get(1).getText()); } @Test - public void shouldAddNoButtons() { + void shouldAddNoButtons() { final KeyboardRow keyboardRow = new KeyboardRow(); keyboardRow.addAll(new ArrayList()); assertTrue(keyboardRow.isEmpty()); diff --git a/telegrambots-meta/src/test/java/org/telegram/telegrambots/meta/test/TestDeserialization.java b/telegrambots-meta/src/test/java/org/telegram/telegrambots/meta/test/TestDeserialization.java index c65db037..02893c15 100644 --- a/telegrambots-meta/src/test/java/org/telegram/telegrambots/meta/test/TestDeserialization.java +++ b/telegrambots-meta/src/test/java/org/telegram/telegrambots/meta/test/TestDeserialization.java @@ -3,9 +3,9 @@ package org.telegram.telegrambots.meta.test; import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.ObjectMapper; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.telegram.telegrambots.meta.api.objects.ApiResponse; import org.telegram.telegrambots.meta.api.objects.Audio; import org.telegram.telegrambots.meta.api.objects.CallbackQuery; import org.telegram.telegrambots.meta.api.objects.Chat; @@ -18,63 +18,67 @@ import org.telegram.telegrambots.meta.api.objects.User; import org.telegram.telegrambots.meta.api.objects.Voice; import org.telegram.telegrambots.meta.api.objects.inlinequery.ChosenInlineQuery; import org.telegram.telegrambots.meta.api.objects.inlinequery.InlineQuery; -import org.telegram.telegrambots.meta.api.objects.ApiResponse; import java.io.IOException; import java.util.ArrayList; import java.util.List; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + /** * @author Ruben Bermudez * @version 1.0 */ -public class TestDeserialization { +class TestDeserialization { private ObjectMapper mapper; - @Before - public void setUp() { + @BeforeEach + void setUp() { mapper = new ObjectMapper(); } @Test - public void TestUpdateDeserialization() throws Exception { + void TestUpdateDeserialization() throws Exception { Update update = mapper.readValue(TelegramBotsHelper.GetUpdate(), Update.class); assertUpdate(update); } @Test - public void TestUpdateDeserializationWithInlineKeyboard() throws Exception { + void TestUpdateDeserializationWithInlineKeyboard() throws Exception { Update update = mapper.readValue(TelegramBotsHelper.GetUpdateWithMessageInCallbackQuery(), Update.class); - Assert.assertNotNull(update); - Assert.assertNotNull(update.getCallbackQuery()); - Assert.assertNotNull(update.getCallbackQuery().getMessage()); - Assert.assertNotNull(update.getCallbackQuery().getMessage().getReplyMarkup()); + assertNotNull(update); + assertNotNull(update.getCallbackQuery()); + assertNotNull(update.getCallbackQuery().getMessage()); + assertNotNull(update.getCallbackQuery().getMessage().getReplyMarkup()); } @Test - public void TestResponseWithoutErrorDeserialization() throws IOException { + void TestResponseWithoutErrorDeserialization() throws IOException { ApiResponse> result = mapper.readValue(TelegramBotsHelper.GetResponseWithoutError(), new TypeReference>>(){}); - Assert.assertNotNull(result); - Assert.assertTrue(result.getOk()); - Assert.assertEquals(1, result.getResult().size()); + assertNotNull(result); + assertTrue(result.getOk()); + assertEquals(1, result.getResult().size()); assertUpdate(result.getResult().get(0)); } @Test - public void TestResponseWithErrorDeserialization() throws IOException { + void TestResponseWithErrorDeserialization() throws IOException { ApiResponse> result = mapper.readValue(TelegramBotsHelper.GetResponseWithError(), new TypeReference>>(){}); - Assert.assertNotNull(result); - Assert.assertFalse(result.getOk()); - Assert.assertEquals(Integer.valueOf(400), result.getErrorCode()); - Assert.assertEquals("Error descriptions", result.getErrorDescription()); - Assert.assertNotNull(result.getParameters()); - Assert.assertEquals(Long.valueOf(12345), result.getParameters().getMigrateToChatId()); - Assert.assertEquals(Integer.valueOf(12), result.getParameters().getRetryAfter()); + assertNotNull(result); + assertFalse(result.getOk()); + assertEquals(Integer.valueOf(400), result.getErrorCode()); + assertEquals("Error descriptions", result.getErrorDescription()); + assertNotNull(result.getParameters()); + assertEquals(Long.valueOf(12345), result.getParameters().getMigrateToChatId()); + assertEquals(Integer.valueOf(12), result.getParameters().getRetryAfter()); } private void assertUpdate(Update update) { - Assert.assertNotNull(update); - Assert.assertEquals((Integer) 10000, update.getUpdateId()); + assertNotNull(update); + assertEquals((Integer) 10000, update.getUpdateId()); assertEditedMessage(update.getEditedMessage()); assertCallbackQuery(update.getCallbackQuery()); assertInlineQuery(update.getInlineQuery()); @@ -83,11 +87,11 @@ public class TestDeserialization { } private void assertMessage(Message message) { - Assert.assertNotNull(message); - Assert.assertEquals(Integer.valueOf(1441645532), message.getDate()); - Assert.assertEquals(Integer.valueOf(1365), message.getMessageId()); - Assert.assertEquals(Integer.valueOf(1441645550), message.getForwardDate()); - Assert.assertEquals("Bold and italics", message.getText()); + assertNotNull(message); + assertEquals(Integer.valueOf(1441645532), message.getDate()); + assertEquals(Integer.valueOf(1365), message.getMessageId()); + assertEquals(Integer.valueOf(1441645550), message.getForwardDate()); + assertEquals("Bold and italics", message.getText()); assertPrivateChat(message.getChat()); assertFromUser(message.getFrom()); assertForwardFrom(message.getForwardFrom()); @@ -99,119 +103,119 @@ public class TestDeserialization { } private void assertDocument(Document document) { - Assert.assertNotNull(document); - Assert.assertEquals("AwADBAADbXXXXXXXXXXXGBdhD2l6_XX", document.getFileId()); - Assert.assertEquals("Testfile.pdf", document.getFileName()); - Assert.assertEquals("application/pdf", document.getMimeType()); - Assert.assertEquals(Integer.valueOf(536392), document.getFileSize()); + assertNotNull(document); + assertEquals("AwADBAADbXXXXXXXXXXXGBdhD2l6_XX", document.getFileId()); + assertEquals("Testfile.pdf", document.getFileName()); + assertEquals("application/pdf", document.getMimeType()); + assertEquals(Integer.valueOf(536392), document.getFileSize()); } private void assertVoice(Voice voice) { - Assert.assertNotNull(voice); - Assert.assertEquals("AwADBAADbXXXXXXXXXXXGBdhD2l6_XX", voice.getFileId()); - Assert.assertEquals(Integer.valueOf(5), voice.getDuration()); - Assert.assertEquals("audio/ogg", voice.getMimeType()); - Assert.assertEquals(Integer.valueOf(23000), voice.getFileSize()); + assertNotNull(voice); + assertEquals("AwADBAADbXXXXXXXXXXXGBdhD2l6_XX", voice.getFileId()); + assertEquals(Integer.valueOf(5), voice.getDuration()); + assertEquals("audio/ogg", voice.getMimeType()); + assertEquals(Integer.valueOf(23000), voice.getFileSize()); } private void assertAudio(Audio audio) { - Assert.assertNotNull(audio); - Assert.assertEquals("AwADBAADbXXXXXXXXXXXGBdhD2l6_XX", audio.getFileId()); - Assert.assertEquals(Integer.valueOf(243), audio.getDuration()); - Assert.assertEquals("audio/mpeg", audio.getMimeType()); - Assert.assertEquals(Integer.valueOf(3897500), audio.getFileSize()); - Assert.assertEquals("Testmusicfile", audio.getTitle()); + assertNotNull(audio); + assertEquals("AwADBAADbXXXXXXXXXXXGBdhD2l6_XX", audio.getFileId()); + assertEquals(Integer.valueOf(243), audio.getDuration()); + assertEquals("audio/mpeg", audio.getMimeType()); + assertEquals(Integer.valueOf(3897500), audio.getFileSize()); + assertEquals("Testmusicfile", audio.getTitle()); } private void assertEntities(List entities) { - Assert.assertNotNull(entities); - Assert.assertEquals(2, entities.size()); - Assert.assertEquals(EntityType.ITALIC, entities.get(0).getType()); - Assert.assertEquals(Integer.valueOf(9), entities.get(0).getOffset()); - Assert.assertEquals(Integer.valueOf(7), entities.get(0).getLength()); - Assert.assertEquals("italics", entities.get(0).getText()); - Assert.assertEquals(EntityType.BOLD, entities.get(1).getType()); - Assert.assertEquals(Integer.valueOf(0), entities.get(1).getOffset()); - Assert.assertEquals(Integer.valueOf(4), entities.get(1).getLength()); - Assert.assertEquals("Bold", entities.get(1).getText()); + assertNotNull(entities); + assertEquals(2, entities.size()); + assertEquals(EntityType.ITALIC, entities.get(0).getType()); + assertEquals(Integer.valueOf(9), entities.get(0).getOffset()); + assertEquals(Integer.valueOf(7), entities.get(0).getLength()); + assertEquals("italics", entities.get(0).getText()); + assertEquals(EntityType.BOLD, entities.get(1).getType()); + assertEquals(Integer.valueOf(0), entities.get(1).getOffset()); + assertEquals(Integer.valueOf(4), entities.get(1).getLength()); + assertEquals("Bold", entities.get(1).getText()); } private void assertReplyToMessage(Message replyToMessage) { - Assert.assertNotNull(replyToMessage); - Assert.assertEquals(Integer.valueOf(1441645000), replyToMessage.getDate()); - Assert.assertEquals(Integer.valueOf(1334), replyToMessage.getMessageId()); - Assert.assertEquals("Original", replyToMessage.getText()); - Assert.assertNotNull(replyToMessage.getChat()); - Assert.assertEquals("ReplyLastname", replyToMessage.getChat().getLastName()); - Assert.assertEquals("ReplyFirstname", replyToMessage.getChat().getFirstName()); - Assert.assertEquals("Testusername", replyToMessage.getChat().getUserName()); - Assert.assertEquals(Long.valueOf(1111112), replyToMessage.getChat().getId()); + assertNotNull(replyToMessage); + assertEquals(Integer.valueOf(1441645000), replyToMessage.getDate()); + assertEquals(Integer.valueOf(1334), replyToMessage.getMessageId()); + assertEquals("Original", replyToMessage.getText()); + assertNotNull(replyToMessage.getChat()); + assertEquals("ReplyLastname", replyToMessage.getChat().getLastName()); + assertEquals("ReplyFirstname", replyToMessage.getChat().getFirstName()); + assertEquals("Testusername", replyToMessage.getChat().getUserName()); + assertEquals(Long.valueOf(1111112), replyToMessage.getChat().getId()); } private void assertForwardFrom(User forwardFrom) { - Assert.assertNotNull(forwardFrom); - Assert.assertEquals("ForwardLastname", forwardFrom.getLastName()); - Assert.assertEquals("ForwardFirstname", forwardFrom.getFirstName()); - Assert.assertEquals(Integer.valueOf(222222), forwardFrom.getId()); + assertNotNull(forwardFrom); + assertEquals("ForwardLastname", forwardFrom.getLastName()); + assertEquals("ForwardFirstname", forwardFrom.getFirstName()); + assertEquals(Integer.valueOf(222222), forwardFrom.getId()); } private void assertPrivateChat(Chat chat) { - Assert.assertNotNull(chat); - Assert.assertEquals(Long.valueOf(1111111), chat.getId()); - Assert.assertTrue(chat.isUserChat()); - Assert.assertEquals("Test Lastname", chat.getLastName()); - Assert.assertEquals("Test Firstname", chat.getFirstName()); - Assert.assertEquals("Testusername", chat.getUserName()); + assertNotNull(chat); + assertEquals(Long.valueOf(1111111), chat.getId()); + assertTrue(chat.isUserChat()); + assertEquals("Test Lastname", chat.getLastName()); + assertEquals("Test Firstname", chat.getFirstName()); + assertEquals("Testusername", chat.getUserName()); } private void assertChosenInlineQuery(ChosenInlineQuery chosenInlineQuery) { - Assert.assertNotNull(chosenInlineQuery); - Assert.assertEquals("12", chosenInlineQuery.getResultId()); - Assert.assertEquals("inline query", chosenInlineQuery.getQuery()); - Assert.assertEquals("1234csdbsk4839", chosenInlineQuery.getInlineMessageId()); + assertNotNull(chosenInlineQuery); + assertEquals("12", chosenInlineQuery.getResultId()); + assertEquals("inline query", chosenInlineQuery.getQuery()); + assertEquals("1234csdbsk4839", chosenInlineQuery.getInlineMessageId()); assertFromUser(chosenInlineQuery.getFrom()); } private void assertInlineQuery(InlineQuery inlineQuery) { - Assert.assertNotNull(inlineQuery); - Assert.assertEquals("134567890097", inlineQuery.getId()); - Assert.assertEquals("inline query", inlineQuery.getQuery()); - Assert.assertEquals("offset", inlineQuery.getOffset()); + assertNotNull(inlineQuery); + assertEquals("134567890097", inlineQuery.getId()); + assertEquals("inline query", inlineQuery.getQuery()); + assertEquals("offset", inlineQuery.getOffset()); assertFromUser(inlineQuery.getFrom()); - Assert.assertNotNull(inlineQuery.getLocation()); - Assert.assertEquals(Float.valueOf("0.234242534"), inlineQuery.getLocation().getLatitude()); - Assert.assertEquals(Float.valueOf("0.234242534"), inlineQuery.getLocation().getLongitude()); + assertNotNull(inlineQuery.getLocation()); + assertEquals(Float.valueOf("0.234242534"), inlineQuery.getLocation().getLatitude()); + assertEquals(Float.valueOf("0.234242534"), inlineQuery.getLocation().getLongitude()); } private void assertCallbackQuery(CallbackQuery callbackQuery) { - Assert.assertNotNull(callbackQuery); - Assert.assertEquals("4382bfdwdsb323b2d9", callbackQuery.getId()); - Assert.assertEquals("Data from button callback", callbackQuery.getData()); - Assert.assertEquals("1234csdbsk4839", callbackQuery.getInlineMessageId()); + assertNotNull(callbackQuery); + assertEquals("4382bfdwdsb323b2d9", callbackQuery.getId()); + assertEquals("Data from button callback", callbackQuery.getData()); + assertEquals("1234csdbsk4839", callbackQuery.getInlineMessageId()); assertFromUser(callbackQuery.getFrom()); } private void assertEditedMessage(Message message) { - Assert.assertEquals((Integer) 1441645532, message.getDate()); - Assert.assertEquals((Integer) 1441646600, message.getEditDate()); - Assert.assertEquals((Integer) 1365, message.getMessageId()); - Assert.assertEquals("Edited text", message.getText()); + assertEquals((Integer) 1441645532, message.getDate()); + assertEquals((Integer) 1441646600, message.getEditDate()); + assertEquals((Integer) 1365, message.getMessageId()); + assertEquals("Edited text", message.getText()); assertChannelChat(message.getChat()); assertFromUser(message.getFrom()); } private void assertFromUser(User from) { - Assert.assertNotNull(from); - Assert.assertEquals((Integer) 1111111, from.getId()); - Assert.assertEquals("Test Lastname", from.getLastName()); - Assert.assertEquals("Test Firstname", from.getFirstName()); - Assert.assertEquals("Testusername", from.getUserName()); + assertNotNull(from); + assertEquals((Integer) 1111111, from.getId()); + assertEquals("Test Lastname", from.getLastName()); + assertEquals("Test Firstname", from.getFirstName()); + assertEquals("Testusername", from.getUserName()); } private void assertChannelChat(Chat chat) { - Assert.assertNotNull(chat); - Assert.assertEquals(Long.valueOf(-10000000000L), chat.getId()); - Assert.assertTrue(chat.isChannelChat()); - Assert.assertEquals("Test channel", chat.getTitle()); + assertNotNull(chat); + assertEquals(Long.valueOf(-10000000000L), chat.getId()); + assertTrue(chat.isChannelChat()); + assertEquals("Test channel", chat.getTitle()); } -} +} \ No newline at end of file diff --git a/telegrambots-meta/src/test/java/org/telegram/telegrambots/meta/test/TestTelegramApi.java b/telegrambots-meta/src/test/java/org/telegram/telegrambots/meta/test/TestTelegramApi.java index 45b28c36..35dce949 100644 --- a/telegrambots-meta/src/test/java/org/telegram/telegrambots/meta/test/TestTelegramApi.java +++ b/telegrambots-meta/src/test/java/org/telegram/telegrambots/meta/test/TestTelegramApi.java @@ -1,46 +1,47 @@ package org.telegram.telegrambots.meta.test; -import org.junit.Assert; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.telegram.telegrambots.meta.TelegramBotsApi; -import org.telegram.telegrambots.meta.test.base.TestBase; import org.telegram.telegrambots.meta.exceptions.TelegramApiRequestException; +import org.telegram.telegrambots.meta.test.base.TestBase; + +import static org.junit.jupiter.api.Assertions.fail; /** * @author Ruben Bermudez * @version 1.0 */ -public class TestTelegramApi extends TestBase { +class TestTelegramApi extends TestBase { @Test - public void TestTelegramApiMustBeInitializableForLongPolling() { + void TestTelegramApiMustBeInitializableForLongPolling() { new TelegramBotsApi(); } @Test - public void TestTelegramApiMustBeInitializableForWebhookWithoutSecureSupport() { + void TestTelegramApiMustBeInitializableForWebhookWithoutSecureSupport() { try { new TelegramBotsApi("externalUrl", "internalUrl"); } catch (TelegramApiRequestException e) { - Assert.fail(); + fail(); } } @Test - public void TestTelegramApiMustBeInitializableForWebhook() { + void TestTelegramApiMustBeInitializableForWebhook() { try { new TelegramBotsApi("keyStore", "keyStorePassword", "externalUrl", "internalUrl"); } catch (TelegramApiRequestException e) { - Assert.fail(); + fail(); } } @Test - public void TestTelegramApiMustBeInitializableForWebhookWithSelfSignedCertificate() { + void TestTelegramApiMustBeInitializableForWebhookWithSelfSignedCertificate() { try { new TelegramBotsApi("keyStore", "keyStorePassword", "externalUrl", "internalUrl", "selfSignedPath"); } catch (TelegramApiRequestException e) { - Assert.fail(); + fail(); } } } diff --git a/telegrambots-meta/src/test/java/org/telegram/telegrambots/meta/test/apimethods/TestAnswerInlineQuery.java b/telegrambots-meta/src/test/java/org/telegram/telegrambots/meta/test/apimethods/TestAnswerInlineQuery.java index eea69669..75b4f6e1 100644 --- a/telegrambots-meta/src/test/java/org/telegram/telegrambots/meta/test/apimethods/TestAnswerInlineQuery.java +++ b/telegrambots-meta/src/test/java/org/telegram/telegrambots/meta/test/apimethods/TestAnswerInlineQuery.java @@ -1,56 +1,57 @@ package org.telegram.telegrambots.meta.test.apimethods; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import org.telegram.telegrambots.meta.api.methods.AnswerInlineQuery; import org.telegram.telegrambots.meta.exceptions.TelegramApiValidationException; import java.util.ArrayList; +import static org.junit.jupiter.api.Assertions.assertEquals; + /** * @author Ruben Bermudez * @version 1.0 */ -public class TestAnswerInlineQuery { +class TestAnswerInlineQuery { private AnswerInlineQuery answerInlineQuery; - @Before - public void setUp() throws Exception { + @BeforeEach + void setUp() { answerInlineQuery = new AnswerInlineQuery(); } @Test - public void TestInlineQueryIdMustBePresent() throws Exception { + void TestInlineQueryIdMustBePresent() { try { answerInlineQuery.validate(); } catch (TelegramApiValidationException e) { - Assert.assertEquals("InlineQueryId can't be empty", e.getMessage()); + assertEquals("InlineQueryId can't be empty", e.getMessage()); } } @Test - public void TestInlineQueryIdCanNotBeEmpty() throws Exception { + void TestInlineQueryIdCanNotBeEmpty() { answerInlineQuery.setInlineQueryId(""); try { answerInlineQuery.validate(); } catch (TelegramApiValidationException e) { - Assert.assertEquals("InlineQueryId can't be empty", e.getMessage()); + assertEquals("InlineQueryId can't be empty", e.getMessage()); } } @Test - public void TestResultsMustBePresent() throws Exception { + void TestResultsMustBePresent() { answerInlineQuery.setInlineQueryId("RANDOMEID"); try { answerInlineQuery.validate(); } catch (TelegramApiValidationException e) { - Assert.assertEquals("Results array can't be null", e.getMessage()); + assertEquals("Results array can't be null", e.getMessage()); } } @Test - public void TestSwitchPmTextCanNotBeEmpty() throws Exception { + void TestSwitchPmTextCanNotBeEmpty() { answerInlineQuery.setInlineQueryId("RANDOMEID"); answerInlineQuery.setResults(new ArrayList<>()); answerInlineQuery.setSwitchPmText(""); @@ -58,12 +59,12 @@ public class TestAnswerInlineQuery { try { answerInlineQuery.validate(); } catch (TelegramApiValidationException e) { - Assert.assertEquals("SwitchPmText can't be empty", e.getMessage()); + assertEquals("SwitchPmText can't be empty", e.getMessage()); } } @Test - public void TestSwitchPmParameterIsMandatoryIfSwitchPmTextIsPresent() throws Exception { + void TestSwitchPmParameterIsMandatoryIfSwitchPmTextIsPresent() { answerInlineQuery.setInlineQueryId("RANDOMEID"); answerInlineQuery.setResults(new ArrayList<>()); answerInlineQuery.setSwitchPmText("Test Text"); @@ -71,12 +72,12 @@ public class TestAnswerInlineQuery { try { answerInlineQuery.validate(); } catch (TelegramApiValidationException e) { - Assert.assertEquals("SwitchPmParameter can't be empty if switchPmText is present", e.getMessage()); + assertEquals("SwitchPmParameter can't be empty if switchPmText is present", e.getMessage()); } } @Test - public void TestSwitchPmParameterCanNotBeEmptyIfSwitchPmTextIsPresent() throws Exception { + void TestSwitchPmParameterCanNotBeEmptyIfSwitchPmTextIsPresent() { answerInlineQuery.setInlineQueryId("RANDOMEID"); answerInlineQuery.setResults(new ArrayList<>()); answerInlineQuery.setSwitchPmText("Test Text"); @@ -85,12 +86,12 @@ public class TestAnswerInlineQuery { try { answerInlineQuery.validate(); } catch (TelegramApiValidationException e) { - Assert.assertEquals("SwitchPmParameter can't be empty if switchPmText is present", e.getMessage()); + assertEquals("SwitchPmParameter can't be empty if switchPmText is present", e.getMessage()); } } @Test - public void TestSwitchPmParameterContainsUpTo64Chars() throws Exception { + void TestSwitchPmParameterContainsUpTo64Chars() { answerInlineQuery.setInlineQueryId("RANDOMEID"); answerInlineQuery.setResults(new ArrayList<>()); answerInlineQuery.setSwitchPmText("Test Text"); @@ -99,12 +100,12 @@ public class TestAnswerInlineQuery { try { answerInlineQuery.validate(); } catch (TelegramApiValidationException e) { - Assert.assertEquals("SwitchPmParameter can't be longer than 64 chars", e.getMessage()); + assertEquals("SwitchPmParameter can't be longer than 64 chars", e.getMessage()); } } @Test - public void TestSwitchPmParameterOnlyContainsAcceptedCharacters() throws Exception { + void TestSwitchPmParameterOnlyContainsAcceptedCharacters() { answerInlineQuery.setInlineQueryId("RANDOMEID"); answerInlineQuery.setResults(new ArrayList<>()); answerInlineQuery.setSwitchPmText("Test Text"); @@ -113,7 +114,7 @@ public class TestAnswerInlineQuery { try { answerInlineQuery.validate(); } catch (TelegramApiValidationException e) { - Assert.assertEquals("SwitchPmParameter only allows A-Z, a-z, 0-9, _ and - characters", e.getMessage()); + assertEquals("SwitchPmParameter only allows A-Z, a-z, 0-9, _ and - characters", e.getMessage()); } } } diff --git a/telegrambots-meta/src/test/java/org/telegram/telegrambots/meta/test/apimethods/TestGetUpdates.java b/telegrambots-meta/src/test/java/org/telegram/telegrambots/meta/test/apimethods/TestGetUpdates.java index 9b4f8659..4d433f6e 100644 --- a/telegrambots-meta/src/test/java/org/telegram/telegrambots/meta/test/apimethods/TestGetUpdates.java +++ b/telegrambots-meta/src/test/java/org/telegram/telegrambots/meta/test/apimethods/TestGetUpdates.java @@ -2,27 +2,29 @@ package org.telegram.telegrambots.meta.test.apimethods; import com.fasterxml.jackson.databind.ObjectMapper; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; -import org.telegram.telegrambots.meta.test.TelegramBotsHelper; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import org.telegram.telegrambots.meta.api.methods.updates.GetUpdates; import org.telegram.telegrambots.meta.api.objects.Update; import org.telegram.telegrambots.meta.exceptions.TelegramApiRequestException; +import org.telegram.telegrambots.meta.test.TelegramBotsHelper; import java.util.ArrayList; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; + /** * @author Ruben Bermudez * @version 1.0 */ -public class TestGetUpdates { +class TestGetUpdates { private GetUpdates getUpdates; private ObjectMapper mapper = new ObjectMapper(); - @Before - public void setUp() throws Exception { + @BeforeEach + void setUp() { getUpdates = new GetUpdates(); getUpdates.setOffset(15); getUpdates.setTimeout(50); @@ -30,28 +32,28 @@ public class TestGetUpdates { } @Test - public void TestGetUpdatesMustBeSerializable() throws Exception { + void TestGetUpdatesMustBeSerializable() throws Exception { String json = mapper.writeValueAsString(getUpdates); - Assert.assertNotNull(json); - Assert.assertEquals("{\"offset\":15,\"limit\":100,\"timeout\":50,\"method\":\"getupdates\"}", json); + assertNotNull(json); + assertEquals("{\"offset\":15,\"limit\":100,\"timeout\":50,\"method\":\"getupdates\"}", json); } @Test - public void TestGetUpdatesMustDeserializeCorrectResponse() throws Exception { + void TestGetUpdatesMustDeserializeCorrectResponse() throws Exception { ArrayList result = getUpdates.deserializeResponse(TelegramBotsHelper.GetResponseWithoutError()); - Assert.assertNotNull(result); - Assert.assertEquals(1, result.size()); + assertNotNull(result); + assertEquals(1, result.size()); } @Test - public void TestGetUpdatesMustThrowAnExceptionForInCorrectResponse() { + void TestGetUpdatesMustThrowAnExceptionForInCorrectResponse() { try { getUpdates.deserializeResponse(TelegramBotsHelper.GetResponseWithError()); } catch (TelegramApiRequestException e) { - Assert.assertNotNull(e.getParameters()); - Assert.assertEquals(Integer.valueOf(400), e.getErrorCode()); - Assert.assertEquals("Error descriptions", e.getApiResponse()); + assertNotNull(e.getParameters()); + assertEquals(Integer.valueOf(400), e.getErrorCode()); + assertEquals("Error descriptions", e.getApiResponse()); } } } diff --git a/telegrambots-meta/src/test/java/org/telegram/telegrambots/meta/test/apimethods/TestSetGameScore.java b/telegrambots-meta/src/test/java/org/telegram/telegrambots/meta/test/apimethods/TestSetGameScore.java index a04a9812..4c9a2835 100644 --- a/telegrambots-meta/src/test/java/org/telegram/telegrambots/meta/test/apimethods/TestSetGameScore.java +++ b/telegrambots-meta/src/test/java/org/telegram/telegrambots/meta/test/apimethods/TestSetGameScore.java @@ -2,26 +2,29 @@ package org.telegram.telegrambots.meta.test.apimethods; import com.fasterxml.jackson.databind.ObjectMapper; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; -import org.telegram.telegrambots.meta.test.TelegramBotsHelper; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import org.telegram.telegrambots.meta.api.methods.games.SetGameScore; import org.telegram.telegrambots.meta.api.objects.Message; +import org.telegram.telegrambots.meta.test.TelegramBotsHelper; import java.io.Serializable; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + /** * @author Ruben Bermudez * @version 1.0 */ -public class TestSetGameScore { +class TestSetGameScore { private SetGameScore setGameScore; private ObjectMapper mapper = new ObjectMapper(); - @Before - public void setUp() throws Exception { + @BeforeEach + void setUp() { setGameScore = new SetGameScore(); setGameScore.setChatId("12345"); setGameScore.setDisableEditMessage(true); @@ -31,25 +34,25 @@ public class TestSetGameScore { } @Test - public void TestGetUpdatesMustBeSerializable() throws Exception { + void TestGetUpdatesMustBeSerializable() throws Exception { String json = mapper.writeValueAsString(setGameScore); - Assert.assertNotNull(json); - Assert.assertEquals("{\"chat_id\":\"12345\",\"message_id\":54321,\"disable_edit_message\":true,\"user_id\":98765,\"score\":12,\"method\":\"setGameScore\"}", json); + assertNotNull(json); + assertEquals("{\"chat_id\":\"12345\",\"message_id\":54321,\"disable_edit_message\":true,\"user_id\":98765,\"score\":12,\"method\":\"setGameScore\"}", json); } @Test - public void TestGetUpdatesMustDeserializeCorrectResponse() throws Exception { + void TestGetUpdatesMustDeserializeCorrectResponse() throws Exception { Serializable result = setGameScore.deserializeResponse(TelegramBotsHelper.GetSetGameScoreBooleanResponse()); - Assert.assertNotNull(result); - Assert.assertTrue(result instanceof Boolean); - Assert.assertTrue((Boolean) result); + assertNotNull(result); + assertTrue(result instanceof Boolean); + assertTrue((Boolean) result); } @Test - public void TestGetUpdatesMustThrowAnExceptionForInCorrectResponse() throws Exception { + void TestGetUpdatesMustThrowAnExceptionForInCorrectResponse() throws Exception { Serializable result = setGameScore.deserializeResponse(TelegramBotsHelper.GetSetGameScoreMessageResponse()); - Assert.assertNotNull(result); - Assert.assertTrue(result instanceof Message); + assertNotNull(result); + assertTrue(result instanceof Message); } } diff --git a/telegrambots-meta/src/test/java/org/telegram/telegrambots/meta/test/base/TestBase.java b/telegrambots-meta/src/test/java/org/telegram/telegrambots/meta/test/base/TestBase.java index 14c18240..08fd07e6 100644 --- a/telegrambots-meta/src/test/java/org/telegram/telegrambots/meta/test/base/TestBase.java +++ b/telegrambots-meta/src/test/java/org/telegram/telegrambots/meta/test/base/TestBase.java @@ -1,11 +1,11 @@ package org.telegram.telegrambots.meta.test.base; -import org.junit.BeforeClass; +import org.junit.jupiter.api.BeforeAll; import org.telegram.telegrambots.meta.ApiContext; -import org.telegram.telegrambots.meta.test.fakes.FakeBotSession; -import org.telegram.telegrambots.meta.test.fakes.FakeWebhook; import org.telegram.telegrambots.meta.generics.BotSession; import org.telegram.telegrambots.meta.generics.Webhook; +import org.telegram.telegrambots.meta.test.fakes.FakeBotSession; +import org.telegram.telegrambots.meta.test.fakes.FakeWebhook; /** * @author Ruben Bermudez @@ -13,7 +13,7 @@ import org.telegram.telegrambots.meta.generics.Webhook; */ public abstract class TestBase { - @BeforeClass + @BeforeAll public static void beforeClass() { ApiContext.register(BotSession.class, FakeBotSession.class); ApiContext.register(Webhook.class, FakeWebhook.class); diff --git a/telegrambots-spring-boot-starter/pom.xml b/telegrambots-spring-boot-starter/pom.xml index f6903d70..c28a9bdf 100644 --- a/telegrambots-spring-boot-starter/pom.xml +++ b/telegrambots-spring-boot-starter/pom.xml @@ -3,9 +3,14 @@ xmlns="http://maven.apache.org/POM/4.0.0" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 - org.telegram + + + org.telegram + Bots + 4.4.0 + + telegrambots-spring-boot-starter - 4.3.1 jar Telegram Bots Spring Boot Starter @@ -57,9 +62,15 @@ + 11 + 8 + ${java.version} + ${java.version} + UTF-8 UTF-8 - 2.0.2.RELEASE + + 2.1.6.RELEASE @@ -67,7 +78,7 @@ org.telegram telegrambots - 4.3.1 + 4.4.0 org.springframework.boot @@ -92,23 +103,8 @@ org.assertj assertj-core test - 3.9.1 + 3.13.1 - - - org.mockito - mockito-all - 2.0.2-beta - test - - - - junit - junit - 4.11 - test - - @@ -121,7 +117,7 @@ org.apache.maven.plugins maven-gpg-plugin - 1.5 + 1.6 sign-artifacts @@ -135,7 +131,7 @@ org.sonatype.plugins nexus-staging-maven-plugin - 1.6.3 + 1.6.8 true ossrh @@ -145,7 +141,7 @@ maven-clean-plugin - 3.0.0 + 3.1.0 clean-project @@ -158,7 +154,7 @@ maven-assembly-plugin - 2.6 + 3.1.1 jar-with-dependencies @@ -177,7 +173,7 @@ org.apache.maven.plugins maven-source-plugin - 3.0.0 + 3.1.0 @@ -189,14 +185,14 @@ org.apache.maven.plugins maven-javadoc-plugin - 2.10.3 + 3.1.0 jar - -Xdoclint:none + none @@ -204,7 +200,7 @@ org.jacoco jacoco-maven-plugin - 0.7.7.201606060606 + 0.8.4 @@ -223,7 +219,7 @@ org.apache.maven.plugins maven-enforcer-plugin - 1.4.1 + 3.0.0-M2 enforce-versions @@ -241,7 +237,7 @@ org.apache.maven.plugins maven-dependency-plugin - 2.4 + 3.1.1 copy @@ -249,15 +245,21 @@ + + org.apache.maven.plugins + maven-surefire-plugin + 3.0.0-M3 + org.apache.maven.plugins maven-compiler-plugin + 3.8.1 - 1.8 - 1.8 + ${java.version} + ${java.version} UTF-8 diff --git a/telegrambots-spring-boot-starter/src/main/java/org/telegram/telegrambots/starter/TelegramBotInitializer.java b/telegrambots-spring-boot-starter/src/main/java/org/telegram/telegrambots/starter/TelegramBotInitializer.java index 241d962d..951dc3b8 100644 --- a/telegrambots-spring-boot-starter/src/main/java/org/telegram/telegrambots/starter/TelegramBotInitializer.java +++ b/telegrambots-spring-boot-starter/src/main/java/org/telegram/telegrambots/starter/TelegramBotInitializer.java @@ -1,12 +1,13 @@ package org.telegram.telegrambots.starter; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; import org.springframework.beans.factory.InitializingBean; import org.telegram.telegrambots.meta.TelegramBotsApi; import org.telegram.telegrambots.meta.exceptions.TelegramApiException; import org.telegram.telegrambots.meta.generics.BotSession; import org.telegram.telegrambots.meta.generics.LongPollingBot; import org.telegram.telegrambots.meta.generics.WebhookBot; -import org.telegram.telegrambots.meta.logging.BotLogger; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; @@ -20,6 +21,7 @@ import static java.lang.String.format; * Receives all beand which are #LongPollingBot and #WebhookBot and register them in #TelegramBotsApi. */ public class TelegramBotInitializer implements InitializingBean { + private static final Logger log = LogManager.getLogger(TelegramBotInitializer.class); private final TelegramBotsApi telegramBotsApi; private final List longPollingBots; @@ -37,7 +39,7 @@ public class TelegramBotInitializer implements InitializingBean { } @Override - public void afterPropertiesSet() throws Exception { + public void afterPropertiesSet() { try { for (LongPollingBot bot : longPollingBots) { BotSession session = telegramBotsApi.registerBot(bot); @@ -54,12 +56,8 @@ public class TelegramBotInitializer implements InitializingBean { private void handleAnnotatedMethod(Object bot, Method method, BotSession session) { try { if (method.getParameterCount() > 1) { - BotLogger.warn(this.getClass().getSimpleName(), - format("Method %s of Type %s has too many parameters", - method.getName(), - method.getDeclaringClass().getCanonicalName() - ) - ); + log.warn(format("Method %s of Type %s has too many parameters", + method.getName(), method.getDeclaringClass().getCanonicalName())); return; } if (method.getParameterCount() == 0) { @@ -70,18 +68,11 @@ public class TelegramBotInitializer implements InitializingBean { method.invoke(bot, session); return; } - BotLogger.warn(this.getClass().getSimpleName(), - format("Method %s of Type %s has invalid parameter type", - method.getName(), - method.getDeclaringClass().getCanonicalName() - ) - ); + log.warn(format("Method %s of Type %s has invalid parameter type", + method.getName(), method.getDeclaringClass().getCanonicalName())); } catch (InvocationTargetException | IllegalAccessException e) { - BotLogger.error(this.getClass().getSimpleName(), - format("Couldn't invoke Method %s of Type %s", - method.getName(), method.getDeclaringClass().getCanonicalName() - ) - ); + log.error(format("Couldn't invoke Method %s of Type %s", + method.getName(), method.getDeclaringClass().getCanonicalName())); } } diff --git a/telegrambots-spring-boot-starter/src/test/java/org/telegram/telegrambots/starter/TestTelegramBotStarterConfiguration.java b/telegrambots-spring-boot-starter/src/test/java/org/telegram/telegrambots/starter/TestTelegramBotStarterConfiguration.java index 938c22ee..42a2d1cc 100644 --- a/telegrambots-spring-boot-starter/src/test/java/org/telegram/telegrambots/starter/TestTelegramBotStarterConfiguration.java +++ b/telegrambots-spring-boot-starter/src/test/java/org/telegram/telegrambots/starter/TestTelegramBotStarterConfiguration.java @@ -1,10 +1,6 @@ package org.telegram.telegrambots.starter; - -import static org.assertj.core.api.Assertions.assertThat; - -import org.junit.Test; -import static org.mockito.Mockito.*; +import org.junit.jupiter.api.Test; import org.springframework.boot.autoconfigure.AutoConfigurations; import org.springframework.boot.test.context.runner.ApplicationContextRunner; import org.springframework.context.annotation.Bean; @@ -13,13 +9,19 @@ import org.telegram.telegrambots.meta.TelegramBotsApi; import org.telegram.telegrambots.meta.generics.LongPollingBot; import org.telegram.telegrambots.meta.generics.WebhookBot; -public class TestTelegramBotStarterConfiguration { +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoMoreInteractions; + +class TestTelegramBotStarterConfiguration { private final ApplicationContextRunner contextRunner = new ApplicationContextRunner() .withConfiguration(AutoConfigurations.of(MockTelegramBotsApi.class, TelegramBotStarterConfiguration.class)); @Test - public void createMockTelegramBotsApiWithDefaultSettings() { + void createMockTelegramBotsApiWithDefaultSettings() { this.contextRunner.run((context) -> { assertThat(context).hasSingleBean(TelegramBotsApi.class); assertThat(context).hasSingleBean(TelegramBotInitializer.class); @@ -30,7 +32,7 @@ public class TestTelegramBotStarterConfiguration { } @Test - public void createOnlyLongPollingBot() { + void createOnlyLongPollingBot() { this.contextRunner.withUserConfiguration(LongPollingBotConfig.class) .run((context) -> { assertThat(context).hasSingleBean(LongPollingBot.class); @@ -44,7 +46,7 @@ public class TestTelegramBotStarterConfiguration { } @Test - public void createOnlyWebhookBot() { + void createOnlyWebhookBot() { this.contextRunner.withUserConfiguration(WebhookBotConfig.class) .run((context) -> { assertThat(context).hasSingleBean(WebhookBot.class); @@ -58,7 +60,7 @@ public class TestTelegramBotStarterConfiguration { } @Test - public void createLongPoolingBotAndWebhookBot() { + void createLongPoolingBotAndWebhookBot() { this.contextRunner.withUserConfiguration(LongPollingBotConfig.class, WebhookBotConfig.class) .run((context) -> { assertThat(context).hasSingleBean(LongPollingBot.class); diff --git a/telegrambots-spring-boot-starter/src/test/java/org/telegram/telegrambots/starter/TestTelegramBotStarterRegistrationHooks.java b/telegrambots-spring-boot-starter/src/test/java/org/telegram/telegrambots/starter/TestTelegramBotStarterRegistrationHooks.java index aba90dad..2f108d81 100644 --- a/telegrambots-spring-boot-starter/src/test/java/org/telegram/telegrambots/starter/TestTelegramBotStarterRegistrationHooks.java +++ b/telegrambots-spring-boot-starter/src/test/java/org/telegram/telegrambots/starter/TestTelegramBotStarterRegistrationHooks.java @@ -1,7 +1,6 @@ package org.telegram.telegrambots.starter; - -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.springframework.boot.autoconfigure.AutoConfigurations; import org.springframework.boot.test.context.runner.ApplicationContextRunner; import org.springframework.context.annotation.Bean; @@ -15,9 +14,14 @@ import org.telegram.telegrambots.meta.generics.LongPollingBot; import org.telegram.telegrambots.updatesreceivers.DefaultBotSession; import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.Mockito.*; +import static org.mockito.Mockito.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoMoreInteractions; +import static org.mockito.Mockito.when; -public class TestTelegramBotStarterRegistrationHooks { +class TestTelegramBotStarterRegistrationHooks { private final ApplicationContextRunner contextRunner = new ApplicationContextRunner() .withConfiguration(AutoConfigurations.of(MockTelegramBotsApi.class, TelegramBotStarterConfiguration.class)); @@ -30,7 +34,7 @@ public class TestTelegramBotStarterRegistrationHooks { private static final TelegramBotsApi mockTelegramBotsApi = mock(TelegramBotsApi.class); @Test - public void longPollingBotWithAnnotatedMethodshouldBeCalled() throws TelegramApiRequestException { + void longPollingBotWithAnnotatedMethodshouldBeCalled() throws TelegramApiRequestException { when(mockTelegramBotsApi.registerBot(any(LongPollingBot.class))).thenReturn(someBotSession); diff --git a/telegrambots/pom.xml b/telegrambots/pom.xml index 9f85279e..1143fd5e 100644 --- a/telegrambots/pom.xml +++ b/telegrambots/pom.xml @@ -3,9 +3,14 @@ xmlns="http://maven.apache.org/POM/4.0.0" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 - org.telegram + + + org.telegram + Bots + 4.4.0 + + telegrambots - 4.3.1 jar Telegram Bots @@ -57,15 +62,21 @@ + 11 + 8 + ${java.version} + ${java.version} + UTF-8 UTF-8 - 2.25.1 + + 2.29 1.19.3 - 4.5.3 + 4.5.9 20180813 2.9.9 - 2.9.0 - 2.5 + 2.9.9 + 2.6 @@ -84,7 +95,7 @@ org.telegram telegrambots-meta - 4.3.1 + 4.4.0 com.fasterxml.jackson.core @@ -96,26 +107,26 @@ jackson-jaxrs-json-provider ${jackson.version} + + com.fasterxml.jackson.module + jackson-module-jaxb-annotations + 2.9.9 + com.fasterxml.jackson.core jackson-databind ${jackson.version} - - - com.fasterxml.jackson.core - jackson-annotations - - + + + org.glassfish.jersey.inject + jersey-hk2 + ${glassfish.version} org.glassfish.jersey.media jersey-media-json-jackson ${glassfish.version} - - com.fasterxml.jackson.core - jackson-annotations - com.fasterxml.jackson.jaxrs jackson-jaxrs-json-provider @@ -169,12 +180,6 @@ ${glassfish.version} test - - org.mockito - mockito-all - 2.0.2-beta - test - @@ -184,10 +189,15 @@ ${project.build.directory}/test-classes ${project.basedir}/src/main/java + + org.apache.maven.plugins + maven-surefire-plugin + 3.0.0-M3 + org.apache.maven.plugins maven-gpg-plugin - 1.5 + 1.6 sign-artifacts @@ -201,7 +211,7 @@ org.sonatype.plugins nexus-staging-maven-plugin - 1.6.3 + 1.6.8 true ossrh @@ -211,7 +221,7 @@ maven-clean-plugin - 3.0.0 + 3.1.0 clean-project @@ -224,7 +234,7 @@ maven-assembly-plugin - 2.6 + 3.1.1 jar-with-dependencies @@ -243,7 +253,7 @@ org.apache.maven.plugins maven-source-plugin - 3.0.0 + 3.1.0 @@ -255,14 +265,14 @@ org.apache.maven.plugins maven-javadoc-plugin - 2.10.3 + 3.1.0 jar - -Xdoclint:none + none @@ -270,7 +280,7 @@ org.jacoco jacoco-maven-plugin - 0.7.7.201606060606 + 0.8.4 @@ -289,7 +299,7 @@ org.apache.maven.plugins maven-enforcer-plugin - 1.4.1 + 3.0.0-M2 enforce-versions @@ -307,7 +317,7 @@ org.apache.maven.plugins maven-dependency-plugin - 2.4 + 3.1.1 copy @@ -321,9 +331,10 @@ org.apache.maven.plugins maven-compiler-plugin + 3.8.1 - 1.8 - 1.8 + ${java.version} + ${java.version} UTF-8 diff --git a/telegrambots/src/main/java/org/telegram/telegrambots/bots/DefaultAbsSender.java b/telegrambots/src/main/java/org/telegram/telegrambots/bots/DefaultAbsSender.java index e7cbcec0..0372eeb9 100644 --- a/telegrambots/src/main/java/org/telegram/telegrambots/bots/DefaultAbsSender.java +++ b/telegrambots/src/main/java/org/telegram/telegrambots/bots/DefaultAbsSender.java @@ -2,7 +2,6 @@ package org.telegram.telegrambots.bots; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; -import org.apache.commons.io.FileUtils; import org.apache.http.HttpEntity; import org.apache.http.client.config.RequestConfig; import org.apache.http.client.methods.CloseableHttpResponse; @@ -14,6 +13,7 @@ import org.apache.http.entity.mime.MultipartEntityBuilder; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.util.EntityUtils; import org.telegram.telegrambots.facilities.TelegramHttpClientBuilder; +import org.telegram.telegrambots.facilities.filedownloader.TelegramFileDownloader; import org.telegram.telegrambots.meta.api.methods.BotApiMethod; import org.telegram.telegrambots.meta.api.methods.groupadministration.SetChatPhoto; import org.telegram.telegrambots.meta.api.methods.send.*; @@ -36,10 +36,9 @@ import org.telegram.telegrambots.meta.updateshandlers.DownloadFileCallback; import org.telegram.telegrambots.meta.updateshandlers.SentCallback; import java.io.IOException; +import java.io.InputStream; import java.io.Serializable; import java.net.InetSocketAddress; -import java.net.MalformedURLException; -import java.net.URL; import java.nio.charset.StandardCharsets; import java.util.List; import java.util.concurrent.ExecutorService; @@ -52,7 +51,7 @@ import static org.telegram.telegrambots.Constants.SOCKET_TIMEOUT; * @version 1.0 * Implementation of all the methods needed to interact with Telegram Servers */ -@SuppressWarnings({"unused", "WeakerAccess"}) +@SuppressWarnings({"unused"}) public abstract class DefaultAbsSender extends AbsSender { private static final ContentType TEXT_PLAIN_CONTENT_TYPE = ContentType.create("text/plain", StandardCharsets.UTF_8); @@ -61,6 +60,7 @@ public abstract class DefaultAbsSender extends AbsSender { private final DefaultBotOptions options; private volatile CloseableHttpClient httpClient; private volatile RequestConfig requestConfig; + private final TelegramFileDownloader telegramFileDownloader = new TelegramFileDownloader(this::getBotToken); protected DefaultAbsSender(DefaultBotOptions options) { super(); @@ -109,37 +109,35 @@ public abstract class DefaultAbsSender extends AbsSender { // Send Requests public final java.io.File downloadFile(String filePath) throws TelegramApiException { - if(filePath == null || filePath.isEmpty()){ - throw new TelegramApiException("Parameter file can not be null"); - } - String url = File.getFileUrl(getBotToken(), filePath); - String tempFileName = Long.toString(System.currentTimeMillis()); - return downloadToTemporaryFileWrappingExceptions(url, tempFileName); + return telegramFileDownloader.downloadFile(filePath); } public final java.io.File downloadFile(File file) throws TelegramApiException { - assertParamNotNull(file, "file"); - String url = file.getFileUrl(getBotToken()); - String tempFileName = file.getFileId(); - return downloadToTemporaryFileWrappingExceptions(url, tempFileName); + return telegramFileDownloader.downloadFile(file); + } + + public final java.io.File downloadFile(File file, java.io.File outputFile) throws TelegramApiException { + return telegramFileDownloader.downloadFile(file, outputFile); + } + + public final java.io.File downloadFile(String filePath, java.io.File outputFile) throws TelegramApiException { + return telegramFileDownloader.downloadFile(filePath, outputFile); } public final void downloadFileAsync(String filePath, DownloadFileCallback callback) throws TelegramApiException { - if(filePath == null || filePath.isEmpty()){ - throw new TelegramApiException("Parameter filePath can not be null"); - } - assertParamNotNull(callback, "callback"); - String url = File.getFileUrl(getBotToken(), filePath); - String tempFileName = Long.toString(System.currentTimeMillis()); - exe.submit(getDownloadFileAsyncJob(filePath, callback, url, tempFileName)); + telegramFileDownloader.downloadFileAsync(filePath, callback); } public final void downloadFileAsync(File file, DownloadFileCallback callback) throws TelegramApiException { - assertParamNotNull(file, "file"); - assertParamNotNull(callback, "callback"); - String url = file.getFileUrl(getBotToken()); - String tempFileName = file.getFileId(); - exe.submit(getDownloadFileAsyncJob(file, callback, url, tempFileName)); + telegramFileDownloader.downloadFileAsync(file, callback); + } + + public final InputStream downloadFileAsStream(String filePath) throws TelegramApiException { + return telegramFileDownloader.downloadFileAsStream(filePath); + } + + public final InputStream downloadFileAsStream(File file) throws TelegramApiException { + return telegramFileDownloader.downloadFileAsStream(file); } // Specific Send Requests @@ -720,38 +718,6 @@ public abstract class DefaultAbsSender extends AbsSender { } } - private Runnable getDownloadFileAsyncJob(T fileIdentifier, DownloadFileCallback callback, String url, String tempFileName) { - //noinspection Convert2Lambda - return new Runnable() { - @Override - public void run() { - try { - callback.onResult(fileIdentifier, downloadToTemporaryFile(url, tempFileName)); - } catch (MalformedURLException e) { - callback.onException(fileIdentifier, new TelegramApiException("Wrong url for file: " + url)); - } catch (IOException e) { - callback.onException(fileIdentifier, new TelegramApiRequestException("Error downloading the file", e)); - } - } - }; - } - - private java.io.File downloadToTemporaryFileWrappingExceptions(String url, String tempFileName) throws TelegramApiException { - try { - return downloadToTemporaryFile(url, tempFileName); - } catch (MalformedURLException e) { - throw new TelegramApiException("Wrong url for file: " + url); - } catch (IOException e) { - throw new TelegramApiRequestException("Error downloading the file", e); - } - } - - private java.io.File downloadToTemporaryFile(String url, String tempFileName) throws IOException { - java.io.File output = java.io.File.createTempFile(tempFileName, ".tmp"); - FileUtils.copyURLToFile(new URL(url), output); - return output; - } - private > String sendMethodRequest(Method method) throws TelegramApiValidationException, IOException { method.validate(); String url = getBaseUrl() + method.getMethod(); diff --git a/telegrambots/src/main/java/org/telegram/telegrambots/facilities/filedownloader/DownloadFileException.java b/telegrambots/src/main/java/org/telegram/telegrambots/facilities/filedownloader/DownloadFileException.java new file mode 100644 index 00000000..d26c3f72 --- /dev/null +++ b/telegrambots/src/main/java/org/telegram/telegrambots/facilities/filedownloader/DownloadFileException.java @@ -0,0 +1,11 @@ +package org.telegram.telegrambots.facilities.filedownloader; + +/** + * Runtime Exception to wrap Exceptions thrown during file download + */ +@SuppressWarnings("WeakerAccess") +public class DownloadFileException extends RuntimeException { + public DownloadFileException(final String message, final Throwable e) { + super(message, e); + } +} diff --git a/telegrambots/src/main/java/org/telegram/telegrambots/facilities/filedownloader/TelegramFileDownloader.java b/telegrambots/src/main/java/org/telegram/telegrambots/facilities/filedownloader/TelegramFileDownloader.java new file mode 100644 index 00000000..02c34c9f --- /dev/null +++ b/telegrambots/src/main/java/org/telegram/telegrambots/facilities/filedownloader/TelegramFileDownloader.java @@ -0,0 +1,172 @@ +package org.telegram.telegrambots.facilities.filedownloader; + +import org.apache.http.HttpResponse; +import org.apache.http.client.HttpClient; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.impl.client.HttpClients; +import org.telegram.telegrambots.meta.api.objects.File; +import org.telegram.telegrambots.meta.exceptions.TelegramApiException; +import org.telegram.telegrambots.meta.updateshandlers.DownloadFileCallback; + +import java.io.IOException; +import java.io.InputStream; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletionException; +import java.util.concurrent.ExecutionException; +import java.util.function.Supplier; + +import static org.apache.commons.io.FileUtils.copyInputStreamToFile; +import static org.apache.http.HttpStatus.SC_OK; + +/** + * Wraps the file downloading code into one class. + * @author Chase22 + * @version 1.0 + */ +public class TelegramFileDownloader { + private final HttpClient httpClient; + private final Supplier botTokenSupplier; + + public TelegramFileDownloader(final Supplier botTokenSupplier) { + this.botTokenSupplier = botTokenSupplier; + httpClient = HttpClients.createDefault(); + } + + public TelegramFileDownloader(final HttpClient httpClient, final Supplier botTokenSupplier) { + this.httpClient = httpClient; + this.botTokenSupplier = botTokenSupplier; + } + + public final java.io.File downloadFile(String filePath) throws TelegramApiException { + String tempFileName = Long.toString(System.currentTimeMillis()); + return downloadFile(filePath, getTempFile(tempFileName)); + } + + public final java.io.File downloadFile(File file) throws TelegramApiException { + return downloadFile(file, getTempFile(file.getFileId())); + } + + public final java.io.File downloadFile(File file, java.io.File outputFile) throws TelegramApiException { + if (file == null) { + throw new TelegramApiException("Parameter file can not be null"); + } + String url = file.getFileUrl(botTokenSupplier.get()); + return downloadToFile(url, outputFile); + } + + public final java.io.File downloadFile(String filePath, java.io.File outputFile) throws TelegramApiException { + if (filePath == null || filePath.isEmpty()) { + throw new TelegramApiException("Parameter file can not be null"); + } + String url = File.getFileUrl(botTokenSupplier.get(), filePath); + return downloadToFile(url, outputFile); + } + + public final InputStream downloadFileAsStream(String filePath) throws TelegramApiException { + try { + return getFileDownloadStreamFuture(File.getFileUrl(botTokenSupplier.get(), filePath)).get(); + } catch (InterruptedException e) { + throw new TelegramApiException("Error downloading file", e); + } catch (ExecutionException e) { + throw new TelegramApiException("Error downloading file", e.getCause()); + } + } + + public final InputStream downloadFileAsStream(File file) throws TelegramApiException { + try { + return getFileDownloadStreamFuture(file.getFileUrl(botTokenSupplier.get())).get(); + } catch (InterruptedException e) { + throw new TelegramApiException("Error downloading file", e); + } catch (ExecutionException e) { + throw new TelegramApiException("Error downloading file", e.getCause()); + } + } + + public final void downloadFileAsync(String filePath, DownloadFileCallback callback) throws TelegramApiException { + if (filePath == null || filePath.isEmpty()) { + throw new TelegramApiException("Parameter filePath can not be null"); + } + if (callback == null) { + throw new TelegramApiException("Parameter callback can not be null"); + } + String url = File.getFileUrl(botTokenSupplier.get(), filePath); + String tempFileName = Long.toString(System.currentTimeMillis()); + + getFileDownloadFuture(url, getTempFile(tempFileName)) + .thenAccept(output -> callback.onResult(filePath, output)) + .exceptionally(throwable -> { + // Unwrap java.util.concurrent.CompletionException + if (throwable instanceof CompletionException) { + callback.onException(filePath, new TelegramApiException("Error downloading file", throwable.getCause())); + } else { + callback.onException(filePath, new TelegramApiException("Error downloading file", throwable)); + } + return null; + }); + } + + public final void downloadFileAsync(File file, DownloadFileCallback callback) throws TelegramApiException { + if (file == null) { + throw new TelegramApiException("Parameter file can not be null"); + } + if (callback == null) { + throw new TelegramApiException("Parameter callback can not be null"); + } + String url = file.getFileUrl(botTokenSupplier.get()); + String tempFileName = file.getFileId(); + + getFileDownloadFuture(url, getTempFile(tempFileName)) + .thenAccept(output -> callback.onResult(file, output)) + .exceptionally(throwable -> { + callback.onException(file, new TelegramApiException("Error downloading file", throwable)); + return null; + }); + + } + + private java.io.File getTempFile(String tempFileName) throws TelegramApiException { + try { + return java.io.File.createTempFile(tempFileName, ".tmp"); + } catch (IOException e) { + throw new TelegramApiException("Error downloading file", e); + } + } + + private java.io.File downloadToFile(String url, java.io.File output) throws TelegramApiException { + try { + return getFileDownloadFuture(url, output).get(); + } catch (InterruptedException e) { + throw new TelegramApiException("File Download got interrupted", e); + } catch (ExecutionException e) { + throw new TelegramApiException("Error downloading file", e.getCause()); + } + } + + private CompletableFuture getFileDownloadFuture(String url, java.io.File output) { + return getFileDownloadStreamFuture(url).thenApply(stream -> { + try { + copyInputStreamToFile(stream, output); + return output; + } catch (IOException e) { + throw new DownloadFileException("Error writing downloaded file", e); + } + }); + } + + private CompletableFuture getFileDownloadStreamFuture(final String url) { + return CompletableFuture.supplyAsync(() -> { + try { + HttpResponse response = httpClient.execute(new HttpGet(url)); + final int statusCode = response.getStatusLine().getStatusCode(); + if (statusCode == SC_OK) { + return response.getEntity().getContent(); + } else { + throw new TelegramApiException("Unexpected Status code while downloading file. Expected 200 got " + statusCode); + } + } catch (IOException | TelegramApiException e) { + throw new DownloadFileException("Error downloading file", e); + } + }); + } + +} diff --git a/telegrambots/src/main/java/org/telegram/telegrambots/facilities/proxysocketfactorys/SocksConnectionSocketFactory.java b/telegrambots/src/main/java/org/telegram/telegrambots/facilities/proxysocketfactorys/SocksConnectionSocketFactory.java index d2b29a5e..2ecd9aa0 100644 --- a/telegrambots/src/main/java/org/telegram/telegrambots/facilities/proxysocketfactorys/SocksConnectionSocketFactory.java +++ b/telegrambots/src/main/java/org/telegram/telegrambots/facilities/proxysocketfactorys/SocksConnectionSocketFactory.java @@ -4,7 +4,6 @@ package org.telegram.telegrambots.facilities.proxysocketfactorys; import org.apache.http.HttpHost; import org.apache.http.conn.socket.PlainConnectionSocketFactory; import org.apache.http.protocol.HttpContext; -import sun.net.SocksProxy; import java.io.IOException; import java.net.InetSocketAddress; @@ -14,10 +13,9 @@ import java.net.Socket; public class SocksConnectionSocketFactory extends PlainConnectionSocketFactory { @Override - public Socket createSocket(final HttpContext context) throws IOException { + public Socket createSocket(final HttpContext context) { InetSocketAddress socksaddr = (InetSocketAddress) context.getAttribute("socketAddress"); - int socksVersion = (Integer) context.getAttribute("socksVersion"); - Proxy proxy = SocksProxy.create(socksaddr, socksVersion); + Proxy proxy = new Proxy(Proxy.Type.SOCKS, socksaddr); return new Socket(proxy); } diff --git a/telegrambots/src/main/java/org/telegram/telegrambots/facilities/proxysocketfactorys/SocksSSLConnectionSocketFactory.java b/telegrambots/src/main/java/org/telegram/telegrambots/facilities/proxysocketfactorys/SocksSSLConnectionSocketFactory.java index cbd46b6a..80dc2adb 100644 --- a/telegrambots/src/main/java/org/telegram/telegrambots/facilities/proxysocketfactorys/SocksSSLConnectionSocketFactory.java +++ b/telegrambots/src/main/java/org/telegram/telegrambots/facilities/proxysocketfactorys/SocksSSLConnectionSocketFactory.java @@ -4,14 +4,14 @@ import org.apache.http.HttpHost; import org.apache.http.conn.ssl.NoopHostnameVerifier; import org.apache.http.conn.ssl.SSLConnectionSocketFactory; import org.apache.http.protocol.HttpContext; -import sun.net.SocksProxy; -import javax.net.ssl.SSLContext; import java.io.IOException; import java.net.InetSocketAddress; import java.net.Proxy; import java.net.Socket; +import javax.net.ssl.SSLContext; + public class SocksSSLConnectionSocketFactory extends SSLConnectionSocketFactory { @@ -20,10 +20,9 @@ public class SocksSSLConnectionSocketFactory extends SSLConnectionSocketFactory } @Override - public Socket createSocket(final HttpContext context) throws IOException { + public Socket createSocket(final HttpContext context) { InetSocketAddress socksaddr = (InetSocketAddress) context.getAttribute("socketAddress"); - int socksVersion = (Integer) context.getAttribute("socksVersion"); - Proxy proxy = SocksProxy.create(socksaddr, socksVersion); + Proxy proxy = new Proxy(Proxy.Type.SOCKS, socksaddr); return new Socket(proxy); } diff --git a/telegrambots/src/main/java/org/telegram/telegrambots/updatesreceivers/DefaultBotSession.java b/telegrambots/src/main/java/org/telegram/telegrambots/updatesreceivers/DefaultBotSession.java index 0c1c9f13..319e39ac 100644 --- a/telegrambots/src/main/java/org/telegram/telegrambots/updatesreceivers/DefaultBotSession.java +++ b/telegrambots/src/main/java/org/telegram/telegrambots/updatesreceivers/DefaultBotSession.java @@ -11,6 +11,8 @@ import org.apache.http.entity.ContentType; import org.apache.http.entity.StringEntity; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.util.EntityUtils; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; import org.json.JSONException; import org.telegram.telegrambots.meta.ApiConstants; import org.telegram.telegrambots.meta.api.methods.updates.GetUpdates; @@ -19,7 +21,6 @@ import org.telegram.telegrambots.bots.DefaultBotOptions; import org.telegram.telegrambots.meta.exceptions.TelegramApiRequestException; import org.telegram.telegrambots.facilities.TelegramHttpClientBuilder; import org.telegram.telegrambots.meta.generics.*; -import org.telegram.telegrambots.meta.logging.BotLogger; import java.io.IOException; import java.io.InvalidObjectException; @@ -39,7 +40,7 @@ import static org.telegram.telegrambots.Constants.SOCKET_TIMEOUT; * Thread to request updates with active wait */ public class DefaultBotSession implements BotSession { - private static final String LOGTAG = "BOTSESSION"; + private static final Logger log = LogManager.getLogger(DefaultBotSession.class); private AtomicBoolean running = new AtomicBoolean(false); @@ -170,7 +171,7 @@ public class DefaultBotSession implements BotSession { try { httpclient.close(); } catch (IOException e) { - BotLogger.warn(LOGTAG, e); + log.warn(e.getLocalizedMessage(), e); } } super.interrupt(); @@ -203,10 +204,10 @@ public class DefaultBotSession implements BotSession { if (!running.get()) { receivedUpdates.clear(); } - BotLogger.debug(LOGTAG, e); + log.debug(e.getLocalizedMessage(), e); interrupt(); } catch (Exception global) { - BotLogger.severe(LOGTAG, global); + log.fatal(global.getLocalizedMessage(), global); try { synchronized (lock) { lock.wait(exponentialBackOff.nextBackOffMillis()); @@ -215,14 +216,14 @@ public class DefaultBotSession implements BotSession { if (!running.get()) { receivedUpdates.clear(); } - BotLogger.debug(LOGTAG, e); + log.debug(e.getLocalizedMessage(), e); interrupt(); } } } } } - BotLogger.debug(LOGTAG, "Reader thread has being closed"); + log.debug("Reader thread has being closed"); } private List getUpdatesFromServer() throws IOException { @@ -248,7 +249,7 @@ public class DefaultBotSession implements BotSession { String responseContent = EntityUtils.toString(buf, StandardCharsets.UTF_8); if (response.getStatusLine().getStatusCode() >= 500) { - BotLogger.warn(LOGTAG, responseContent); + log.warn(responseContent); synchronized (lock) { lock.wait(500); } @@ -258,15 +259,15 @@ public class DefaultBotSession implements BotSession { exponentialBackOff.reset(); return updates; } catch (JSONException e) { - BotLogger.severe(responseContent, LOGTAG, e); + log.error("Error deserializing update: " + responseContent, e); } } } catch (SocketException | InvalidObjectException | TelegramApiRequestException e) { - BotLogger.severe(LOGTAG, e); + log.fatal(e.getLocalizedMessage(), e); } catch (SocketTimeoutException e) { - BotLogger.fine(LOGTAG, e); + log.info(e.getLocalizedMessage(), e); } catch (InterruptedException e) { - BotLogger.fine(LOGTAG, e); + log.info(e.getLocalizedMessage(), e); interrupt(); } return Collections.emptyList(); @@ -305,13 +306,13 @@ public class DefaultBotSession implements BotSession { } callback.onUpdatesReceived(updates); } catch (InterruptedException e) { - BotLogger.debug(LOGTAG, e); + log.debug(e.getLocalizedMessage(), e); interrupt(); } catch (Exception e) { - BotLogger.severe(LOGTAG, e); + log.fatal(e.getLocalizedMessage(), e); } } - BotLogger.debug(LOGTAG, "Handler thread has being closed"); + log.debug("Handler thread has being closed"); } } } diff --git a/telegrambots/src/main/java/org/telegram/telegrambots/updatesreceivers/ExponentialBackOff.java b/telegrambots/src/main/java/org/telegram/telegrambots/updatesreceivers/ExponentialBackOff.java index 2fbf096c..80769b29 100644 --- a/telegrambots/src/main/java/org/telegram/telegrambots/updatesreceivers/ExponentialBackOff.java +++ b/telegrambots/src/main/java/org/telegram/telegrambots/updatesreceivers/ExponentialBackOff.java @@ -70,22 +70,22 @@ import com.google.common.base.Preconditions; */ public class ExponentialBackOff { /** The default initial interval value in milliseconds (0.5 seconds). */ - public static final int DEFAULT_INITIAL_INTERVAL_MILLIS = 500; + private static final int DEFAULT_INITIAL_INTERVAL_MILLIS = 500; /** * The default randomization factor (0.5 which results in a random period ranging between 50% * below and 50% above the retry interval). */ - public static final double DEFAULT_RANDOMIZATION_FACTOR = 0.5; + private static final double DEFAULT_RANDOMIZATION_FACTOR = 0.5; /** The default multiplier value (1.5 which is 50% increase per back off). */ - public 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). */ - public static final int DEFAULT_MAX_INTERVAL_MILLIS = 30000; + private static final int DEFAULT_MAX_INTERVAL_MILLIS = 30000; /** The default maximum elapsed time in milliseconds (60 minutes). */ - public static final int DEFAULT_MAX_ELAPSED_TIME_MILLIS = 3600000; + private static final int DEFAULT_MAX_ELAPSED_TIME_MILLIS = 3600000; /** The current retry interval in milliseconds. */ private int currentIntervalMillis; @@ -116,7 +116,7 @@ public class ExponentialBackOff { * The system time in nanoseconds. It is calculated when an ExponentialBackOffPolicy instance is * created and is reset when {@link #reset()} is called. */ - long startTimeNanos; + private long startTimeNanos; /** * The maximum elapsed time after instantiating {@link ExponentialBackOff} or calling @@ -139,14 +139,14 @@ public class ExponentialBackOff { *
  • {@code maxElapsedTimeMillis} defaults in {@link #DEFAULT_MAX_ELAPSED_TIME_MILLIS}
  • * */ - public ExponentialBackOff() { + ExponentialBackOff() { this(new Builder()); } /** * @param builder builder */ - protected ExponentialBackOff(Builder builder) { + private ExponentialBackOff(Builder builder) { initialIntervalMillis = builder.initialIntervalMillis; randomizationFactor = builder.randomizationFactor; multiplier = builder.multiplier; @@ -161,7 +161,7 @@ public class ExponentialBackOff { } /** Sets the interval back to the initial retry interval and restarts the timer. */ - public final void reset() { + final void reset() { currentIntervalMillis = initialIntervalMillis; startTimeNanos = nanoTime(); } @@ -178,7 +178,7 @@ public class ExponentialBackOff { * Subclasses may override if a different algorithm is required. *

    */ - public long nextBackOffMillis() { + long nextBackOffMillis() { // Make sure we have not gone over the maximum elapsed time. if (getElapsedTimeMillis() > maxElapsedTimeMillis) { return maxElapsedTimeMillis; @@ -193,7 +193,7 @@ public class ExponentialBackOff { * Returns a random value from the interval [randomizationFactor * currentInterval, * randomizationFactor * currentInterval]. */ - static int getRandomValueFromInterval( + private static int getRandomValueFromInterval( double randomizationFactor, double random, int currentIntervalMillis) { double delta = randomizationFactor * currentIntervalMillis; double minInterval = currentIntervalMillis - delta; @@ -201,60 +201,7 @@ public class ExponentialBackOff { // Get a random value from the range [minInterval, maxInterval]. // The formula used below has a +1 because if the minInterval is 1 and the maxInterval is 3 then // we want a 33% chance for selecting either 1, 2 or 3. - int randomValue = (int) (minInterval + (random * (maxInterval - minInterval + 1))); - return randomValue; - } - - /** Returns the initial retry interval in milliseconds. */ - public final int getInitialIntervalMillis() { - return initialIntervalMillis; - } - - /** - * Returns the randomization factor to use for creating a range around the retry interval. - * - *

    - * A randomization factor of 0.5 results in a random period ranging between 50% below and 50% - * above the retry interval. - *

    - */ - public final double getRandomizationFactor() { - return randomizationFactor; - } - - /** - * Returns the current retry interval in milliseconds. - */ - public final int getCurrentIntervalMillis() { - return currentIntervalMillis; - } - - /** - * Returns the value to multiply the current interval with for each retry attempt. - */ - public final double getMultiplier() { - return multiplier; - } - - /** - * Returns the maximum value of the back off period in milliseconds. Once the current interval - * reaches this value it stops increasing. - */ - public final int getMaxIntervalMillis() { - return maxIntervalMillis; - } - - /** - * Returns the maximum elapsed time in milliseconds. - * - *

    - * If the time elapsed since an {@link ExponentialBackOff} instance is created goes past the - * max_elapsed_time then the method {@link #nextBackOffMillis()} starts returning - * this value. The elapsed time can be reset by calling {@link #reset()}. - *

    - */ - public final int getMaxElapsedTimeMillis() { - return maxElapsedTimeMillis; + return (int) (minInterval + (random * (maxInterval - minInterval + 1))); } /** @@ -265,7 +212,7 @@ public class ExponentialBackOff { * The elapsed time is computed using {@link System#nanoTime()}. *

    */ - public final long getElapsedTimeMillis() { + private long getElapsedTimeMillis() { return (nanoTime() - startTimeNanos) / 1000000; } @@ -327,152 +274,12 @@ public class ExponentialBackOff { */ int maxElapsedTimeMillis = DEFAULT_MAX_ELAPSED_TIME_MILLIS; - public Builder() { + Builder() { } /** Builds a new instance of {@link ExponentialBackOff}. */ public ExponentialBackOff build() { return new ExponentialBackOff(this); } - - /** - * Returns the initial retry interval in milliseconds. The default value is - * {@link #DEFAULT_INITIAL_INTERVAL_MILLIS}. - */ - public final int getInitialIntervalMillis() { - return initialIntervalMillis; - } - - /** - * Sets the initial retry interval in milliseconds. The default value is - * {@link #DEFAULT_INITIAL_INTERVAL_MILLIS}. Must be {@code > 0}. - * - *

    - * Overriding is only supported for the purpose of calling the super implementation and changing - * the return type, but nothing else. - *

    - */ - public Builder setInitialIntervalMillis(int initialIntervalMillis) { - this.initialIntervalMillis = initialIntervalMillis; - return this; - } - - /** - * Returns the randomization factor to use for creating a range around the retry interval. The - * default value is {@link #DEFAULT_RANDOMIZATION_FACTOR}. - * - *

    - * A randomization factor of 0.5 results in a random period ranging between 50% below and 50% - * above the retry interval. - *

    - * - *

    - * Overriding is only supported for the purpose of calling the super implementation and changing - * the return type, but nothing else. - *

    - */ - public final double getRandomizationFactor() { - return randomizationFactor; - } - - /** - * Sets the randomization factor to use for creating a range around the retry interval. The - * default value is {@link #DEFAULT_RANDOMIZATION_FACTOR}. Must fall in the range - * {@code 0 <= randomizationFactor < 1}. - * - *

    - * A randomization factor of 0.5 results in a random period ranging between 50% below and 50% - * above the retry interval. - *

    - * - *

    - * Overriding is only supported for the purpose of calling the super implementation and changing - * the return type, but nothing else. - *

    - */ - public Builder setRandomizationFactor(double randomizationFactor) { - this.randomizationFactor = randomizationFactor; - return this; - } - - /** - * Returns the value to multiply the current interval with for each retry attempt. The default - * value is {@link #DEFAULT_MULTIPLIER}. - */ - public final double getMultiplier() { - return multiplier; - } - - /** - * Sets the value to multiply the current interval with for each retry attempt. The default - * value is {@link #DEFAULT_MULTIPLIER}. Must be {@code >= 1}. - * - *

    - * Overriding is only supported for the purpose of calling the super implementation and changing - * the return type, but nothing else. - *

    - */ - public Builder setMultiplier(double multiplier) { - this.multiplier = multiplier; - return this; - } - - /** - * Returns the maximum value of the back off period in milliseconds. Once the current interval - * reaches this value it stops increasing. The default value is - * {@link #DEFAULT_MAX_INTERVAL_MILLIS}. Must be {@code >= initialInterval}. - */ - public final int getMaxIntervalMillis() { - return maxIntervalMillis; - } - - /** - * Sets the maximum value of the back off period in milliseconds. Once the current interval - * reaches this value it stops increasing. The default value is - * {@link #DEFAULT_MAX_INTERVAL_MILLIS}. - * - *

    - * Overriding is only supported for the purpose of calling the super implementation and changing - * the return type, but nothing else. - *

    - */ - public Builder setMaxIntervalMillis(int maxIntervalMillis) { - this.maxIntervalMillis = maxIntervalMillis; - return this; - } - - /** - * Returns the maximum elapsed time in milliseconds. The default value is - * {@link #DEFAULT_MAX_ELAPSED_TIME_MILLIS}. - * - *

    - * If the time elapsed since an {@link ExponentialBackOff} instance is created goes past the - * max_elapsed_time then the method {@link #nextBackOffMillis()} starts returning - * this value. The elapsed time can be reset by calling {@link #reset()}. - *

    - */ - public final int getMaxElapsedTimeMillis() { - return maxElapsedTimeMillis; - } - - /** - * Sets the maximum elapsed time in milliseconds. The default value is - * {@link #DEFAULT_MAX_ELAPSED_TIME_MILLIS}. Must be {@code > 0}. - * - *

    - * If the time elapsed since an {@link ExponentialBackOff} instance is created goes past the - * max_elapsed_time then the method {@link #nextBackOffMillis()} starts returning - * this value. The elapsed time can be reset by calling {@link #reset()}. - *

    - * - *

    - * Overriding is only supported for the purpose of calling the super implementation and changing - * the return type, but nothing else. - *

    - */ - public Builder setMaxElapsedTimeMillis(int maxElapsedTimeMillis) { - this.maxElapsedTimeMillis = maxElapsedTimeMillis; - return this; - } } } \ No newline at end of file diff --git a/telegrambots/src/main/java/org/telegram/telegrambots/updatesreceivers/RestApi.java b/telegrambots/src/main/java/org/telegram/telegrambots/updatesreceivers/RestApi.java index baf3a046..35fbc7f1 100644 --- a/telegrambots/src/main/java/org/telegram/telegrambots/updatesreceivers/RestApi.java +++ b/telegrambots/src/main/java/org/telegram/telegrambots/updatesreceivers/RestApi.java @@ -1,12 +1,11 @@ package org.telegram.telegrambots.updatesreceivers; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; import org.telegram.telegrambots.meta.api.methods.BotApiMethod; import org.telegram.telegrambots.meta.api.objects.Update; import org.telegram.telegrambots.meta.exceptions.TelegramApiValidationException; import org.telegram.telegrambots.meta.generics.WebhookBot; -import org.telegram.telegrambots.meta.logging.BotLogger; - -import java.util.concurrent.ConcurrentHashMap; import javax.ws.rs.Consumes; import javax.ws.rs.GET; @@ -16,15 +15,16 @@ import javax.ws.rs.PathParam; import javax.ws.rs.Produces; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; +import java.util.concurrent.ConcurrentHashMap; /** * @author Ruben Bermudez * @version 1.0 - * @brief Rest api to for webhook callback function - * @date 20 of June of 2015 + * Rest api to for webhook callback function */ @Path("callback") public class RestApi { + private static final Logger log = LogManager.getLogger(RestApi.class); private final ConcurrentHashMap callbacks = new ConcurrentHashMap<>(); @@ -50,7 +50,7 @@ public class RestApi { } return Response.ok(response).build(); } catch (TelegramApiValidationException e) { - BotLogger.severe("RESTAPI", e); + log.error(e.getLocalizedMessage(), e); return Response.serverError().build(); } } diff --git a/telegrambots/src/main/java/org/telegram/telegrambots/util/WebhookUtils.java b/telegrambots/src/main/java/org/telegram/telegrambots/util/WebhookUtils.java index 7db6f898..a294738d 100644 --- a/telegrambots/src/main/java/org/telegram/telegrambots/util/WebhookUtils.java +++ b/telegrambots/src/main/java/org/telegram/telegrambots/util/WebhookUtils.java @@ -43,7 +43,7 @@ public final class WebhookUtils { builder.addTextBody(SetWebhook.MAXCONNECTIONS_FIELD, botOptions.getMaxWebhookConnections().toString()); } if (botOptions.getAllowedUpdates() != null) { - builder.addTextBody(SetWebhook.ALLOWEDUPDATES_FIELD, new JSONArray(botOptions.getMaxWebhookConnections()).toString()); + builder.addTextBody(SetWebhook.ALLOWEDUPDATES_FIELD, new JSONArray(botOptions.getAllowedUpdates()).toString()); } if (publicCertificatePath != null) { File certificate = new File(publicCertificatePath); diff --git a/telegrambots/src/test/java/org/telegram/telegrambots/test/TelegramFileDownloaderTest.java b/telegrambots/src/test/java/org/telegram/telegrambots/test/TelegramFileDownloaderTest.java new file mode 100644 index 00000000..e6f9366e --- /dev/null +++ b/telegrambots/src/test/java/org/telegram/telegrambots/test/TelegramFileDownloaderTest.java @@ -0,0 +1,115 @@ +package org.telegram.telegrambots.test; + +import org.apache.http.HttpEntity; +import org.apache.http.HttpResponse; +import org.apache.http.client.HttpClient; +import org.apache.http.client.methods.HttpUriRequest; +import org.apache.http.message.BasicStatusLine; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.ArgumentCaptor; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import org.mockito.junit.jupiter.MockitoSettings; +import org.mockito.quality.Strictness; +import org.telegram.telegrambots.facilities.filedownloader.TelegramFileDownloader; +import org.telegram.telegrambots.meta.exceptions.TelegramApiException; +import org.telegram.telegrambots.meta.updateshandlers.DownloadFileCallback; + +import java.io.File; +import java.io.IOException; +import java.util.function.Supplier; + +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.core.IsInstanceOf.instanceOf; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertThat; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.timeout; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +@ExtendWith(MockitoExtension.class) +@MockitoSettings(strictness = Strictness.LENIENT) +class TelegramFileDownloaderTest { + + private TelegramFileDownloader telegramFileDownloader; + + @Mock + private DownloadFileCallback downloadFileCallbackMock; + + @Mock + private HttpClient httpClientMock; + + @Mock + private HttpResponse httpResponseMock; + + @Mock + private HttpEntity httpEntityMock; + + private Supplier tokenSupplierMock = () -> "someToken"; + + @BeforeEach + void setup() throws IOException { + when(httpResponseMock.getStatusLine()).thenReturn(new BasicStatusLine(HTTP_1_1, 200, "emptyString")); + when(httpResponseMock.getEntity()).thenReturn(httpEntityMock); + + when(httpEntityMock.getContent()).thenReturn(toInputStream("Some File Content", defaultCharset())); + when(httpClientMock.execute(any(HttpUriRequest.class))).thenReturn(httpResponseMock); + + telegramFileDownloader = new TelegramFileDownloader(httpClientMock, tokenSupplierMock); + } + + @Test + void testFileDownload() throws TelegramApiException, IOException { + File returnFile = telegramFileDownloader.downloadFile("someFilePath"); + String content = readFileToString(returnFile, defaultCharset()); + + assertEquals("Some File Content", content); + } + + @Test + void testDownloadException() { + when(httpResponseMock.getStatusLine()).thenReturn(new BasicStatusLine(HTTP_1_1, 500, "emptyString")); + + Assertions.assertThrows(TelegramApiException.class, + () -> telegramFileDownloader.downloadFile("someFilePath")); + } + + @Test + void testAsyncDownload() throws TelegramApiException, IOException { + final ArgumentCaptor fileArgumentCaptor = ArgumentCaptor.forClass(File.class); + + telegramFileDownloader.downloadFileAsync("someFilePath", downloadFileCallbackMock); + + verify(downloadFileCallbackMock, timeout(100) + .times(1)) + .onResult(any(), fileArgumentCaptor.capture()); + + String content = readFileToString(fileArgumentCaptor.getValue(), defaultCharset()); + assertEquals("Some File Content", content); + } + + @Test + void testAsyncException() throws TelegramApiException { + final ArgumentCaptor exceptionArgumentCaptor = ArgumentCaptor.forClass(Exception.class); + + when(httpResponseMock.getStatusLine()).thenReturn(new BasicStatusLine(HTTP_1_1, 500, "emptyString")); + + telegramFileDownloader.downloadFileAsync("someFilePath", downloadFileCallbackMock); + + verify(downloadFileCallbackMock, timeout(100) + .times(1)) + .onException(any(), exceptionArgumentCaptor.capture()); + + Exception e = exceptionArgumentCaptor.getValue(); + assertThat(e, instanceOf(TelegramApiException.class)); + assertEquals(e.getCause().getCause().getMessage(), "Unexpected Status code while downloading file. Expected 200 got 500"); + } + +} diff --git a/telegrambots/src/test/java/org/telegram/telegrambots/test/TelegramLongPollingBotTest.java b/telegrambots/src/test/java/org/telegram/telegrambots/test/TelegramLongPollingBotTest.java index 21ea2f08..fdef3699 100644 --- a/telegrambots/src/test/java/org/telegram/telegrambots/test/TelegramLongPollingBotTest.java +++ b/telegrambots/src/test/java/org/telegram/telegrambots/test/TelegramLongPollingBotTest.java @@ -2,23 +2,23 @@ package org.telegram.telegrambots.test; import org.junit.Test; import org.mockito.Mockito; -import org.telegram.telegrambots.meta.api.objects.Update; import org.telegram.telegrambots.bots.DefaultBotOptions; import org.telegram.telegrambots.bots.TelegramLongPollingBot; +import org.telegram.telegrambots.meta.api.objects.Update; import org.telegram.telegrambots.updatesreceivers.DefaultBotSession; -import static java.util.Arrays.asList; -import static org.hamcrest.CoreMatchers.is; -import static org.junit.Assert.*; -import static org.mockito.Matchers.any; - import java.util.concurrent.ExecutorService; 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.mockito.ArgumentMatchers.any; + public class TelegramLongPollingBotTest { @Test - public void testOnUpdateReceived() throws Exception { + public void testOnUpdateReceived() { TelegramLongPollingBot bot = Mockito.mock(TelegramLongPollingBot.class); Mockito.doCallRealMethod().when(bot).onUpdatesReceived(any()); Update update1 = new Update(); diff --git a/telegrambots/src/test/java/org/telegram/telegrambots/test/TestDefaultBotSession.java b/telegrambots/src/test/java/org/telegram/telegrambots/test/TestDefaultBotSession.java index 206ee35d..941b3508 100644 --- a/telegrambots/src/test/java/org/telegram/telegrambots/test/TestDefaultBotSession.java +++ b/telegrambots/src/test/java/org/telegram/telegrambots/test/TestDefaultBotSession.java @@ -11,10 +11,9 @@ import org.junit.After; import org.junit.Assert; import org.junit.Before; import org.junit.Test; -import org.mockito.Matchers; import org.mockito.Mockito; -import org.telegram.telegrambots.meta.api.objects.Update; import org.telegram.telegrambots.bots.DefaultBotOptions; +import org.telegram.telegrambots.meta.api.objects.Update; import org.telegram.telegrambots.meta.generics.LongPollingBot; import org.telegram.telegrambots.test.Fakes.FakeLongPollingBot; import org.telegram.telegrambots.updatesreceivers.DefaultBotSession; @@ -22,17 +21,18 @@ import org.telegram.telegrambots.updatesreceivers.DefaultBotSession; import java.io.IOException; import java.util.Arrays; import java.util.Collections; -import java.util.List; import java.util.concurrent.atomic.AtomicInteger; import java.util.stream.IntStream; +import static org.mockito.ArgumentMatchers.any; + /** * @author Ruben Bermudez * @version 1.0 - * @brief Test for DefaultBotSession + * Test for DefaultBotSession */ public class TestDefaultBotSession { - DefaultBotSession session; + private DefaultBotSession session; @Before public void setUp() throws Exception { @@ -40,14 +40,14 @@ public class TestDefaultBotSession { } @After - public void tearDown() throws Exception { + public void tearDown() { if (session != null && session.isRunning()) { session.stop(); } } @Test - public void TestDefaultBotSessionIsNotRunningWhenCreated() throws Exception { + public void TestDefaultBotSessionIsNotRunningWhenCreated() { Assert.assertFalse(session.isRunning()); } @@ -96,7 +96,7 @@ public class TestDefaultBotSession { session.setUpdatesSupplier(createFakeUpdatesSupplier(flag, updates)); session.start(); Thread.sleep(1000); - Mockito.verify(bot, Mockito.never()).onUpdateReceived(Matchers.any()); + Mockito.verify(bot, Mockito.never()).onUpdateReceived(any()); flag.compareAndSet(0, 1); Thread.sleep(1000); Mockito.verify(bot).onUpdateReceived(updates[0]); @@ -124,7 +124,7 @@ public class TestDefaultBotSession { session.setUpdatesSupplier(createFakeUpdatesSupplier(flag, updates)); session.start(); Thread.sleep(1000); - Mockito.verify(bot, Mockito.never()).onUpdateReceived(Matchers.any()); + Mockito.verify(bot, Mockito.never()).onUpdateReceived(any()); flag.compareAndSet(0, 1); Thread.sleep(1000); Mockito.verify(bot).onUpdatesReceived(Arrays.asList(updates[0], updates[1])); @@ -146,18 +146,15 @@ public class TestDefaultBotSession { } private DefaultBotSession.UpdatesSupplier createFakeUpdatesSupplier(AtomicInteger flag, Update[] updates) { - return new DefaultBotSession.UpdatesSupplier() { - @Override - public List getUpdates() throws InterruptedException, Exception { - if (flag.compareAndSet(1, 2)) { - return Arrays.asList(updates[0], updates[1]); - } else if (flag.compareAndSet(3, 4)) { - return Arrays.asList(updates[2], updates[3], updates[4]); - } else if (flag.compareAndSet(5, 6)) { - return Arrays.asList(updates[5], updates[6], updates[7], updates[8]); - } - return Collections.emptyList(); + return () -> { + if (flag.compareAndSet(1, 2)) { + return Arrays.asList(updates[0], updates[1]); + } else if (flag.compareAndSet(3, 4)) { + return Arrays.asList(updates[2], updates[3], updates[4]); + } else if (flag.compareAndSet(5, 6)) { + return Arrays.asList(updates[5], updates[6], updates[7], updates[8]); } + return Collections.emptyList(); }; } @@ -172,7 +169,7 @@ public class TestDefaultBotSession { response.setEntity(new StringEntity("{}")); HttpClient mockHttpClient = Mockito.mock(HttpClient.class); - Mockito.when(mockHttpClient.execute(Mockito.any(HttpPost.class))) + Mockito.when(mockHttpClient.execute(any(HttpPost.class))) .thenReturn(response); DefaultBotSession session = new DefaultBotSession(); session.setCallback(bot);