From bf5f2142d73a5745124d03f6b6f06c59873e47de Mon Sep 17 00:00:00 2001 From: Vitaly Takmazov Date: Wed, 27 Dec 2017 16:23:28 +0300 Subject: Messenger bot --- .../src/main/java/com/juick/api/MessengerBot.java | 33 ----- .../main/java/com/juick/api/MessengerManager.java | 143 +++++++++++++++++++++ .../juick/api/configuration/ApiInitializer.java | 2 +- .../api/configuration/MessengerConfiguration.java | 39 ------ .../juick/api/controllers/MessengerWebhook.java | 11 +- 5 files changed, 150 insertions(+), 78 deletions(-) delete mode 100644 juick-api/src/main/java/com/juick/api/MessengerBot.java create mode 100644 juick-api/src/main/java/com/juick/api/MessengerManager.java delete mode 100644 juick-api/src/main/java/com/juick/api/configuration/MessengerConfiguration.java (limited to 'juick-api/src') diff --git a/juick-api/src/main/java/com/juick/api/MessengerBot.java b/juick-api/src/main/java/com/juick/api/MessengerBot.java deleted file mode 100644 index 8a568c42..00000000 --- a/juick-api/src/main/java/com/juick/api/MessengerBot.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright (C) 2008-2017, 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 . - */ - -package com.juick.api; - -/** - * Created by vitalyster on 27.03.2017. - */ -public class MessengerBot { - private String verifyToken; - - public String getVerifyToken() { - return verifyToken; - } - - public void setVerifyToken(String verifyToken) { - this.verifyToken = verifyToken; - } -} diff --git a/juick-api/src/main/java/com/juick/api/MessengerManager.java b/juick-api/src/main/java/com/juick/api/MessengerManager.java new file mode 100644 index 00000000..9587dc11 --- /dev/null +++ b/juick-api/src/main/java/com/juick/api/MessengerManager.java @@ -0,0 +1,143 @@ +package com.juick.api; + +import com.github.messenger4j.Messenger; +import com.github.messenger4j.exception.MessengerApiException; +import com.github.messenger4j.exception.MessengerIOException; +import com.github.messenger4j.exception.MessengerVerificationException; +import com.github.messenger4j.send.MessagePayload; +import com.github.messenger4j.send.message.TemplateMessage; +import com.github.messenger4j.send.message.TextMessage; +import com.github.messenger4j.send.message.template.ButtonTemplate; +import com.github.messenger4j.send.message.template.button.UrlButton; +import com.github.messenger4j.userprofile.UserProfile; +import com.github.messenger4j.webhook.event.TextMessageEvent; +import com.juick.Message; +import com.juick.User; +import com.juick.server.component.MessageEvent; +import com.juick.service.MessagesService; +import com.juick.service.MessengerService; +import com.juick.service.SubscriptionService; +import com.juick.service.UserService; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.ApplicationListener; +import org.springframework.stereotype.Component; +import org.springframework.util.StringUtils; + +import javax.annotation.Nonnull; +import javax.annotation.PostConstruct; +import javax.inject.Inject; +import java.net.MalformedURLException; +import java.net.URL; +import java.time.Instant; +import java.util.Collections; +import java.util.Optional; + +import static com.juick.formatters.PlainTextFormatter.formatPost; +import static com.juick.formatters.PlainTextFormatter.formatUrl; + +@Component +public class MessengerManager implements ApplicationListener { + private static final Logger logger = LoggerFactory.getLogger(MessengerManager.class); + @Inject + private MessagesService messagesService; + @Inject + private SubscriptionService subscriptionService; + @Inject + private UserService userService; + @Inject + private MessengerService messengerService; + @Inject + private ApiServer apiServer; + + @Value("${fb_page_access_token}") + private String facebookPageAccessToken; + @Value("${fb_verify_token}") + private String facebookVerifyToken; + @Value("${fb_secret}") + private String facebookSecret; + + private Messenger messenger; + + @PostConstruct + public void init() { + messenger = Messenger.create(facebookPageAccessToken, facebookSecret, facebookVerifyToken); + } + + public String getFacebookVerifyToken() { + return facebookVerifyToken; + } + + public void processUpdate(String signature , String data) throws MessengerVerificationException { + messenger.onReceiveEvents(data, Optional.of(signature), event -> { + final String senderId = event.senderId(); + final Instant timestamp = event.timestamp(); + + User user_from = userService.getUserByUID(messengerService.getUserId(senderId)).orElse(new User()); + logger.info("Found juick user {}", user_from.getUid()); + if (user_from.getUid() == 0) { + try { + UserProfile profile = messenger.queryUserProfile(senderId); + signupNotify(senderId, messengerService.getSignUpHash(senderId, profile.firstName())); + } catch (MessengerApiException | MessengerIOException | MalformedURLException e) { + logger.warn("messenger profile error", e); + try { + signupNotify(senderId, messengerService.getSignUpHash(senderId, "anonymous")); + } catch (MalformedURLException | MessengerApiException | MessengerIOException e1) { + logger.warn("signup error", e1); + } + } + } else { + if (event.isTextMessageEvent()) { + final TextMessageEvent textMessageEvent = event.asTextMessageEvent(); + final String messageId = textMessageEvent.messageId(); + final String text = textMessageEvent.text(); + logger.info("Received text message from '{}' at '{}' with content: {} (mid: {})", + senderId, timestamp, text, messageId); + apiServer.processMessage(user_from, text, null); + messengerNotify(senderId, "Message sent", null); + } + } + }); + } + + @Override + public void onApplicationEvent(@Nonnull MessageEvent event) { + Message msg = event.getMessage(); + if (msg.getRid() == 0) { + String subject = formatPost(msg); + subscriptionService.getSubscribedUsers(msg.getUser().getUid(), msg.getMid()) + .forEach(user -> messengerService.getSenderId(user) + .ifPresent(t -> messengerNotify(t, subject, formatUrl(msg)))); + } else { + // get quote + com.juick.Message jmsg = messagesService.getReply(msg.getMid(), msg.getRid()); + String subject = formatPost(jmsg); + subscriptionService.getUsersSubscribedToComments(msg.getMid(), msg.getUser().getUid()) + .forEach(user -> messengerService.getSenderId(user) + .ifPresent(t -> messengerNotify(t, subject, formatUrl(jmsg)))); + } + } + + void messengerNotify(String messengerUser, String text, String url) { + try { + if (!StringUtils.isEmpty(url)) { + final UrlButton showMessage = UrlButton.create("VIEW MESSAGE", new URL(url)); + ButtonTemplate template = ButtonTemplate.create(text, Collections.singletonList(showMessage)); + messenger.send(MessagePayload.create(messengerUser, TemplateMessage.create(template))); + } else { + messenger.send(MessagePayload.create(messengerUser, TextMessage.create(text))); + } + } catch (MessengerApiException | MessengerIOException | MalformedURLException e) { + logger.warn("messenger error", e); + } + } + void signupNotify(String messengerUser, String hash) throws MalformedURLException, MessengerApiException, MessengerIOException { + final UrlButton urlButton = UrlButton.create("LOGIN", + new URL("https://juick.com/signup?type=messenger&hash=" + hash)); + ButtonTemplate template = ButtonTemplate.create("Login to receive notifications", + Collections.singletonList(urlButton)); + messenger.send(MessagePayload.create(messengerUser, TemplateMessage.create(template))); + } +} diff --git a/juick-api/src/main/java/com/juick/api/configuration/ApiInitializer.java b/juick-api/src/main/java/com/juick/api/configuration/ApiInitializer.java index 3380df10..32a88a0c 100644 --- a/juick-api/src/main/java/com/juick/api/configuration/ApiInitializer.java +++ b/juick-api/src/main/java/com/juick/api/configuration/ApiInitializer.java @@ -43,7 +43,7 @@ public class ApiInitializer extends AbstractAnnotationConfigDispatcherServletIni @Override protected Class[] getServletConfigClasses() { - return new Class[]{ MessengerConfiguration.class }; + return null; } @Override diff --git a/juick-api/src/main/java/com/juick/api/configuration/MessengerConfiguration.java b/juick-api/src/main/java/com/juick/api/configuration/MessengerConfiguration.java deleted file mode 100644 index a9f07af4..00000000 --- a/juick-api/src/main/java/com/juick/api/configuration/MessengerConfiguration.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright (C) 2008-2017, 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 . - */ - -package com.juick.api.configuration; - -import com.juick.api.MessengerBot; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; - -/** - * Created by vital on 28.03.2017. - */ -@Configuration -public class MessengerConfiguration { - @Value("${fb_verify_token}") - private String messengerBotVerifyToken; - - @Bean - public MessengerBot fbBot() { - MessengerBot bot = new MessengerBot(); - bot.setVerifyToken(messengerBotVerifyToken); - return bot; - } -} diff --git a/juick-api/src/main/java/com/juick/api/controllers/MessengerWebhook.java b/juick-api/src/main/java/com/juick/api/controllers/MessengerWebhook.java index fa57c017..835165ba 100644 --- a/juick-api/src/main/java/com/juick/api/controllers/MessengerWebhook.java +++ b/juick-api/src/main/java/com/juick/api/controllers/MessengerWebhook.java @@ -17,7 +17,8 @@ package com.juick.api.controllers; -import com.juick.api.MessengerBot; +import com.github.messenger4j.exception.MessengerVerificationException; +import com.juick.api.MessengerManager; import com.juick.server.util.HttpForbiddenException; import org.apache.commons.io.IOUtils; import org.slf4j.Logger; @@ -41,21 +42,21 @@ public class MessengerWebhook { private static Logger logger = LoggerFactory.getLogger(MessengerWebhook.class); @Inject - MessengerBot fbBot; + private MessengerManager messengerManager; @RequestMapping(value = "/fbwbhk", method = RequestMethod.GET) public ResponseEntity verifyHook(@RequestParam(name = "hub.mode") String hubMode, @RequestParam(name = "hub.challenge") Integer hubChallenge, @RequestParam(name = "hub.verify_token") String verifyToken) { - if (hubMode.equals("subscribe") && verifyToken.equals(fbBot.getVerifyToken())) { + if (hubMode.equals("subscribe") && verifyToken.equals(messengerManager.getFacebookVerifyToken())) { return new ResponseEntity<>(hubChallenge, HttpStatus.OK); } throw new HttpForbiddenException(); } @RequestMapping(value = "/fbwbhk", method = RequestMethod.POST) @ResponseStatus(value = HttpStatus.OK) - public void processUpdate(InputStream body) throws IOException { + public void processUpdate(@RequestHeader(name = "X-Hub-Signature", required = false) String signature, InputStream body) throws IOException, MessengerVerificationException { String data = IOUtils.toString(body, StandardCharsets.UTF_8); - logger.info("got data: {}", data); + messengerManager.processUpdate(signature, data); } } -- cgit v1.2.3