diff --git a/.gitignore b/.gitignore index c0b06615..6c05a0ab 100644 --- a/.gitignore +++ b/.gitignore @@ -35,12 +35,11 @@ hs_err_pid* .idea/ copyright/ *.iml +*.ipr +*.iws .classpath .project .settings/ #File System specific files -.DS_STORE - -# Default ignored files -/Bots.iws \ No newline at end of file +.DS_Store diff --git a/Bots.ipr b/Bots.ipr deleted file mode 100644 index 7aff4efa..00000000 --- a/Bots.ipr +++ /dev/null @@ -1,2104 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - /usr/local/bin/bower - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 1.8 - - - - - - - - \ No newline at end of file diff --git a/README.md b/README.md index 88a0fe9f..77d7a7ef 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.8.1 + 4.9 ``` ```gradle - compile "org.telegram:telegrambots:4.8.1" + compile "org.telegram:telegrambots:4.9" ``` - 2. Using Jitpack from [here](https://jitpack.io/#rubenlagus/TelegramBots/4.8.1) - 3. Download the jar(including all dependencies) from [here](https://mvnrepository.com/artifact/org.telegram/telegrambots/4.8.1) + 2. Using Jitpack from [here](https://jitpack.io/#rubenlagus/TelegramBots/4.9) + 3. Download the jar(including all dependencies) from [here](https://mvnrepository.com/artifact/org.telegram/telegrambots/4.9) 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 05fa77f1..e8efbbc5 100644 --- a/TelegramBots.wiki/Changelog.md +++ b/TelegramBots.wiki/Changelog.md @@ -1,3 +1,7 @@ +### 4.9 ### +1. Update Api version [4.9](https://core.telegram.org/bots/api-changelog#june-4-2020) +2. Bug fixing: #731, #749, #752 and #753 + ### 4.8.1 ### 1. Update Api version [4.8](https://core.telegram.org/bots/api-changelog#april-24-2020) 2. Add stats for Abilities diff --git a/TelegramBots.wiki/Getting-Started.md b/TelegramBots.wiki/Getting-Started.md index 79af258e..24e4fa58 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.8.1 + 4.9 ``` * With **Gradle**: ```groovy - compile group: 'org.telegram', name: 'telegrambots', version: '4.8.1' + compile group: 'org.telegram', name: 'telegrambots', version: '4.9' ``` 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/Advanced.md b/TelegramBots.wiki/abilities/Advanced.md index 044a55b0..45f90300 100644 --- a/TelegramBots.wiki/abilities/Advanced.md +++ b/TelegramBots.wiki/abilities/Advanced.md @@ -31,4 +31,7 @@ As an example, if you want to restrict the updates to photos only, then you may public boolean checkGlobalFlags(Update update) { return Flag.PHOTO; } -``` \ No newline at end of file +``` + +## Statistics +AbilityBot can accrue basic statistics about the usage of your abilities and replies. Simply `enableStats()` on an Ability builder or `enableStats()` on replies to activate this feature. Once activated, you may call `/stats` and the bot will print a basic list of statistics. At the moment, AbilityBot only tracks hits. In the future, this will be enhanced to track more stats. \ No newline at end of file diff --git a/TelegramBots.wiki/abilities/Simple-Example.md b/TelegramBots.wiki/abilities/Simple-Example.md index fff16424..bd234493 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.8.1 + 4.9 ``` * **Gradle** ```groovy - implementation group: 'org.telegram', name: 'telegrambots-abilities', version: '4.8.1' + implementation group: 'org.telegram', name: 'telegrambots-abilities', version: '4.9' ``` * [JitPack](https://jitpack.io/#rubenlagus/TelegramBots) diff --git a/TelegramBots.wiki/abilities/State-Machines.md b/TelegramBots.wiki/abilities/State-Machines.md index 34891134..525d16e9 100644 --- a/TelegramBots.wiki/abilities/State-Machines.md +++ b/TelegramBots.wiki/abilities/State-Machines.md @@ -70,30 +70,29 @@ Now, after your naughty bot retaliates, the user can say "go left or else" to fo ## Complete Example ```java -public static class ReplyFlowBot extends AbilityBot { - public class ReplyFlowBot extends AbilityBot { +public class ReplyFlowBot extends AbilityBot { public ReplyFlowBot(String botToken, String botUsername) { - super(botToken, botUsername); + super(botToken, botUsername); } @Override public int creatorId() { - return ; + return ; } public ReplyFlow directionFlow() { - Reply saidLeft = Reply.of(upd -> silent.send("Sir, I have gone left.", getChatId(upd)), + Reply saidLeft = Reply.of(upd -> silent.send("Sir, I have gone left.", getChatId(upd)), hasMessageWith("go left or else")); - ReplyFlow leftflow = ReplyFlow.builder(db) + ReplyFlow leftflow = ReplyFlow.builder(db) .action(upd -> silent.send("I don't know how to go left.", getChatId(upd))) .onlyIf(hasMessageWith("left")) .next(saidLeft).build(); - Reply saidRight = Reply.of(upd -> silent.send("Sir, I have gone right.", getChatId(upd)), + Reply saidRight = Reply.of(upd -> silent.send("Sir, I have gone right.", getChatId(upd)), hasMessageWith("right")); - return ReplyFlow.builder(db) + return ReplyFlow.builder(db) .action(upd -> silent.send("Command me to go left or right!", getChatId(upd))) .onlyIf(hasMessageWith("wake up")) .next(leftflow) @@ -103,9 +102,9 @@ public static class ReplyFlowBot extends AbilityBot { @NotNull private Predicate hasMessageWith(String msg) { - return upd -> upd.getMessage().getText().equalsIgnoreCase(msg); + return upd -> upd.getMessage().getText().equalsIgnoreCase(msg); } - } +} ``` ## Inline Declaration As you can see in the above example, we used a bottom-up approach. We declared the leaf replies before we got to the root reply flow. diff --git a/pom.xml b/pom.xml index a5a3d3d3..e54ebacc 100644 --- a/pom.xml +++ b/pom.xml @@ -7,7 +7,7 @@ org.telegram Bots pom - 4.8.1 + 4.9 telegrambots diff --git a/telegrambots-abilities/README.md b/telegrambots-abilities/README.md index 13d5c381..496ba550 100644 --- a/telegrambots-abilities/README.md +++ b/telegrambots-abilities/README.md @@ -18,19 +18,19 @@ Usage org.telegram telegrambots-abilities - 4.8.1 + 4.9 ``` **Gradle** ```gradle - compile "org.telegram:telegrambots-abilities:4.8.1" + compile "org.telegram:telegrambots-abilities:4.9" ``` -**JitPack** - [JitPack](https://jitpack.io/#rubenlagus/TelegramBots/v4.8.1) +**JitPack** - [JitPack](https://jitpack.io/#rubenlagus/TelegramBots/v4.9) -**Plain imports** - [Here](https://github.com/rubenlagus/TelegramBots/releases/tag/v4.8.1) +**Plain imports** - [Here](https://github.com/rubenlagus/TelegramBots/releases/tag/v4.9) Motivation ---------- diff --git a/telegrambots-abilities/pom.xml b/telegrambots-abilities/pom.xml index 6b69ccac..ec692783 100644 --- a/telegrambots-abilities/pom.xml +++ b/telegrambots-abilities/pom.xml @@ -7,7 +7,7 @@ org.telegram Bots - 4.8.1 + 4.9 telegrambots-abilities @@ -84,7 +84,7 @@ org.telegram telegrambots - 4.8.1 + 4.9 org.apache.commons 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 8e3b8365..c3bc3e31 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 @@ -1,6 +1,6 @@ package org.telegram.abilitybots.api.bot; -import com.google.common.collect.ImmutableList; +import com.google.common.collect.*; import com.google.common.collect.ImmutableList.Builder; import com.google.common.collect.ImmutableMap; import org.jetbrains.annotations.NotNull; @@ -33,15 +33,18 @@ import java.util.function.Predicate; import java.util.stream.Collectors; import java.util.stream.Stream; +import static com.google.common.collect.Sets.difference; import static java.lang.String.format; import static java.time.ZonedDateTime.now; import static java.util.Arrays.stream; 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.toSet; import static org.telegram.abilitybots.api.objects.Locality.*; import static org.telegram.abilitybots.api.objects.MessageContext.newContext; import static org.telegram.abilitybots.api.objects.Privacy.*; +import static org.telegram.abilitybots.api.objects.Stats.createStats; import static org.telegram.abilitybots.api.util.AbilityMessageCodes.*; import static org.telegram.abilitybots.api.util.AbilityUtils.*; @@ -87,6 +90,7 @@ public abstract class BaseAbilityBot extends DefaultAbsSender implements Ability public static final String USERS = "USERS"; public static final String USER_ID = "USER_ID"; public static final String BLACKLIST = "BLACKLIST"; + public static final String STATS = "ABILITYBOT_STATS"; // DB and sender protected final DBContext db; @@ -102,6 +106,7 @@ public abstract class BaseAbilityBot extends DefaultAbsSender implements Ability // Ability registry private Map abilities; + private Map stats; // Reply registry private List replies; @@ -119,6 +124,7 @@ public abstract class BaseAbilityBot extends DefaultAbsSender implements Ability silent = new SilentSender(sender); registerAbilities(); + initStats(); } /** @@ -149,6 +155,13 @@ public abstract class BaseAbilityBot extends DefaultAbsSender implements Ability return db.getSet(ADMINS); } + /** + * @return a mapping of ability and reply names to their corresponding statistics + */ + protected Map stats() { + return stats; + } + /** * @return the immutable map of */ @@ -163,6 +176,7 @@ public abstract class BaseAbilityBot extends DefaultAbsSender implements Ability return replies; } + /** * This method contains the stream of actions that are applied on any update. *

@@ -180,6 +194,7 @@ public abstract class BaseAbilityBot extends DefaultAbsSender implements Ability .filter(this::checkBlacklist) .map(this::addUser) .filter(this::filterReply) + .filter(this::hasUser) .map(this::getAbility) .filter(this::validateAbility) .filter(this::checkPrivacy) @@ -188,6 +203,7 @@ public abstract class BaseAbilityBot extends DefaultAbsSender implements Ability .filter(this::checkMessageFlags) .map(this::getContext) .map(this::consumeUpdate) + .map(this::updateStats) .forEach(this::postConsumption); // Commit to DB now after all the actions have been dealt @@ -275,6 +291,19 @@ public abstract class BaseAbilityBot extends DefaultAbsSender implements Ability } } + private void initStats() { + Set enabledStats = Stream.concat( + replies.stream().filter(Reply::statsEnabled).map(Reply::name), + abilities.entrySet().stream() + .filter(entry -> entry.getValue().statsEnabled()) + .map(Map.Entry::getKey)).collect(toSet()); + stats = db.getMap(STATS); + Set toBeRemoved = difference(stats.keySet(), enabledStats); + toBeRemoved.forEach(stats::remove); + enabledStats.forEach(abName -> stats.computeIfAbsent(abName, + name -> createStats(abName, 0))); + } + /** * @param clazz the type to be tested * @return a predicate testing the return type of the method corresponding to the class parameter @@ -344,6 +373,26 @@ public abstract class BaseAbilityBot extends DefaultAbsSender implements Ability return pair; } + Pair updateStats(Pair pair) { + Ability ab = pair.b(); + if (ab.statsEnabled()) { + updateStats(pair.b().name()); + } + return pair; + } + + private void updateReplyStats(Reply reply) { + if (reply.statsEnabled()) { + updateStats(reply.name()); + } + } + + void updateStats(String name) { + Stats statsObj = stats.get(name); + statsObj.hit(); + stats.put(name, statsObj); + } + Pair getContext(Trio trio) { Update update = trio.a(); User user = AbilityUtils.getUser(update); @@ -487,6 +536,12 @@ public abstract class BaseAbilityBot extends DefaultAbsSender implements Ability return update; } + private boolean hasUser(Update update) { + // Valid updates without users should return an empty user + // Updates that are not recognized by the getUser method will throw an exception + return !AbilityUtils.getUser(update).equals(EMPTY_USER); + } + private void updateUserId(User oldUser, User newUser) { if (oldUser != null && oldUser.getUserName() != null) { // Remove old username -> ID @@ -504,6 +559,7 @@ public abstract class BaseAbilityBot extends DefaultAbsSender implements Ability .filter(reply -> reply.isOkFor(update)) .map(reply -> { reply.actOn(update); + updateReplyStats(reply); return false; }) .reduce(true, Boolean::logicalAnd); diff --git a/telegrambots-abilities/src/main/java/org/telegram/abilitybots/api/bot/DefaultAbilities.java b/telegrambots-abilities/src/main/java/org/telegram/abilitybots/api/bot/DefaultAbilities.java index bdcf9456..6e1139bb 100644 --- a/telegrambots-abilities/src/main/java/org/telegram/abilitybots/api/bot/DefaultAbilities.java +++ b/telegrambots-abilities/src/main/java/org/telegram/abilitybots/api/bot/DefaultAbilities.java @@ -26,6 +26,7 @@ import java.io.PrintStream; import java.util.Map; import java.util.Optional; import java.util.Set; +import java.util.StringJoiner; import static com.google.common.base.Strings.isNullOrEmpty; import static com.google.common.collect.MultimapBuilder.hashKeys; @@ -76,6 +77,7 @@ public final class DefaultAbilities implements AbilityExtension { public static final String RECOVER = "recover"; public static final String COMMANDS = "commands"; public static final String REPORT = "report"; + public static final String STATS = "stats"; private static final Logger log = LoggerFactory.getLogger(DefaultAbilities.class); private final BaseAbilityBot bot; @@ -179,6 +181,26 @@ public final class DefaultAbilities implements AbilityExtension { .build(); } + /** + * @return the ability to report statistics for abilities and replies. + */ + public Ability reportStats() { + return builder() + .name(STATS) + .locality(ALL) + .privacy(ADMIN) + .input(0) + .action(ctx -> { + String stats = bot.stats().entrySet().stream() + .map(entry -> String.format("%s: %d", entry.getKey(), entry.getValue().hits())) + .reduce(new StringJoiner("\n"), StringJoiner::add, StringJoiner::merge) + .toString(); + + bot.silent.send(stats, ctx.chatId()); + }) + .build(); + } + /** * This backup ability returns the object defined by {@link DBContext#backup()} as a message document. *

@@ -212,6 +234,7 @@ public final class DefaultAbilities implements AbilityExtension { .build(); } + /** * Recovers the bot database using {@link DBContext#recover(Object)}. *

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 f9ddcd71..0b6691bb 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 @@ -42,13 +42,14 @@ public final class Ability { private final Locality locality; private final Privacy privacy; private final int argNum; + private final boolean statsEnabled; private final Consumer action; private final Consumer postAction; private final List replies; private final List> flags; @SafeVarargs - private Ability(String name, String info, Locality locality, Privacy privacy, int argNum, Consumer action, Consumer postAction, List replies, Predicate... flags) { + private Ability(String name, String info, Locality locality, Privacy privacy, int argNum, boolean statsEnabled, Consumer action, Consumer postAction, List replies, Predicate... flags) { checkArgument(!isEmpty(name), "Method name cannot be empty"); checkArgument(!containsWhitespace(name), "Method name cannot contain spaces"); checkArgument(isAlphanumeric(name), "Method name can only be alpha-numeric", name); @@ -70,6 +71,7 @@ public final class Ability { this.postAction = postAction; this.replies = replies; + this.statsEnabled = statsEnabled; } public static AbilityBuilder builder() { @@ -96,6 +98,10 @@ public final class Ability { return argNum; } + public boolean statsEnabled() { + return statsEnabled; + } + public Consumer action() { return action; } @@ -147,12 +153,14 @@ public final class Ability { private Privacy privacy; private Locality locality; private int argNum; + private boolean statsEnabled; private Consumer action; private Consumer postAction; private List replies; private Predicate[] flags; private AbilityBuilder() { + statsEnabled = false; replies = newArrayList(); } @@ -186,6 +194,11 @@ public final class Ability { return this; } + public AbilityBuilder enableStats() { + statsEnabled = true; + return this; + } + public AbilityBuilder privacy(Privacy privacy) { this.privacy = privacy; return this; @@ -202,6 +215,11 @@ public final class Ability { return this; } + public final AbilityBuilder reply(Reply reply) { + replies.add(reply); + return this; + } + public AbilityBuilder basedOn(Ability ability) { replies.clear(); replies.addAll(ability.replies()); @@ -216,7 +234,7 @@ public final class Ability { } public Ability build() { - return new Ability(name, info, locality, privacy, argNum, action, postAction, replies, flags); + return new Ability(name, info, locality, privacy, argNum, statsEnabled, action, postAction, replies, flags); } } } diff --git a/telegrambots-abilities/src/main/java/org/telegram/abilitybots/api/objects/Reply.java b/telegrambots-abilities/src/main/java/org/telegram/abilitybots/api/objects/Reply.java index 6af4c921..e7479489 100644 --- a/telegrambots-abilities/src/main/java/org/telegram/abilitybots/api/objects/Reply.java +++ b/telegrambots-abilities/src/main/java/org/telegram/abilitybots/api/objects/Reply.java @@ -26,12 +26,15 @@ import static java.util.Arrays.asList; public class Reply { public final List> conditions; public final Consumer action; + private boolean statsEnabled; + private String name; Reply(List> conditions, Consumer action) { this.conditions = ImmutableList.>builder() .addAll(conditions) .build(); this.action = action; + statsEnabled = false; } public static Reply of(Consumer action, List> conditions) { @@ -65,6 +68,20 @@ public class Reply { return Stream.of(this); } + public Reply enableStats(String name) { + this.name = name; + statsEnabled = true; + return this; + } + + public boolean statsEnabled() { + return statsEnabled; + } + + public String name() { + return name; + } + @Override public boolean equals(Object o) { if (this == o) diff --git a/telegrambots-abilities/src/main/java/org/telegram/abilitybots/api/objects/Stats.java b/telegrambots-abilities/src/main/java/org/telegram/abilitybots/api/objects/Stats.java new file mode 100644 index 00000000..43b6b350 --- /dev/null +++ b/telegrambots-abilities/src/main/java/org/telegram/abilitybots/api/objects/Stats.java @@ -0,0 +1,64 @@ +package org.telegram.abilitybots.api.objects; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.google.common.base.MoreObjects; +import org.json.JSONPropertyIgnore; + +import java.io.Serializable; +import java.util.Objects; + +/** + * Basic POJO to track ability and reply hits. The current implementation is NOT thread safe. + * + * @author Abbas Abou Daya + */ +public final class Stats implements Serializable { + @JsonProperty + private final String name; + @JsonProperty + private long hits; + + private Stats(String name) { + this.name = name; + } + + @JsonCreator + public static Stats createStats(@JsonProperty("name") String name, @JsonProperty("hits") long hits) { + return new Stats(name); + } + + public String name() { + return name; + } + + public long hits() { + return hits; + } + + public void hit() { + hits++; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + Stats that = (Stats) o; + return hits == that.hits && + Objects.equals(name, that.name); + } + + @Override + public int hashCode() { + return Objects.hash(name, hits); + } + + @Override + public String toString() { + return MoreObjects.toStringHelper(this) + .add("name", name) + .add("hits", hits) + .toString(); + } +} diff --git a/telegrambots-abilities/src/main/java/org/telegram/abilitybots/api/util/AbilityUtils.java b/telegrambots-abilities/src/main/java/org/telegram/abilitybots/api/util/AbilityUtils.java index 241bf141..6382f866 100644 --- a/telegrambots-abilities/src/main/java/org/telegram/abilitybots/api/util/AbilityUtils.java +++ b/telegrambots-abilities/src/main/java/org/telegram/abilitybots/api/util/AbilityUtils.java @@ -24,7 +24,7 @@ import static org.telegram.abilitybots.api.objects.Flag.*; * Helper and utility methods */ public final class AbilityUtils { - public static User EMPTY_USER = new User(); + public static User EMPTY_USER = new User(0, "", false, "", "", ""); private AbilityUtils() { @@ -150,6 +150,14 @@ public final class AbilityUtils { return update.getEditedMessage().getChatId(); } else if (CHOSEN_INLINE_QUERY.test(update)) { return (long) update.getChosenInlineQuery().getFrom().getId(); + } else if (SHIPPING_QUERY.test(update)) { + return (long) update.getShippingQuery().getFrom().getId(); + } else if (PRECHECKOUT_QUERY.test(update)) { + return (long) update.getPreCheckoutQuery().getFrom().getId(); + } else if (POLL_ANSWER.test(update)) { + return (long) update.getPollAnswer().getUser().getId(); + } else if (POLL.test(update)) { + return (long) EMPTY_USER.getId(); } else { throw new IllegalStateException("Could not retrieve originating chat ID from update"); } @@ -170,10 +178,8 @@ public final class AbilityUtils { return update.getEditedChannelPost().isUserMessage(); } else if (EDITED_MESSAGE.test(update)) { return update.getEditedMessage().isUserMessage(); - } else if (CHOSEN_INLINE_QUERY.test(update) || INLINE_QUERY.test(update)) { - return true; } else { - throw new IllegalStateException("Could not retrieve update context origin (user/group)"); + return true; } } 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 36717ac0..476b3b1e 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 @@ -8,10 +8,12 @@ import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.mockito.ArgumentMatchers; +import org.mockito.Mockito; import org.telegram.abilitybots.api.db.DBContext; import org.telegram.abilitybots.api.objects.*; import org.telegram.abilitybots.api.sender.MessageSender; import org.telegram.abilitybots.api.sender.SilentSender; +import org.telegram.abilitybots.api.util.AbilityUtils; import org.telegram.abilitybots.api.util.Pair; import org.telegram.abilitybots.api.util.Trio; import org.telegram.telegrambots.meta.api.methods.groupadministration.GetChatAdministrators; @@ -25,6 +27,7 @@ import java.util.Arrays; import java.util.Map; import java.util.Optional; import java.util.Set; +import java.util.function.Consumer; import static com.google.common.collect.Lists.newArrayList; import static com.google.common.collect.Sets.newHashSet; @@ -38,8 +41,8 @@ import static org.junit.jupiter.api.Assertions.*; import static org.mockito.Mockito.*; import static org.mockito.internal.verification.VerificationModeFactory.times; import static org.telegram.abilitybots.api.bot.DefaultBot.getDefaultBuilder; -import static org.telegram.abilitybots.api.bot.TestUtils.*; import static org.telegram.abilitybots.api.bot.TestUtils.CREATOR; +import static org.telegram.abilitybots.api.bot.TestUtils.*; import static org.telegram.abilitybots.api.db.MapDBContext.offlineInstance; import static org.telegram.abilitybots.api.objects.Flag.DOCUMENT; import static org.telegram.abilitybots.api.objects.Flag.MESSAGE; @@ -120,6 +123,49 @@ public class AbilityBotTest { verify(silent, times(1)).send("reply", USER.getId()); } + @Test + void canProcessUpdatesWithoutUserInfo() { + Update update = mock(Update.class); + // At the moment, only poll updates carry no user information + when(update.hasPoll()).thenReturn(true); + + bot.onUpdateReceived(update); + } + + @Test + void getUserHasAllMethodsDefined() { + Arrays.stream(Update.class.getMethods()) + // filter to all these methods of hasXXX (hasPoll, hasMessage, etc...) + .filter(method -> method.getName().startsWith("has")) + // Gotta filter out hashCode + .filter(method -> method.getReturnType().getName().equals("boolean")) + .forEach(method -> { + Update update = mock(Update.class); + try { + // Mock the method and make sure it returns true so that it gets processed by the following method + when(method.invoke(update)).thenReturn(true); + // Call the getUser function, throws an IllegalStateException if there's an update that can't be processed + AbilityUtils.getUser(update); + } catch (IllegalStateException e) { + throw new RuntimeException( + format("Found an update variation that is not handled by the getUser util method [%s]", method.getName()), e); + } catch (NullPointerException | ReflectiveOperationException e) { + // This is fine, the mock isn't complete and we're only + // looking for IllegalStateExceptions thrown by the method + } + }); + } + + @Test + void getChatIdCanHandleAllKindsOfUpdates() { + handlesAllUpdates(AbilityUtils::getUser); + } + + @Test + void getUserCanHandleAllKindsOfUpdates() { + handlesAllUpdates(AbilityUtils::getChatId); + } + @Test void canBackupDB() throws TelegramApiException { MessageContext context = defaultContext(); @@ -130,6 +176,30 @@ public class AbilityBotTest { verify(sender, times(1)).sendDocument(any()); } + @Test + void canReportStatistics() { + MessageContext context = defaultContext(); + + defaultAbs.reportStats().action().accept(context); + + verify(silent, times(1)).send("count: 0\nmustreply: 0", GROUP_ID); + } + + @Test + void canReportUpdatedStatistics() { + Update upd1 = mockFullUpdate(bot, CREATOR, "/count 1 2 3 4"); + bot.onUpdateReceived(upd1); + Update upd2 = mockFullUpdate(bot, CREATOR, "must reply"); + bot.onUpdateReceived(upd2); + + Mockito.reset(silent); + + Update statUpd = mockFullUpdate(bot, CREATOR, "/stats"); + bot.onUpdateReceived(statUpd); + + verify(silent, times(1)).send("count: 1\nmustreply: 1", CREATOR.getId()); + } + @Test void canRecoverDB() throws TelegramApiException, IOException { Update update = mockBackupUpdate(); @@ -553,7 +623,7 @@ public class AbilityBotTest { defaultAbs.commands().action().accept(creatorCtx); - String expected = "PUBLIC\n/commands\n/count\n/default - dis iz default command\n/group\n/test\nADMIN\n/admin\n/ban\n/demote\n/promote\n/unban\nCREATOR\n/backup\n/claim\n/recover\n/report"; + String expected = "PUBLIC\n/commands\n/count\n/default - dis iz default command\n/group\n/test\nADMIN\n/admin\n/ban\n/demote\n/promote\n/stats\n/unban\nCREATOR\n/backup\n/claim\n/recover\n/report"; verify(silent, times(1)).send(expected, GROUP_ID); } @@ -574,6 +644,29 @@ public class AbilityBotTest { verify(silent, times(1)).send(expected, GROUP_ID); } + private void handlesAllUpdates(Consumer utilMethod) { + Arrays.stream(Update.class.getMethods()) + // filter to all these methods of hasXXX (hasPoll, hasMessage, etc...) + .filter(method -> method.getName().startsWith("has")) + // Gotta filter out hashCode + .filter(method -> method.getReturnType().getName().equals("boolean")) + .forEach(method -> { + Update update = mock(Update.class); + try { + // Mock the method and make sure it returns true so that it gets processed by the following method + when(method.invoke(update)).thenReturn(true); + // Call the function, throws an IllegalStateException if there's an update that can't be processed + utilMethod.accept(update); + } catch (IllegalStateException e) { + throw new RuntimeException( + format("Found an update variation that is not handled by the getChatId util method [%s]", method.getName()), e); + } catch (NullPointerException | ReflectiveOperationException e) { + // This is fine, the mock isn't complete and we're only + // looking for IllegalStateExceptions thrown by the method + } + }); + } + private void mockUser(Update update, Message message, User user) { when(update.hasMessage()).thenReturn(true); when(update.getMessage()).thenReturn(message); diff --git a/telegrambots-abilities/src/test/java/org/telegram/abilitybots/api/bot/DefaultBot.java b/telegrambots-abilities/src/test/java/org/telegram/abilitybots/api/bot/DefaultBot.java index 12db53f1..462453da 100644 --- a/telegrambots-abilities/src/test/java/org/telegram/abilitybots/api/bot/DefaultBot.java +++ b/telegrambots-abilities/src/test/java/org/telegram/abilitybots/api/bot/DefaultBot.java @@ -3,6 +3,7 @@ package org.telegram.abilitybots.api.bot; import org.telegram.abilitybots.api.db.DBContext; import org.telegram.abilitybots.api.objects.Ability; import org.telegram.abilitybots.api.objects.Ability.AbilityBuilder; +import org.telegram.abilitybots.api.objects.Reply; import org.telegram.abilitybots.api.toggle.AbilityToggle; import static org.telegram.abilitybots.api.objects.Ability.builder; @@ -41,7 +42,7 @@ public class DefaultBot extends AbilityBot { return getDefaultBuilder() .name(DEFAULT) .info("dis iz default command") - .reply(upd -> silent.send("reply", upd.getMessage().getChatId()), MESSAGE, update -> update.getMessage().getText().equals("must reply")) + .reply(Reply.of(upd -> silent.send("reply", upd.getMessage().getChatId()), MESSAGE, update -> update.getMessage().getText().equals("must reply")).enableStats("mustreply")) .reply(upd -> silent.send("reply", upd.getCallbackQuery().getMessage().getChatId()), CALLBACK_QUERY) .build(); } @@ -67,6 +68,7 @@ public class DefaultBot extends AbilityBot { .privacy(PUBLIC) .locality(USER) .input(4) + .enableStats() .build(); } diff --git a/telegrambots-abilities/src/test/java/org/telegram/abilitybots/api/bot/ReplyFlowTest.java b/telegrambots-abilities/src/test/java/org/telegram/abilitybots/api/bot/ReplyFlowTest.java index fb198278..bb5cd9e3 100644 --- a/telegrambots-abilities/src/test/java/org/telegram/abilitybots/api/bot/ReplyFlowTest.java +++ b/telegrambots-abilities/src/test/java/org/telegram/abilitybots/api/bot/ReplyFlowTest.java @@ -5,11 +5,13 @@ 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.Flag; import org.telegram.abilitybots.api.objects.Reply; import org.telegram.abilitybots.api.objects.ReplyFlow; import org.telegram.abilitybots.api.sender.MessageSender; import org.telegram.abilitybots.api.sender.SilentSender; import org.telegram.telegrambots.meta.api.objects.Update; +import org.telegram.telegrambots.meta.api.objects.polls.Poll; import java.io.IOException; import java.util.function.Predicate; @@ -106,6 +108,20 @@ public class ReplyFlowTest { assertFalse(db.getMap(STATES).containsKey(chatId), "User still has state after terminal reply"); } + @Test + void repliesHandlePollResponse() { + Update update = mock(Update.class); + when(update.hasPoll()).thenReturn(true); + when(update.hasMessage()).thenReturn(false); + + Poll poll = mock(Poll.class); + when(poll.getId()).thenReturn("1"); + when(update.getPoll()).thenReturn(poll); + + // This should not be processed as a reply, so we wouldn't filter out (true) + assertTrue(bot.filterReply(update)); + } + public static class ReplyFlowBot extends AbilityBot { private ReplyFlowBot(String botToken, String botUsername, DBContext db) { @@ -139,7 +155,7 @@ public class ReplyFlowTest { @NotNull private Predicate hasMessageWith(String msg) { - return upd -> upd.getMessage().getText().equalsIgnoreCase(msg); + return upd -> Flag.MESSAGE.test(upd) && upd.getMessage().getText().equalsIgnoreCase(msg); } } } diff --git a/telegrambots-chat-session-bot/README.md b/telegrambots-chat-session-bot/README.md index fd1783b4..4b80eb7d 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.8.1 + 4.9 ``` diff --git a/telegrambots-chat-session-bot/pom.xml b/telegrambots-chat-session-bot/pom.xml index 8efda9c9..715e0224 100644 --- a/telegrambots-chat-session-bot/pom.xml +++ b/telegrambots-chat-session-bot/pom.xml @@ -7,7 +7,7 @@ org.telegram Bots - 4.8.1 + 4.9 telegrambots-chat-session-bot @@ -84,7 +84,7 @@ org.telegram telegrambots - 4.8.1 + 4.9 diff --git a/telegrambots-extensions/README.md b/telegrambots-extensions/README.md index 76f2f969..247bb691 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.8.1 + 4.9 ``` 2. Using Gradle: ```gradle - compile "org.telegram:telegrambotsextensions:4.8.1" + compile "org.telegram:telegrambotsextensions:4.9" ``` \ No newline at end of file diff --git a/telegrambots-extensions/pom.xml b/telegrambots-extensions/pom.xml index d60c5552..7fde69c6 100644 --- a/telegrambots-extensions/pom.xml +++ b/telegrambots-extensions/pom.xml @@ -7,7 +7,7 @@ org.telegram Bots - 4.8.1 + 4.9 telegrambotsextensions @@ -75,7 +75,7 @@ org.telegram telegrambots - 4.8.1 + 4.9 diff --git a/telegrambots-meta/pom.xml b/telegrambots-meta/pom.xml index a8f8e112..6a060936 100644 --- a/telegrambots-meta/pom.xml +++ b/telegrambots-meta/pom.xml @@ -7,7 +7,7 @@ org.telegram Bots - 4.8.1 + 4.9 telegrambots-meta diff --git a/telegrambots-meta/src/main/java/org/telegram/telegrambots/meta/api/methods/send/SendDice.java b/telegrambots-meta/src/main/java/org/telegram/telegrambots/meta/api/methods/send/SendDice.java index b1366ee2..a81c0fe4 100644 --- a/telegrambots-meta/src/main/java/org/telegram/telegrambots/meta/api/methods/send/SendDice.java +++ b/telegrambots-meta/src/main/java/org/telegram/telegrambots/meta/api/methods/send/SendDice.java @@ -10,14 +10,18 @@ import org.telegram.telegrambots.meta.exceptions.TelegramApiRequestException; import org.telegram.telegrambots.meta.exceptions.TelegramApiValidationException; import java.io.IOException; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; /** * @author Ruben Bermudez * @version 4.7 - * Use this method to send a dice, which will have a random value from 1 to 6. On success, the sent Message is returned. - * (Yes, we're aware of the “proper” singular of die. But it's awkward, and we decided to help it change. One dice at a time!) + * Use this method to send an animated emoji that will display a random value. On success, the sent Message is returned. */ public class SendDice extends BotApiMethod { + private static final List VALIDEMOJIS = Collections.unmodifiableList(Arrays.asList("\uD83C\uDFB2", "\uD83C\uDFAF", "\uD83C\uDFC0")); + public static final String PATH = "sendDice"; private static final String CHATID_FIELD = "chat_id"; @@ -28,8 +32,12 @@ public class SendDice extends BotApiMethod { @JsonProperty(CHATID_FIELD) private String chatId; ///< Unique identifier for the target chat or username of the target channel (in the format @channelusername) + /** + * Emoji on which the dice throw animation is based. Currently, must be one of “🎲”, “🎯”, or “🏀”. + * Dice can have values 1-6 for “🎲” and “🎯”, and values 1-5 for “🏀”. Defauts to “🎲” + */ @JsonProperty(EMOJI_FIELD) - private String emoji; ///< Optional. Emoji on which the dice throw animation is based. Currently, must be one of “🎲” or “🎯”. Defauts to “🎲” + private String emoji; @JsonProperty(DISABLENOTIFICATION_FIELD) private Boolean disableNotification; ///< Optional. Sends the message silently. Users will receive a notification with no sound. @JsonProperty(REPLYTOMESSAGEID_FIELD) @@ -121,8 +129,8 @@ public class SendDice extends BotApiMethod { if (chatId == null) { throw new TelegramApiValidationException("ChatId parameter can't be empty", this); } - if (emoji != null && !emoji.equals("\uD83C\uDFB2") && !emoji.equals("\uD83C\uDFAF")) { - throw new TelegramApiValidationException("Only \uD83C\uDFB2 and \uD83C\uDFAF are allowed in Emoji field ", this); + if (emoji != null && !VALIDEMOJIS.contains(emoji)) { + throw new TelegramApiValidationException("Only \uD83C\uDFB2, \uD83C\uDFAF or \uD83C\uDFC0 are allowed in Emoji field ", this); } if (replyMarkup != null) { replyMarkup.validate(); diff --git a/telegrambots-meta/src/main/java/org/telegram/telegrambots/meta/api/objects/Dice.java b/telegrambots-meta/src/main/java/org/telegram/telegrambots/meta/api/objects/Dice.java index 2b57eb80..b0983a63 100644 --- a/telegrambots-meta/src/main/java/org/telegram/telegrambots/meta/api/objects/Dice.java +++ b/telegrambots-meta/src/main/java/org/telegram/telegrambots/meta/api/objects/Dice.java @@ -6,15 +6,14 @@ import org.telegram.telegrambots.meta.api.interfaces.BotApiObject; /** * @author Ruben Bermudez * @version 4.7 - * This object represents a dice with random value from 1 to 6. - * (Yes, we're aware of the “proper” singular of die. But it's awkward, and we decided to help it change. One dice at a time!) + * This object represents an animated emoji that displays a random value. */ public class Dice implements BotApiObject { private static final String VALUE_FIELD = "value"; private static final String EMOJI_FIELD = "emoji"; @JsonProperty(VALUE_FIELD) - private Integer value; ///< Value of the dice, 1-6 + private Integer value; ///< Value of the dice, 1-6 for “🎲” and “🎯” base emoji, 1-5 for “🏀” base emoji @JsonProperty(EMOJI_FIELD) private String emoji; ///< Emoji on which the dice throw animation is based diff --git a/telegrambots-meta/src/main/java/org/telegram/telegrambots/meta/api/objects/Message.java b/telegrambots-meta/src/main/java/org/telegram/telegrambots/meta/api/objects/Message.java index 551922ab..b0723615 100644 --- a/telegrambots-meta/src/main/java/org/telegram/telegrambots/meta/api/objects/Message.java +++ b/telegrambots-meta/src/main/java/org/telegram/telegrambots/meta/api/objects/Message.java @@ -68,6 +68,7 @@ public class Message implements BotApiObject { private static final String POLL_FIELD = "poll"; private static final String REPLY_MARKUP_FIELD = "reply_markup"; private static final String DICE_FIELD = "dice"; + private static final String VIABOT_FIELD = "via_bot"; @JsonProperty(MESSAGEID_FIELD) private Integer messageId; ///< Integer Unique message identifier @@ -210,7 +211,8 @@ public class Message implements BotApiObject { private InlineKeyboardMarkup replyMarkup; @JsonProperty(DICE_FIELD) private Dice dice; // Optional. Message is a dice with random value from 1 to 6 - + @JsonProperty(VIABOT_FIELD) + private User viaBot; // Optional. Bot through which the message was sent public Message() { super(); } @@ -521,6 +523,14 @@ public class Message implements BotApiObject { return dice != null; } + public User getViaBot() { + return viaBot; + } + + public boolean hasViaBot() { + return viaBot != null; + } + public boolean hasReplyMarkup() { return replyMarkup != null; } @@ -579,6 +589,8 @@ public class Message implements BotApiObject { ", forwardSenderName='" + forwardSenderName + '\'' + ", poll=" + poll + ", replyMarkup=" + replyMarkup + + ", dice=" + dice + + ", viaBot=" + viaBot + '}'; } } diff --git a/telegrambots-meta/src/main/java/org/telegram/telegrambots/meta/api/objects/inlinequery/result/InlineQueryResultGif.java b/telegrambots-meta/src/main/java/org/telegram/telegrambots/meta/api/objects/inlinequery/result/InlineQueryResultGif.java index b290ec8d..3a037830 100644 --- a/telegrambots-meta/src/main/java/org/telegram/telegrambots/meta/api/objects/inlinequery/result/InlineQueryResultGif.java +++ b/telegrambots-meta/src/main/java/org/telegram/telegrambots/meta/api/objects/inlinequery/result/InlineQueryResultGif.java @@ -7,6 +7,10 @@ import org.telegram.telegrambots.meta.api.objects.inlinequery.inputmessageconten import org.telegram.telegrambots.meta.api.objects.replykeyboard.InlineKeyboardMarkup; import org.telegram.telegrambots.meta.exceptions.TelegramApiValidationException; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + /** * @author Ruben Bermudez * @version 1.0 @@ -16,12 +20,15 @@ import org.telegram.telegrambots.meta.exceptions.TelegramApiValidationException; */ @JsonDeserialize public class InlineQueryResultGif implements InlineQueryResult { + private static final List VALIDTHUMBTYPES = Collections.unmodifiableList(Arrays.asList("image/jpeg", "image/gif", "video/mp4")); + private static final String TYPE_FIELD = "type"; private static final String ID_FIELD = "id"; private static final String GIFURL_FIELD = "gif_url"; private static final String GIFWIDTH_FIELD = "gif_width"; private static final String GIFHEIGHT_FIELD = "gif_height"; private static final String THUMBURL_FIELD = "thumb_url"; + private static final String THUMBMIMETYPE_FIELD = "thumb_mime_type"; private static final String TITLE_FIELD = "title"; private static final String CAPTION_FIELD = "caption"; private static final String INPUTMESSAGECONTENT_FIELD = "input_message_content"; @@ -40,7 +47,9 @@ public class InlineQueryResultGif implements InlineQueryResult { @JsonProperty(GIFHEIGHT_FIELD) private Integer gifHeight; ///< Optional. Height of the GIF @JsonProperty(THUMBURL_FIELD) - private String thumbUrl; ///< Optional. URL of a static thumbnail for the result (jpeg or gif) + private String thumbUrl; ///< Optional. URL of the static (JPEG or GIF) or animated (MPEG4) thumbnail for the result + @JsonProperty(THUMBMIMETYPE_FIELD) + private String thumbUrlType; ///< Optional. MIME type of the thumbnail, must be one of “image/jpeg”, “image/gif”, or “video/mp4” @JsonProperty(TITLE_FIELD) private String title; ///< Optional. Title for the result @JsonProperty(CAPTION_FIELD) @@ -107,6 +116,15 @@ public class InlineQueryResultGif implements InlineQueryResult { return this; } + public String getThumbUrlType() { + return thumbUrlType; + } + + public InlineQueryResultGif setThumbUrlType(String thumbUrlType) { + this.thumbUrlType = thumbUrlType; + return this; + } + public String getTitle() { return title; } @@ -169,6 +187,9 @@ public class InlineQueryResultGif implements InlineQueryResult { if (gifUrl == null || gifUrl.isEmpty()) { throw new TelegramApiValidationException("GifUrl parameter can't be empty", this); } + if (thumbUrlType != null && !VALIDTHUMBTYPES.contains(thumbUrlType)) { + throw new TelegramApiValidationException("ThumbUrlType parameter must be one of “image/jpeg”, “image/gif”, or “video/mp4”", this); + } if (inputMessageContent != null) { inputMessageContent.validate(); } @@ -186,6 +207,7 @@ public class InlineQueryResultGif implements InlineQueryResult { ", gifWidth=" + gifWidth + ", gifHeight=" + gifHeight + ", thumbUrl='" + thumbUrl + '\'' + + ", thumbUrlType='" + thumbUrlType + '\'' + ", title='" + title + '\'' + ", caption='" + caption + '\'' + ", inputMessageContent=" + inputMessageContent + diff --git a/telegrambots-meta/src/main/java/org/telegram/telegrambots/meta/api/objects/inlinequery/result/cached/InlineQueryResultCachedGif.java b/telegrambots-meta/src/main/java/org/telegram/telegrambots/meta/api/objects/inlinequery/result/cached/InlineQueryResultCachedGif.java index 17661bb3..bee3d835 100644 --- a/telegrambots-meta/src/main/java/org/telegram/telegrambots/meta/api/objects/inlinequery/result/cached/InlineQueryResultCachedGif.java +++ b/telegrambots-meta/src/main/java/org/telegram/telegrambots/meta/api/objects/inlinequery/result/cached/InlineQueryResultCachedGif.java @@ -8,6 +8,10 @@ import org.telegram.telegrambots.meta.api.objects.inlinequery.result.InlineQuery import org.telegram.telegrambots.meta.api.objects.replykeyboard.InlineKeyboardMarkup; import org.telegram.telegrambots.meta.exceptions.TelegramApiValidationException; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + /** * @author Ruben Bermudez * @version 1.0 @@ -17,11 +21,15 @@ import org.telegram.telegrambots.meta.exceptions.TelegramApiValidationException; */ @JsonDeserialize public class InlineQueryResultCachedGif implements InlineQueryResult { + private static final List VALIDTHUMBTYPES = Collections.unmodifiableList(Arrays.asList("image/jpeg", "image/gif", "video/mp4")); + private static final String TYPE_FIELD = "type"; private static final String ID_FIELD = "id"; private static final String GIF_FILE_ID_FIELD = "gif_file_id"; private static final String TITLE_FIELD = "title"; private static final String CAPTION_FIELD = "caption"; + private static final String THUMBURL_FIELD = "thumb_url"; + private static final String THUMBMIMETYPE_FIELD = "thumb_mime_type"; private static final String INPUTMESSAGECONTENT_FIELD = "input_message_content"; private static final String REPLY_MARKUP_FIELD = "reply_markup"; private static final String PARSEMODE_FIELD = "parse_mode"; @@ -42,6 +50,10 @@ public class InlineQueryResultCachedGif implements InlineQueryResult { private InlineKeyboardMarkup replyMarkup; ///< Optional. Inline keyboard attached to the message @JsonProperty(PARSEMODE_FIELD) private String parseMode; ///< Send Markdown or HTML, if you want Telegram apps to show bold, italic, fixed-width text or inline URLs in the media caption. + @JsonProperty(THUMBURL_FIELD) + private String thumbUrl; ///< Optional. URL of the static (JPEG or GIF) or animated (MPEG4) thumbnail for the result + @JsonProperty(THUMBMIMETYPE_FIELD) + private String thumbUrlType; public InlineQueryResultCachedGif() { super(); @@ -114,6 +126,24 @@ public class InlineQueryResultCachedGif implements InlineQueryResult { return this; } + public String getThumbUrl() { + return thumbUrl; + } + + public InlineQueryResultCachedGif setThumbUrl(String thumbUrl) { + this.thumbUrl = thumbUrl; + return this; + } + + public String getThumbUrlType() { + return thumbUrlType; + } + + public InlineQueryResultCachedGif setThumbUrlType(String thumbUrlType) { + this.thumbUrlType = thumbUrlType; + return this; + } + @Override public void validate() throws TelegramApiValidationException { if (id == null || id.isEmpty()) { @@ -122,6 +152,9 @@ public class InlineQueryResultCachedGif implements InlineQueryResult { if (gifFileId == null || gifFileId.isEmpty()) { throw new TelegramApiValidationException("GifFileId parameter can't be empty", this); } + if (thumbUrlType != null && !VALIDTHUMBTYPES.contains(thumbUrlType)) { + throw new TelegramApiValidationException("ThumbUrlType parameter must be one of “image/jpeg”, “image/gif”, or “video/mp4”", this); + } if (inputMessageContent != null) { inputMessageContent.validate(); } @@ -141,6 +174,8 @@ public class InlineQueryResultCachedGif implements InlineQueryResult { ", inputMessageContent=" + inputMessageContent + ", replyMarkup=" + replyMarkup + ", parseMode='" + parseMode + '\'' + + ", thumbUrl='" + thumbUrl + '\'' + + ", thumbUrlType='" + thumbUrlType + '\'' + '}'; } } diff --git a/telegrambots-spring-boot-starter/pom.xml b/telegrambots-spring-boot-starter/pom.xml index 79c6a4c3..b9d59a0a 100644 --- a/telegrambots-spring-boot-starter/pom.xml +++ b/telegrambots-spring-boot-starter/pom.xml @@ -7,7 +7,7 @@ org.telegram Bots - 4.8.1 + 4.9 telegrambots-spring-boot-starter @@ -79,7 +79,7 @@ org.telegram telegrambots - 4.8.1 + 4.9 org.springframework.boot diff --git a/telegrambots/pom.xml b/telegrambots/pom.xml index 981a1f55..03123e30 100644 --- a/telegrambots/pom.xml +++ b/telegrambots/pom.xml @@ -7,7 +7,7 @@ org.telegram Bots - 4.8.1 + 4.9 telegrambots @@ -95,7 +95,7 @@ org.telegram telegrambots-meta - 4.8.1 + 4.9 com.fasterxml.jackson.core