From 8131f4131369afd83ed074617a6cb773207191a8 Mon Sep 17 00:00:00 2001 From: LamGC Date: Tue, 19 Apr 2022 00:17:57 +0800 Subject: [PATCH] =?UTF-8?q?feat(extension):=20=E5=88=9D=E6=AD=A5=E6=B7=BB?= =?UTF-8?q?=E5=8A=A0=E4=B8=80=E4=BA=9B=E5=B7=A5=E5=85=B7=E6=96=B9=E6=B3=95?= =?UTF-8?q?.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 添加 AbilityBots 类, 向开发者提供一些"工具"方法, 该方法将有助于插件的功能开发. --- scalabot-extension/build.gradle.kts | 5 +- .../scalabot/extension/util/AbilityBots.java | 52 ++++++++ .../extension/util/AbilityBotsTest.java | 121 ++++++++++++++++++ 3 files changed, 176 insertions(+), 2 deletions(-) create mode 100644 scalabot-extension/src/main/java/net/lamgc/scalabot/extension/util/AbilityBots.java create mode 100644 scalabot-extension/src/test/java/net/lamgc/scalabot/extension/util/AbilityBotsTest.java diff --git a/scalabot-extension/build.gradle.kts b/scalabot-extension/build.gradle.kts index acb624c..5571593 100644 --- a/scalabot-extension/build.gradle.kts +++ b/scalabot-extension/build.gradle.kts @@ -10,8 +10,9 @@ dependencies { api("org.telegram:telegrambots-abilities:6.0.1") api("org.slf4j:slf4j-api:1.7.36") - // There is nothing to test. - // testImplementation(kotlin("test")) + testImplementation("org.junit.jupiter:junit-jupiter-api:5.8.2") + testImplementation("org.mockito:mockito-core:4.4.0") + testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine") } tasks.withType { diff --git a/scalabot-extension/src/main/java/net/lamgc/scalabot/extension/util/AbilityBots.java b/scalabot-extension/src/main/java/net/lamgc/scalabot/extension/util/AbilityBots.java new file mode 100644 index 0000000..f5b73b1 --- /dev/null +++ b/scalabot-extension/src/main/java/net/lamgc/scalabot/extension/util/AbilityBots.java @@ -0,0 +1,52 @@ +package net.lamgc.scalabot.extension.util; + +import org.telegram.abilitybots.api.bot.BaseAbilityBot; + +import java.util.Map; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class AbilityBots { + + private final static Pattern botTokenPattern = Pattern.compile("([1-9]\\d+):([A-Za-z\\d_-]{35,})"); + + private AbilityBots() { + } + + /** + * 获取 AbilityBot 的账户 Id. + * + *

账户 Id 来自于 botToken 中, token 的格式为 "[AccountId]:[Secret]". + *

账户 Id 的真实性与 botToken 的有效性有关, 本方法并不会确保 botToken 的有效性, 一般情况下也无需考虑 Id 的有效性, + * 如果有需要, 可尝试通过调用 {@link org.telegram.telegrambots.meta.api.methods.GetMe} 来确保 botToken 的有效性. + * + * @param bot 要获取账户 Id 的 AbilityBot 对象. + * @return 返回 AbilityBot 的账户 Id. + * @throws IllegalArgumentException 当 AbilityBot 的 botToken 格式错误时抛出该异常. + */ + public static long getBotAccountId(BaseAbilityBot bot) { + String botToken = bot.getBotToken(); + Matcher matcher = botTokenPattern.matcher(botToken); + if (!matcher.matches()) { + throw new IllegalArgumentException("Invalid token format."); + } + return Long.parseLong(matcher.group(1)); + } + + /** + * 取消某一对话的状态机. + * + * @param bot AbilityBot 实例. + * @param chatId 要删除状态机的聊天 Id. + * @return 如果状态机存在, 则删除后返回 true, 不存在(未开启任何状态机, 即没有触发任何 Reply)则返回 false. + */ + public static boolean cancelReplyState(BaseAbilityBot bot, long chatId) { + Map stateMap = bot.db().getMap("user_state_replies"); + if (!stateMap.containsKey(chatId)) { + return false; + } + stateMap.remove(chatId); + return true; + } + +} diff --git a/scalabot-extension/src/test/java/net/lamgc/scalabot/extension/util/AbilityBotsTest.java b/scalabot-extension/src/test/java/net/lamgc/scalabot/extension/util/AbilityBotsTest.java new file mode 100644 index 0000000..00f249d --- /dev/null +++ b/scalabot-extension/src/test/java/net/lamgc/scalabot/extension/util/AbilityBotsTest.java @@ -0,0 +1,121 @@ +package net.lamgc.scalabot.extension.util; + +import org.junit.jupiter.api.Test; +import org.mapdb.DBMaker; +import org.telegram.abilitybots.api.bot.AbilityBot; +import org.telegram.abilitybots.api.bot.BaseAbilityBot; +import org.telegram.abilitybots.api.db.MapDBContext; +import org.telegram.abilitybots.api.objects.*; +import org.telegram.abilitybots.api.sender.SilentSender; +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 static org.junit.jupiter.api.Assertions.*; +import static org.mockito.Mockito.*; + +public class AbilityBotsTest { + + public static final User USER = new User(1L, "first", false, "last", "username", null, false, false, false); + public static final User CREATOR = new User(1337L, "creatorFirst", false, "creatorLast", "creatorUsername", null, false, false, false); + + static Update mockFullUpdate(BaseAbilityBot bot, User user, String args) { + bot.users().put(USER.getId(), USER); + bot.users().put(CREATOR.getId(), CREATOR); + bot.userIds().put(CREATOR.getUserName(), CREATOR.getId()); + bot.userIds().put(USER.getUserName(), USER.getId()); + + bot.admins().add(CREATOR.getId()); + + Update update = mock(Update.class); + when(update.hasMessage()).thenReturn(true); + Message message = mock(Message.class); + when(message.getFrom()).thenReturn(user); + when(message.getText()).thenReturn(args); + when(message.hasText()).thenReturn(true); + when(message.isUserMessage()).thenReturn(true); + when(message.getChatId()).thenReturn(user.getId()); + when(update.getMessage()).thenReturn(message); + return update; + } + + @Test + void getBotAccountIdTest() { + String expectToken = "1234567890:AAHXcNDBRZTKfyPED5Gi3PZDIKPOM6xhxwo"; + long actual = AbilityBots.getBotAccountId(new TestingAbilityBot(expectToken, "test")); + assertEquals(1234567890, actual); + + String badTokenA = "12c34d56a7890:AAHXcNDBRZTKfyPED5Gi3PZDIKPOM6xhxwo"; + assertThrows(IllegalArgumentException.class, () -> + AbilityBots.getBotAccountId(new TestingAbilityBot(badTokenA, "test"))); + + String badTokenB = "12c34d56a7890AAHXcNDBRZTKfyPED5Gi3PZDIKPOM6xhxwo"; + assertThrows(IllegalArgumentException.class, () -> + AbilityBots.getBotAccountId(new TestingAbilityBot(badTokenB, "test"))); + } + + @Test + void cancelReplyStateTest() { + User userA = new User(10001L, "first", false, "last", "username", null, false, false, false); + User userB = new User(10101L, "first", false, "last", "username", null, false, false, false); + SilentSender silent = mock(SilentSender.class); + BaseAbilityBot bot = new TestingAbilityBot("", "", silent); + bot.onRegister(); + bot.onUpdateReceived(mockFullUpdate(bot, userA, "/set_reply")); + verify(silent, times(1)).send("Reply set!", userA.getId()); + bot.onUpdateReceived(mockFullUpdate(bot, userA, "reply_01")); + verify(silent, times(1)).send("Reply 01", userA.getId()); + assertTrue(AbilityBots.cancelReplyState(bot, userA.getId())); + bot.onUpdateReceived(mockFullUpdate(bot, userA, "reply_02")); + verify(silent, never()).send("Reply 02", userA.getId()); + + assertFalse(AbilityBots.cancelReplyState(bot, userB.getId())); + + silent = mock(SilentSender.class); + bot = new TestingAbilityBot("", "", silent); + bot.onRegister(); + + bot.onUpdateReceived(mockFullUpdate(bot, userA, "/set_reply")); + verify(silent, times(1)).send("Reply set!", userA.getId()); + bot.onUpdateReceived(mockFullUpdate(bot, userA, "reply_01")); + verify(silent, times(1)).send("Reply 01", userA.getId()); + bot.onUpdateReceived(mockFullUpdate(bot, userA, "reply_02")); + verify(silent, times(1)).send("Reply 02", userA.getId()); + } + + public static class TestingAbilityBot extends AbilityBot { + + public TestingAbilityBot(String botToken, String botUsername) { + super(botToken, botUsername, new MapDBContext(DBMaker.heapDB().make())); + } + + public TestingAbilityBot(String botToken, String botUsername, SilentSender silentSender) { + super(botToken, botUsername, new MapDBContext(DBMaker.heapDB().make())); + this.silent = silentSender; + } + + public Ability setReply() { + return Ability.builder() + .name("set_reply") + .enableStats() + .locality(Locality.ALL) + .privacy(Privacy.PUBLIC) + .action(ctx -> ctx.bot().silent().send("Reply set!", ctx.chatId())) + .reply(ReplyFlow.builder(db()) + .action((bot, upd) -> bot.silent().send("Reply 01", upd.getMessage().getChatId())) + .onlyIf(upd -> upd.hasMessage() && upd.getMessage().getText().equals("reply_01")) + .next(Reply.of((bot, upd) -> + bot.silent().send("Reply 02", upd.getMessage().getChatId()), + upd -> upd.hasMessage() && upd.getMessage().getText().equals("reply_02"))) + .build() + ) + .build(); + } + + @Override + public long creatorId() { + return 0; + } + } + +}