Merge pull request #671 from addo37/add-ability-toggle
Add Abillity toggles and export default abilities to their own class
This commit is contained in:
commit
fc12de81c0
@ -8,6 +8,7 @@
|
||||
* [[Simple Example]]
|
||||
* [[Hello Ability]]
|
||||
* [[Using Replies]]
|
||||
* [[Ability Toggle]]
|
||||
* [[State Machines]]
|
||||
* [[Database Handling]]
|
||||
* [[Ability Extensions]]
|
||||
|
42
TelegramBots.wiki/abilities/Ability-Toggle.md
Normal file
42
TelegramBots.wiki/abilities/Ability-Toggle.md
Normal file
@ -0,0 +1,42 @@
|
||||
# Ability Toggle
|
||||
Well, what if you don't like all the default abilities that AbilityBot supplies? Fear not, you are able to disable all of them, even rename them if you will!
|
||||
|
||||
You may pass a custom toggle to your abilitybot constructor to customize how these abilities get registered.
|
||||
|
||||
## The Barebone Toggle
|
||||
The barebone toggle is used to **turn off** all the default abilities that come with the bot (ban, unban, demote, promte, etc...). To use the barebone toggle, call your super constructor with:
|
||||
```java
|
||||
import org.telegram.abilitybots.api.toggle.BareboneToggle;
|
||||
|
||||
public class YourAwesomeBot extends AbilityBot {
|
||||
public YourAwesomeBot(String token, String username) {
|
||||
BareboneToggle toggle = new BareboneToggle();
|
||||
super(token, username, toggle);
|
||||
}
|
||||
|
||||
// Override ceatorId()
|
||||
}
|
||||
```
|
||||
Obviously, you can export this as a parameter that you can pass to your bot's constructor.
|
||||
|
||||
## The Custom Toggle
|
||||
The custom toggle allows you to customize or turn off the names of the abilities that the abilitybot exposes.
|
||||
```java
|
||||
import org.telegram.abilitybots.api.toggle.CustomToggle;
|
||||
|
||||
public class YourAwesomeBot extends AbilityBot {
|
||||
public YourAwesomeBot(String token, String username) {
|
||||
CustomToggle toggle = new CustomToggle()
|
||||
.turnOff("ban")
|
||||
.toggle("promote", "upgrade");
|
||||
|
||||
super(token, username, toggle);
|
||||
}
|
||||
|
||||
// Override ceatorId()
|
||||
}
|
||||
```
|
||||
|
||||
With these changes, the ability "ban" is no longer available and the "promote" ability has been renamed to "upgrade".
|
||||
## The Default Toggle
|
||||
The default toggle is automatically used if the user does not specify a toggle. The default toggle allows all the abilities to be effective and unchanged.
|
@ -1,6 +1,8 @@
|
||||
package org.telegram.abilitybots.api.bot;
|
||||
|
||||
import org.telegram.abilitybots.api.db.DBContext;
|
||||
import org.telegram.abilitybots.api.toggle.AbilityToggle;
|
||||
import org.telegram.abilitybots.api.toggle.DefaultToggle;
|
||||
import org.telegram.telegrambots.meta.api.objects.Update;
|
||||
import org.telegram.telegrambots.bots.DefaultBotOptions;
|
||||
import org.telegram.telegrambots.bots.TelegramLongPollingBot;
|
||||
@ -16,18 +18,34 @@ import static org.telegram.abilitybots.api.db.MapDBContext.onlineInstance;
|
||||
* @author Abbas Abou Daya
|
||||
*/
|
||||
public abstract class AbilityBot extends BaseAbilityBot implements LongPollingBot {
|
||||
protected AbilityBot(String botToken, String botUsername, DBContext db, DefaultBotOptions botOptions) {
|
||||
super(botToken, botUsername, db, botOptions);
|
||||
protected AbilityBot(String botToken, String botUsername, DBContext db, AbilityToggle toggle, DefaultBotOptions botOptions) {
|
||||
super(botToken, botUsername, db, toggle, botOptions);
|
||||
}
|
||||
|
||||
protected AbilityBot(String botToken, String botUsername, DBContext db) {
|
||||
this(botToken, botUsername, db, new DefaultBotOptions());
|
||||
protected AbilityBot(String botToken, String botUsername, AbilityToggle toggle, DefaultBotOptions options) {
|
||||
this(botToken, botUsername, onlineInstance(botUsername), toggle, options);
|
||||
}
|
||||
|
||||
protected AbilityBot(String botToken, String botUsername, DBContext db, AbilityToggle toggle) {
|
||||
this(botToken, botUsername, db, toggle, new DefaultBotOptions());
|
||||
}
|
||||
|
||||
protected AbilityBot(String botToken, String botUsername, DBContext db, DefaultBotOptions options) {
|
||||
this(botToken, botUsername, db, new DefaultToggle(), options);
|
||||
}
|
||||
|
||||
protected AbilityBot(String botToken, String botUsername, DefaultBotOptions botOptions) {
|
||||
this(botToken, botUsername, onlineInstance(botUsername), botOptions);
|
||||
}
|
||||
|
||||
protected AbilityBot(String botToken, String botUsername, AbilityToggle toggle) {
|
||||
this(botToken, botUsername, onlineInstance(botUsername), toggle);
|
||||
}
|
||||
|
||||
protected AbilityBot(String botToken, String botUsername, DBContext db) {
|
||||
this(botToken, botUsername, db, new DefaultToggle());
|
||||
}
|
||||
|
||||
protected AbilityBot(String botToken, String botUsername) {
|
||||
this(botToken, botUsername, onlineInstance(botUsername));
|
||||
}
|
||||
|
@ -1,6 +1,8 @@
|
||||
package org.telegram.abilitybots.api.bot;
|
||||
|
||||
import org.telegram.abilitybots.api.db.DBContext;
|
||||
import org.telegram.abilitybots.api.toggle.AbilityToggle;
|
||||
import org.telegram.abilitybots.api.toggle.DefaultToggle;
|
||||
import org.telegram.telegrambots.meta.api.methods.BotApiMethod;
|
||||
import org.telegram.telegrambots.meta.api.objects.Update;
|
||||
import org.telegram.telegrambots.bots.DefaultBotOptions;
|
||||
@ -21,19 +23,35 @@ public abstract class AbilityWebhookBot extends BaseAbilityBot implements Webhoo
|
||||
|
||||
private final String botPath;
|
||||
|
||||
protected AbilityWebhookBot(String botToken, String botUsername, String botPath, DBContext db, DefaultBotOptions botOptions) {
|
||||
super(botToken, botUsername, db, botOptions);
|
||||
protected AbilityWebhookBot(String botToken, String botUsername, String botPath, DBContext db, AbilityToggle toggle, DefaultBotOptions botOptions) {
|
||||
super(botToken, botUsername, db, toggle, botOptions);
|
||||
this.botPath = botPath;
|
||||
}
|
||||
|
||||
protected AbilityWebhookBot(String botToken, String botUsername, String botPath, DBContext db) {
|
||||
this(botToken, botUsername, botPath, db, new DefaultBotOptions());
|
||||
protected AbilityWebhookBot(String botToken, String botUsername, String botPath, AbilityToggle toggle, DefaultBotOptions options) {
|
||||
this(botToken, botUsername, botPath, onlineInstance(botUsername), toggle, options);
|
||||
}
|
||||
|
||||
protected AbilityWebhookBot(String botToken, String botUsername, String botPath, DBContext db, AbilityToggle toggle) {
|
||||
this(botToken, botUsername, botPath, db, toggle, new DefaultBotOptions());
|
||||
}
|
||||
|
||||
protected AbilityWebhookBot(String botToken, String botUsername, String botPath, DBContext db, DefaultBotOptions options) {
|
||||
this(botToken, botUsername, botPath, db, new DefaultToggle(), options);
|
||||
}
|
||||
|
||||
protected AbilityWebhookBot(String botToken, String botUsername, String botPath, DefaultBotOptions botOptions) {
|
||||
this(botToken, botUsername, botPath, onlineInstance(botUsername), botOptions);
|
||||
}
|
||||
|
||||
protected AbilityWebhookBot(String botToken, String botUsername, String botPath, AbilityToggle toggle) {
|
||||
this(botToken, botUsername, botPath, onlineInstance(botUsername), toggle);
|
||||
}
|
||||
|
||||
protected AbilityWebhookBot(String botToken, String botUsername, String botPath, DBContext db) {
|
||||
this(botToken, botUsername, botPath, db, new DefaultToggle());
|
||||
}
|
||||
|
||||
protected AbilityWebhookBot(String botToken, String botUsername, String botPath) {
|
||||
this(botToken, botUsername, botPath, onlineInstance(botUsername));
|
||||
}
|
||||
|
@ -3,21 +3,15 @@ package org.telegram.abilitybots.api.bot;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableList.Builder;
|
||||
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.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.objects.*;
|
||||
import org.telegram.abilitybots.api.sender.DefaultSender;
|
||||
import org.telegram.abilitybots.api.sender.MessageSender;
|
||||
import org.telegram.abilitybots.api.sender.SilentSender;
|
||||
import org.telegram.abilitybots.api.toggle.AbilityToggle;
|
||||
import org.telegram.abilitybots.api.util.AbilityExtension;
|
||||
import org.telegram.abilitybots.api.util.AbilityUtils;
|
||||
import org.telegram.abilitybots.api.util.Pair;
|
||||
@ -25,85 +19,31 @@ import org.telegram.abilitybots.api.util.Trio;
|
||||
import org.telegram.telegrambots.bots.DefaultAbsSender;
|
||||
import org.telegram.telegrambots.bots.DefaultBotOptions;
|
||||
import org.telegram.telegrambots.bots.TelegramLongPollingBot;
|
||||
import org.telegram.telegrambots.meta.api.methods.GetFile;
|
||||
import org.telegram.telegrambots.meta.api.methods.groupadministration.GetChatAdministrators;
|
||||
import org.telegram.telegrambots.meta.api.methods.send.SendDocument;
|
||||
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.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileReader;
|
||||
import java.io.PrintStream;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
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.*;
|
||||
import java.util.function.BiFunction;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import static com.google.common.base.Strings.isNullOrEmpty;
|
||||
import static com.google.common.collect.MultimapBuilder.hashKeys;
|
||||
import static java.lang.String.format;
|
||||
import static java.time.ZonedDateTime.now;
|
||||
import static java.util.Arrays.stream;
|
||||
import static java.util.Comparator.comparing;
|
||||
import static java.util.Objects.nonNull;
|
||||
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 org.apache.commons.lang3.StringUtils.isEmpty;
|
||||
import static org.telegram.abilitybots.api.objects.Ability.builder;
|
||||
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.Locality.*;
|
||||
import static org.telegram.abilitybots.api.objects.MessageContext.newContext;
|
||||
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;
|
||||
import static org.telegram.abilitybots.api.objects.Privacy.*;
|
||||
import static org.telegram.abilitybots.api.util.AbilityMessageCodes.*;
|
||||
import static org.telegram.abilitybots.api.util.AbilityUtils.*;
|
||||
|
||||
/**
|
||||
* The <b>father</b> of all ability bots. Bots that need to utilize abilities need to extend this bot.
|
||||
@ -141,29 +81,21 @@ import static org.telegram.abilitybots.api.util.AbilityUtils.stripTag;
|
||||
public abstract class BaseAbilityBot extends DefaultAbsSender implements AbilityExtension {
|
||||
private static final Logger log = LogManager.getLogger(BaseAbilityBot.class);
|
||||
|
||||
protected static final String DEFAULT = "default";
|
||||
// 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";
|
||||
|
||||
// DB and sender
|
||||
protected final DBContext db;
|
||||
protected MessageSender sender;
|
||||
protected SilentSender silent;
|
||||
|
||||
// Ability toggle
|
||||
private final AbilityToggle toggle;
|
||||
|
||||
// Bot token and username
|
||||
private final String botToken;
|
||||
private final String botUsername;
|
||||
@ -176,12 +108,13 @@ public abstract class BaseAbilityBot extends DefaultAbsSender implements Ability
|
||||
|
||||
public abstract int creatorId();
|
||||
|
||||
protected BaseAbilityBot(String botToken, String botUsername, DBContext db, DefaultBotOptions botOptions) {
|
||||
protected BaseAbilityBot(String botToken, String botUsername, DBContext db, AbilityToggle toggle, DefaultBotOptions botOptions) {
|
||||
super(botOptions);
|
||||
|
||||
this.botToken = botToken;
|
||||
this.botUsername = botUsername;
|
||||
this.db = db;
|
||||
this.toggle = toggle;
|
||||
this.sender = new DefaultSender(this);
|
||||
silent = new SilentSender(sender);
|
||||
|
||||
@ -281,374 +214,6 @@ public abstract class BaseAbilityBot extends DefaultAbsSender implements Ability
|
||||
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));
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Format of the report:
|
||||
* <p>
|
||||
* [command1] - [description1]
|
||||
* <p>
|
||||
* [command2] - [description2]
|
||||
* <p>
|
||||
* ...
|
||||
* <p>
|
||||
* Once you invoke it, the bot will send the available commands to the chat. This is a public ability so anyone can invoke it.
|
||||
* <p>
|
||||
* Usage: <code>/commands</code>
|
||||
*
|
||||
* @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:
|
||||
* <p>
|
||||
* PUBLIC
|
||||
* <p>
|
||||
* [command1] - [description1]
|
||||
* <p>
|
||||
* [command2] - [description2]
|
||||
* <p>
|
||||
* GROUP_ADMIN
|
||||
* <p>
|
||||
* [command1] - [description1]
|
||||
* <p>
|
||||
* ...
|
||||
*
|
||||
* @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<Privacy, String> 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.
|
||||
* <p>
|
||||
* This is a high-profile ability and is restricted to the CREATOR only.
|
||||
* <p>
|
||||
* Usage: <code>/backup</code>
|
||||
*
|
||||
* @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)}.
|
||||
* <p>
|
||||
* The bot recovery process hugely depends on the implementation of the recovery method of {@link DBContext}.
|
||||
* <p>
|
||||
* Usage: <code>/recover</code>
|
||||
*
|
||||
* @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}.
|
||||
* <p>
|
||||
* Usage: <code>/ban @username</code>
|
||||
* <p>
|
||||
* <u>Note that admins who try to ban the creator, get banned.</u>
|
||||
*
|
||||
* @return the ability to ban the user from any kind of <b>bot interaction</b>
|
||||
*/
|
||||
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<Integer> 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: <code>/unban @username</code>
|
||||
*
|
||||
* @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<Integer> 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<Integer> 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<Integer> 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 <b>banned</b>.
|
||||
*
|
||||
* @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<Integer> 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<Message> send(String message, MessageContext ctx, String... args) {
|
||||
return silent.send(getLocalizedMessage(message, ctx.user().getLanguageCode(), args), ctx.chatId());
|
||||
}
|
||||
|
||||
private Optional<Message> sendMd(String message, MessageContext ctx, String... args) {
|
||||
return silent.sendMd(getLocalizedMessage(message, ctx.user().getLanguageCode(), args), ctx.chatId());
|
||||
}
|
||||
|
||||
private Optional<Message> 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.
|
||||
* <p>
|
||||
@ -665,11 +230,19 @@ public abstract class BaseAbilityBot extends DefaultAbsSender implements Ability
|
||||
// Add the bot itself as it is an AbilityExtension
|
||||
extensions.add(this);
|
||||
|
||||
DefaultAbilities defaultAbs = new DefaultAbilities(this);
|
||||
Stream<Ability> defaultAbsStream = stream(DefaultAbilities.class.getMethods())
|
||||
.filter(checkReturnType(Ability.class))
|
||||
.map(returnAbility(defaultAbs))
|
||||
.filter(ab -> !toggle.isOff(ab))
|
||||
.map(toggle::processAbility);
|
||||
|
||||
// Extract all abilities from every single extension instance
|
||||
abilities = extensions.stream()
|
||||
abilities = Stream.concat(defaultAbsStream,
|
||||
extensions.stream()
|
||||
.flatMap(ext -> stream(ext.getClass().getMethods())
|
||||
.filter(checkReturnType(Ability.class))
|
||||
.map(returnAbility(ext)))
|
||||
.map(returnAbility(ext))))
|
||||
// Abilities are immutable, build it respectively
|
||||
.collect(ImmutableMap::<String, Ability>builder,
|
||||
(b, a) -> b.put(a.name(), a),
|
||||
@ -703,7 +276,7 @@ public abstract class BaseAbilityBot extends DefaultAbsSender implements Ability
|
||||
* @param clazz the type to be tested
|
||||
* @return a predicate testing the return type of the method corresponding to the class parameter
|
||||
*/
|
||||
private Predicate<Method> checkReturnType(Class<?> clazz) {
|
||||
private static Predicate<Method> checkReturnType(Class<?> clazz) {
|
||||
return method -> clazz.isAssignableFrom(method.getReturnType());
|
||||
}
|
||||
|
||||
@ -730,7 +303,7 @@ public abstract class BaseAbilityBot extends DefaultAbsSender implements Ability
|
||||
* @param obj a 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<? super Method, Ability> returnAbility(Object obj) {
|
||||
private static Function<? super Method, Ability> returnAbility(Object obj) {
|
||||
return method -> {
|
||||
try {
|
||||
return (Ability) method.invoke(obj);
|
||||
@ -747,7 +320,7 @@ public abstract class BaseAbilityBot extends DefaultAbsSender implements Ability
|
||||
* @param obj a 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<? super Method, Reply> returnReply(Object obj) {
|
||||
private static Function<? super Method, Reply> returnReply(Object obj) {
|
||||
return method -> {
|
||||
try {
|
||||
return (Reply) method.invoke(obj);
|
||||
@ -834,7 +407,7 @@ public abstract class BaseAbilityBot extends DefaultAbsSender implements Ability
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private Privacy getPrivacy(Update update, int id) {
|
||||
Privacy getPrivacy(Update update, int id) {
|
||||
return isCreator(id) ?
|
||||
CREATOR : isAdmin(id) ?
|
||||
ADMIN : (isGroupUpdate(update) || isSuperGroupUpdate(update)) && isGroupAdmin(update, id) ?
|
||||
@ -939,13 +512,4 @@ public abstract class BaseAbilityBot extends DefaultAbsSender implements Ability
|
||||
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("_", "\\_");
|
||||
}
|
||||
}
|
@ -0,0 +1,435 @@
|
||||
package org.telegram.abilitybots.api.bot;
|
||||
|
||||
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.telegram.abilitybots.api.db.DBContext;
|
||||
import org.telegram.abilitybots.api.objects.Ability;
|
||||
import org.telegram.abilitybots.api.objects.MessageContext;
|
||||
import org.telegram.abilitybots.api.objects.Privacy;
|
||||
import org.telegram.abilitybots.api.util.AbilityExtension;
|
||||
import org.telegram.abilitybots.api.util.AbilityUtils;
|
||||
import org.telegram.abilitybots.api.util.Pair;
|
||||
import org.telegram.telegrambots.meta.api.methods.GetFile;
|
||||
import org.telegram.telegrambots.meta.api.methods.send.SendDocument;
|
||||
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.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileReader;
|
||||
import java.io.PrintStream;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
|
||||
import static com.google.common.base.Strings.isNullOrEmpty;
|
||||
import static com.google.common.collect.MultimapBuilder.hashKeys;
|
||||
import static java.lang.String.format;
|
||||
import static java.util.Comparator.comparing;
|
||||
import static java.util.Objects.nonNull;
|
||||
import static java.util.stream.Collectors.joining;
|
||||
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.ALL;
|
||||
import static org.telegram.abilitybots.api.objects.Locality.USER;
|
||||
import static org.telegram.abilitybots.api.objects.Privacy.*;
|
||||
import static org.telegram.abilitybots.api.util.AbilityMessageCodes.*;
|
||||
import static org.telegram.abilitybots.api.util.AbilityUtils.*;
|
||||
|
||||
public final class DefaultAbilities implements AbilityExtension {
|
||||
// Default commands
|
||||
public static final String CLAIM = "claim";
|
||||
public static final String BAN = "ban";
|
||||
public static final String PROMOTE = "promote";
|
||||
public static final String DEMOTE = "demote";
|
||||
public static final String UNBAN = "unban";
|
||||
public static final String BACKUP = "backup";
|
||||
public static final String RECOVER = "recover";
|
||||
public static final String COMMANDS = "commands";
|
||||
public static final String REPORT = "report";
|
||||
private static final Logger log = LogManager.getLogger(DefaultAbilities.class);
|
||||
private final BaseAbilityBot bot;
|
||||
|
||||
public DefaultAbilities(BaseAbilityBot bot) {
|
||||
this.bot = bot;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Format of the report:
|
||||
* <p>
|
||||
* [command1] - [description1]
|
||||
* <p>
|
||||
* [command2] - [description2]
|
||||
* <p>
|
||||
* ...
|
||||
* <p>
|
||||
* Once you invoke it, the bot will send the available commands to the chat. This is a public ability so anyone can invoke it.
|
||||
* <p>
|
||||
* Usage: <code>/commands</code>
|
||||
*
|
||||
* @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 = bot.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()));
|
||||
|
||||
bot.silent.send(commands, ctx.chatId());
|
||||
})
|
||||
.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* Default format:
|
||||
* <p>
|
||||
* PUBLIC
|
||||
* <p>
|
||||
* [command1] - [description1]
|
||||
* <p>
|
||||
* [command2] - [description2]
|
||||
* <p>
|
||||
* GROUP_ADMIN
|
||||
* <p>
|
||||
* [command1] - [description1]
|
||||
* <p>
|
||||
* ...
|
||||
*
|
||||
* @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 = bot.getPrivacy(ctx.update(), ctx.user().getId());
|
||||
|
||||
ListMultimap<Privacy, String> abilitiesPerPrivacy = bot.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(Map.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());
|
||||
|
||||
bot.silent.send(commands, ctx.chatId());
|
||||
})
|
||||
.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* This backup ability returns the object defined by {@link DBContext#backup()} as a message document.
|
||||
* <p>
|
||||
* This is a high-profile ability and is restricted to the CREATOR only.
|
||||
* <p>
|
||||
* Usage: <code>/backup</code>
|
||||
*
|
||||
* @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(bot.db.backup());
|
||||
bot.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)}.
|
||||
* <p>
|
||||
* The bot recovery process hugely depends on the implementation of the recovery method of {@link DBContext}.
|
||||
* <p>
|
||||
* Usage: <code>/recover</code>
|
||||
*
|
||||
* @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 -> bot.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 (bot.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}.
|
||||
* <p>
|
||||
* Usage: <code>/ban @username</code>
|
||||
* <p>
|
||||
* <u>Note that admins who try to ban the creator, get banned.</u>
|
||||
*
|
||||
* @return the ability to ban the user from any kind of <b>bot interaction</b>
|
||||
*/
|
||||
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 == bot.creatorId()) {
|
||||
userId = ctx.user().getId();
|
||||
bannedUser = isNullOrEmpty(ctx.user().getUserName()) ? addTag(ctx.user().getUserName()) : shortName(ctx.user());
|
||||
} else {
|
||||
bannedUser = addTag(username);
|
||||
}
|
||||
|
||||
Set<Integer> blacklist = bot.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(bot.db))
|
||||
.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* Usage: <code>/unban @username</code>
|
||||
*
|
||||
* @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<Integer> blacklist = bot.blacklist();
|
||||
|
||||
if (!blacklist.remove(userId))
|
||||
bot.silent.sendMd(getLocalizedMessage(ABILITY_UNBAN_FAIL, ctx.user().getLanguageCode(), escape(username)), ctx.chatId());
|
||||
else {
|
||||
bot.silent.sendMd(getLocalizedMessage(ABILITY_UNBAN_SUCCESS, ctx.user().getLanguageCode(), escape(username)), ctx.chatId());
|
||||
}
|
||||
})
|
||||
.post(commitTo(bot.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<Integer> admins = bot.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(bot.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<Integer> admins = bot.admins();
|
||||
if (admins.remove(userId)) {
|
||||
sendMd(ABILITY_DEMOTE_SUCCESS, ctx, escape(username));
|
||||
} else {
|
||||
sendMd(ABILITY_DEMOTE_FAIL, ctx, escape(username));
|
||||
}
|
||||
})
|
||||
.post(commitTo(bot.db))
|
||||
.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* Regular users and admins who try to claim the bot will get <b>banned</b>.
|
||||
*
|
||||
* @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<Integer> admins = bot.admins();
|
||||
int id = bot.creatorId();
|
||||
|
||||
if (admins.contains(id))
|
||||
send(ABILITY_CLAIM_FAIL, ctx);
|
||||
else {
|
||||
admins.add(id);
|
||||
send(ABILITY_CLAIM_SUCCESS, ctx);
|
||||
}
|
||||
})
|
||||
.post(commitTo(bot.db))
|
||||
.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the user with the specified username.
|
||||
*
|
||||
* @param username the username of the required user
|
||||
* @return the user
|
||||
*/
|
||||
private User getUser(String username) {
|
||||
Integer id = bot.userIds().get(username.toLowerCase());
|
||||
if (id == null) {
|
||||
throw new IllegalStateException(format("Could not find ID corresponding to username [%s]", username));
|
||||
}
|
||||
|
||||
return getUser(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the user with the specified ID.
|
||||
*
|
||||
* @param id the id of the required user
|
||||
* @return the user
|
||||
*/
|
||||
private User getUser(int id) {
|
||||
User user = bot.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
|
||||
*/
|
||||
private int getUserIdSendError(String username, MessageContext ctx) {
|
||||
try {
|
||||
return getUser(username).getId();
|
||||
} catch (IllegalStateException ex) {
|
||||
bot.silent.send(getLocalizedMessage(USER_NOT_FOUND, ctx.user().getLanguageCode(), username), ctx.chatId());
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private Optional<Message> send(String message, MessageContext ctx, String... args) {
|
||||
return bot.silent.send(getLocalizedMessage(message, ctx.user().getLanguageCode(), args), ctx.chatId());
|
||||
}
|
||||
|
||||
private Optional<Message> sendMd(String message, MessageContext ctx, String... args) {
|
||||
return bot.silent.sendMd(getLocalizedMessage(message, ctx.user().getLanguageCode(), args), ctx.chatId());
|
||||
}
|
||||
|
||||
private Optional<Message> send(String message, Update upd) {
|
||||
Long chatId = upd.getMessage().getChatId();
|
||||
return bot.silent.send(getLocalizedMessage(message, AbilityUtils.getUser(upd).getLanguageCode()), chatId);
|
||||
}
|
||||
|
||||
protected File downloadFileWithId(String fileId) throws TelegramApiException {
|
||||
return bot.sender.downloadFile(bot.sender.execute(new GetFile().setFileId(fileId)));
|
||||
}
|
||||
}
|
@ -147,8 +147,8 @@ public final class Ability {
|
||||
private Privacy privacy;
|
||||
private Locality locality;
|
||||
private int argNum;
|
||||
private Consumer<MessageContext> consumer;
|
||||
private Consumer<MessageContext> postConsumer;
|
||||
private Consumer<MessageContext> action;
|
||||
private Consumer<MessageContext> postAction;
|
||||
private List<Reply> replies;
|
||||
private Predicate<Update>[] flags;
|
||||
|
||||
@ -157,7 +157,7 @@ public final class Ability {
|
||||
}
|
||||
|
||||
public AbilityBuilder action(Consumer<MessageContext> consumer) {
|
||||
this.consumer = consumer;
|
||||
this.action = consumer;
|
||||
return this;
|
||||
}
|
||||
|
||||
@ -191,8 +191,8 @@ public final class Ability {
|
||||
return this;
|
||||
}
|
||||
|
||||
public AbilityBuilder post(Consumer<MessageContext> postConsumer) {
|
||||
this.postConsumer = postConsumer;
|
||||
public AbilityBuilder post(Consumer<MessageContext> postAction) {
|
||||
this.postAction = postAction;
|
||||
return this;
|
||||
}
|
||||
|
||||
@ -202,8 +202,21 @@ public final class Ability {
|
||||
return this;
|
||||
}
|
||||
|
||||
public AbilityBuilder basedOn(Ability ability) {
|
||||
replies.clear();
|
||||
replies.addAll(ability.replies());
|
||||
|
||||
return name(ability.name())
|
||||
.info(ability.info())
|
||||
.input(ability.tokens())
|
||||
.locality(ability.locality())
|
||||
.privacy(ability.privacy())
|
||||
.action(ability.action())
|
||||
.post(ability.postAction());
|
||||
}
|
||||
|
||||
public Ability build() {
|
||||
return new Ability(name, info, locality, privacy, argNum, consumer, postConsumer, replies, flags);
|
||||
return new Ability(name, info, locality, privacy, argNum, action, postAction, replies, flags);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,21 @@
|
||||
package org.telegram.abilitybots.api.toggle;
|
||||
|
||||
import org.telegram.abilitybots.api.objects.Ability;
|
||||
|
||||
/**
|
||||
* This interface can be used to toggle or customize unwanted default abilities by the user.
|
||||
*/
|
||||
public interface AbilityToggle {
|
||||
/**
|
||||
* @param ab the target ability
|
||||
* @return true if the ability has been turned off
|
||||
*/
|
||||
boolean isOff(Ability ab);
|
||||
|
||||
/**
|
||||
* Abilities that are ON (and have failed the {@link AbilityToggle#isOff} condition) will be processed by this method.
|
||||
* @param ab the target ability
|
||||
* @return the processed ability
|
||||
*/
|
||||
Ability processAbility(Ability ab);
|
||||
}
|
@ -0,0 +1,20 @@
|
||||
package org.telegram.abilitybots.api.toggle;
|
||||
|
||||
import org.telegram.abilitybots.api.objects.Ability;
|
||||
|
||||
/**
|
||||
* This toggle can be used as-is to turn off ALL the default abilities supplied by the library.
|
||||
* This is for users who are interested in the barebone functionality of AbilityBot.
|
||||
*/
|
||||
public class BareboneToggle implements AbilityToggle {
|
||||
@Override
|
||||
public boolean isOff(Ability ability) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Ability processAbility(Ability ab) {
|
||||
// Should never hit this
|
||||
throw new RuntimeException("Should not process any ability in a vanilla toggle");
|
||||
}
|
||||
}
|
@ -0,0 +1,56 @@
|
||||
package org.telegram.abilitybots.api.toggle;
|
||||
|
||||
import org.telegram.abilitybots.api.objects.Ability;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* This custom toggle can be used to customize default abilities supplied by the library. Users can call {@link CustomToggle#toggle} to
|
||||
* rename the default abilites or {@link CustomToggle#turnOff} to simply turn off the said ability.
|
||||
*/
|
||||
public class CustomToggle implements AbilityToggle {
|
||||
public static final String OFF = "turn_off_base_ability";
|
||||
|
||||
private final Map<String, String> baseMapping;
|
||||
|
||||
public CustomToggle() {
|
||||
baseMapping = new HashMap<>();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isOff(Ability ability) {
|
||||
return OFF.equalsIgnoreCase(baseMapping.get(ability.name()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Ability processAbility(Ability ability) {
|
||||
if (baseMapping.containsKey(ability.name())) {
|
||||
return Ability.builder()
|
||||
.basedOn(ability)
|
||||
.name(baseMapping.get(ability.name()))
|
||||
.build();
|
||||
}
|
||||
|
||||
return ability;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param abilityName the ability you want to change
|
||||
* @param targetName the final name for this ability
|
||||
* @return the toggle instance
|
||||
*/
|
||||
public CustomToggle toggle(String abilityName, String targetName) {
|
||||
baseMapping.put(abilityName, targetName);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ability the ability name you would like turned off
|
||||
* @return the toggle instance
|
||||
*/
|
||||
public CustomToggle turnOff(String ability) {
|
||||
baseMapping.put(ability, OFF);
|
||||
return this;
|
||||
}
|
||||
}
|
@ -0,0 +1,19 @@
|
||||
package org.telegram.abilitybots.api.toggle;
|
||||
|
||||
import org.telegram.abilitybots.api.objects.Ability;
|
||||
|
||||
/**
|
||||
* If the user does not supply a toggle to their constructor, the default toggle will be instantiated.
|
||||
* This default toggle allows all the default abilities to be registered.
|
||||
*/
|
||||
public class DefaultToggle implements AbilityToggle {
|
||||
@Override
|
||||
public boolean isOff(Ability ability) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Ability processAbility(Ability ab) {
|
||||
return ab;
|
||||
}
|
||||
}
|
@ -244,4 +244,8 @@ public final class AbilityUtils {
|
||||
|
||||
return name.toString();
|
||||
}
|
||||
|
||||
public static String escape(String username) {
|
||||
return username.replace("_", "\\_");
|
||||
}
|
||||
}
|
@ -24,6 +24,7 @@ class AbilityBotI18nTest {
|
||||
|
||||
private DBContext db;
|
||||
private NoPublicCommandsBot bot;
|
||||
private DefaultAbilities defaultAbs;
|
||||
|
||||
private MessageSender sender;
|
||||
private SilentSender silent;
|
||||
@ -32,6 +33,7 @@ class AbilityBotI18nTest {
|
||||
void setUp() {
|
||||
db = offlineInstance("db");
|
||||
bot = new NoPublicCommandsBot(EMPTY, EMPTY, db);
|
||||
defaultAbs = new DefaultAbilities(bot);
|
||||
|
||||
sender = mock(MessageSender.class);
|
||||
silent = mock(SilentSender.class);
|
||||
@ -50,7 +52,7 @@ class AbilityBotI18nTest {
|
||||
void missingPublicCommandsLocalizedInEnglishByDefault() {
|
||||
MessageContext context = mockContext(NO_LANGUAGE_USER);
|
||||
|
||||
bot.reportCommands().action().accept(context);
|
||||
defaultAbs.reportCommands().action().accept(context);
|
||||
|
||||
verify(silent, times(1))
|
||||
.send("No available commands found.", NO_LANGUAGE_USER.getId());
|
||||
@ -60,7 +62,7 @@ class AbilityBotI18nTest {
|
||||
void missingPublicCommandsLocalizedInItalian() {
|
||||
MessageContext context = mockContext(ITALIAN_USER);
|
||||
|
||||
bot.reportCommands().action().accept(context);
|
||||
defaultAbs.reportCommands().action().accept(context);
|
||||
|
||||
verify(silent, times(1))
|
||||
.send("Non sono presenti comandi disponibile.", ITALIAN_USER.getId());
|
||||
|
@ -59,6 +59,7 @@ public class AbilityBotTest {
|
||||
private static final String[] TEXT = {TEST};
|
||||
|
||||
private DefaultBot bot;
|
||||
private DefaultAbilities defaultAbs;
|
||||
private DBContext db;
|
||||
private MessageSender sender;
|
||||
private SilentSender silent;
|
||||
@ -67,6 +68,7 @@ public class AbilityBotTest {
|
||||
void setUp() {
|
||||
db = offlineInstance("db");
|
||||
bot = new DefaultBot(EMPTY, EMPTY, db);
|
||||
defaultAbs = new DefaultAbilities(bot);
|
||||
|
||||
sender = mock(MessageSender.class);
|
||||
silent = mock(SilentSender.class);
|
||||
@ -122,7 +124,7 @@ public class AbilityBotTest {
|
||||
void canBackupDB() throws TelegramApiException {
|
||||
MessageContext context = defaultContext();
|
||||
|
||||
bot.backupDB().action().accept(context);
|
||||
defaultAbs.backupDB().action().accept(context);
|
||||
deleteQuietly(new java.io.File("backup.json"));
|
||||
|
||||
verify(sender, times(1)).sendDocument(any());
|
||||
@ -137,7 +139,7 @@ public class AbilityBotTest {
|
||||
// Support for null parameter matching since due to mocking API changes
|
||||
when(sender.downloadFile(ArgumentMatchers.<File>isNull())).thenReturn(backupFile);
|
||||
|
||||
bot.recoverDB().replies().get(0).actOn(update);
|
||||
defaultAbs.recoverDB().replies().get(0).actOn(update);
|
||||
|
||||
verify(silent, times(1)).send(RECOVER_SUCCESS, GROUP_ID);
|
||||
assertEquals(db.getSet(TEST), newHashSet(TEST), "Bot recovered but the DB is still not in sync");
|
||||
@ -159,7 +161,7 @@ public class AbilityBotTest {
|
||||
|
||||
MessageContext context = defaultContext();
|
||||
|
||||
bot.demoteAdmin().action().accept(context);
|
||||
defaultAbs.demoteAdmin().action().accept(context);
|
||||
|
||||
Set<Integer> actual = bot.admins();
|
||||
Set<Integer> expected = emptySet();
|
||||
@ -172,7 +174,7 @@ public class AbilityBotTest {
|
||||
|
||||
MessageContext context = defaultContext();
|
||||
|
||||
bot.promoteAdmin().action().accept(context);
|
||||
defaultAbs.promoteAdmin().action().accept(context);
|
||||
|
||||
Set<Integer> actual = bot.admins();
|
||||
Set<Integer> expected = newHashSet(USER.getId());
|
||||
@ -184,7 +186,7 @@ public class AbilityBotTest {
|
||||
addUsers(USER);
|
||||
MessageContext context = defaultContext();
|
||||
|
||||
bot.banUser().action().accept(context);
|
||||
defaultAbs.banUser().action().accept(context);
|
||||
|
||||
Set<Integer> actual = bot.blacklist();
|
||||
Set<Integer> expected = newHashSet(USER.getId());
|
||||
@ -198,7 +200,7 @@ public class AbilityBotTest {
|
||||
|
||||
MessageContext context = defaultContext();
|
||||
|
||||
bot.unbanUser().action().accept(context);
|
||||
defaultAbs.unbanUser().action().accept(context);
|
||||
|
||||
Set<Integer> actual = bot.blacklist();
|
||||
Set<Integer> expected = newHashSet();
|
||||
@ -215,7 +217,7 @@ public class AbilityBotTest {
|
||||
addUsers(USER, CREATOR);
|
||||
MessageContext context = mockContext(USER, GROUP_ID, CREATOR.getUserName());
|
||||
|
||||
bot.banUser().action().accept(context);
|
||||
defaultAbs.banUser().action().accept(context);
|
||||
|
||||
Set<Integer> actual = bot.blacklist();
|
||||
Set<Integer> expected = newHashSet(USER.getId());
|
||||
@ -233,7 +235,7 @@ public class AbilityBotTest {
|
||||
void creatorCanClaimBot() {
|
||||
MessageContext context = mockContext(CREATOR, GROUP_ID);
|
||||
|
||||
bot.claimCreator().action().accept(context);
|
||||
defaultAbs.claimCreator().action().accept(context);
|
||||
|
||||
Set<Integer> actual = bot.admins();
|
||||
Set<Integer> expected = newHashSet(CREATOR.getId());
|
||||
@ -534,7 +536,7 @@ public class AbilityBotTest {
|
||||
void canReportCommands() {
|
||||
MessageContext context = mockContext(USER, GROUP_ID);
|
||||
|
||||
bot.reportCommands().action().accept(context);
|
||||
defaultAbs.reportCommands().action().accept(context);
|
||||
|
||||
verify(silent, times(1)).send("default - dis iz default command", GROUP_ID);
|
||||
}
|
||||
@ -549,7 +551,7 @@ public class AbilityBotTest {
|
||||
when(message.hasText()).thenReturn(true);
|
||||
MessageContext creatorCtx = newContext(update, CREATOR, GROUP_ID);
|
||||
|
||||
bot.commands().action().accept(creatorCtx);
|
||||
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";
|
||||
verify(silent, times(1)).send(expected, GROUP_ID);
|
||||
@ -566,7 +568,7 @@ public class AbilityBotTest {
|
||||
|
||||
MessageContext userCtx = newContext(update, USER, GROUP_ID);
|
||||
|
||||
bot.commands().action().accept(userCtx);
|
||||
defaultAbs.commands().action().accept(userCtx);
|
||||
|
||||
String expected = "PUBLIC\n/commands\n/count\n/default - dis iz default command\n/group\n/test";
|
||||
verify(silent, times(1)).send(expected, GROUP_ID);
|
||||
|
@ -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.toggle.AbilityToggle;
|
||||
|
||||
import static org.telegram.abilitybots.api.objects.Ability.builder;
|
||||
import static org.telegram.abilitybots.api.objects.Flag.CALLBACK_QUERY;
|
||||
@ -17,6 +18,10 @@ public class DefaultBot extends AbilityBot {
|
||||
super(token, username, db);
|
||||
}
|
||||
|
||||
public DefaultBot(String token, String username, DBContext db, AbilityToggle toggle) {
|
||||
super(token, username, db, toggle);
|
||||
}
|
||||
|
||||
public static AbilityBuilder getDefaultBuilder() {
|
||||
return builder()
|
||||
.name("test")
|
||||
|
@ -0,0 +1,47 @@
|
||||
package org.telegram.abilitybots.api.toggle;
|
||||
|
||||
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.abilitybots.api.bot.DefaultAbilities;
|
||||
import org.telegram.abilitybots.api.bot.DefaultBot;
|
||||
import org.telegram.abilitybots.api.db.DBContext;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import static org.apache.commons.lang3.StringUtils.EMPTY;
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
import static org.telegram.abilitybots.api.db.MapDBContext.offlineInstance;
|
||||
|
||||
public class BareboneToggleTest {
|
||||
|
||||
private DBContext db;
|
||||
private AbilityToggle toggle;
|
||||
private DefaultBot bareboneBot;
|
||||
private DefaultAbilities defaultAbs;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
db = offlineInstance("db");
|
||||
toggle = new BareboneToggle();
|
||||
bareboneBot = new DefaultBot(EMPTY, EMPTY, db, toggle);
|
||||
defaultAbs = new DefaultAbilities(bareboneBot);
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
void tearDown() throws IOException {
|
||||
db.clear();
|
||||
db.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void turnsOffAllAbilities() {
|
||||
assertFalse(bareboneBot.abilities().containsKey(DefaultAbilities.CLAIM));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void throwsOnProcessingAbility() {
|
||||
Assertions.assertThrows(RuntimeException.class, () -> toggle.processAbility(defaultAbs.claimCreator()));
|
||||
}
|
||||
}
|
@ -0,0 +1,51 @@
|
||||
package org.telegram.abilitybots.api.toggle;
|
||||
|
||||
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.abilitybots.api.bot.DefaultAbilities;
|
||||
import org.telegram.abilitybots.api.bot.DefaultBot;
|
||||
import org.telegram.abilitybots.api.db.DBContext;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import static org.apache.commons.lang3.StringUtils.EMPTY;
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
import static org.telegram.abilitybots.api.db.MapDBContext.offlineInstance;
|
||||
|
||||
class CustomToggleTest {
|
||||
private DBContext db;
|
||||
private AbilityToggle toggle;
|
||||
private DefaultBot customBot;
|
||||
private DefaultAbilities defaultAbs;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
db = offlineInstance("db");
|
||||
defaultAbs = new DefaultAbilities(customBot);
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
void tearDown() throws IOException {
|
||||
db.clear();
|
||||
db.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void canTurnOffAbilities() {
|
||||
toggle = new CustomToggle().turnOff(DefaultAbilities.CLAIM);
|
||||
customBot = new DefaultBot(EMPTY, EMPTY, db, toggle);
|
||||
assertFalse(customBot.abilities().containsKey(DefaultAbilities.CLAIM));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void canProcessAbilities() {
|
||||
String targetName = DefaultAbilities.CLAIM + "1toggle";
|
||||
toggle = new CustomToggle().toggle(DefaultAbilities.CLAIM, targetName);
|
||||
customBot = new DefaultBot(EMPTY, EMPTY, db, toggle);
|
||||
|
||||
assertTrue(customBot.abilities().containsKey(targetName));
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,69 @@
|
||||
package org.telegram.abilitybots.api.toggle;
|
||||
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.telegram.abilitybots.api.bot.DefaultAbilities;
|
||||
import org.telegram.abilitybots.api.bot.DefaultBot;
|
||||
import org.telegram.abilitybots.api.db.DBContext;
|
||||
import org.telegram.abilitybots.api.objects.Ability;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Set;
|
||||
|
||||
import static com.google.common.collect.Sets.newHashSet;
|
||||
import static org.apache.commons.lang3.StringUtils.EMPTY;
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
import static org.telegram.abilitybots.api.bot.DefaultAbilities.*;
|
||||
import static org.telegram.abilitybots.api.db.MapDBContext.offlineInstance;
|
||||
|
||||
class DefaultToggleTest {
|
||||
private DBContext db;
|
||||
private AbilityToggle toggle;
|
||||
private DefaultBot defaultBot;
|
||||
private DefaultAbilities defaultAbs;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
db = offlineInstance("db");
|
||||
defaultAbs = new DefaultAbilities(defaultBot);
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
void tearDown() throws IOException {
|
||||
db.clear();
|
||||
db.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void claimsEveryAbilityIsOn() {
|
||||
Ability random = DefaultBot.getDefaultBuilder()
|
||||
.name("randomsomethingrandom").build();
|
||||
toggle = new DefaultToggle();
|
||||
defaultBot = new DefaultBot(EMPTY, EMPTY, db, toggle);
|
||||
|
||||
assertFalse(toggle.isOff(random));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void passedSameAbilityRefOnProcess() {
|
||||
Ability random = DefaultBot.getDefaultBuilder()
|
||||
.name("randomsomethingrandom").build();
|
||||
toggle = new DefaultToggle();
|
||||
defaultBot = new DefaultBot(EMPTY, EMPTY, db, toggle);
|
||||
|
||||
assertSame(random, toggle.processAbility(random), "Toggle returned a different ability");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void allAbilitiesAreRegistered() {
|
||||
toggle = new DefaultToggle();
|
||||
defaultBot = new DefaultBot(EMPTY, EMPTY, db, toggle);
|
||||
Set<String> defaultNames = newHashSet(
|
||||
CLAIM, BAN, UNBAN,
|
||||
PROMOTE, DEMOTE, RECOVER,
|
||||
BACKUP, REPORT, COMMANDS);
|
||||
|
||||
assertTrue(defaultBot.abilities().keySet().containsAll(defaultNames), "Toggle returned a different ability");
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user