From d2e0ab9a3f0efcaa8743a5e5be1c662335cde359 Mon Sep 17 00:00:00 2001 From: MrBesen Date: Sat, 29 Feb 2020 11:59:32 +0100 Subject: [PATCH] feedback working --- pom.xml | 7 +- .../java/de/mrbesen/telegram/TelegramAPI.java | 51 ++++--- .../telegram/commands/FeedbackCommand.java | 132 +++++++++++++----- .../mrbesen/telegram/event/EventManager.java | 8 +- 4 files changed, 133 insertions(+), 65 deletions(-) diff --git a/pom.xml b/pom.xml index 75179ea..a3b2311 100644 --- a/pom.xml +++ b/pom.xml @@ -3,7 +3,7 @@ 4.0.0 TelegramAPI TelegramAPI - 0.0.2 + 0.0.3 src/main/java @@ -39,13 +39,13 @@ org.json json - 20180813 + 20190722 compile org.projectlombok lombok - LATEST + 1.18.12 @@ -54,5 +54,4 @@ UTF-8 UTF-8 - \ No newline at end of file diff --git a/src/main/java/de/mrbesen/telegram/TelegramAPI.java b/src/main/java/de/mrbesen/telegram/TelegramAPI.java index 3e4b99b..f286bca 100644 --- a/src/main/java/de/mrbesen/telegram/TelegramAPI.java +++ b/src/main/java/de/mrbesen/telegram/TelegramAPI.java @@ -1,28 +1,11 @@ package de.mrbesen.telegram; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStreamWriter; -import java.net.URL; -import java.net.URLEncoder; -import java.util.LinkedList; -import java.util.List; -import java.util.Scanner; - -import javax.net.ssl.HttpsURLConnection; - -import de.mrbesen.telegram.commands.FeedbackCommand; -import de.mrbesen.telegram.commands.JSONCommandHandler; -import lombok.Getter; -import lombok.Setter; -import org.json.JSONArray; -import org.json.JSONObject; - import de.mrbesen.telegram.AsyncHandler.Callback; import de.mrbesen.telegram.AsyncHandler.Task; import de.mrbesen.telegram.MessageBuilder.AsyncSendable; import de.mrbesen.telegram.MessageBuilder.SendableMessage; import de.mrbesen.telegram.commands.CommandManager; +import de.mrbesen.telegram.commands.FeedbackCommand; import de.mrbesen.telegram.event.Event; import de.mrbesen.telegram.event.EventManager; import de.mrbesen.telegram.event.events.UserCallbackEvent; @@ -37,14 +20,27 @@ import de.mrbesen.telegram.objects.TMessage; import de.mrbesen.telegram.objects.TReplyMarkup; import de.mrbesen.telegram.objects.TUser; import de.mrbesen.telegram.objects.TUser.Status; -import sun.awt.image.ImageWatched; +import lombok.Getter; +import lombok.Setter; +import org.json.JSONArray; +import org.json.JSONObject; + +import javax.net.ssl.HttpsURLConnection; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStreamWriter; +import java.net.URL; +import java.net.URLEncoder; +import java.util.LinkedList; +import java.util.List; +import java.util.Scanner; public class TelegramAPI implements Runnable { private static final String API_URL = "https://api.telegram.org/bot"; private static final String TOKENREGEX = "^\\d{4,10}:[\\w-]{12,64}$"; private static final int TELEGRAMFILESIZELIMIT = 20000000;//20MB filesize https://core.telegram.org/bots/api#sending-files - public static final String APIVERSION = "3.8";//May 18, 2019 + public static final String APIVERSION = "3.9";//Feb 29, 2020 private int msg_offset = 0; private int updateInterval = 60; @@ -69,6 +65,8 @@ public class TelegramAPI implements Runnable { private CommandManager cmdmgr = new CommandManager(this); private EventManager evntmgr = new EventManager(); + private FeedbackCommand feedbackCmd; + //async private AsyncHandler async = new AsyncHandler(this); public static Callback IOE400supressor = new Callback() { @@ -109,8 +107,8 @@ public class TelegramAPI implements Runnable { if(thread == null) { if(!disableFeedback) { //init Feedback - FeedbackCommand fcmd = new FeedbackCommand(); - cmdmgr.registerCommand("feedback", fcmd); + feedbackCmd = new FeedbackCommand(this, admins); + cmdmgr.registerCommand("feedback", feedbackCmd); } run = true; thread = new Thread(this, "TelegramAPI"); @@ -506,6 +504,10 @@ public class TelegramAPI implements Runnable { } else { e = new UserSendMessageEvent(getMsg()); + //call feedback cmd first + if(feedbackCmd.onMsg((UserSendMessageEvent) e)) { + e = null; + } } getEventManager().callEvent(e); } @@ -516,7 +518,10 @@ public class TelegramAPI implements Runnable { String data = cbq.getString("data"); String id = cbq.getString("id"); TMessage msg = new TMessage(cbq.getJSONObject("message"), api); - getEventManager().callEvent(new UserCallbackEvent(from, data, id, msg)); + UserCallbackEvent event = new UserCallbackEvent(from, data, id, msg); + + if(!feedbackCmd.onCallback(event)) + getEventManager().callEvent(event); } } diff --git a/src/main/java/de/mrbesen/telegram/commands/FeedbackCommand.java b/src/main/java/de/mrbesen/telegram/commands/FeedbackCommand.java index 0545d52..3c84915 100644 --- a/src/main/java/de/mrbesen/telegram/commands/FeedbackCommand.java +++ b/src/main/java/de/mrbesen/telegram/commands/FeedbackCommand.java @@ -1,6 +1,5 @@ package de.mrbesen.telegram.commands; -import com.sun.istack.internal.Nullable; import de.mrbesen.telegram.AsyncHandler; import de.mrbesen.telegram.MessageBuilder; import de.mrbesen.telegram.TelegramAPI; @@ -10,36 +9,41 @@ import de.mrbesen.telegram.objects.TInlineKeyboardMarkup; import de.mrbesen.telegram.objects.TMessage; import de.mrbesen.telegram.objects.TUser; -import java.util.*; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.TreeMap; public class FeedbackCommand implements JSONCommandHandler { - protected final TInlineKeyboardMarkup cancel = new TInlineKeyboardMarkup(1); + protected final TInlineKeyboardMarkup cancelMarkup = new TInlineKeyboardMarkup(1); protected final Map awaitingFeedback = new TreeMap<>(); //maps users chat id -> message that said "please send feedback" TODO: make persistent? + protected final Map awnser = new TreeMap<>(); // chatid -> [chatid, messageid] to awnser to; next message from key will be fwd to value[0] and reply to value[1] protected final TelegramAPI api; - protected final Collection admins; + protected final List admins; protected final static String CANCELFEEDBACK = "cancelfeedback", REPLYFEEDBACK = "replyFeedback "; - public FeedbackCommand(TelegramAPI api, Collection admins) { + public FeedbackCommand(TelegramAPI api, List admins) { this.api = api; - this.admins = admins; + this.admins = (admins == null ? new LinkedList<>() : admins); + //build markup - cancel.addCallbackButton("❌ cancel", CANCELFEEDBACK, 0); - api.getEventManager().registerEvent(UserSendMessageEvent.class, this::onMsg); - api.getEventManager().registerEvent(UserCallbackEvent.class, this::onCallback); + cancelMarkup.addCallbackButton("❌ cancel", CANCELFEEDBACK, 1); } @Override public boolean onCommand(TUser sender, String cmd, String[] args, TMessage json) { + if(json.getChatID() < 0) return false; //do not handle group chats + if(cmd.equalsIgnoreCase("feedback")) { removeMsg(sender.getID(), null); awaitingFeedback.put(sender.getID(), null); MessageBuilder mb = new MessageBuilder(); - mb.setAsync().setMarkup(cancel).setText("Your next Message will be forwarded to the admins.") + mb.setAsync().setReciver(sender).setMarkup(cancelMarkup).setText("Your next Message will be forwarded to the admins.") .setCallback(new AsyncHandler.Callback() { @Override - public Object call(TMessage msg) throws Throwable { + public Object call(TMessage msg) { awaitingFeedback.put(sender.getID(), msg); return null; } @@ -50,48 +54,98 @@ public class FeedbackCommand implements JSONCommandHandler { return false; } - public void onMsg(Object event) { - UserSendMessageEvent e = (UserSendMessageEvent) event; + public boolean onMsg(UserSendMessageEvent e) { TUser user = e.getUser(); TMessage msg = e.getMessage(); - if(isFeedback(msg.getText())) { - if (awaitingFeedback.containsKey(user.getID())) { - removeMsg(user.getID(), e.getMessage()); - + System.out.println("msg: " + msg.getText()); + if (awaitingFeedback.containsKey(user.getID())) { + removeMsg(user.getID(), e.getMessage()); + if(isFeedback(msg.getText())) { //fwd to admins admins.forEach(a -> TMessage.forwardAsync(api, a, msg)); - StringBuilder info = new StringBuilder("Feedbackinfo:\n"); - info.append("userid: ").append(user.getID()); - info.append("\nusername: ").append(user.getName()); - info.append("\nfullname: ").append(user.getFirstName()).append(' ').append(user.getLastName()); - TInlineKeyboardMarkup markup = new TInlineKeyboardMarkup(1); - markup.addUrlButton("chat with user", "tg://" + user.getName(), 1); - markup.addCallbackButton("reply ↩", REPLYFEEDBACK + user.getID() + " " + msg.getMessageID(), 1); - admins.forEach(a -> api.sendAsync(a, info.toString())); + MessageBuilder mb = createInfo(user, msg.getMessageID()); + admins.forEach(a -> api.sendMessage(mb.setReciver(a).build())); + } else { + System.out.println("feedback omitted: " + msg.getText()); + } + return true; + } else { + Long[] rplymsg = awnser.remove(user.getID()); + if(rplymsg != null) { + if(admins.contains(user.getID())) { + System.out.println("is admin!"); + //admin to user -> copy text send as new msg from bot to disguise admin + TInlineKeyboardMarkup mu = new TInlineKeyboardMarkup(1); + mu.addCallbackButton("↩ reply", buildRplyCallback(user.getID(), msg.getMessageID()), 1); + + MessageBuilder mb = new MessageBuilder().setAsync().setReciver(rplymsg[0]) + .setReplyTo(Math.toIntExact(rplymsg[1])).setText(msg.getText()).setMarkup(mu); + api.sendMessage(mb.build()); + + awnser.put(rplymsg[0], new Long[]{user.getID(), Long.valueOf(msg.getMessageID())}); + } else { + System.out.println("is user!"); + //user to admin -> fwd message + TMessage.forwardAsync(api, rplymsg[0], msg); + + //send info + MessageBuilder mb = createInfo(user, msg.getMessageID()); + api.sendMessage(mb.setReciver(rplymsg[0]).setReplyTo(Math.toIntExact(rplymsg[1])).build()); + } + System.out.println("Feedback reply from " + user.getID() + " to " + rplymsg[0] + ":" + rplymsg[1] + " send."); + return true; } } + return false; } - public void onCallback(Object event) { - UserCallbackEvent e = (UserCallbackEvent) event; + protected MessageBuilder createInfo(TUser u, int msgid) { + String info = "Feedbackinfo:\n" + "userid: " + u.getID() + "\nusername: " + u.getName() + "\nfullname: " + u.getFirstName() + ' ' + u.getLastName(); + TInlineKeyboardMarkup markup = new TInlineKeyboardMarkup(1); + markup.addUrlButton("chat with user", "https://t.me/" + u.getName(), 1); + markup.addCallbackButton("↩ reply", buildRplyCallback(u.getID(), msgid), 1); + return new MessageBuilder().setAsync().setText(info).setMarkup(markup); + } + + public boolean onCallback(UserCallbackEvent e) { if(e.getData().equals(CANCELFEEDBACK)) { removeMsg(e.getUser().getID(), e.getMsg()); api.answerCallbackQuery(e.getID(), "Cancelled", true); + return true; } else if(e.getData().startsWith(REPLYFEEDBACK)) { String rest = e.getData().substring(REPLYFEEDBACK.length()); - //TODO + long chatid = 0; + long msgid = -1; + try { + String[] spl = rest.split(" ",2); + long adminid = Long.parseLong(spl[0]); + msgid = Integer.parseInt(spl[1]); + //convert admin id to chat id + if(adminid <= 0) { + chatid = admins.get((int) -adminid); + } else + chatid = adminid; + } catch (NumberFormatException ex) { + api.answerCallbackQuery(e.getID(), "Error. Sorry :/", true); + ex.printStackTrace(); + } + if(msgid > -1) { + awnser.put(e.getUser().getID(), new Long[]{chatid, msgid}); + api.answerCallbackQuery(e.getID(), "Write a Message", true); + } + return true; } + return false; } /** * looks up msg from awaiting feedback map, if not present try to use fallback_msg * is Async * removes user from awaitingFeedback - * @param chat - * @param fallback_msg + * */ - protected void removeMsg(long chat, @Nullable TMessage fallback_msg) { + protected void removeMsg(long chat, TMessage fallback_msg) { TMessage msg = awaitingFeedback.remove(chat); if(msg == null) msg = fallback_msg; @@ -105,6 +159,20 @@ public class FeedbackCommand implements JSONCommandHandler { */ protected boolean isFeedback(String msg) { msg = msg.trim(); - return !msg.startsWith("/") && msg.length() > 5 && !msg.startsWith("http"); + return (!msg.startsWith("/")) && (msg.length() > 5) && (!msg.startsWith("http")); + } + + protected int getAdminID(long adminchat) { + for(int i = 0; i < admins.size(); i++) { + if(admins.get(i) == adminchat) + return i; + } + return -1; + } + + protected String buildRplyCallback(long user, int msgid) { + int adminid = getAdminID(user); + if(adminid >= 0) user = -adminid; + return REPLYFEEDBACK + user + " " + msgid; } } diff --git a/src/main/java/de/mrbesen/telegram/event/EventManager.java b/src/main/java/de/mrbesen/telegram/event/EventManager.java index 89f5da7..4542907 100644 --- a/src/main/java/de/mrbesen/telegram/event/EventManager.java +++ b/src/main/java/de/mrbesen/telegram/event/EventManager.java @@ -1,9 +1,5 @@ package de.mrbesen.telegram.event; -import de.mrbesen.telegram.TelegramAPI; - -import java.lang.reflect.Array; -import java.lang.reflect.Method; import java.util.ArrayList; import java.util.HashMap; import java.util.function.Consumer; @@ -33,8 +29,8 @@ public class EventManager { } public Event callEvent(Event e) { - if(e == null) - throw new NullPointerException("event is not allowed to be null!"); + if(e == null) return e; + ArrayList listner = listeners.get(e.getClass()); if(listner != null) { for (Consumer listn : listner) {