aboutsummaryrefslogtreecommitdiff
path: root/src/main/java/com/juick/server/TelegramBotManager.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/java/com/juick/server/TelegramBotManager.java')
-rw-r--r--src/main/java/com/juick/server/TelegramBotManager.java465
1 files changed, 0 insertions, 465 deletions
diff --git a/src/main/java/com/juick/server/TelegramBotManager.java b/src/main/java/com/juick/server/TelegramBotManager.java
deleted file mode 100644
index 3c38e5de..00000000
--- a/src/main/java/com/juick/server/TelegramBotManager.java
+++ /dev/null
@@ -1,465 +0,0 @@
-/*
- * Copyright (C) 2008-2019, Juick
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-package com.juick.server;
-
-import com.juick.model.User;
-import com.juick.model.AnonymousUser;
-import com.juick.model.CommandResult;
-import com.juick.www.api.SystemActivity;
-import com.juick.server.util.HttpUtils;
-import com.juick.service.MessagesService;
-import com.juick.service.TelegramService;
-import com.juick.service.UserService;
-import com.juick.service.component.SystemEvent;
-import com.juick.service.component.NotificationListener;
-import com.juick.service.component.PingEvent;
-import com.juick.util.MessageUtils;
-import com.pengrad.telegrambot.Callback;
-import com.pengrad.telegrambot.TelegramBot;
-import com.pengrad.telegrambot.UpdatesListener;
-import com.pengrad.telegrambot.model.Message;
-import com.pengrad.telegrambot.model.MessageEntity;
-import com.pengrad.telegrambot.model.PhotoSize;
-import com.pengrad.telegrambot.model.Update;
-import com.pengrad.telegrambot.model.request.ParseMode;
-import com.pengrad.telegrambot.request.GetFile;
-import com.pengrad.telegrambot.request.SendMessage;
-import com.pengrad.telegrambot.request.SendPhoto;
-import com.pengrad.telegrambot.request.SetWebhook;
-import com.pengrad.telegrambot.response.GetFileResponse;
-import com.pengrad.telegrambot.response.SendResponse;
-import org.apache.commons.lang3.StringUtils;
-import org.apache.commons.lang3.tuple.Pair;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.springframework.beans.factory.annotation.Value;
-import org.springframework.context.ApplicationEventPublisher;
-import org.springframework.web.util.UriComponents;
-import org.springframework.web.util.UriComponentsBuilder;
-
-import javax.annotation.Nonnull;
-import javax.annotation.PostConstruct;
-import javax.inject.Inject;
-import java.io.IOException;
-import java.net.URI;
-import java.net.URL;
-import java.util.*;
-
-import static com.juick.formatters.PlainTextFormatter.formatPost;
-import static com.juick.formatters.PlainTextFormatter.formatUrl;
-
-/**
- * Created by vt on 12/05/16.
- */
-public class TelegramBotManager implements NotificationListener {
- private static final Logger logger = LoggerFactory.getLogger("Telegram");
-
- private TelegramBot bot;
-
- @Value("${telegram_api_url:}")
- private String apiUrl;
- @Value("${telegram_file_api_url:}")
- private String fileApiUrl;
- @Value("${telegram_webhook_url:}")
- private String webhookUrl;
- @Value("${telegram_token:12345678}")
- private String telegramToken;
- @Value("${telegram_debug:false}")
- private boolean telegramDebug;
- @Inject
- private TelegramService telegramService;
- @Inject
- private MessagesService messagesService;
- @Inject
- private UserService userService;
- @Inject
- private CommandsManager commandsManager;
- @Inject
- private ApplicationEventPublisher applicationEventPublisher;
- @Value("${upload_tmp_dir:#{systemEnvironment['TEMP'] ?: '/tmp'}}")
- private String tmpDir;
- @Value("${service_user:juick}")
- private String serviceUser;
-
- private static final String MSG_LINK = "🔗";
-
- @PostConstruct
- public void init() {
- TelegramBot.Builder tgBuilder = new TelegramBot.Builder(telegramToken);
- if (StringUtils.isNotEmpty(apiUrl)) {
- tgBuilder.apiUrl(apiUrl).fileApiUrl(fileApiUrl);
- }
- bot = tgBuilder.build();
- if (!telegramDebug) {
- try {
- SetWebhook webhook = new SetWebhook().url(webhookUrl);
- if (!bot.execute(webhook).isOk()) {
- logger.error("error setting webhook");
- }
- } catch (Exception e) {
- logger.warn("couldn't initialize telegram bot", e);
- }
- } else {
- bot.setUpdatesListener(updates -> {
- logger.info("got updates: {}", updates);
- updates.forEach(this::processUpdate);
- return UpdatesListener.CONFIRMED_UPDATES_ALL;
- });
- }
- }
-
- public void processUpdate(Update update) {
- Message message = update.message();
- if (update.message() == null) {
- message = update.editedMessage();
- if (message == null) {
- logger.error("error parsing telegram update: {}", update);
- return;
- }
- User user_from = userService.getUserByUID(telegramService.getUser(message.chat().id())).orElse(AnonymousUser.INSTANCE);
- logger.info("Found juick user {}", user_from.getUid());
- Optional<Pair<Integer, Integer>> originalMessageData = messagesService.findMessageByProperty("durovId",
- String.valueOf(message.messageId()));
- if (originalMessageData.isPresent()) {
- int mid = originalMessageData.get().getLeft();
- int rid = originalMessageData.get().getRight();
- // TODO: this is copypaste from api, need switch to api
- com.juick.model.Message originalMessage = rid == 0 ? messagesService.getMessage(mid).orElseThrow(IllegalStateException::new)
- : messagesService.getReply(mid, rid);
- User author = originalMessage.getUser();
- String newMessageText = StringUtils.defaultString(message.text());
- if (user_from.equals(author) && canUpdateMessage(originalMessage, newMessageText)) {
- if (messagesService.updateMessage(mid, rid, newMessageText)) {
- telegramNotify(message.chat().id(), "Message updated", new com.juick.model.Message());
- return;
- }
- }
- telegramNotify(message.chat().id(), "Error updating message", new com.juick.model.Message());
- }
- } else {
- User user_from = userService.getUserByUID(telegramService.getUser(message.chat().id())).orElse(AnonymousUser.INSTANCE);
- logger.info("Found juick user {}", user_from.getUid());
-
- String username = message.from().username();
- if (username == null) {
- username = message.from().firstName();
- }
- if (!user_from.isAnonymous()) {
- URI attachment = URI.create(StringUtils.EMPTY);
- if (message.photo() != null) {
- String fileId = Arrays.stream(message.photo()).max(Comparator.comparingInt(PhotoSize::fileSize))
- .orElse(new PhotoSize()).fileId();
- if (StringUtils.isNotEmpty(fileId)) {
- GetFile request = new GetFile(fileId);
- GetFileResponse response = bot.execute(request);
- logger.info("got file {}", response.file());
- try {
- URL fileURL = new URL(bot.getFullFilePath(response.file()));
- attachment = HttpUtils.downloadImage(fileURL, tmpDir);
- } catch (Exception e) {
- logger.warn("attachment exception", e);
- }
- logger.info("received {}", attachment);
- }
- }
- String text = message.text();
- if (StringUtils.isBlank(text)) {
- text = message.caption();
- }
- if (StringUtils.isBlank(text)) {
- text = StringUtils.EMPTY;
- }
- if (StringUtils.isNotEmpty(text) || StringUtils.isNotEmpty(attachment.toString())) {
- if (text.equalsIgnoreCase("LOGIN")
- || text.equalsIgnoreCase("PING")
- || text.equalsIgnoreCase("HELP")
- || text.equalsIgnoreCase("/login")
- || text.equalsIgnoreCase("/logout")
- || text.equalsIgnoreCase("/start")
- || text.equalsIgnoreCase("/help")) {
- String msgUrl = "http://juick.com/login?hash=" + userService.getHashByUID(user_from.getUid());
- String msg = String.format("Hi, %s!\nYou can post messages and images to Juick there.\n" +
- "Tap to [log into website](%s) to get more info", user_from.getName(), msgUrl);
- telegramNotify(message.from().id().longValue(), msg, new com.juick.model.Message());
- } else {
- Message replyMessage = message.replyToMessage();
- if (replyMessage != null) {
- MessageEntity[] entities = replyMessage.entities();
- if (entities == null) {
- entities = replyMessage.captionEntities();
- }
- if (entities != null) {
- Optional<MessageEntity> juickLink = Arrays.stream(entities)
- .filter(this::isJuickLink)
- .findFirst();
- if (juickLink.isPresent()) {
- if (StringUtils.isNotEmpty(juickLink.get().url())) {
- UriComponents uriComponents = UriComponentsBuilder.fromUriString(
- juickLink.get().url()).build();
- String path = uriComponents.getPath();
- if (StringUtils.isNotEmpty(path) && path.length() > 1) {
- int mid;
- try {
- mid = Integer.parseInt(path.substring(3));
- } catch (NumberFormatException e) {
- logger.warn("wrong mid received");
- return;
- }
- String prefix = String.format("#%d ", mid);
- if (StringUtils.isNotEmpty(uriComponents.getFragment())) {
- int rid = Integer.parseInt(uriComponents.getFragment());
- prefix = String.format("#%d/%d ", mid, rid);
- }
- executeCommand(message.messageId(), message.from().id().longValue(),
- user_from, prefix + text, attachment);
- } else {
- logger.warn("invalid path: {}", path);
- }
- } else {
- logger.warn("invalid entity: {}", juickLink);
- }
- } else {
- telegramNotify(message.from().id().longValue(),
- "Can not reply to this message", replyMessage.messageId(), new com.juick.model.Message());
- }
- } else {
- telegramNotify(message.from().id().longValue(),
- "Can not reply to this message", replyMessage.messageId(), new com.juick.model.Message());
- }
- } else {
- executeCommand(message.messageId(), message.from().id().longValue(),
- user_from, text, attachment);
- }
- }
- }
- messagesService.getUnread(user_from).forEach(mid -> messagesService.setRead(user_from, mid));
- } else {
- List<Long> chats = telegramService.getAnonymous();
- if (!chats.contains(message.chat().id())) {
- logger.info("added chat with {}", username);
- telegramService.createTelegramUser(message.from().id(), username);
- }
- telegramSignupNotify(message.from().id().longValue(), userService.getSignUpHashByTelegramID(message.from().id().longValue(), username));
- }
- }
- }
-
- /*
- validate user input
- */
- private boolean canUpdateMessage(com.juick.model.Message message, String newData) {
- if (StringUtils.isEmpty(newData)) {
- // allow empty text only when image is present
- return StringUtils.isNotEmpty(message.getAttachmentType());
- }
- return true;
- }
-
- private void executeCommand(Integer messageId, Long userId, User user_from, String text, URI attachment) {
- try {
- CommandResult result = commandsManager.processCommand(user_from, text, attachment);
- if (result.getNewMessage().isPresent()) {
- com.juick.model.Message newMessage = result.getNewMessage().get();
- messagesService.setMessageProperty(newMessage.getMid(), newMessage.getRid(), "durovId",
- String.valueOf(messageId));
- }
- String messageTxt = StringUtils.isNotEmpty(result.getMarkdown()) ? result.getMarkdown()
- : "Unknown error or unsupported command";
- telegramNotify(userId, messageTxt, new com.juick.model.Message());
- } catch (Exception e) {
- logger.warn("telegram exception", e);
- }
- }
-
- private boolean isJuickLink(MessageEntity e) {
- return e.offset() == 0 && e.type().equals(MessageEntity.Type.text_link) && e.length() == 2;
- }
-
- public void telegramNotify(Long chatId, String msg, @Nonnull com.juick.model.Message source) {
- telegramNotify(chatId, msg, 0, source);
- }
-
- public void telegramNotify(Long chatId, String msg, Integer replyTo, @Nonnull com.juick.model.Message source) {
- String attachment = MessageUtils.attachmentUrl(source);
- boolean isSendTxt = true;
- if (!StringUtils.isEmpty(attachment)) {
- SendPhoto telegramPhoto = new SendPhoto(chatId, attachment);
- if (replyTo > 0) {
- telegramPhoto.replyToMessageId(replyTo);
- }
- telegramPhoto.parseMode(ParseMode.Markdown);
- if(msg.length() < 1024) {
- telegramPhoto.caption(msg);
- isSendTxt = false;
- }
- bot.execute(telegramPhoto, new Callback<>() {
- @Override
- public void onResponse(SendPhoto request, SendResponse response) {
- processTelegramResponse(chatId, response, source);
- }
-
- @Override
- public void onFailure(SendPhoto request, IOException e) {
- logger.warn("telegram failure", e);
- }
- });
- }
- if (isSendTxt){
- SendMessage telegramMessage = new SendMessage(chatId, msg);
- if (replyTo > 0) {
- telegramMessage.replyToMessageId(replyTo);
- }
- telegramMessage.parseMode(ParseMode.Markdown).disableWebPagePreview(true);
- bot.execute(telegramMessage, new Callback<>() {
- @Override
- public void onResponse(SendMessage request, SendResponse response) {
- processTelegramResponse(chatId, response, source);
- }
-
- @Override
- public void onFailure(SendMessage request, IOException e) {
- logger.warn("telegram failure", e);
- }
- });
- }
- }
-
- private void processTelegramResponse(Long chatId, SendResponse response, com.juick.model.Message source) {
- int userId = telegramService.getUser(chatId);
- if (!response.isOk()) {
- if (response.errorCode() == 403) {
- // remove from anonymous users
- telegramService.getAnonymous().stream().filter(c -> c.equals(chatId)).findFirst().ifPresent(
- d -> {
- telegramService.deleteAnonymous(d);
- logger.info("deleted {} chat", d);
- }
- );
- if (userId > 0) {
- User userToDelete = userService.getUserByUID(userId)
- .orElseThrow(IllegalStateException::new);
- boolean status = telegramService.deleteTelegramUser(userToDelete.getUid());
- logger.info("deleting telegram id of @{} : {}", userToDelete.getName(), status);
- }
- } else {
- logger.warn("error response, isOk: {}, errorCode: {}, description: {}",
- response.isOk(), response.errorCode(), response.description());
- }
- } else {
- if (MessageUtils.isReply(source)) {
- messagesService.setLastReadComment(userService.getUserByUID(userId)
- .orElseThrow(IllegalStateException::new), source.getMid(), source.getRid());
- User user = userService.getUserByUID(userId).orElseThrow(IllegalStateException::new);
- userService.updateLastSeen(user);
- applicationEventPublisher.publishEvent(
- new SystemEvent(this, SystemActivity.read(user, source)));
- }
- }
- }
-
- public void telegramSignupNotify(Long telegramId, String hash) {
- bot.execute(new SendMessage(telegramId,
- String.format("You are subscribed to all Juick messages. " +
- "[Create or link](http://juick.com/signup?type=durov&hash=%s) " +
- "an existing Juick account to get your subscriptions and ability to post messages", hash))
- .parseMode(ParseMode.Markdown), new Callback<>() {
- @Override
- public void onResponse(SendMessage request, SendResponse response) {
- logger.info("got response: {}", response.message());
- }
-
- @Override
- public void onFailure(SendMessage request, IOException e) {
- logger.warn("telegram failure", e);
- }
- });
- }
-
- @Override
- public void processSystemEvent(SystemEvent systemEvent) {
- var activity = systemEvent.getActivity();
- var type = activity.getType();
- if (type.equals(SystemActivity.ActivityType.message)) {
- processMessage(activity.getMessage(), activity.getTo());
- } else if (type.equals(SystemActivity.ActivityType.like)) {
- if (systemEvent.getActivity().getFrom().getName().equals(serviceUser)) {
- processTop(systemEvent.getActivity().getMessage());
- } else {
- processLike(activity.getFrom(), activity.getMessage(), activity.getTo());
- }
- } else if (type.equals(SystemActivity.ActivityType.follow)) {
- processFollow(activity.getFrom(), activity.getTo());
- }
- }
- private void processMessage(com.juick.model.Message jmsg, List<User> subscribedUsers) {
- if (jmsg.isService()) {
- return;
- }
- String msgUrl = formatUrl(jmsg);
- if (MessageUtils.isPM(jmsg)) {
- telegramService.getTelegramIdentifiers(Collections.singletonList(jmsg.getTo()))
- .forEach(c -> telegramNotify(c, formatPost(jmsg, true), jmsg));
- } else if (MessageUtils.isReply(jmsg)) {
- String fmsg = String.format("[%s](%s) %s", MSG_LINK, msgUrl, formatPost(jmsg, true));
- telegramService.getTelegramIdentifiers(
- subscribedUsers
- ).forEach(c -> telegramNotify(c, fmsg, jmsg));
- } else {
- String msg = String.format("[%s](%s) %s", MSG_LINK, msgUrl, formatPost(jmsg, true));
-
- List<Long> users = telegramService.getTelegramIdentifiers(subscribedUsers);
- List<Long> chats = telegramService.getAnonymous();
- // registered subscribed users
-
- users.forEach(c -> telegramNotify(c, msg, jmsg));
- // anonymous
- chats.stream().filter(u -> telegramService.getUser(u) == 0).forEach(c -> telegramNotify(c, msg, jmsg));
- }
- }
-
- private void processLike(User liker, com.juick.model.Message message, List<User> subscribers) {
- if (!liker.getName().equals(serviceUser)) {
- logger.info("Like received in tg listener");
- if (!userService.isInBLAny(message.getUser().getUid(), liker.getUid())) {
- telegramService.getTelegramIdentifiers(Collections.singletonList(message.getUser()))
- .forEach(c -> telegramNotify(c, String.format("%s recommends your [post](%s)",
- MessageUtils.getMarkdownUser(liker), formatUrl(message)), new com.juick.model.Message()));
- }
- telegramService.getTelegramIdentifiers(subscribers)
- .forEach(c -> telegramNotify(c, String.format("%s recommends you someone's [post](%s)",
- MessageUtils.getMarkdownUser(liker), formatUrl(message)), new com.juick.model.Message()));
- }
- }
-
- @Override
- public void processPingEvent(PingEvent pingEvent) {
-
- }
-
- private void processTop(com.juick.model.Message message) {
- telegramService.getTelegramIdentifiers(Collections.singletonList(message.getUser()))
- .forEach(c -> telegramNotify(c, String.format("Your [post](%s) became popular!",
- formatUrl(message)), new com.juick.model.Message()));
- }
-
- private void processFollow(User subscriber, List<User> target) {
- telegramService.getTelegramIdentifiers(target)
- .forEach(c -> telegramNotify(c, String.format("%s subscribed to your blog",
- MessageUtils.getMarkdownUser(subscriber)), new com.juick.model.Message()));
- }
-}