Global Keyboard WIP

This commit is contained in:
Patrick Haßel 2024-07-30 09:15:40 +02:00
parent 13fa1939ad
commit 08cc0e1474
13 changed files with 125 additions and 41 deletions

View File

@ -7,10 +7,7 @@ import de.ph87.kleinanzeigen.telegram.chat.ChatDto;
import de.ph87.kleinanzeigen.telegram.chat.ChatService; import de.ph87.kleinanzeigen.telegram.chat.ChatService;
import de.ph87.kleinanzeigen.telegram.chat.message.MessageDto; import de.ph87.kleinanzeigen.telegram.chat.message.MessageDto;
import de.ph87.kleinanzeigen.telegram.chat.message.MessageService; import de.ph87.kleinanzeigen.telegram.chat.message.MessageService;
import de.ph87.kleinanzeigen.telegram.request.ChatRequestEnable; import de.ph87.kleinanzeigen.telegram.request.*;
import de.ph87.kleinanzeigen.telegram.request.ChatRequestUndo;
import de.ph87.kleinanzeigen.telegram.request.MessageRequestHide;
import de.ph87.kleinanzeigen.telegram.request.MessageRequestRemember;
import jakarta.annotation.PostConstruct; import jakarta.annotation.PostConstruct;
import jakarta.annotation.PreDestroy; import jakarta.annotation.PreDestroy;
import lombok.NonNull; import lombok.NonNull;
@ -97,6 +94,12 @@ public class TelegramAdapter {
messageService.undo(request); messageService.undo(request);
} }
@Async
@EventListener(ChatRequestHelp.class)
public void onChatHelp(@NonNull final ChatRequestHelp request) {
chatService.help(request);
}
@Async @Async
@EventListener(MessageRequestHide.class) @EventListener(MessageRequestHide.class)
public void onMessageHide(@NonNull final MessageRequestHide request) { public void onMessageHide(@NonNull final MessageRequestHide request) {
@ -133,7 +136,7 @@ public class TelegramAdapter {
private boolean mayDelete(final @NonNull MessageDto message) { private boolean mayDelete(final @NonNull MessageDto message) {
if (message.needsToBeDeleted()) { if (message.needsToBeDeleted()) {
TlgMessage.of(message).ifPresent(tlgMessage -> { TlgMessage.of(bot, message).ifPresent(tlgMessage -> {
bot.delete(tlgMessage); bot.delete(tlgMessage);
messageService.markDeleted(tlgMessage); messageService.markDeleted(tlgMessage);
}); });
@ -175,7 +178,7 @@ public class TelegramAdapter {
} catch (TelegramApiException | JsonProcessingException e) { } catch (TelegramApiException | JsonProcessingException e) {
if (e.toString().endsWith("Bad Request: message to edit not found")) { if (e.toString().endsWith("Bad Request: message to edit not found")) {
log.info("Message has been deleted by User. Marking has hidden: {}", message); log.info("Message has been deleted by User. Marking has hidden: {}", message);
TlgMessage.of(message).ifPresent(messageService::markDeleted); TlgMessage.of(bot, message).ifPresent(messageService::markDeleted);
} else if (e.toString().endsWith("Bad Request: message is not modified: specified new message content and reply markup are exactly the same as a current content and reply markup of the message")) { } else if (e.toString().endsWith("Bad Request: message is not modified: specified new message content and reply markup are exactly the same as a current content and reply markup of the message")) {
log.debug("Ignoring complaint from telegram-bot-api about unmodified message: {}", message); log.debug("Ignoring complaint from telegram-bot-api about unmodified message: {}", message);
} else { } else {

View File

@ -2,14 +2,12 @@ package de.ph87.kleinanzeigen.telegram;
import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import de.ph87.kleinanzeigen.telegram.request.ChatRequestEnable; import de.ph87.kleinanzeigen.telegram.request.*;
import de.ph87.kleinanzeigen.telegram.request.ChatRequestUndo;
import de.ph87.kleinanzeigen.telegram.request.MessageRequestHide;
import de.ph87.kleinanzeigen.telegram.request.MessageRequestRemember;
import jakarta.annotation.PreDestroy; import jakarta.annotation.PreDestroy;
import lombok.NonNull; import lombok.NonNull;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.context.ApplicationEventPublisher; import org.springframework.context.ApplicationEventPublisher;
import org.springframework.data.jpa.repository.JpaContext;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.telegram.telegrambots.bots.TelegramLongPollingBot; import org.telegram.telegrambots.bots.TelegramLongPollingBot;
import org.telegram.telegrambots.meta.TelegramBotsApi; import org.telegram.telegrambots.meta.TelegramBotsApi;
@ -35,7 +33,9 @@ public class TelegramBot extends TelegramLongPollingBot {
private final DefaultBotSession session; private final DefaultBotSession session;
public TelegramBot(final TelegramConfig config, final ObjectMapper objectMapper, final ApplicationEventPublisher publisher) throws TelegramApiException { private final JpaContext jpaContext;
public TelegramBot(final TelegramConfig config, final ObjectMapper objectMapper, final ApplicationEventPublisher publisher, final JpaContext jpaContext) throws TelegramApiException {
super(config.getToken()); super(config.getToken());
this.config = config; this.config = config;
@ -47,6 +47,7 @@ public class TelegramBot extends TelegramLongPollingBot {
session = (DefaultBotSession) api.registerBot(this); session = (DefaultBotSession) api.registerBot(this);
log.info("Telegram bot registered."); log.info("Telegram bot registered.");
this.objectMapper = objectMapper; this.objectMapper = objectMapper;
this.jpaContext = jpaContext;
} }
@PreDestroy @PreDestroy
@ -71,13 +72,14 @@ public class TelegramBot extends TelegramLongPollingBot {
} }
private void handleMessage(@NonNull final Message message) { private void handleMessage(@NonNull final Message message) {
final String command = message.getText().toLowerCase(Locale.ROOT).replaceAll("\\W+", ""); final String[] command = message.getText().toLowerCase(Locale.ROOT).replaceAll("[^\\w\\s]+", "").replaceAll("\\s+", " ").split(" ");
switch (command) { switch (command[0]) {
case "start" -> publisher.publishEvent(new ChatRequestEnable(message, true)); case "start" -> publisher.publishEvent(new ChatRequestEnable(this, message, true));
case "undo" -> publisher.publishEvent(new ChatRequestUndo(message)); case "stop" -> publisher.publishEvent(new ChatRequestEnable(this, message, false));
case "stop" -> publisher.publishEvent(new ChatRequestEnable(message, false)); case "r", "undo", "rückgängig" -> publisher.publishEvent(new ChatRequestUndo(this, message));
case "h", "hilfe", "help" -> publisher.publishEvent(new ChatRequestHelp(this, message));
} }
delete(new TlgMessage(message)); delete(new TlgMessage(this, message));
} }
private void handleCallback(@NonNull final CallbackQuery callback) { private void handleCallback(@NonNull final CallbackQuery callback) {
@ -86,8 +88,8 @@ public class TelegramBot extends TelegramLongPollingBot {
final InlineDto dto = objectMapper.readValue(callback.getData(), InlineDto.class); final InlineDto dto = objectMapper.readValue(callback.getData(), InlineDto.class);
switch (dto.getCommand()) { switch (dto.getCommand()) {
case HIDE -> hide(message); case HIDE -> hide(message);
case REMEMBER -> publisher.publishEvent(new MessageRequestRemember(message, true)); case REMEMBER -> publisher.publishEvent(new MessageRequestRemember(this, message, true));
case UNREMEMBER -> publisher.publishEvent(new MessageRequestRemember(message, false)); case UNREMEMBER -> publisher.publishEvent(new MessageRequestRemember(this, message, false));
} }
} catch (JsonProcessingException e) { } catch (JsonProcessingException e) {
log.error("Failed to read InlineDto.", e); log.error("Failed to read InlineDto.", e);
@ -95,7 +97,7 @@ public class TelegramBot extends TelegramLongPollingBot {
} }
private void hide(final MaybeInaccessibleMessage message) { private void hide(final MaybeInaccessibleMessage message) {
final MessageRequestHide event = new MessageRequestHide(message); final MessageRequestHide event = new MessageRequestHide(this, message);
delete(event); delete(event);
publisher.publishEvent(event); publisher.publishEvent(event);
} }
@ -103,7 +105,7 @@ public class TelegramBot extends TelegramLongPollingBot {
public void delete(@NonNull final TlgMessage tlgMessage) { public void delete(@NonNull final TlgMessage tlgMessage) {
try { try {
log.info("Removing TlgMessage: tlgMessage={}", tlgMessage); log.info("Removing TlgMessage: tlgMessage={}", tlgMessage);
execute(new DeleteMessage(tlgMessage.chatId + "", tlgMessage.messageId)); execute(new DeleteMessage(tlgMessage.chat.idStr, tlgMessage.id));
} catch (TelegramApiException e) { } catch (TelegramApiException e) {
log.error("Failed to remove TlgMessage: tlgMessage={}", tlgMessage); log.error("Failed to remove TlgMessage: tlgMessage={}", tlgMessage);
} }

View File

@ -2,15 +2,34 @@ package de.ph87.kleinanzeigen.telegram;
import lombok.NonNull; import lombok.NonNull;
import lombok.ToString; import lombok.ToString;
import org.telegram.telegrambots.meta.api.methods.BotApiMethod;
import org.telegram.telegrambots.meta.api.objects.MaybeInaccessibleMessage; import org.telegram.telegrambots.meta.api.objects.MaybeInaccessibleMessage;
import org.telegram.telegrambots.meta.exceptions.TelegramApiException;
import java.io.Serializable;
@ToString @ToString
public class TlgChat { public class TlgChat {
public final TelegramBot bot;
public final long id; public final long id;
public TlgChat(@NonNull final MaybeInaccessibleMessage message) { public final String idStr;
this.id = message.getChatId();
public TlgChat(@NonNull final TelegramBot bot, final long id) {
this.bot = bot;
this.id = id;
this.idStr = this.id + "";
}
public TlgChat(@NonNull final TelegramBot bot, @NonNull final MaybeInaccessibleMessage message) {
this(bot, message.getChatId());
}
@NonNull
public <T extends Serializable, Method extends BotApiMethod<T>> T execute(@NonNull final Method method) throws TelegramApiException {
return bot.execute(method);
} }
} }

View File

@ -3,31 +3,39 @@ package de.ph87.kleinanzeigen.telegram;
import de.ph87.kleinanzeigen.telegram.chat.message.MessageDto; import de.ph87.kleinanzeigen.telegram.chat.message.MessageDto;
import lombok.NonNull; import lombok.NonNull;
import lombok.ToString; import lombok.ToString;
import org.telegram.telegrambots.meta.api.methods.BotApiMethod;
import org.telegram.telegrambots.meta.api.objects.MaybeInaccessibleMessage; import org.telegram.telegrambots.meta.api.objects.MaybeInaccessibleMessage;
import org.telegram.telegrambots.meta.exceptions.TelegramApiException;
import java.io.Serializable;
import java.util.Optional; import java.util.Optional;
@ToString @ToString
public class TlgMessage { public class TlgMessage {
public final long chatId; public final TlgChat chat;
public final int messageId; public final int id;
private TlgMessage(final long chatId, final int messageId) { private TlgMessage(@NonNull final TelegramBot bot, final long chatId, final int id) {
this.chatId = chatId; this.chat = new TlgChat(bot, chatId);
this.messageId = messageId; this.id = id;
} }
public TlgMessage(@NonNull final MaybeInaccessibleMessage message) { public TlgMessage(@NonNull final TelegramBot bot, @NonNull final MaybeInaccessibleMessage message) {
this(message.getChatId(), message.getMessageId()); this(bot, message.getChatId(), message.getMessageId());
} }
public static Optional<TlgMessage> of(@NonNull final MessageDto message) { public static Optional<TlgMessage> of(@NonNull final TelegramBot bot, @NonNull final MessageDto message) {
if (message.getTelegramMessageId() == null) { if (message.getTelegramMessageId() == null) {
return Optional.empty(); return Optional.empty();
} }
return Optional.of(new TlgMessage(message.getChat().getId(), message.getTelegramMessageId())); return Optional.of(new TlgMessage(bot, message.getChat().getId(), message.getTelegramMessageId()));
}
@NonNull
public <T extends Serializable, Method extends BotApiMethod<T>> T execute(@NonNull final Method method) throws TelegramApiException {
return chat.bot.execute(method);
} }
} }

View File

@ -1,5 +1,6 @@
package de.ph87.kleinanzeigen.telegram.chat; package de.ph87.kleinanzeigen.telegram.chat;
import jakarta.annotation.Nullable;
import jakarta.persistence.Column; import jakarta.persistence.Column;
import jakarta.persistence.Entity; import jakarta.persistence.Entity;
import jakarta.persistence.Id; import jakarta.persistence.Id;
@ -22,6 +23,11 @@ public class Chat {
@Column(nullable = false) @Column(nullable = false)
private String name; private String name;
@Setter
@Column
@Nullable
private Long keyboardMessageId = null;
public Chat(final long id, final boolean enabled, @NonNull final String name) { public Chat(final long id, final boolean enabled, @NonNull final String name) {
this.id = id; this.id = id;
this.enabled = enabled; this.enabled = enabled;

View File

@ -1,5 +1,6 @@
package de.ph87.kleinanzeigen.telegram.chat; package de.ph87.kleinanzeigen.telegram.chat;
import jakarta.annotation.Nullable;
import lombok.Data; import lombok.Data;
@Data @Data
@ -11,10 +12,14 @@ public class ChatDto {
private final String name; private final String name;
@Nullable
private final Long keyboardMessageId;
public ChatDto(final Chat chat) { public ChatDto(final Chat chat) {
this.id = chat.getId(); this.id = chat.getId();
this.enabled = chat.isEnabled(); this.enabled = chat.isEnabled();
this.name = chat.getName(); this.name = chat.getName();
this.keyboardMessageId = chat.getKeyboardMessageId();
} }
} }

View File

@ -2,11 +2,17 @@ package de.ph87.kleinanzeigen.telegram.chat;
import de.ph87.kleinanzeigen.telegram.TelegramConfig; import de.ph87.kleinanzeigen.telegram.TelegramConfig;
import de.ph87.kleinanzeigen.telegram.TlgChat; import de.ph87.kleinanzeigen.telegram.TlgChat;
import de.ph87.kleinanzeigen.telegram.request.ChatRequestHelp;
import lombok.NonNull; import lombok.NonNull;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import org.telegram.telegrambots.meta.api.methods.send.SendMessage;
import org.telegram.telegrambots.meta.api.objects.replykeyboard.ReplyKeyboardMarkup;
import org.telegram.telegrambots.meta.api.objects.replykeyboard.buttons.KeyboardButton;
import org.telegram.telegrambots.meta.api.objects.replykeyboard.buttons.KeyboardRow;
import org.telegram.telegrambots.meta.exceptions.TelegramApiException;
import java.util.List; import java.util.List;
@ -45,6 +51,21 @@ public class ChatService {
return chat; return chat;
} }
public void help(@NonNull final ChatRequestHelp request) {
final SendMessage send = new SendMessage(request.idStr, "");
final KeyboardRow row0 = new KeyboardRow(List.of(
new KeyboardButton("Rückgängig"),
new KeyboardButton("Alles löschen")
));
final List<KeyboardRow> keyboard = List.of(row0);
send.setReplyMarkup(new ReplyKeyboardMarkup(keyboard));
try {
request.execute(send);
} catch (TelegramApiException e) {
log.error("Failed to printHelp: request={}, error={}", request, e.toString());
}
}
private void update(@NonNull final Chat chat, final boolean enabled, final @NonNull String username) { private void update(@NonNull final Chat chat, final boolean enabled, final @NonNull String username) {
chat.setName(username); chat.setName(username);
if (chat.isEnabled() != enabled) { if (chat.isEnabled() != enabled) {

View File

@ -86,7 +86,7 @@ public class MessageService {
} }
private Optional<Message> find(final @NonNull TlgMessage tlgMessage) { private Optional<Message> find(final @NonNull TlgMessage tlgMessage) {
return messageRepository.findByChat_IdAndTelegramMessageId(tlgMessage.chatId, tlgMessage.messageId); return messageRepository.findByChat_IdAndTelegramMessageId(tlgMessage.chat.id, tlgMessage.id);
} }
private void publish(@NonNull final Message message) { private void publish(@NonNull final Message message) {

View File

@ -1,5 +1,6 @@
package de.ph87.kleinanzeigen.telegram.request; package de.ph87.kleinanzeigen.telegram.request;
import de.ph87.kleinanzeigen.telegram.TelegramBot;
import de.ph87.kleinanzeigen.telegram.TlgChat; import de.ph87.kleinanzeigen.telegram.TlgChat;
import lombok.Getter; import lombok.Getter;
import lombok.NonNull; import lombok.NonNull;
@ -13,8 +14,8 @@ public class ChatRequestEnable extends TlgChat {
@NonNull @NonNull
private final String username; private final String username;
public ChatRequestEnable(@NonNull final Message message, final boolean enable) { public ChatRequestEnable(@NonNull final TelegramBot bot, @NonNull final Message message, final boolean enable) {
super(message); super(bot, message);
this.enable = enable; this.enable = enable;
this.username = message.getFrom().getUserName() == null ? "" : message.getFrom().getUserName(); this.username = message.getFrom().getUserName() == null ? "" : message.getFrom().getUserName();
} }

View File

@ -0,0 +1,16 @@
package de.ph87.kleinanzeigen.telegram.request;
import de.ph87.kleinanzeigen.telegram.TelegramBot;
import de.ph87.kleinanzeigen.telegram.TlgChat;
import lombok.Getter;
import lombok.NonNull;
import org.telegram.telegrambots.meta.api.objects.Message;
@Getter
public class ChatRequestHelp extends TlgChat {
public ChatRequestHelp(@NonNull final TelegramBot bot, @NonNull final Message message) {
super(bot, message);
}
}

View File

@ -1,5 +1,6 @@
package de.ph87.kleinanzeigen.telegram.request; package de.ph87.kleinanzeigen.telegram.request;
import de.ph87.kleinanzeigen.telegram.TelegramBot;
import de.ph87.kleinanzeigen.telegram.TlgChat; import de.ph87.kleinanzeigen.telegram.TlgChat;
import lombok.Getter; import lombok.Getter;
import lombok.NonNull; import lombok.NonNull;
@ -8,8 +9,8 @@ import org.telegram.telegrambots.meta.api.objects.Message;
@Getter @Getter
public class ChatRequestUndo extends TlgChat { public class ChatRequestUndo extends TlgChat {
public ChatRequestUndo(@NonNull final Message message) { public ChatRequestUndo(@NonNull final TelegramBot bot, @NonNull final Message message) {
super(message); super(bot, message);
} }
} }

View File

@ -1,5 +1,6 @@
package de.ph87.kleinanzeigen.telegram.request; package de.ph87.kleinanzeigen.telegram.request;
import de.ph87.kleinanzeigen.telegram.TelegramBot;
import de.ph87.kleinanzeigen.telegram.TlgMessage; import de.ph87.kleinanzeigen.telegram.TlgMessage;
import lombok.Getter; import lombok.Getter;
import lombok.NonNull; import lombok.NonNull;
@ -8,8 +9,8 @@ import org.telegram.telegrambots.meta.api.objects.MaybeInaccessibleMessage;
@Getter @Getter
public class MessageRequestHide extends TlgMessage { public class MessageRequestHide extends TlgMessage {
public MessageRequestHide(@NonNull final MaybeInaccessibleMessage message) { public MessageRequestHide(@NonNull final TelegramBot bot, @NonNull final MaybeInaccessibleMessage message) {
super(message); super(bot, message);
} }
} }

View File

@ -1,5 +1,6 @@
package de.ph87.kleinanzeigen.telegram.request; package de.ph87.kleinanzeigen.telegram.request;
import de.ph87.kleinanzeigen.telegram.TelegramBot;
import de.ph87.kleinanzeigen.telegram.TlgMessage; import de.ph87.kleinanzeigen.telegram.TlgMessage;
import lombok.Getter; import lombok.Getter;
import lombok.NonNull; import lombok.NonNull;
@ -10,8 +11,8 @@ public class MessageRequestRemember extends TlgMessage {
private final boolean remember; private final boolean remember;
public MessageRequestRemember(@NonNull final MaybeInaccessibleMessage message, final boolean remember) { public MessageRequestRemember(@NonNull final TelegramBot bot, @NonNull final MaybeInaccessibleMessage message, final boolean remember) {
super(message); super(bot, message);
this.remember = remember; this.remember = remember;
} }