REFACTOR WIP
This commit is contained in:
parent
038b0b76c9
commit
1bcecaac51
@ -1,5 +0,0 @@
|
||||
package de.ph87.kleinanzeigen.telegram;
|
||||
|
||||
public class AccessDenied extends Exception {
|
||||
|
||||
}
|
||||
@ -5,20 +5,26 @@ import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import de.ph87.kleinanzeigen.kleinanzeigen.offer.OfferDto;
|
||||
import de.ph87.kleinanzeigen.telegram.chat.ChatDto;
|
||||
import de.ph87.kleinanzeigen.telegram.chat.ChatService;
|
||||
import de.ph87.kleinanzeigen.telegram.chat.message.MessageDeleted;
|
||||
import de.ph87.kleinanzeigen.telegram.chat.message.MessageDto;
|
||||
import de.ph87.kleinanzeigen.telegram.chat.message.MessageService;
|
||||
import de.ph87.kleinanzeigen.telegram.request.ChatRequestEnable;
|
||||
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.PreDestroy;
|
||||
import lombok.NonNull;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.context.event.EventListener;
|
||||
import org.springframework.scheduling.annotation.Async;
|
||||
import org.springframework.scheduling.annotation.EnableAsync;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.event.TransactionalEventListener;
|
||||
import org.telegram.telegrambots.meta.api.methods.send.SendPhoto;
|
||||
import org.telegram.telegrambots.meta.api.methods.updatingmessages.DeleteMessage;
|
||||
import org.telegram.telegrambots.meta.api.methods.updatingmessages.EditMessageCaption;
|
||||
import org.telegram.telegrambots.meta.api.objects.*;
|
||||
import org.telegram.telegrambots.meta.api.objects.InputFile;
|
||||
import org.telegram.telegrambots.meta.api.objects.Message;
|
||||
import org.telegram.telegrambots.meta.api.objects.replykeyboard.InlineKeyboardMarkup;
|
||||
import org.telegram.telegrambots.meta.api.objects.replykeyboard.buttons.InlineKeyboardButton;
|
||||
import org.telegram.telegrambots.meta.exceptions.TelegramApiException;
|
||||
@ -33,37 +39,37 @@ import java.util.List;
|
||||
|
||||
@Slf4j
|
||||
@Service
|
||||
@EnableAsync
|
||||
@RequiredArgsConstructor
|
||||
public class TelegramService {
|
||||
public class TelegramAdapter {
|
||||
|
||||
private static final String ICON_CHECK = "✅";
|
||||
|
||||
private static final String ICON_REMOVE = "❌";
|
||||
|
||||
private final TelegramConfig config;
|
||||
|
||||
private final ChatService chatService;
|
||||
|
||||
private final MessageService messageService;
|
||||
|
||||
private final TelegramBot bot;
|
||||
|
||||
private final ObjectMapper objectMapper;
|
||||
|
||||
private byte[] NO_IMAGE = null;
|
||||
|
||||
private TelegramBot bot = null;
|
||||
|
||||
@PostConstruct
|
||||
public void postConstruct() throws IOException {
|
||||
final BufferedImage img = new BufferedImage(1, 1, BufferedImage.TYPE_INT_ARGB);
|
||||
final ByteArrayOutputStream stream = new ByteArrayOutputStream();
|
||||
ImageIO.write(img, "PNG", stream);
|
||||
NO_IMAGE = stream.toByteArray();
|
||||
|
||||
try {
|
||||
bot = new TelegramBot(config.getToken(), config.getUsername(), this::onUpdateReceived);
|
||||
} catch (TelegramApiException | IOException e) {
|
||||
log.error("Failed to start TelegramBot: {}", e.toString());
|
||||
}
|
||||
|
||||
@PreDestroy
|
||||
public void stop() {
|
||||
log.info("Stopping Telegram bot...");
|
||||
bot.stop();
|
||||
log.info("Telegram bot stopped");
|
||||
}
|
||||
|
||||
@TransactionalEventListener(OfferDto.class)
|
||||
@ -75,72 +81,62 @@ public class TelegramService {
|
||||
.stream()
|
||||
.filter(m -> m.getChat().getId() == chat.getId())
|
||||
.findFirst()
|
||||
.ifPresentOrElse(message -> update(message, false), () -> send(offer, chat));
|
||||
.ifPresentOrElse(this::update, () -> send(offer, chat));
|
||||
}
|
||||
}
|
||||
|
||||
@TransactionalEventListener(MessageDeleted.class)
|
||||
public void onMessageDeleted(final MessageDeleted messageDeleted) {
|
||||
remove(messageDeleted.getChatId(), messageDeleted.getMessageId());
|
||||
@Async
|
||||
@EventListener(ChatRequestEnable.class)
|
||||
public void onChatEnable(@NonNull final ChatRequestEnable request) {
|
||||
chatService.setEnabled(request, request.isEnable(), request.getUsername());
|
||||
}
|
||||
|
||||
@PreDestroy
|
||||
public void stop() {
|
||||
log.info("Stopping Telegram bot...");
|
||||
bot.stop();
|
||||
log.info("Telegram bot stopped");
|
||||
@Async
|
||||
@EventListener(ChatRequestUndo.class)
|
||||
public void onChatUndo(@NonNull final ChatRequestUndo request) {
|
||||
messageService.undo(request);
|
||||
}
|
||||
|
||||
private void onUpdateReceived(@NonNull final Update update) {
|
||||
try {
|
||||
if (update.hasMessage() && update.getMessage().hasText()) {
|
||||
handleMessage(update.getMessage());
|
||||
} else if (update.hasCallbackQuery()) {
|
||||
handleCallback(update.getCallbackQuery());
|
||||
}
|
||||
} catch (AccessDenied e) {
|
||||
log.warn("Access denied: {}", update);
|
||||
}
|
||||
@Async
|
||||
@EventListener(MessageRequestHide.class)
|
||||
public void onMessageHide(@NonNull final MessageRequestHide request) {
|
||||
messageService.setHide(request);
|
||||
}
|
||||
|
||||
private void handleMessage(@NonNull final Message tlgMessage) throws AccessDenied {
|
||||
switch (tlgMessage.getText()) {
|
||||
case "/stop" -> chatService.setEnabled(tlgMessage.getChatId(), false, tlgMessage.getFrom().getUserName());
|
||||
case "undo" -> undo(tlgMessage);
|
||||
}
|
||||
@Async
|
||||
@EventListener(MessageRequestRemember.class)
|
||||
public void onMessageRemember(@NonNull final MessageRequestRemember request) {
|
||||
messageService.setRemember(request, request.isRemember());
|
||||
}
|
||||
|
||||
private void undo(@NonNull final Message tlgMessage) {
|
||||
messageService.undo(tlgMessage.getChatId()).ifPresent(message -> update(message, true));
|
||||
remove(tlgMessage);
|
||||
@TransactionalEventListener(MessageDto.class)
|
||||
public void update(@NonNull final MessageDto message) {
|
||||
if (maySend(message)) {
|
||||
return;
|
||||
}
|
||||
if (mayDelete(message)) {
|
||||
return;
|
||||
}
|
||||
if (message.getTelegramMessageId() == null) {
|
||||
return;
|
||||
}
|
||||
edit(message);
|
||||
}
|
||||
|
||||
private void handleCallback(@NonNull final CallbackQuery callback) throws AccessDenied {
|
||||
final MaybeInaccessibleMessage tlgMessage = callback.getMessage();
|
||||
chatService.setEnabled(tlgMessage.getChatId(), true, callback.getFrom().getUserName());
|
||||
try {
|
||||
final InlineDto dto = objectMapper.readValue(callback.getData(), InlineDto.class);
|
||||
switch (dto.getCommand()) {
|
||||
case HIDE -> hide(tlgMessage);
|
||||
case REMEMBER -> remember(tlgMessage, true);
|
||||
case UNREMEMBER -> remember(tlgMessage, false);
|
||||
default -> update(tlgMessage);
|
||||
}
|
||||
} catch (JsonProcessingException e) {
|
||||
log.error("Failed to read InlineDto.", e);
|
||||
private boolean maySend(final @NonNull MessageDto message) {
|
||||
if (message.needsToBeSent()) {
|
||||
send(message.getOffer(), message.getChat());
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private void hide(@NonNull final MaybeInaccessibleMessage tlgMessage) {
|
||||
messageService.setHide(tlgMessage, true).ifPresentOrElse(message -> update(message, false), () -> remove(tlgMessage));
|
||||
private boolean mayDelete(final @NonNull MessageDto message) {
|
||||
if (message.needsToBeDeleted()) {
|
||||
TlgMessage.of(message).ifPresent(this::delete);
|
||||
return true;
|
||||
}
|
||||
|
||||
private void remember(@NonNull final MaybeInaccessibleMessage tlgMessage, final boolean remember) {
|
||||
messageService.setRemember(tlgMessage, remember).ifPresentOrElse(message -> update(message, false), () -> remove(tlgMessage));
|
||||
}
|
||||
|
||||
private void update(@NonNull final MaybeInaccessibleMessage tlgMessage) {
|
||||
messageService.findDtoByTelegramMessage(tlgMessage).ifPresentOrElse(message -> update(message, false), () -> remove(tlgMessage));
|
||||
return false;
|
||||
}
|
||||
|
||||
private void send(@NonNull final OfferDto offerDto, @NonNull final ChatDto chatDto) {
|
||||
@ -159,41 +155,7 @@ public class TelegramService {
|
||||
}
|
||||
}
|
||||
|
||||
private void update(@NonNull final MessageDto message, final boolean forceResend) {
|
||||
if (resend(message, forceResend)) {
|
||||
return;
|
||||
}
|
||||
if (deleteFromTelegram(message)) {
|
||||
return;
|
||||
}
|
||||
if (message.getTelegramMessageId() == null) {
|
||||
return;
|
||||
}
|
||||
_update(message);
|
||||
}
|
||||
|
||||
private boolean resend(final MessageDto message, final boolean forceResend) {
|
||||
final boolean resendOnPriceChange = message.getOffer().isResendOnPriceChange() && message.getOffer().getPriceChanged() != null && message.getHide() != null && !message.getOffer().getPriceChanged().isBefore(message.getHide());
|
||||
if (forceResend || resendOnPriceChange) {
|
||||
messageService.setHide(message, false);
|
||||
if (message.getTelegramMessageId() == null) {
|
||||
send(message.getOffer(), message.getChat());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean deleteFromTelegram(final MessageDto message) {
|
||||
if (message.getHide() != null && message.getTelegramMessageId() != null) {
|
||||
remove(message.getChat().getId(), message.getTelegramMessageId());
|
||||
messageService.clearTelegramMessageId(message);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private void _update(final MessageDto message) {
|
||||
private void edit(@NonNull final MessageDto message) {
|
||||
try {
|
||||
final EditMessageCaption edit = new EditMessageCaption(
|
||||
message.getChat().getId() + "",
|
||||
@ -210,7 +172,7 @@ public class TelegramService {
|
||||
} catch (TelegramApiException | JsonProcessingException e) {
|
||||
if (e.toString().endsWith("Bad Request: message to edit not found")) {
|
||||
log.info("Message has been deleted by User. Marking has hidden: {}", message);
|
||||
messageService.setHide(message, true);
|
||||
TlgMessage.of(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")) {
|
||||
log.debug("Ignoring complaint from telegram-bot-api about unmodified message: {}", message);
|
||||
} else {
|
||||
@ -219,7 +181,8 @@ public class TelegramService {
|
||||
}
|
||||
}
|
||||
|
||||
private String createText(final OfferDto offer) {
|
||||
@NonNull
|
||||
private String createText(@NonNull final OfferDto offer) {
|
||||
return "%s\n%s\n%s %s (%d km)\n%s\n%s\n".formatted(
|
||||
offer.getTitle().replaceAll("\\[", "(").replaceAll("]", ")"),
|
||||
offer.combinePrice(),
|
||||
@ -231,6 +194,7 @@ public class TelegramService {
|
||||
);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private InlineKeyboardMarkup createKeyboard(final boolean remember) throws JsonProcessingException {
|
||||
final InlineKeyboardMarkup markup = new InlineKeyboardMarkup();
|
||||
final ArrayList<List<InlineKeyboardButton>> keyboard = new ArrayList<>();
|
||||
@ -246,21 +210,18 @@ public class TelegramService {
|
||||
return markup;
|
||||
}
|
||||
|
||||
private void addButton(final ArrayList<InlineKeyboardButton> row, final String caption, final InlineCommand command) throws JsonProcessingException {
|
||||
private void addButton(@NonNull final ArrayList<InlineKeyboardButton> row, @NonNull final String caption, @NonNull final InlineCommand command) throws JsonProcessingException {
|
||||
final String data = objectMapper.writeValueAsString(new InlineDto(command));
|
||||
row.add(new InlineKeyboardButton(caption, null, data, null, null, null, null, null, null));
|
||||
}
|
||||
|
||||
private void remove(final MaybeInaccessibleMessage tlgMessage) {
|
||||
remove(tlgMessage.getChatId(), tlgMessage.getMessageId());
|
||||
}
|
||||
|
||||
private void remove(final long chatId, final int messageId) {
|
||||
private void delete(@NonNull final TlgMessage tlgMessage) {
|
||||
try {
|
||||
log.info("Removing Message chat={} message={}", chatId, messageId);
|
||||
bot.execute(new DeleteMessage(chatId + "", messageId));
|
||||
log.info("Removing Message tlgMessage={}", tlgMessage);
|
||||
bot.execute(tlgMessage.newDeleteMessage());
|
||||
messageService.markDeleted(tlgMessage);
|
||||
} catch (TelegramApiException e) {
|
||||
log.error("Failed to remove Message chat={} message={}", chatId, messageId);
|
||||
log.error("Failed to remove Message tlgMessage={}", tlgMessage);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,44 +1,106 @@
|
||||
package de.ph87.kleinanzeigen.telegram;
|
||||
|
||||
import lombok.Getter;
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import de.ph87.kleinanzeigen.telegram.request.ChatRequestEnable;
|
||||
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 lombok.NonNull;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.context.ApplicationEventPublisher;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.telegram.telegrambots.bots.TelegramLongPollingBot;
|
||||
import org.telegram.telegrambots.meta.TelegramBotsApi;
|
||||
import org.telegram.telegrambots.meta.api.methods.updatingmessages.DeleteMessage;
|
||||
import org.telegram.telegrambots.meta.api.objects.CallbackQuery;
|
||||
import org.telegram.telegrambots.meta.api.objects.MaybeInaccessibleMessage;
|
||||
import org.telegram.telegrambots.meta.api.objects.Message;
|
||||
import org.telegram.telegrambots.meta.api.objects.Update;
|
||||
import org.telegram.telegrambots.meta.exceptions.TelegramApiException;
|
||||
import org.telegram.telegrambots.updatesreceivers.DefaultBotSession;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.Locale;
|
||||
|
||||
@Slf4j
|
||||
@Service
|
||||
public class TelegramBot extends TelegramLongPollingBot {
|
||||
|
||||
private final TelegramConfig config;
|
||||
|
||||
private final ObjectMapper objectMapper;
|
||||
|
||||
private final ApplicationEventPublisher publisher;
|
||||
|
||||
private final DefaultBotSession session;
|
||||
|
||||
private final Consumer<Update> onUpdate;
|
||||
public TelegramBot(final TelegramConfig config, final ObjectMapper objectMapper, final ApplicationEventPublisher publisher) throws TelegramApiException {
|
||||
super(config.getToken());
|
||||
|
||||
@Getter
|
||||
private final String botUsername;
|
||||
this.config = config;
|
||||
this.publisher = publisher;
|
||||
|
||||
public TelegramBot(final String token, final String username, final Consumer<Update> onUpdate) throws IOException, TelegramApiException {
|
||||
super(token);
|
||||
this.botUsername = username;
|
||||
this.onUpdate = onUpdate;
|
||||
getOptions().setGetUpdatesTimeout(10);
|
||||
log.info("Starting telegram bot...");
|
||||
final TelegramBotsApi api = new TelegramBotsApi(DefaultBotSession.class);
|
||||
session = (DefaultBotSession) api.registerBot(this);
|
||||
log.info("Telegram bot registered.");
|
||||
this.objectMapper = objectMapper;
|
||||
}
|
||||
|
||||
@PreDestroy
|
||||
public void stop() {
|
||||
log.info("Stopping Telegram bot...");
|
||||
session.stop();
|
||||
log.info("Telegram bot stopped");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUpdateReceived(final Update update) {
|
||||
onUpdate.accept(update);
|
||||
public String getBotUsername() {
|
||||
return config.getUsername();
|
||||
}
|
||||
|
||||
public void stop() {
|
||||
session.stop();
|
||||
@Override
|
||||
public void onUpdateReceived(@NonNull final Update update) {
|
||||
if (update.hasMessage() && update.getMessage().hasText()) {
|
||||
handleMessage(update.getMessage());
|
||||
} else if (update.hasCallbackQuery()) {
|
||||
handleCallback(update.getCallbackQuery());
|
||||
}
|
||||
}
|
||||
|
||||
private void handleMessage(@NonNull final Message message) {
|
||||
final String command = message.getText().toLowerCase(Locale.ROOT).replaceAll("\\W+", "");
|
||||
switch (command) {
|
||||
case "start" -> publisher.publishEvent(new ChatRequestEnable(message, true));
|
||||
case "undo" -> publisher.publishEvent(new ChatRequestUndo(message));
|
||||
case "stop" -> publisher.publishEvent(new ChatRequestEnable(message, false));
|
||||
}
|
||||
remove(new TlgMessage(message));
|
||||
}
|
||||
|
||||
private void handleCallback(@NonNull final CallbackQuery callback) {
|
||||
final MaybeInaccessibleMessage message = callback.getMessage();
|
||||
try {
|
||||
final InlineDto dto = objectMapper.readValue(callback.getData(), InlineDto.class);
|
||||
switch (dto.getCommand()) {
|
||||
case HIDE -> publisher.publishEvent(new MessageRequestHide(message));
|
||||
case REMEMBER -> publisher.publishEvent(new MessageRequestRemember(message, true));
|
||||
case UNREMEMBER -> publisher.publishEvent(new MessageRequestRemember(message, false));
|
||||
}
|
||||
} catch (JsonProcessingException e) {
|
||||
log.error("Failed to read InlineDto.", e);
|
||||
}
|
||||
}
|
||||
|
||||
private void remove(@NonNull final TlgMessage tlgMessage) {
|
||||
try {
|
||||
log.info("Removing TlgMessage: tlgMessage={}", tlgMessage);
|
||||
execute(new DeleteMessage(tlgMessage.chatId + "", tlgMessage.messageId));
|
||||
} catch (TelegramApiException e) {
|
||||
log.error("Failed to remove TlgMessage: tlgMessage={}", tlgMessage);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
16
src/main/java/de/ph87/kleinanzeigen/telegram/TlgChat.java
Normal file
16
src/main/java/de/ph87/kleinanzeigen/telegram/TlgChat.java
Normal file
@ -0,0 +1,16 @@
|
||||
package de.ph87.kleinanzeigen.telegram;
|
||||
|
||||
import lombok.NonNull;
|
||||
import lombok.ToString;
|
||||
import org.telegram.telegrambots.meta.api.objects.MaybeInaccessibleMessage;
|
||||
|
||||
@ToString
|
||||
public class TlgChat {
|
||||
|
||||
public final long id;
|
||||
|
||||
public TlgChat(@NonNull final MaybeInaccessibleMessage message) {
|
||||
this.id = message.getChatId();
|
||||
}
|
||||
|
||||
}
|
||||
39
src/main/java/de/ph87/kleinanzeigen/telegram/TlgMessage.java
Normal file
39
src/main/java/de/ph87/kleinanzeigen/telegram/TlgMessage.java
Normal file
@ -0,0 +1,39 @@
|
||||
package de.ph87.kleinanzeigen.telegram;
|
||||
|
||||
import de.ph87.kleinanzeigen.telegram.chat.message.MessageDto;
|
||||
import lombok.NonNull;
|
||||
import lombok.ToString;
|
||||
import org.telegram.telegrambots.meta.api.methods.updatingmessages.DeleteMessage;
|
||||
import org.telegram.telegrambots.meta.api.objects.MaybeInaccessibleMessage;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
@ToString
|
||||
public class TlgMessage {
|
||||
|
||||
public final long chatId;
|
||||
|
||||
public final int messageId;
|
||||
|
||||
private TlgMessage(final long chatId, final int messageId) {
|
||||
this.chatId = chatId;
|
||||
this.messageId = messageId;
|
||||
}
|
||||
|
||||
public TlgMessage(@NonNull final MaybeInaccessibleMessage message) {
|
||||
this(message.getChatId(), message.getMessageId());
|
||||
}
|
||||
|
||||
public static Optional<TlgMessage> of(@NonNull final MessageDto message) {
|
||||
if (message.getTelegramMessageId() == null) {
|
||||
return Optional.empty();
|
||||
}
|
||||
return Optional.of(new TlgMessage(message.getChat().getId(), message.getTelegramMessageId()));
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public DeleteMessage newDeleteMessage() {
|
||||
return new DeleteMessage(chatId + "", messageId);
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,6 +1,6 @@
|
||||
package de.ph87.kleinanzeigen.telegram.chat;
|
||||
|
||||
import jakarta.annotation.Nullable;
|
||||
import jakarta.persistence.Column;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.Id;
|
||||
import lombok.*;
|
||||
@ -18,7 +18,8 @@ public class Chat {
|
||||
private boolean enabled;
|
||||
|
||||
@Setter
|
||||
@Nullable
|
||||
@NonNull
|
||||
@Column(nullable = false)
|
||||
private String name;
|
||||
|
||||
public Chat(final long id, final boolean enabled, @NonNull final String name) {
|
||||
|
||||
@ -1,7 +1,8 @@
|
||||
package de.ph87.kleinanzeigen.telegram.chat;
|
||||
|
||||
import de.ph87.kleinanzeigen.telegram.AccessDenied;
|
||||
import de.ph87.kleinanzeigen.telegram.TelegramConfig;
|
||||
import de.ph87.kleinanzeigen.telegram.TlgChat;
|
||||
import lombok.NonNull;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
@ -23,26 +24,33 @@ public class ChatService {
|
||||
return chatRepository.findAllByEnabledTrue().stream().filter(chat -> config.isOnWhitelist(chat.getId())).map(this::toDto).toList();
|
||||
}
|
||||
|
||||
public void setEnabled(final long id, final boolean enabled, final String name) throws AccessDenied {
|
||||
if (!config.isOnWhitelist(id)) {
|
||||
throw new AccessDenied();
|
||||
public void setEnabled(@NonNull final TlgChat tlgChat, final boolean enabled, final @NonNull String username) {
|
||||
if (!config.isOnWhitelist(tlgChat.id)) {
|
||||
log.warn("Not on whitelist: {}", tlgChat);
|
||||
return;
|
||||
}
|
||||
|
||||
chatRepository
|
||||
.findById(id)
|
||||
.findById(tlgChat.id)
|
||||
.stream()
|
||||
.peek(chat -> {
|
||||
chat.setName(name);
|
||||
.peek(chat -> update(chat, enabled, username))
|
||||
.findFirst()
|
||||
.orElseGet(() -> create(tlgChat, enabled, username));
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private Chat create(@NonNull final TlgChat tlgChat, final boolean enabled, final @NonNull String username) {
|
||||
final Chat chat = chatRepository.save(new Chat(tlgChat.id, enabled, username));
|
||||
log.info("Chat created: {}", chat);
|
||||
return chat;
|
||||
}
|
||||
|
||||
private void update(@NonNull final Chat chat, final boolean enabled, final @NonNull String username) {
|
||||
chat.setName(username);
|
||||
if (chat.isEnabled() != enabled) {
|
||||
chat.setEnabled(enabled);
|
||||
log.info("Chat {}: {}", enabled ? "ENABLED" : "DISABLED", chat);
|
||||
}
|
||||
})
|
||||
.findFirst()
|
||||
.orElseGet(() -> {
|
||||
final Chat chat = chatRepository.save(new Chat(id, enabled, name));
|
||||
log.info("Chat created: {}", chat);
|
||||
return chat;
|
||||
});
|
||||
}
|
||||
|
||||
public Chat getByDto(final ChatDto chatDto) {
|
||||
|
||||
@ -31,7 +31,6 @@ public class Message {
|
||||
@Nullable
|
||||
private Integer telegramMessageId;
|
||||
|
||||
@Setter
|
||||
@Column
|
||||
@Nullable
|
||||
private ZonedDateTime hide = null;
|
||||
@ -46,4 +45,19 @@ public class Message {
|
||||
this.telegramMessageId = tlgMessage.getMessageId();
|
||||
}
|
||||
|
||||
public void setHide(final boolean hide) {
|
||||
if (hide) {
|
||||
if (this.hide == null) {
|
||||
this.hide = ZonedDateTime.now();
|
||||
}
|
||||
} else {
|
||||
this.hide = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public ZonedDateTime getHide() {
|
||||
return hide;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -1,17 +0,0 @@
|
||||
package de.ph87.kleinanzeigen.telegram.chat.message;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class MessageDeleted {
|
||||
|
||||
private final long chatId;
|
||||
|
||||
private final int messageId;
|
||||
|
||||
public MessageDeleted(final long chatId, final int messageId) {
|
||||
this.chatId = chatId;
|
||||
this.messageId = messageId;
|
||||
}
|
||||
|
||||
}
|
||||
@ -36,4 +36,12 @@ public class MessageDto {
|
||||
remember = message.isRemember();
|
||||
}
|
||||
|
||||
public boolean needsToBeSent() {
|
||||
return hide == null && telegramMessageId == null;
|
||||
}
|
||||
|
||||
public boolean needsToBeDeleted() {
|
||||
return hide != null && telegramMessageId != null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -3,26 +3,26 @@ package de.ph87.kleinanzeigen.telegram.chat.message;
|
||||
import de.ph87.kleinanzeigen.kleinanzeigen.offer.Offer;
|
||||
import de.ph87.kleinanzeigen.kleinanzeigen.offer.OfferDto;
|
||||
import de.ph87.kleinanzeigen.kleinanzeigen.offer.OfferService;
|
||||
import de.ph87.kleinanzeigen.telegram.TlgChat;
|
||||
import de.ph87.kleinanzeigen.telegram.TlgMessage;
|
||||
import de.ph87.kleinanzeigen.telegram.chat.Chat;
|
||||
import de.ph87.kleinanzeigen.telegram.chat.ChatDto;
|
||||
import de.ph87.kleinanzeigen.telegram.chat.ChatService;
|
||||
import lombok.NonNull;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.scheduling.annotation.EnableScheduling;
|
||||
import org.springframework.context.ApplicationEventPublisher;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Propagation;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.telegram.telegrambots.meta.api.objects.MaybeInaccessibleMessage;
|
||||
|
||||
import java.time.ZonedDateTime;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
@Slf4j
|
||||
@Service
|
||||
@Transactional
|
||||
@EnableScheduling
|
||||
@RequiredArgsConstructor
|
||||
public class MessageService {
|
||||
|
||||
@ -32,6 +32,8 @@ public class MessageService {
|
||||
|
||||
private final ChatService chatService;
|
||||
|
||||
private final ApplicationEventPublisher applicationEventPublisher;
|
||||
|
||||
@Transactional(propagation = Propagation.REQUIRES_NEW)
|
||||
public void updateOrCreate(final OfferDto offerDto, final ChatDto chatDto, final org.telegram.telegrambots.meta.api.objects.Message tlgMessage) {
|
||||
final Offer offer = offerService.getByDto(offerDto);
|
||||
@ -42,48 +44,57 @@ public class MessageService {
|
||||
);
|
||||
}
|
||||
|
||||
@SuppressWarnings("UnusedReturnValue")
|
||||
public Optional<MessageDto> setHide(final MaybeInaccessibleMessage tlgMessage, final boolean hide) {
|
||||
return findByTelegramMessage(tlgMessage).stream().peek(offer -> offer.setHide(hide ? ZonedDateTime.now() : null)).findFirst().map(this::toDto);
|
||||
public void setHide(@NonNull final TlgMessage tlgMessage) {
|
||||
set(tlgMessage, message -> message.setHide(true));
|
||||
}
|
||||
|
||||
public Optional<MessageDto> setRemember(final MaybeInaccessibleMessage tlgMessage, final boolean remember) {
|
||||
return findByTelegramMessage(tlgMessage).stream().peek(offer -> offer.setRemember(remember)).findFirst().map(this::toDto);
|
||||
public void setRemember(@NonNull final TlgMessage tlgMessage, final boolean remember) {
|
||||
set(tlgMessage, message -> message.setRemember(remember));
|
||||
}
|
||||
|
||||
public Optional<MessageDto> findDtoByTelegramMessage(final MaybeInaccessibleMessage tlgMessage) {
|
||||
return findByTelegramMessage(tlgMessage).map(this::toDto);
|
||||
}
|
||||
|
||||
public void clearTelegramMessageId(final MessageDto dto) {
|
||||
findByDto(dto).ifPresent(message -> message.setTelegramMessageId(null));
|
||||
}
|
||||
|
||||
public void setHide(final MessageDto dto, final boolean hide) {
|
||||
findByDto(dto).ifPresent(offer -> offer.setHide(hide ? ZonedDateTime.now() : null));
|
||||
}
|
||||
|
||||
private Optional<Message> findByTelegramMessage(final MaybeInaccessibleMessage tlgMessage) {
|
||||
return messageRepository.findByChat_IdAndTelegramMessageId(tlgMessage.getChatId(), tlgMessage.getMessageId());
|
||||
}
|
||||
|
||||
private Optional<Message> findByDto(final MessageDto dto) {
|
||||
return messageRepository.findById(dto.getId());
|
||||
}
|
||||
|
||||
public List<MessageDto> findAllDtoByOfferDto(final OfferDto offer) {
|
||||
@NonNull
|
||||
public List<MessageDto> findAllDtoByOfferDto(@NonNull final OfferDto offer) {
|
||||
return messageRepository.findAllByOffer_Id(offer.getId()).stream().map(this::toDto).toList();
|
||||
}
|
||||
|
||||
private MessageDto toDto(final Message message) {
|
||||
public void undo(@NonNull final TlgChat chat) {
|
||||
messageRepository.findFirstByChat_IdAndHideNotNullOrderByHideDesc(chat.id).ifPresentOrElse(
|
||||
set(message -> message.setHide(false)),
|
||||
() -> log.warn("Nothing to undo for chat: {}", chat)
|
||||
);
|
||||
}
|
||||
|
||||
public void markDeleted(@NonNull final TlgMessage tlgMessage) {
|
||||
set(tlgMessage, message -> {
|
||||
message.setHide(true);
|
||||
message.setTelegramMessageId(null);
|
||||
});
|
||||
}
|
||||
|
||||
private void set(@NonNull final TlgMessage tlgMessage, @NonNull final Consumer<Message> setter) {
|
||||
find(tlgMessage).ifPresent(set(setter));
|
||||
}
|
||||
|
||||
private Consumer<Message> set(@NonNull final Consumer<Message> setter) {
|
||||
return message -> {
|
||||
setter.accept(message);
|
||||
publish(message);
|
||||
};
|
||||
}
|
||||
|
||||
private Optional<Message> find(final @NonNull TlgMessage tlgMessage) {
|
||||
return messageRepository.findByChat_IdAndTelegramMessageId(tlgMessage.chatId, tlgMessage.messageId);
|
||||
}
|
||||
|
||||
private void publish(@NonNull final Message message) {
|
||||
applicationEventPublisher.publishEvent(toDto(message));
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private MessageDto toDto(@NonNull final Message message) {
|
||||
final ChatDto chatDto = chatService.toDto(message.getChat());
|
||||
final OfferDto offerDto = offerService.toDto(message.getOffer());
|
||||
return new MessageDto(message, chatDto, offerDto);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public Optional<MessageDto> undo(final long chatId) {
|
||||
return messageRepository.findFirstByChat_IdAndHideNotNullOrderByHideDesc(chatId).stream().peek(message -> message.setHide(null)).map(this::toDto).findFirst();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -0,0 +1,22 @@
|
||||
package de.ph87.kleinanzeigen.telegram.request;
|
||||
|
||||
import de.ph87.kleinanzeigen.telegram.TlgChat;
|
||||
import lombok.Getter;
|
||||
import lombok.NonNull;
|
||||
import org.telegram.telegrambots.meta.api.objects.Message;
|
||||
|
||||
@Getter
|
||||
public class ChatRequestEnable extends TlgChat {
|
||||
|
||||
private final boolean enable;
|
||||
|
||||
@NonNull
|
||||
private final String username;
|
||||
|
||||
public ChatRequestEnable(@NonNull final Message message, final boolean enable) {
|
||||
super(message);
|
||||
this.enable = enable;
|
||||
this.username = message.getFrom().getUserName() == null ? "" : message.getFrom().getUserName();
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,15 @@
|
||||
package de.ph87.kleinanzeigen.telegram.request;
|
||||
|
||||
import de.ph87.kleinanzeigen.telegram.TlgChat;
|
||||
import lombok.Getter;
|
||||
import lombok.NonNull;
|
||||
import org.telegram.telegrambots.meta.api.objects.Message;
|
||||
|
||||
@Getter
|
||||
public class ChatRequestUndo extends TlgChat {
|
||||
|
||||
public ChatRequestUndo(@NonNull final Message message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,15 @@
|
||||
package de.ph87.kleinanzeigen.telegram.request;
|
||||
|
||||
import de.ph87.kleinanzeigen.telegram.TlgMessage;
|
||||
import lombok.Getter;
|
||||
import lombok.NonNull;
|
||||
import org.telegram.telegrambots.meta.api.objects.MaybeInaccessibleMessage;
|
||||
|
||||
@Getter
|
||||
public class MessageRequestHide extends TlgMessage {
|
||||
|
||||
public MessageRequestHide(@NonNull final MaybeInaccessibleMessage message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,18 @@
|
||||
package de.ph87.kleinanzeigen.telegram.request;
|
||||
|
||||
import de.ph87.kleinanzeigen.telegram.TlgMessage;
|
||||
import lombok.Getter;
|
||||
import lombok.NonNull;
|
||||
import org.telegram.telegrambots.meta.api.objects.MaybeInaccessibleMessage;
|
||||
|
||||
@Getter
|
||||
public class MessageRequestRemember extends TlgMessage {
|
||||
|
||||
private final boolean remember;
|
||||
|
||||
public MessageRequestRemember(@NonNull final MaybeInaccessibleMessage message, final boolean remember) {
|
||||
super(message);
|
||||
this.remember = remember;
|
||||
}
|
||||
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user