diff --git a/pom.xml b/pom.xml index 6016751..75179ea 100644 --- a/pom.xml +++ b/pom.xml @@ -42,6 +42,11 @@ 20180813 compile + + org.projectlombok + lombok + LATEST + 1.8 diff --git a/src/main/java/de/mrbesen/telegram/TelegramAPI.java b/src/main/java/de/mrbesen/telegram/TelegramAPI.java index eb4a993..3e4b99b 100644 --- a/src/main/java/de/mrbesen/telegram/TelegramAPI.java +++ b/src/main/java/de/mrbesen/telegram/TelegramAPI.java @@ -6,11 +6,15 @@ 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; @@ -33,6 +37,7 @@ 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; public class TelegramAPI implements Runnable { @@ -47,14 +52,10 @@ public class TelegramAPI implements Runnable { private String botname; private Thread thread; private boolean run = true; + @Getter @Setter private boolean longpolling = true; - public boolean isLongpolling() { - return longpolling; - } - - public void setLongpolling(boolean longpolling) { - this.longpolling = longpolling; - } + @Setter @Getter + private boolean disableFeedback = false; private String helpmessage = "generic helppage\nuse TelegramAPI.setHelpText(java.lang.String) to change this."; @@ -63,6 +64,8 @@ public class TelegramAPI implements Runnable { protected long start = 0; private LinkedList users = new LinkedList<>(); + @Setter + private List admins = new LinkedList<>(); //required for feedback private CommandManager cmdmgr = new CommandManager(this); private EventManager evntmgr = new EventManager(); @@ -104,6 +107,11 @@ public class TelegramAPI implements Runnable { public void start() { if(thread == null) { + if(!disableFeedback) { + //init Feedback + FeedbackCommand fcmd = new FeedbackCommand(); + cmdmgr.registerCommand("feedback", fcmd); + } run = true; thread = new Thread(this, "TelegramAPI"); thread.start(); @@ -112,6 +120,10 @@ public class TelegramAPI implements Runnable { } } + public void addAdmin(long admin) { + admins.add(admin); + } + public void request(Task task) { async.enque(task); } diff --git a/src/main/java/de/mrbesen/telegram/commands/FeedbackCommand.java b/src/main/java/de/mrbesen/telegram/commands/FeedbackCommand.java new file mode 100644 index 0000000..0545d52 --- /dev/null +++ b/src/main/java/de/mrbesen/telegram/commands/FeedbackCommand.java @@ -0,0 +1,110 @@ +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; +import de.mrbesen.telegram.event.events.UserCallbackEvent; +import de.mrbesen.telegram.event.events.UserSendMessageEvent; +import de.mrbesen.telegram.objects.TInlineKeyboardMarkup; +import de.mrbesen.telegram.objects.TMessage; +import de.mrbesen.telegram.objects.TUser; + +import java.util.*; + +public class FeedbackCommand implements JSONCommandHandler { + + protected final TInlineKeyboardMarkup cancel = new TInlineKeyboardMarkup(1); + protected final Map awaitingFeedback = new TreeMap<>(); //maps users chat id -> message that said "please send feedback" TODO: make persistent? + protected final TelegramAPI api; + protected final Collection admins; + protected final static String CANCELFEEDBACK = "cancelfeedback", REPLYFEEDBACK = "replyFeedback "; + + + public FeedbackCommand(TelegramAPI api, Collection admins) { + this.api = api; + this.admins = admins; + //build markup + cancel.addCallbackButton("❌ cancel", CANCELFEEDBACK, 0); + api.getEventManager().registerEvent(UserSendMessageEvent.class, this::onMsg); + api.getEventManager().registerEvent(UserCallbackEvent.class, this::onCallback); + } + + @Override + public boolean onCommand(TUser sender, String cmd, String[] args, TMessage json) { + 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.") + .setCallback(new AsyncHandler.Callback() { + @Override + public Object call(TMessage msg) throws Throwable { + awaitingFeedback.put(sender.getID(), msg); + return null; + } + }); + api.sendMessage(mb.build()); + return true; + } + return false; + } + + public void onMsg(Object event) { + UserSendMessageEvent e = (UserSendMessageEvent) event; + TUser user = e.getUser(); + TMessage msg = e.getMessage(); + if(isFeedback(msg.getText())) { + if (awaitingFeedback.containsKey(user.getID())) { + removeMsg(user.getID(), e.getMessage()); + + //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())); + } + } + } + + public void onCallback(Object event) { + UserCallbackEvent e = (UserCallbackEvent) event; + if(e.getData().equals(CANCELFEEDBACK)) { + removeMsg(e.getUser().getID(), e.getMsg()); + api.answerCallbackQuery(e.getID(), "Cancelled", true); + } else if(e.getData().startsWith(REPLYFEEDBACK)) { + String rest = e.getData().substring(REPLYFEEDBACK.length()); + //TODO + } + } + + /** + * 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) { + TMessage msg = awaitingFeedback.remove(chat); + if(msg == null) msg = fallback_msg; + + if(msg != null) TMessage.delete(api, msg.getChatID(), msg.getMessageID(), true); + } + + /** + * check if a message is allowed as feedback + * @param msg + * @return + */ + protected boolean isFeedback(String msg) { + msg = msg.trim(); + return !msg.startsWith("/") && msg.length() > 5 && !msg.startsWith("http"); + } +} diff --git a/src/main/java/de/mrbesen/telegram/objects/TUser.java b/src/main/java/de/mrbesen/telegram/objects/TUser.java index 70842eb..2f834cf 100644 --- a/src/main/java/de/mrbesen/telegram/objects/TUser.java +++ b/src/main/java/de/mrbesen/telegram/objects/TUser.java @@ -1,5 +1,6 @@ package de.mrbesen.telegram.objects; +import lombok.Getter; import org.json.JSONObject; import de.mrbesen.telegram.AsyncHandler.Callback; @@ -9,48 +10,44 @@ import de.mrbesen.telegram.TelegramAPI; public class TUser { - private long id; + @Getter + private long ID; private String uname;//optional - private String firstname; - private String lastname;//optional + @Getter + private String firstName; + @Getter + private String lastName;//optional + @Getter private String langcode; // optional private boolean isBot = false; private TelegramAPI api = null; TUser(long chatid, String uname, TelegramAPI api) { - this.id = chatid; + this.ID = chatid; this.uname = uname; this.api = api; } public TUser(long chatid, TelegramAPI api) { this.api = api; - this.id = chatid; + this.ID = chatid; } public TUser(JSONObject o, TelegramAPI api) { this.api = api; - firstname = o.getString("first_name"); + firstName = o.getString("first_name"); isBot = o.getBoolean("is_bot"); - id = o.getLong("id"); + ID = o.getLong("id"); if(o.has("last_name")) - lastname = o.getString("last_name"); + lastName = o.getString("last_name"); if(o.has("username")) uname = o.getString("username"); if(o.has("language_code")) langcode = o.getString("language_code"); } - public String getFirstName() { - return firstname; - } - - public String getLastName() { - return lastname; - } - public String getLangcode() { return langcode; } @@ -59,10 +56,6 @@ public class TUser { return isBot; } - public long getID() { - return id; - } - public String getName() { return uname; } @@ -76,7 +69,7 @@ public class TUser { } public boolean sendMessage(String text, TReplyMarkup rm, int reply_to_msg) { - return sendMessage(api, id, text, rm, reply_to_msg, false, null); + return sendMessage(api, ID, text, rm, reply_to_msg, false, null); } /** @@ -100,14 +93,14 @@ public class TUser { public void sendStatus(Status status) { try { - api.request("sendChatAction", "chat_id="+id+"&action=" + status.getAPIName()); + api.request("sendChatAction", "chat_id="+ ID +"&action=" + status.getAPIName()); } catch (Exception e) { System.err.println("Failed to send status."); } } public boolean sendImage(String caption, String url) { - return sendImage(api, id, caption, url, null, null) != null; + return sendImage(api, ID, caption, url, null, null) != null; } public static TMessage sendImage(TelegramAPI api, long userid, String caption, String url, TReplyMarkup rply, Callback async) { @@ -116,7 +109,7 @@ public class TUser { } public boolean sendAnimation(String caption, String url) { - return sendAnimation(api, id, caption, url, null, null) != null; + return sendAnimation(api, ID, caption, url, null, null) != null; } public static TMessage sendAnimation(TelegramAPI api, long userid, String caption, String url, TReplyMarkup rply, Callback async) { @@ -127,7 +120,7 @@ public class TUser { @Override public boolean equals(Object user) { if(user instanceof TUser) { - return ((TUser) user).getID() == id; + return ((TUser) user).getID() == ID; } return false; }