initial commit
This commit is contained in:
19
.gitignore
vendored
Normal file
19
.gitignore
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
target/
|
||||
!.mvn/wrapper/maven-wrapper.jar
|
||||
!**/src/main/**/target/
|
||||
!**/src/test/**/target/
|
||||
|
||||
### STS ###
|
||||
.apt_generated
|
||||
.classpath
|
||||
.factorypath
|
||||
.project
|
||||
.settings
|
||||
.springBeans
|
||||
.sts4-cache
|
||||
|
||||
### IntelliJ IDEA ###
|
||||
.idea
|
||||
*.iws
|
||||
*.iml
|
||||
*.ipr
|
||||
17
README.MD
Normal file
17
README.MD
Normal file
@@ -0,0 +1,17 @@
|
||||
## Простой фреймворк\фасад для Telegram-бота
|
||||
|
||||
### Цели
|
||||
|
||||
* Предоставить удобные абстракции
|
||||
* Предоставить инструменты для тестирования
|
||||
* Отделить логику бота от конкретной реализации
|
||||
|
||||
### Основная идея
|
||||
|
||||
Цепочка из `Command` принимает `BotRequest` и `BotResponse`, и после обработки вызывает следующий `Command`.
|
||||
|
||||
`BotRequest` содержит информации о действии пользователя.
|
||||
|
||||
`BotResponse` позволяет отправить ответ в виде `Screen`.
|
||||
|
||||
`Screen` содержит отображаемый текст и действия -- кнопки для клавиатуры или inline-кнопки с данными.
|
||||
57
pom.xml
Normal file
57
pom.xml
Normal file
@@ -0,0 +1,57 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<packaging>pom</packaging>
|
||||
|
||||
<groupId>ru.penkrat.stbf</groupId>
|
||||
<artifactId>stbf-parent</artifactId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
<name>stbf-parent</name>
|
||||
|
||||
<description>Simple Telegram Bot Facade</description>
|
||||
<properties>
|
||||
<java.version>1.8</java.version>
|
||||
<lombok.version>1.18.6</lombok.version>
|
||||
<slf4j.version>1.7.25</slf4j.version>
|
||||
</properties>
|
||||
|
||||
<modules>
|
||||
<module>stbf-api</module>
|
||||
<module>stbf-pengrad</module>
|
||||
<module>stbf-test</module>
|
||||
<module>stbf-common</module>
|
||||
<module>stbf-rubenlagus</module>
|
||||
</modules>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-api</artifactId>
|
||||
<version>${slf4j.version}</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
<version>${lombok.version}</version>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<configuration>
|
||||
<source>${java.version}</source>
|
||||
<target>${java.version}</target>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
</project>
|
||||
30
stbf-api/pom.xml
Normal file
30
stbf-api/pom.xml
Normal file
@@ -0,0 +1,30 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<parent>
|
||||
<groupId>ru.penkrat.stbf</groupId>
|
||||
<artifactId>stbf-parent</artifactId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>stbf-api</artifactId>
|
||||
<name>stbf-api</name>
|
||||
<description>Simple Telegram Bot Facade API Module</description>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<configuration>
|
||||
<source>${java.version}</source>
|
||||
<target>${java.version}</target>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
</project>
|
||||
57
stbf-api/src/main/java/ru/penkrat/stbf/api/Action.java
Normal file
57
stbf-api/src/main/java/ru/penkrat/stbf/api/Action.java
Normal file
@@ -0,0 +1,57 @@
|
||||
package ru.penkrat.stbf.api;
|
||||
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
import lombok.NonNull;
|
||||
import lombok.ToString;
|
||||
|
||||
@Getter
|
||||
@Builder
|
||||
@ToString(of = "text")
|
||||
public class Action {
|
||||
|
||||
public static Action simple(String text) {
|
||||
return builder().text(text).build();
|
||||
}
|
||||
|
||||
public static Action simple(String text, String cmd) {
|
||||
validateCmd(cmd);
|
||||
return builder().text(text).cmd(cmd).build();
|
||||
}
|
||||
|
||||
public static Action callback(String text, String callbackData) {
|
||||
return builder().inline(true).text(text).callbackData(callbackData).build();
|
||||
}
|
||||
|
||||
public static Action requestContact(String text) {
|
||||
return builder().text(text).requestContact(true).build();
|
||||
}
|
||||
|
||||
private boolean inline;
|
||||
|
||||
private String text;
|
||||
|
||||
private String cmd;
|
||||
|
||||
// in-line
|
||||
private String callbackData;
|
||||
private String url;
|
||||
|
||||
// keyboard
|
||||
private boolean requestContact;
|
||||
private boolean requestLocation;
|
||||
|
||||
/**
|
||||
* Text of the command, 1-32 characters. Can contain only lowercase English
|
||||
* letters, digits and underscores.
|
||||
*/
|
||||
private static void validateCmd(@NonNull String cmd) {
|
||||
if (cmd.length() > 32) {
|
||||
throw new IllegalArgumentException("Max length - 32 characters");
|
||||
}
|
||||
if (!cmd.startsWith("/")) {
|
||||
throw new IllegalArgumentException("Command must start / character");
|
||||
}
|
||||
// TODO validate lowercase etc
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
package ru.penkrat.stbf.api;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import lombok.AccessLevel;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
@Slf4j
|
||||
@RequiredArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
public class BotCommandChain implements CommandChain {
|
||||
|
||||
private final List<Command> commands;
|
||||
|
||||
public BotCommandChain() {
|
||||
this(new ArrayList<>());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void processCommand(BotRequest botRequest, BotResponse botResponse) {
|
||||
if (!commands.isEmpty()) {
|
||||
try {
|
||||
Command command = commands.get(0);
|
||||
log.debug("Run command {}", command.getClass().getSimpleName());
|
||||
command.process(botRequest, botResponse,
|
||||
new BotCommandChain(commands.subList(1, commands.size())));
|
||||
} catch (Exception e) {
|
||||
log.error("Error in command:", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public BotCommandChain add(Command cmd) {
|
||||
commands.add(cmd);
|
||||
return this;
|
||||
}
|
||||
|
||||
}
|
||||
17
stbf-api/src/main/java/ru/penkrat/stbf/api/BotRequest.java
Normal file
17
stbf-api/src/main/java/ru/penkrat/stbf/api/BotRequest.java
Normal file
@@ -0,0 +1,17 @@
|
||||
package ru.penkrat.stbf.api;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
public interface BotRequest {
|
||||
|
||||
Optional<String> getMessageText();
|
||||
|
||||
Optional<String> getPhoneNumber();
|
||||
|
||||
Optional<String> getCallbackData();
|
||||
|
||||
Optional<String> getCallbackMessageText();
|
||||
|
||||
Long getChatId();
|
||||
|
||||
}
|
||||
15
stbf-api/src/main/java/ru/penkrat/stbf/api/BotResponse.java
Normal file
15
stbf-api/src/main/java/ru/penkrat/stbf/api/BotResponse.java
Normal file
@@ -0,0 +1,15 @@
|
||||
package ru.penkrat.stbf.api;
|
||||
|
||||
public interface BotResponse {
|
||||
|
||||
void send(Screen screen);
|
||||
|
||||
void sendFile(String filename, byte[] data);
|
||||
|
||||
void editMessage(String text);
|
||||
|
||||
void deleteMessage();
|
||||
|
||||
void edit(Screen screen);
|
||||
|
||||
}
|
||||
7
stbf-api/src/main/java/ru/penkrat/stbf/api/Command.java
Normal file
7
stbf-api/src/main/java/ru/penkrat/stbf/api/Command.java
Normal file
@@ -0,0 +1,7 @@
|
||||
package ru.penkrat.stbf.api;
|
||||
|
||||
public interface Command {
|
||||
|
||||
void process(BotRequest botRequest, BotResponse botResponse, CommandChain chain);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package ru.penkrat.stbf.api;
|
||||
|
||||
public interface CommandChain {
|
||||
|
||||
void processCommand(BotRequest botRequest, BotResponse botResponse);
|
||||
|
||||
}
|
||||
5
stbf-api/src/main/java/ru/penkrat/stbf/api/Keyboard.java
Normal file
5
stbf-api/src/main/java/ru/penkrat/stbf/api/Keyboard.java
Normal file
@@ -0,0 +1,5 @@
|
||||
package ru.penkrat.stbf.api;
|
||||
|
||||
public interface Keyboard {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
package ru.penkrat.stbf.api;
|
||||
|
||||
import java.util.ServiceLoader;
|
||||
|
||||
public interface KeyboardBuilder {
|
||||
|
||||
ServiceLoader<KeyboardBuilder> keyboardBuilderLoader = ServiceLoader.load(KeyboardBuilder.class);
|
||||
|
||||
public static KeyboardBuilder newKeyboard() {
|
||||
for (KeyboardBuilder kb : keyboardBuilderLoader) {
|
||||
return kb.newInstance();
|
||||
}
|
||||
throw new IllegalStateException("No service KeyboardBuilder found");
|
||||
}
|
||||
|
||||
KeyboardBuilder newInstance();
|
||||
|
||||
public static Keyboard singleKey(Action action) {
|
||||
return newKeyboard().add(action).build();
|
||||
}
|
||||
|
||||
default KeyboardBuilder add(String text, String callbackData) {
|
||||
return add(Action.callback(text, callbackData));
|
||||
}
|
||||
|
||||
KeyboardBuilder add(Action action);
|
||||
|
||||
KeyboardBuilder row(Action... buttons);
|
||||
|
||||
KeyboardBuilder column(Action... buttons);
|
||||
|
||||
Keyboard build();
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package ru.penkrat.stbf.api;
|
||||
|
||||
@FunctionalInterface
|
||||
public interface RequestMatcher {
|
||||
|
||||
boolean match(BotRequest botRequest);
|
||||
|
||||
}
|
||||
14
stbf-api/src/main/java/ru/penkrat/stbf/api/Screen.java
Normal file
14
stbf-api/src/main/java/ru/penkrat/stbf/api/Screen.java
Normal file
@@ -0,0 +1,14 @@
|
||||
package ru.penkrat.stbf.api;
|
||||
|
||||
public interface Screen {
|
||||
|
||||
String getText();
|
||||
|
||||
default Keyboard getKeyboard() {
|
||||
return null;
|
||||
}
|
||||
|
||||
default ScreenProperties getScreenProperties() {
|
||||
return ScreenProperties.DEFAULT;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
package ru.penkrat.stbf.api;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@Accessors(chain = true)
|
||||
public class ScreenProperties {
|
||||
|
||||
public static final ScreenProperties DEFAULT = new ScreenProperties()
|
||||
.setDisableWebPagePreview(true)
|
||||
.setDisableNotification(true)
|
||||
.setParseModeHtml(true);
|
||||
|
||||
private boolean disableWebPagePreview;
|
||||
|
||||
private boolean disableNotification;
|
||||
|
||||
private boolean parseModeHtml;
|
||||
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
ru.penkrat.stbf.impl.pengrad.PengradKeyboardBuilder
|
||||
41
stbf-common/pom.xml
Normal file
41
stbf-common/pom.xml
Normal file
@@ -0,0 +1,41 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<artifactId>stbf-parent</artifactId>
|
||||
<groupId>ru.penkrat.stbf</groupId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>stbf-common</artifactId>
|
||||
<name>stbf-common</name>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>ru.penkrat.stbf</groupId>
|
||||
<artifactId>stbf-api</artifactId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<version>4.11</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<configuration>
|
||||
<source>${java.version}</source>
|
||||
<target>${java.version}</target>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
@@ -0,0 +1,29 @@
|
||||
package ru.penkrat.stbf.common.command;
|
||||
|
||||
import ru.penkrat.stbf.api.Action;
|
||||
import ru.penkrat.stbf.api.BotRequest;
|
||||
import ru.penkrat.stbf.api.BotResponse;
|
||||
import ru.penkrat.stbf.api.Command;
|
||||
import ru.penkrat.stbf.api.CommandChain;
|
||||
import ru.penkrat.stbf.api.RequestMatcher;
|
||||
import ru.penkrat.stbf.tools.RequestMatchers;
|
||||
|
||||
public abstract class AbstractActionCommand implements Command {
|
||||
|
||||
private RequestMatcher matcher;
|
||||
|
||||
public AbstractActionCommand(Action action) {
|
||||
matcher = RequestMatchers.action(action);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void process(BotRequest botRequest, BotResponse botResponse, CommandChain chain) {
|
||||
if (matcher.match(botRequest)) {
|
||||
doProcess(botRequest, botResponse);
|
||||
}
|
||||
|
||||
chain.processCommand(botRequest, botResponse);
|
||||
}
|
||||
|
||||
protected abstract void doProcess(BotRequest botRequest, BotResponse botResponse);
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
package ru.penkrat.stbf.common.command;
|
||||
|
||||
import ru.penkrat.stbf.api.Action;
|
||||
import ru.penkrat.stbf.api.BotRequest;
|
||||
import ru.penkrat.stbf.api.BotResponse;
|
||||
import ru.penkrat.stbf.api.Command;
|
||||
import ru.penkrat.stbf.api.CommandChain;
|
||||
import ru.penkrat.stbf.api.RequestMatcher;
|
||||
import ru.penkrat.stbf.api.Screen;
|
||||
import ru.penkrat.stbf.common.screen.TextScreen;
|
||||
import ru.penkrat.stbf.tools.RequestMatchers;
|
||||
|
||||
public class SimpleCommand implements Command {
|
||||
|
||||
private final RequestMatcher matcher;
|
||||
private final Screen screen;
|
||||
|
||||
public SimpleCommand(String input, String output) {
|
||||
this(Action.simple(input), new TextScreen(output));
|
||||
}
|
||||
|
||||
public SimpleCommand(Action action, Screen screen) {
|
||||
this.screen = screen;
|
||||
matcher = RequestMatchers.action(action);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void process(BotRequest botRequest, BotResponse botResponse, CommandChain chain) {
|
||||
if (matcher.match(botRequest)) {
|
||||
botResponse.send(screen);
|
||||
}
|
||||
|
||||
chain.processCommand(botRequest, botResponse);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package ru.penkrat.stbf.common.screen;
|
||||
|
||||
import lombok.Getter;
|
||||
import ru.penkrat.stbf.api.Action;
|
||||
import ru.penkrat.stbf.api.Keyboard;
|
||||
import ru.penkrat.stbf.api.Screen;
|
||||
import ru.penkrat.stbf.api.KeyboardBuilder;
|
||||
|
||||
@Getter
|
||||
public class TextScreen implements Screen {
|
||||
|
||||
private final String text;
|
||||
|
||||
private final Keyboard keyboard;
|
||||
|
||||
public TextScreen(String text) {
|
||||
this.text = text;
|
||||
this.keyboard = null;
|
||||
}
|
||||
|
||||
public TextScreen(String text, Keyboard keyboard) {
|
||||
this.text = text;
|
||||
this.keyboard = keyboard;
|
||||
}
|
||||
|
||||
public TextScreen(String text, Action btn) {
|
||||
this(text, KeyboardBuilder.singleKey(btn));
|
||||
}
|
||||
|
||||
public TextScreen(String text, Action btn1, Action btn2) {
|
||||
this(text, KeyboardBuilder.newKeyboard().add(btn1).add(btn2).build());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
package ru.penkrat.stbf.tools;
|
||||
|
||||
import lombok.experimental.UtilityClass;
|
||||
import ru.penkrat.stbf.api.Action;
|
||||
import ru.penkrat.stbf.api.RequestMatcher;
|
||||
|
||||
@UtilityClass
|
||||
public class RequestMatchers {
|
||||
|
||||
public RequestMatcher action(Action action) {
|
||||
return request -> request.getMessageText()
|
||||
.filter(text -> matchText(action, text))
|
||||
.isPresent();
|
||||
}
|
||||
|
||||
private static boolean matchText(Action action, String inputText) {
|
||||
return inputText.equalsIgnoreCase(action.getText())
|
||||
|| (action.getCmd() != null && inputText.equalsIgnoreCase(action.getCmd()));
|
||||
}
|
||||
}
|
||||
20
stbf-common/src/test/java/ru/penkrat/stbf/AppTest.java
Normal file
20
stbf-common/src/test/java/ru/penkrat/stbf/AppTest.java
Normal file
@@ -0,0 +1,20 @@
|
||||
package ru.penkrat.stbf;
|
||||
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* Unit test for simple App.
|
||||
*/
|
||||
public class AppTest
|
||||
{
|
||||
/**
|
||||
* Rigorous Test :-)
|
||||
*/
|
||||
@Test
|
||||
public void shouldAnswerWithTrue()
|
||||
{
|
||||
assertTrue( true );
|
||||
}
|
||||
}
|
||||
43
stbf-pengrad/pom.xml
Normal file
43
stbf-pengrad/pom.xml
Normal file
@@ -0,0 +1,43 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<parent>
|
||||
<groupId>ru.penkrat.stbf</groupId>
|
||||
<artifactId>stbf-parent</artifactId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>stbf-pengrad</artifactId>
|
||||
<name>stbf-pengrad</name>
|
||||
<description>Simple Telegram Bot Facade with com.github.pengrad implementation</description>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>ru.penkrat.stbf</groupId>
|
||||
<artifactId>stbf-api</artifactId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.github.pengrad</groupId>
|
||||
<artifactId>java-telegram-bot-api</artifactId>
|
||||
<version>[4.9.0,5.2.0]</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<configuration>
|
||||
<source>${java.version}</source>
|
||||
<target>${java.version}</target>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
</project>
|
||||
@@ -0,0 +1,61 @@
|
||||
package ru.penkrat.stbf.impl.pengrad;
|
||||
|
||||
import static lombok.AccessLevel.PROTECTED;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
import com.pengrad.telegrambot.model.CallbackQuery;
|
||||
import com.pengrad.telegrambot.model.Contact;
|
||||
import com.pengrad.telegrambot.model.Message;
|
||||
import com.pengrad.telegrambot.model.Update;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import ru.penkrat.stbf.api.BotRequest;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
public class BotRequestImpl implements BotRequest {
|
||||
|
||||
@Getter(PROTECTED)
|
||||
private final Update update;
|
||||
|
||||
@Override
|
||||
public Optional<String> getMessageText() {
|
||||
if (update.message() != null) {
|
||||
return Optional.ofNullable(update.message().text());
|
||||
}
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<String> getPhoneNumber() {
|
||||
return Optional.of(update)
|
||||
.map(Update::message)
|
||||
.map(Message::contact)
|
||||
.map(Contact::phoneNumber);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<String> getCallbackData() {
|
||||
return Optional.of(update)
|
||||
.map(Update::callbackQuery)
|
||||
.map(CallbackQuery::data);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<String> getCallbackMessageText() {
|
||||
return Optional.of(update)
|
||||
.map(Update::callbackQuery)
|
||||
.map(CallbackQuery::message)
|
||||
.map(Message::text);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long getChatId() {
|
||||
return Optional.of(update)
|
||||
.map(Update::callbackQuery)
|
||||
.map(CallbackQuery::message)
|
||||
.orElseGet(() -> update.message()).chat().id();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,151 @@
|
||||
package ru.penkrat.stbf.impl.pengrad;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import com.google.gson.internal.reflect.ReflectionAccessor;
|
||||
import com.pengrad.telegrambot.TelegramBot;
|
||||
import com.pengrad.telegrambot.model.Update;
|
||||
import com.pengrad.telegrambot.model.request.InlineKeyboardButton;
|
||||
import com.pengrad.telegrambot.model.request.InlineKeyboardMarkup;
|
||||
import com.pengrad.telegrambot.model.request.KeyboardButton;
|
||||
import com.pengrad.telegrambot.model.request.ParseMode;
|
||||
import com.pengrad.telegrambot.model.request.ReplyKeyboardMarkup;
|
||||
import com.pengrad.telegrambot.request.DeleteMessage;
|
||||
import com.pengrad.telegrambot.request.EditMessageText;
|
||||
import com.pengrad.telegrambot.request.SendDocument;
|
||||
import com.pengrad.telegrambot.request.SendMessage;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.SneakyThrows;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import ru.penkrat.stbf.api.BotResponse;
|
||||
import ru.penkrat.stbf.api.Screen;
|
||||
|
||||
@Slf4j
|
||||
@RequiredArgsConstructor
|
||||
public class BotResponseImpl implements BotResponse {
|
||||
|
||||
private final Update update;
|
||||
|
||||
private final TelegramBot telegramBot;
|
||||
|
||||
@Override
|
||||
public void send(Screen screen) {
|
||||
log.debug("Send message: \n============\n{}\n============", screen.getText().trim());
|
||||
|
||||
SendMessage sendMessage = new SendMessage(chatId(), screen.getText().trim())
|
||||
.parseMode(screen.getScreenProperties().isParseModeHtml() ? ParseMode.HTML : ParseMode.MarkdownV2)
|
||||
.disableWebPagePreview(screen.getScreenProperties().isDisableWebPagePreview())
|
||||
.disableNotification(screen.getScreenProperties().isDisableNotification());
|
||||
|
||||
if (screen.getKeyboard() instanceof KeyboardImpl) {
|
||||
KeyboardImpl kk = (KeyboardImpl) screen.getKeyboard();
|
||||
KeyboardButton[][] keyboard = kk.getKeyboard();
|
||||
InlineKeyboardButton[][] inlineKeyboard = kk.getInlineKeyboard();
|
||||
|
||||
if (inlineKeyboard != null && inlineKeyboard.length > 0) {
|
||||
logKeyboard(inlineKeyboard);
|
||||
sendMessage = sendMessage.replyMarkup(new InlineKeyboardMarkup(inlineKeyboard));
|
||||
} else if (keyboard != null && keyboard.length > 0) {
|
||||
logKeyboard(keyboard);
|
||||
sendMessage = sendMessage.replyMarkup(new ReplyKeyboardMarkup(keyboard));
|
||||
} else {
|
||||
log.debug("No keyboard");
|
||||
}
|
||||
}
|
||||
|
||||
telegramBot.execute(sendMessage);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendFile(String filename, byte[] data) {
|
||||
telegramBot.execute(new SendDocument(chatId(), data).fileName(filename));
|
||||
}
|
||||
|
||||
@Override
|
||||
@Deprecated
|
||||
public void editMessage(String text) {
|
||||
telegramBot.execute(new EditMessageText(chatId(), messageId(), text)
|
||||
.parseMode(ParseMode.HTML)
|
||||
.disableWebPagePreview(true));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void edit(Screen screen) {
|
||||
EditMessageText editMessage = new EditMessageText(chatId(), messageId(), screen.getText())
|
||||
.parseMode(screen.getScreenProperties().isParseModeHtml() ? ParseMode.HTML : ParseMode.MarkdownV2)
|
||||
.disableWebPagePreview(screen.getScreenProperties().isDisableWebPagePreview());
|
||||
|
||||
if (screen.getKeyboard() instanceof KeyboardImpl) {
|
||||
KeyboardImpl kk = (KeyboardImpl) screen.getKeyboard();
|
||||
InlineKeyboardButton[][] inlineKeyboard = kk.getInlineKeyboard();
|
||||
|
||||
if (inlineKeyboard != null && inlineKeyboard.length > 0) {
|
||||
logKeyboard(inlineKeyboard);
|
||||
editMessage = editMessage.replyMarkup(new InlineKeyboardMarkup(inlineKeyboard));
|
||||
} else {
|
||||
log.debug("No keyboard");
|
||||
}
|
||||
}
|
||||
|
||||
telegramBot.execute(editMessage);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteMessage() {
|
||||
telegramBot.execute(new DeleteMessage(chatId(), messageId()));
|
||||
}
|
||||
|
||||
private Long chatId() {
|
||||
if (update.callbackQuery() != null) {
|
||||
return update.callbackQuery().message().chat().id();
|
||||
}
|
||||
return update.message().chat().id();
|
||||
}
|
||||
|
||||
private Integer messageId() {
|
||||
if (update.callbackQuery() != null) {
|
||||
return update.callbackQuery().message().messageId();
|
||||
}
|
||||
return update.message().messageId();
|
||||
}
|
||||
|
||||
private void logKeyboard(KeyboardButton[][] keyboard) {
|
||||
if (log.isDebugEnabled()) {
|
||||
for (int i = 0; i < keyboard.length; i++) {
|
||||
if (keyboard[i].length > 0) {
|
||||
String row = Stream.of(keyboard[i]).map(this::getText).collect(Collectors.joining(" | "));
|
||||
log.debug("Keyboard: {}", row);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void logKeyboard(InlineKeyboardButton[][] keyboard) {
|
||||
if (log.isDebugEnabled()) {
|
||||
for (int i = 0; i < keyboard.length; i++) {
|
||||
if (keyboard[i].length > 0) {
|
||||
String row = Stream.of(keyboard[i]).map(this::getText).collect(Collectors.joining(" | "));
|
||||
log.debug("Inline keyboard: {}", row);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
private String getText(KeyboardButton btn) {
|
||||
Field text = KeyboardButton.class.getDeclaredField("text");
|
||||
ReflectionAccessor.getInstance().makeAccessible(text);
|
||||
return String.valueOf(text.get(btn));
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
private String getText(InlineKeyboardButton btn) {
|
||||
Field text = InlineKeyboardButton.class.getDeclaredField("text");
|
||||
ReflectionAccessor.getInstance().makeAccessible(text);
|
||||
return String.valueOf(text.get(btn));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package ru.penkrat.stbf.impl.pengrad;
|
||||
|
||||
import com.pengrad.telegrambot.model.request.InlineKeyboardButton;
|
||||
import com.pengrad.telegrambot.model.request.KeyboardButton;
|
||||
|
||||
import lombok.Value;
|
||||
import ru.penkrat.stbf.api.Keyboard;
|
||||
|
||||
@Value
|
||||
class KeyboardImpl implements Keyboard {
|
||||
|
||||
private KeyboardButton[][] keyboard;
|
||||
|
||||
private InlineKeyboardButton[][] inlineKeyboard;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,149 @@
|
||||
package ru.penkrat.stbf.impl.pengrad;
|
||||
|
||||
import com.pengrad.telegrambot.model.request.InlineKeyboardButton;
|
||||
import com.pengrad.telegrambot.model.request.KeyboardButton;
|
||||
|
||||
import ru.penkrat.stbf.api.Action;
|
||||
import ru.penkrat.stbf.api.Keyboard;
|
||||
import ru.penkrat.stbf.api.KeyboardBuilder;
|
||||
|
||||
public class PengradKeyboardBuilder implements KeyboardBuilder {
|
||||
|
||||
private KeyboardButton[][] keyboard;
|
||||
|
||||
private InlineKeyboardButton[][] inlineKeyboard;
|
||||
|
||||
public static Keyboard singleKey(Action action) {
|
||||
return KeyboardBuilder.newKeyboard().add(action).build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Keyboard build() {
|
||||
return new KeyboardImpl(keyboard, inlineKeyboard);
|
||||
}
|
||||
|
||||
public KeyboardBuilder addGetContact(String text) {
|
||||
put(new KeyboardButton(text).requestContact(true));
|
||||
return self();
|
||||
}
|
||||
|
||||
public KeyboardBuilder add(String text) {
|
||||
put(new KeyboardButton(text));
|
||||
return self();
|
||||
}
|
||||
|
||||
@Override
|
||||
public KeyboardBuilder add(Action action) {
|
||||
put(action);
|
||||
return self();
|
||||
}
|
||||
|
||||
public KeyboardBuilder row(KeyboardButton... buttons) {
|
||||
for (int i = 0; i < buttons.length; i++) {
|
||||
put(buttons[i]);
|
||||
}
|
||||
nextRow();
|
||||
return self();
|
||||
}
|
||||
|
||||
@Override
|
||||
public KeyboardBuilder row(Action... buttons) {
|
||||
for (int i = 0; i < buttons.length; i++) {
|
||||
put(buttons[i]);
|
||||
}
|
||||
nextRow();
|
||||
return self();
|
||||
}
|
||||
|
||||
@Override
|
||||
public KeyboardBuilder column(Action... buttons) {
|
||||
for (int i = 0; i < buttons.length; i++) {
|
||||
put(buttons[i]);
|
||||
if (buttons[i].isInline()) {
|
||||
nextRowI();
|
||||
} else {
|
||||
nextRow();
|
||||
}
|
||||
}
|
||||
return self();
|
||||
}
|
||||
|
||||
public KeyboardBuilder addNl(String text) {
|
||||
add(text);
|
||||
nextRow();
|
||||
return self();
|
||||
}
|
||||
|
||||
public PengradKeyboardBuilder add(String text, String data) {
|
||||
put(new InlineKeyboardButton(text).callbackData(data));
|
||||
return self();
|
||||
}
|
||||
|
||||
public KeyboardBuilder addNl(String text, String data) {
|
||||
add(text, data);
|
||||
nextRowI();
|
||||
return self();
|
||||
}
|
||||
|
||||
private void nextRow() {
|
||||
KeyboardButton[][] n = new KeyboardButton[keyboard.length + 1][];
|
||||
System.arraycopy(keyboard, 0, n, 0, keyboard.length);
|
||||
keyboard = n;
|
||||
keyboard[keyboard.length - 1] = new KeyboardButton[] {};
|
||||
}
|
||||
|
||||
private void nextRowI() {
|
||||
InlineKeyboardButton[][] n = new InlineKeyboardButton[inlineKeyboard.length + 1][];
|
||||
System.arraycopy(inlineKeyboard, 0, n, 0, inlineKeyboard.length);
|
||||
inlineKeyboard = n;
|
||||
inlineKeyboard[inlineKeyboard.length - 1] = new InlineKeyboardButton[] {};
|
||||
}
|
||||
|
||||
protected PengradKeyboardBuilder self() {
|
||||
return this;
|
||||
}
|
||||
|
||||
private void put(Action action) {
|
||||
if (action.isInline()) {
|
||||
put(new InlineKeyboardButton(action.getText()).callbackData(action.getCallbackData()));
|
||||
} else {
|
||||
put(new KeyboardButton(action.getText()).requestContact(action.isRequestContact()));
|
||||
}
|
||||
}
|
||||
|
||||
private void put(KeyboardButton btn) {
|
||||
if (keyboard == null) {
|
||||
keyboard = new KeyboardButton[][] {
|
||||
new KeyboardButton[] { btn }
|
||||
};
|
||||
} else {
|
||||
KeyboardButton[] k = keyboard[keyboard.length - 1];
|
||||
KeyboardButton[] n = new KeyboardButton[k.length + 1];
|
||||
System.arraycopy(k, 0, n, 0, k.length);
|
||||
n[k.length] = btn;
|
||||
keyboard[keyboard.length - 1] = n;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void put(InlineKeyboardButton btn) {
|
||||
if (inlineKeyboard == null) {
|
||||
inlineKeyboard = new InlineKeyboardButton[][] {
|
||||
new InlineKeyboardButton[] { btn }
|
||||
};
|
||||
} else {
|
||||
InlineKeyboardButton[] k = inlineKeyboard[inlineKeyboard.length - 1];
|
||||
InlineKeyboardButton[] n = new InlineKeyboardButton[k.length + 1];
|
||||
System.arraycopy(k, 0, n, 0, k.length);
|
||||
n[k.length] = btn;
|
||||
inlineKeyboard[inlineKeyboard.length - 1] = n;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public KeyboardBuilder newInstance() {
|
||||
return new PengradKeyboardBuilder();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package ru.penkrat.stbf.impl.pengrad;
|
||||
|
||||
import com.pengrad.telegrambot.TelegramBot;
|
||||
import com.pengrad.telegrambot.UpdatesListener;
|
||||
import com.pengrad.telegrambot.model.Update;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import ru.penkrat.stbf.api.CommandChain;
|
||||
|
||||
@Slf4j
|
||||
public class PengradTelegramBot extends TelegramBot implements AutoCloseable {
|
||||
|
||||
public PengradTelegramBot(String botToken, CommandChain commandChain) {
|
||||
super(botToken);
|
||||
this.setUpdatesListener(updates -> {
|
||||
for (Update update : updates) {
|
||||
try {
|
||||
commandChain.processCommand(
|
||||
new BotRequestImpl(update),
|
||||
new BotResponseImpl(update, this));
|
||||
} catch (Exception e) {
|
||||
log.error("Bot Error:", e);
|
||||
}
|
||||
}
|
||||
return UpdatesListener.CONFIRMED_UPDATES_ALL;
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws Exception {
|
||||
removeGetUpdatesListener();
|
||||
log.debug("Bot closed.");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
ru.penkrat.stbf.impl.pengrad.PengradKeyboardBuilder
|
||||
41
stbf-rubenlagus/pom.xml
Normal file
41
stbf-rubenlagus/pom.xml
Normal file
@@ -0,0 +1,41 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<artifactId>stbf-parent</artifactId>
|
||||
<groupId>ru.penkrat.stbf</groupId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>stbf-rubenlagus</artifactId>
|
||||
<name>stbf-rubenlagus</name>
|
||||
<description>Simple Telegram Bot Facade with https://github.com/rubenlagus/TelegramBots implementation</description>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>ru.penkrat.stbf</groupId>
|
||||
<artifactId>stbf-api</artifactId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.telegram</groupId>
|
||||
<artifactId>telegrambots</artifactId>
|
||||
<version>5.3.0</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<configuration>
|
||||
<source>${java.version}</source>
|
||||
<target>${java.version}</target>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
@@ -0,0 +1,58 @@
|
||||
package ru.penkrat.stbf.impl.rubenlagus;
|
||||
|
||||
import static lombok.AccessLevel.PROTECTED;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
import org.telegram.telegrambots.meta.api.objects.CallbackQuery;
|
||||
import org.telegram.telegrambots.meta.api.objects.Contact;
|
||||
import org.telegram.telegrambots.meta.api.objects.Message;
|
||||
import org.telegram.telegrambots.meta.api.objects.Update;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import ru.penkrat.stbf.api.BotRequest;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
class BotRequestImpl implements BotRequest {
|
||||
|
||||
@Getter(PROTECTED)
|
||||
private final Update update;
|
||||
|
||||
@Override
|
||||
public Optional<String> getMessageText() {
|
||||
if (update.hasMessage()) {
|
||||
return Optional.ofNullable(update.getMessage().getText());
|
||||
}
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<String> getPhoneNumber() {
|
||||
return Optional.of(update)
|
||||
.map(Update::getMessage)
|
||||
.map(Message::getContact)
|
||||
.map(Contact::getPhoneNumber);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<String> getCallbackData() {
|
||||
return Optional.of(update)
|
||||
.map(Update::getCallbackQuery)
|
||||
.map(CallbackQuery::getData);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<String> getCallbackMessageText() {
|
||||
return Optional.of(update)
|
||||
.map(Update::getCallbackQuery)
|
||||
.map(CallbackQuery::getMessage)
|
||||
.map(Message::getText);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long getChatId() {
|
||||
return update.getMessage().getChatId();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,113 @@
|
||||
package ru.penkrat.stbf.impl.rubenlagus;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.telegram.telegrambots.bots.TelegramLongPollingBot;
|
||||
import org.telegram.telegrambots.meta.api.methods.send.SendMessage;
|
||||
import org.telegram.telegrambots.meta.api.methods.updatingmessages.DeleteMessage;
|
||||
import org.telegram.telegrambots.meta.api.methods.updatingmessages.EditMessageText;
|
||||
import org.telegram.telegrambots.meta.api.objects.Update;
|
||||
import org.telegram.telegrambots.meta.api.objects.replykeyboard.InlineKeyboardMarkup;
|
||||
import org.telegram.telegrambots.meta.api.objects.replykeyboard.ReplyKeyboardMarkup;
|
||||
import org.telegram.telegrambots.meta.api.objects.replykeyboard.buttons.InlineKeyboardButton;
|
||||
import org.telegram.telegrambots.meta.api.objects.replykeyboard.buttons.KeyboardRow;
|
||||
import org.telegram.telegrambots.meta.exceptions.TelegramApiException;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import ru.penkrat.stbf.api.BotResponse;
|
||||
import ru.penkrat.stbf.api.Screen;
|
||||
|
||||
@Slf4j
|
||||
@RequiredArgsConstructor
|
||||
class BotResponseImpl implements BotResponse {
|
||||
|
||||
private final Update update;
|
||||
|
||||
private final TelegramLongPollingBot bot;
|
||||
|
||||
@Override
|
||||
public void send(Screen screen) {
|
||||
SendMessage send = new SendMessage(chatId(), screen.getText());
|
||||
|
||||
if (screen.getKeyboard() instanceof KeyboardImpl) {
|
||||
KeyboardImpl kk = (KeyboardImpl) screen.getKeyboard();
|
||||
List<KeyboardRow> keyboard = kk.getKeyboard();
|
||||
List<List<InlineKeyboardButton>> inlineKeyboard = kk.getInlineKeyboard();
|
||||
|
||||
if (inlineKeyboard != null && !inlineKeyboard.isEmpty()) {
|
||||
send.setReplyMarkup(new InlineKeyboardMarkup(inlineKeyboard));
|
||||
} else if (keyboard != null && !keyboard.isEmpty()) {
|
||||
send.setReplyMarkup(new ReplyKeyboardMarkup(keyboard));
|
||||
} else {
|
||||
log.debug("No keyboard");
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
bot.execute(send);
|
||||
} catch (TelegramApiException e) {
|
||||
log.error("Send error", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendFile(String filename, byte[] data) {
|
||||
throw new IllegalStateException("Not inplemented");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void editMessage(String text) {
|
||||
EditMessageText send = new EditMessageText(text);
|
||||
send.setChatId(chatId());
|
||||
send.setMessageId(messageId());
|
||||
if (update.hasCallbackQuery()) {
|
||||
send.setInlineMessageId(update.getCallbackQuery().getInlineMessageId());
|
||||
}
|
||||
try {
|
||||
bot.execute(send);
|
||||
} catch (TelegramApiException e) {
|
||||
log.error("Send error", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteMessage() {
|
||||
DeleteMessage send = new DeleteMessage(chatId(), messageId());
|
||||
try {
|
||||
bot.execute(send);
|
||||
} catch (TelegramApiException e) {
|
||||
log.error("Send error", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void edit(Screen screen) {
|
||||
EditMessageText send = new EditMessageText(screen.getText());
|
||||
send.setChatId(chatId());
|
||||
send.setMessageId(messageId());
|
||||
if (update.hasCallbackQuery()) {
|
||||
send.setInlineMessageId(update.getCallbackQuery().getInlineMessageId());
|
||||
}
|
||||
try {
|
||||
bot.execute(send);
|
||||
} catch (TelegramApiException e) {
|
||||
log.error("Send error", e);
|
||||
}
|
||||
}
|
||||
|
||||
private String chatId() {
|
||||
if (update.hasCallbackQuery()) {
|
||||
return Long.toString(update.getCallbackQuery().getMessage().getChatId());
|
||||
}
|
||||
return Long.toString(update.getMessage().getChatId());
|
||||
}
|
||||
|
||||
private Integer messageId() {
|
||||
if (update.hasCallbackQuery()) {
|
||||
return Integer.parseInt(update.getCallbackQuery().getInlineMessageId());
|
||||
}
|
||||
return update.getMessage().getMessageId();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package ru.penkrat.stbf.impl.rubenlagus;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.telegram.telegrambots.meta.api.objects.replykeyboard.buttons.InlineKeyboardButton;
|
||||
import org.telegram.telegrambots.meta.api.objects.replykeyboard.buttons.KeyboardRow;
|
||||
|
||||
import lombok.Value;
|
||||
import ru.penkrat.stbf.api.Keyboard;
|
||||
|
||||
@Value
|
||||
class KeyboardImpl implements Keyboard {
|
||||
|
||||
private List<KeyboardRow> keyboard;
|
||||
|
||||
private List<List<InlineKeyboardButton>> inlineKeyboard;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,150 @@
|
||||
package ru.penkrat.stbf.impl.rubenlagus;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.telegram.telegrambots.meta.api.objects.replykeyboard.buttons.InlineKeyboardButton;
|
||||
import org.telegram.telegrambots.meta.api.objects.replykeyboard.buttons.KeyboardButton;
|
||||
import org.telegram.telegrambots.meta.api.objects.replykeyboard.buttons.KeyboardRow;
|
||||
|
||||
import ru.penkrat.stbf.api.Action;
|
||||
import ru.penkrat.stbf.api.Keyboard;
|
||||
import ru.penkrat.stbf.api.KeyboardBuilder;
|
||||
|
||||
public class RubenlagusKeyboardBuilder implements KeyboardBuilder {
|
||||
|
||||
private List<KeyboardRow> keyboard;
|
||||
|
||||
private List<List<InlineKeyboardButton>> inlineKeyboard;
|
||||
|
||||
public static Keyboard singleKey(Action action) {
|
||||
return KeyboardBuilder.newKeyboard().add(action).build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Keyboard build() {
|
||||
return new KeyboardImpl(keyboard, inlineKeyboard);
|
||||
}
|
||||
|
||||
public KeyboardBuilder addGetContact(String text) {
|
||||
KeyboardButton keyboardButton = new KeyboardButton(text);
|
||||
keyboardButton.setRequestContact(true);
|
||||
put(keyboardButton);
|
||||
return self();
|
||||
}
|
||||
|
||||
public KeyboardBuilder add(String text) {
|
||||
put(new KeyboardButton(text));
|
||||
return self();
|
||||
}
|
||||
|
||||
@Override
|
||||
public KeyboardBuilder add(Action action) {
|
||||
put(action);
|
||||
return self();
|
||||
}
|
||||
|
||||
public KeyboardBuilder row(KeyboardButton... buttons) {
|
||||
for (int i = 0; i < buttons.length; i++) {
|
||||
put(buttons[i]);
|
||||
}
|
||||
nextRow();
|
||||
return self();
|
||||
}
|
||||
|
||||
@Override
|
||||
public KeyboardBuilder row(Action... buttons) {
|
||||
for (int i = 0; i < buttons.length; i++) {
|
||||
put(buttons[i]);
|
||||
}
|
||||
nextRow();
|
||||
return self();
|
||||
}
|
||||
|
||||
@Override
|
||||
public KeyboardBuilder column(Action... buttons) {
|
||||
for (int i = 0; i < buttons.length; i++) {
|
||||
put(buttons[i]);
|
||||
if (buttons[i].isInline()) {
|
||||
nextRowI();
|
||||
} else {
|
||||
nextRow();
|
||||
}
|
||||
}
|
||||
return self();
|
||||
}
|
||||
|
||||
public KeyboardBuilder addNl(String text) {
|
||||
add(text);
|
||||
nextRow();
|
||||
return self();
|
||||
}
|
||||
|
||||
public RubenlagusKeyboardBuilder add(String text, String data) {
|
||||
InlineKeyboardButton inlineKeyboardButton = new InlineKeyboardButton(text);
|
||||
inlineKeyboardButton.setCallbackData(data);
|
||||
put(inlineKeyboardButton);
|
||||
return self();
|
||||
}
|
||||
|
||||
public KeyboardBuilder addNl(String text, String data) {
|
||||
add(text, data);
|
||||
nextRowI();
|
||||
return self();
|
||||
}
|
||||
|
||||
private void nextRow() {
|
||||
KeyboardRow row = new KeyboardRow();
|
||||
keyboard.add(row);
|
||||
}
|
||||
|
||||
private void nextRowI() {
|
||||
List<InlineKeyboardButton> row = new ArrayList<>();
|
||||
inlineKeyboard.add(row);
|
||||
}
|
||||
|
||||
protected RubenlagusKeyboardBuilder self() {
|
||||
return this;
|
||||
}
|
||||
|
||||
private void put(Action action) {
|
||||
if (action.isInline()) {
|
||||
InlineKeyboardButton inlineKeyboardButton = new InlineKeyboardButton(action.getText());
|
||||
inlineKeyboardButton.setCallbackData(action.getCallbackData());
|
||||
put(inlineKeyboardButton);
|
||||
} else {
|
||||
KeyboardButton keyboardButton = new KeyboardButton(action.getText());
|
||||
keyboardButton.setRequestContact(action.isRequestContact());
|
||||
put(keyboardButton);
|
||||
}
|
||||
}
|
||||
|
||||
private void put(KeyboardButton btn) {
|
||||
if (keyboard == null) {
|
||||
keyboard = new ArrayList<KeyboardRow>();
|
||||
KeyboardRow row = new KeyboardRow();
|
||||
keyboard.add(row);
|
||||
row.add(btn);
|
||||
} else {
|
||||
keyboard.get(keyboard.size() - 1).add(btn);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void put(InlineKeyboardButton btn) {
|
||||
if (inlineKeyboard == null) {
|
||||
inlineKeyboard = new ArrayList<List<InlineKeyboardButton>>();
|
||||
List<InlineKeyboardButton> row = new ArrayList<>();
|
||||
inlineKeyboard.add(row);
|
||||
row.add(btn);
|
||||
} else {
|
||||
inlineKeyboard.get(inlineKeyboard.size() - 1).add(btn);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public KeyboardBuilder newInstance() {
|
||||
return new RubenlagusKeyboardBuilder();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
package ru.penkrat.stbf.impl.rubenlagus;
|
||||
|
||||
import org.telegram.telegrambots.bots.TelegramLongPollingBot;
|
||||
import org.telegram.telegrambots.meta.TelegramBotsApi;
|
||||
import org.telegram.telegrambots.meta.api.objects.Update;
|
||||
import org.telegram.telegrambots.meta.exceptions.TelegramApiException;
|
||||
import org.telegram.telegrambots.updatesreceivers.DefaultBotSession;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import ru.penkrat.stbf.api.BotCommandChain;
|
||||
|
||||
@Slf4j
|
||||
public class RubenlagusTelegramBot extends TelegramLongPollingBot {
|
||||
|
||||
private final String botUsername;
|
||||
private final String botToken;
|
||||
private final BotCommandChain commandChain;
|
||||
|
||||
public RubenlagusTelegramBot(String botUsername, String botToken, BotCommandChain botCommandChain) {
|
||||
this.botUsername = botUsername;
|
||||
this.botToken = botToken;
|
||||
this.commandChain = botCommandChain;
|
||||
|
||||
TelegramBotsApi telegramBotsApi;
|
||||
try {
|
||||
telegramBotsApi = new TelegramBotsApi(DefaultBotSession.class);
|
||||
telegramBotsApi.registerBot(this);
|
||||
} catch (TelegramApiException e) {
|
||||
log.error("Error", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUpdateReceived(Update update) {
|
||||
try {
|
||||
commandChain.processCommand(
|
||||
new BotRequestImpl(update),
|
||||
new BotResponseImpl(update, this));
|
||||
} catch (Exception e) {
|
||||
log.error("Bot Error:", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getBotUsername() {
|
||||
return botUsername;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getBotToken() {
|
||||
return botToken;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
ru.penkrat.stbf.impl.rubenlagus.RubenlagusKeyboardBuilder
|
||||
53
stbf-test/pom.xml
Normal file
53
stbf-test/pom.xml
Normal file
@@ -0,0 +1,53 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<artifactId>stbf-parent</artifactId>
|
||||
<groupId>ru.penkrat.stbf</groupId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>stbf-test</artifactId>
|
||||
<name>stbf-test</name>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>ru.penkrat.stbf</groupId>
|
||||
<artifactId>stbf-api</artifactId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ru.penkrat.stbf</groupId>
|
||||
<artifactId>stbf-common</artifactId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<version>4.11</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.hamcrest</groupId>
|
||||
<artifactId>hamcrest</artifactId>
|
||||
<version>2.2</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<configuration>
|
||||
<source>${java.version}</source>
|
||||
<target>${java.version}</target>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
@@ -0,0 +1,42 @@
|
||||
package ru.penkrat.stbf.test;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.Random;
|
||||
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
import ru.penkrat.stbf.api.BotRequest;
|
||||
|
||||
@Builder
|
||||
class BotRequestImpl implements BotRequest {
|
||||
|
||||
private String messageText;
|
||||
private String phoneNumber;
|
||||
private String callbackData;
|
||||
private String callbackMessageText;
|
||||
|
||||
@Getter
|
||||
@Builder.Default
|
||||
private Long chatId = new Random().nextLong();
|
||||
|
||||
@Override
|
||||
public Optional<String> getMessageText() {
|
||||
return Optional.ofNullable(messageText);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<String> getPhoneNumber() {
|
||||
return Optional.ofNullable(phoneNumber);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<String> getCallbackData() {
|
||||
return Optional.ofNullable(callbackData);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<String> getCallbackMessageText() {
|
||||
return Optional.ofNullable(callbackMessageText);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
package ru.penkrat.stbf.test;
|
||||
|
||||
import ru.penkrat.stbf.api.BotResponse;
|
||||
import ru.penkrat.stbf.api.Screen;
|
||||
|
||||
class BotResponseImpl implements BotResponse {
|
||||
|
||||
private Result result;
|
||||
|
||||
public BotResponseImpl(Result result) {
|
||||
this.result = result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void send(Screen screen) {
|
||||
result.addScreen(screen);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendFile(String filename, byte[] data) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void editMessage(String text) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteMessage() {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void edit(Screen screen) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
23
stbf-test/src/main/java/ru/penkrat/stbf/test/Result.java
Normal file
23
stbf-test/src/main/java/ru/penkrat/stbf/test/Result.java
Normal file
@@ -0,0 +1,23 @@
|
||||
package ru.penkrat.stbf.test;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import ru.penkrat.stbf.api.Screen;
|
||||
|
||||
public class Result {
|
||||
|
||||
private final List<Screen> screens = new ArrayList<>();
|
||||
|
||||
public String text() {
|
||||
if (screens.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
return screens.get(0).getText();
|
||||
}
|
||||
|
||||
public void addScreen(Screen screen) {
|
||||
screens.add(screen);
|
||||
}
|
||||
|
||||
}
|
||||
43
stbf-test/src/main/java/ru/penkrat/stbf/test/TestBot.java
Normal file
43
stbf-test/src/main/java/ru/penkrat/stbf/test/TestBot.java
Normal file
@@ -0,0 +1,43 @@
|
||||
package ru.penkrat.stbf.test;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import ru.penkrat.stbf.api.BotCommandChain;
|
||||
import ru.penkrat.stbf.api.BotRequest;
|
||||
import ru.penkrat.stbf.api.Command;
|
||||
import ru.penkrat.stbf.api.CommandChain;
|
||||
import ru.penkrat.stbf.test.BotRequestImpl;
|
||||
import ru.penkrat.stbf.test.BotResponseImpl;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
public class TestBot {
|
||||
|
||||
public static TestBot from(Command... commands) {
|
||||
BotCommandChain bcc = new BotCommandChain();
|
||||
for (int i = 0; i < commands.length; i++) {
|
||||
bcc.add(commands[i]);
|
||||
}
|
||||
return new TestBot(bcc);
|
||||
}
|
||||
|
||||
private final CommandChain commandChain;
|
||||
|
||||
public Result whenText(String input) {
|
||||
return process(BotRequestImpl.builder().messageText(input).build());
|
||||
}
|
||||
|
||||
public Result whenPhoneNumber(String input) {
|
||||
return process(BotRequestImpl.builder().phoneNumber(input).build());
|
||||
}
|
||||
|
||||
public Result whenCallback(String data) {
|
||||
return process(BotRequestImpl.builder().callbackData(data).build());
|
||||
}
|
||||
|
||||
private Result process(BotRequest botRequest) {
|
||||
Result result = new Result();
|
||||
commandChain.processCommand(botRequest, new BotResponseImpl(result));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
23
stbf-test/src/test/java/ru/penkrat/stbf/BotTest.java
Normal file
23
stbf-test/src/test/java/ru/penkrat/stbf/BotTest.java
Normal file
@@ -0,0 +1,23 @@
|
||||
package ru.penkrat.stbf;
|
||||
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import ru.penkrat.stbf.api.Command;
|
||||
import ru.penkrat.stbf.common.command.SimpleCommand;
|
||||
import ru.penkrat.stbf.test.Result;
|
||||
import ru.penkrat.stbf.test.TestBot;
|
||||
|
||||
public class BotTest {
|
||||
|
||||
private Command start = new SimpleCommand("/start", "Hello, world");
|
||||
|
||||
@Test
|
||||
public void shouldAnswerWithHello() {
|
||||
Result result = TestBot.from(start).whenText("/start");
|
||||
|
||||
assertThat(result.text(), containsString("Hello, world"));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user