Merge pull request #859 from Narryel/dev

add multiple reply declaration support
This commit is contained in:
Ruben Bermudez 2021-03-06 11:15:38 +00:00 committed by GitHub
commit 7287c38444
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 103 additions and 5 deletions

View File

@ -350,16 +350,25 @@ public abstract class BaseAbilityBot extends DefaultAbsSender implements Ability
.map(returnReply(ext)))
.flatMap(Reply::stream);
// Extract all replies from extension instances methods, returning ReplyCollection
Stream<Reply> extensionCollectionReplies = extensions.stream()
.flatMap(extension -> stream(extension.getClass().getMethods())
.filter(checkReturnType(ReplyCollection.class))
.map(returnReplyCollection(extension))
.flatMap(ReplyCollection::stream));
// Replies can be standalone or attached to abilities, fetch those too
Stream<Reply> abilityReplies = abilities.values().stream()
.flatMap(ability -> ability.replies().stream())
.flatMap(Reply::stream);
// Now create the replies registry (list)
replies = Stream.concat(abilityReplies, extensionReplies).collect(
ImmutableList::<Reply>builder,
Builder::add,
(b1, b2) -> b1.addAll(b2.build()))
replies = Stream.of(abilityReplies, extensionReplies, extensionCollectionReplies)
.flatMap(replyStream -> replyStream)
.collect(
ImmutableList::<Reply>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);
@ -439,6 +448,23 @@ public abstract class BaseAbilityBot extends DefaultAbsSender implements Ability
};
}
/**
* Invokes the method and retrieves its return {@link ReplyCollection}.
*
* @param obj a bot or extension that this method is invoked with
* @return a {@link Function} which returns the {@link ReplyCollection} returned by the given method
*/
private static Function<? super Method, ReplyCollection> returnReplyCollection(Object obj) {
return method -> {
try {
return (ReplyCollection) method.invoke(obj);
} catch (IllegalAccessException | InvocationTargetException e) {
log.error("Could not add Reply Collection", e);
throw new RuntimeException(e);
}
};
}
private void postConsumption(Pair<MessageContext, Ability> pair) {
ofNullable(pair.b().postAction())
.ifPresent(consumer -> consumer.accept(pair.a()));

View File

@ -0,0 +1,32 @@
package org.telegram.abilitybots.api.objects;
import java.util.Collection;
import java.util.stream.Stream;
import static com.google.common.collect.Lists.newArrayList;
/**
* A wrapping object containing Replies. Return this in your bot class to get replies registered.
*
* @see Reply
*/
public class ReplyCollection {
public final Collection<Reply> replies;
public ReplyCollection(Collection<Reply> replies) {
this.replies = replies;
}
public Collection<Reply> getReplies() {
return replies;
}
public Stream<Reply> stream(){
return replies.stream();
}
public static ReplyCollection of(Reply... replies){
return new ReplyCollection(newArrayList(replies));
}
}

View File

@ -40,7 +40,7 @@ import static org.apache.commons.lang3.StringUtils.EMPTY;
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.DefaultBot.*;
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;
@ -661,6 +661,30 @@ public class AbilityBotTest {
verify(silent, times(1)).send(expected, 1);
}
@Test
void canProcessRepliesRegisteredInCollection() {
Update firstUpdate = mock(Update.class);
Message firstMessage = mock(Message.class);
when(firstMessage.getText()).thenReturn(FIRST_REPLY_KEY_MESSAGE);
when(firstMessage.getChatId()).thenReturn(1L);
Update secondUpdate = mock(Update.class);
Message secondMessage = mock(Message.class);
when(secondMessage.getText()).thenReturn(SECOND_REPLY_KEY_MESSAGE);
when(secondMessage.getChatId()).thenReturn(1L);
mockUser(firstUpdate, firstMessage, USER);
mockUser(secondUpdate, secondMessage, USER);
bot.onUpdateReceived(firstUpdate);
bot.onUpdateReceived(secondUpdate);
verify(silent, times(2)).send(anyString(), anyLong());
verify(silent, times(1)).send("first reply answer", 1);
verify(silent, times(1)).send("second reply answer", 1);
}
private void handlesAllUpdates(Consumer<Update> utilMethod) {
Arrays.stream(Update.class.getMethods())
// filter to all these methods of hasXXX (hasPoll, hasMessage, etc...)

View File

@ -5,6 +5,7 @@ import org.telegram.abilitybots.api.objects.Ability;
import org.telegram.abilitybots.api.objects.Ability.AbilityBuilder;
import org.telegram.abilitybots.api.objects.Flag;
import org.telegram.abilitybots.api.objects.Reply;
import org.telegram.abilitybots.api.objects.ReplyCollection;
import org.telegram.abilitybots.api.toggle.AbilityToggle;
import static org.telegram.abilitybots.api.objects.Ability.builder;
@ -15,6 +16,8 @@ import static org.telegram.abilitybots.api.objects.Privacy.ADMIN;
import static org.telegram.abilitybots.api.objects.Privacy.PUBLIC;
public class DefaultBot extends AbilityBot {
public static final String FIRST_REPLY_KEY_MESSAGE = "first reply key string";
public static final String SECOND_REPLY_KEY_MESSAGE = "second reply key string";
public DefaultBot(String token, String username, DBContext db) {
super(token, username, db);
@ -79,6 +82,19 @@ public class DefaultBot extends AbilityBot {
);
}
public ReplyCollection createReplyCollection() {
return ReplyCollection.of(
Reply.of(
upd -> silent.send("first reply answer", upd.getMessage().getChatId()),
update -> update.getMessage().getText().equalsIgnoreCase(FIRST_REPLY_KEY_MESSAGE)
),
Reply.of(
upd -> silent.send("second reply answer", upd.getMessage().getChatId()),
update -> update.getMessage().getText().equalsIgnoreCase(SECOND_REPLY_KEY_MESSAGE)
)
);
}
public Ability testAbility() {
return getDefaultBuilder().build();
}