diff options
52 files changed, 395 insertions, 451 deletions
diff --git a/juick-api/build.gradle b/juick-api/build.gradle new file mode 100644 index 00000000..2899529a --- /dev/null +++ b/juick-api/build.gradle @@ -0,0 +1,7 @@ +apply plugin: 'java' + +dependencies { + compile project(':juick-common') + compile project(':juick-server-jdbc') + compile 'org.apache.commons:commons-email:1.5' +}
\ No newline at end of file diff --git a/juick-server/src/main/java/com/juick/server/api/Post.java b/juick-api/src/main/java/com/juick/server/api/Post.java index 486e9c0f..5757db09 100644 --- a/juick-server/src/main/java/com/juick/server/api/Post.java +++ b/juick-api/src/main/java/com/juick/server/api/Post.java @@ -21,17 +21,12 @@ import com.juick.Reaction; import com.juick.Status; import com.juick.User; import com.juick.server.CommandsManager; -import com.juick.server.EmailManager; -import com.juick.server.XMPPConnection; import com.juick.server.helpers.CommandResult; import com.juick.server.util.*; import com.juick.service.MessagesService; import com.juick.service.SubscriptionService; import com.juick.service.UserService; -import org.apache.commons.codec.digest.DigestUtils; -import org.apache.commons.io.IOUtils; import org.apache.commons.lang3.StringUtils; -import org.apache.commons.mail.util.MimeMessageParser; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Value; @@ -39,21 +34,12 @@ import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; import org.springframework.web.bind.annotation.*; import org.springframework.web.multipart.MultipartFile; -import springfox.documentation.annotations.ApiIgnore; import javax.inject.Inject; -import javax.mail.Session; -import javax.mail.internet.InternetAddress; -import javax.mail.internet.MimeMessage; import javax.validation.constraints.NotNull; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; import java.net.URI; import java.net.URL; -import java.nio.charset.StandardCharsets; -import java.nio.file.Paths; -import java.util.*; +import java.util.List; /** * Created by vt on 24/11/2016. @@ -65,8 +51,6 @@ public class Post { @Inject private UserService userService; @Inject - private XMPPConnection xmppConnection; - @Inject private MessagesService messagesService; @Inject private SubscriptionService subscriptionService; @@ -74,15 +58,13 @@ public class Post { private String tmpDir; @Value("${img_path:#{systemEnvironment['TEMP'] ?: '/tmp'}}") private String imgDir; - @Value("${api_user:juick}") - private String serviceUser; @Inject CommandsManager commandsManager; @RequestMapping(value = "/post", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_UTF8_VALUE) @ResponseStatus(value = HttpStatus.OK) - public void doPostMessage( - @RequestParam String body, + public CommandResult doPostMessage( + @RequestParam(required = false, defaultValue = StringUtils.EMPTY) String body, @RequestParam(required = false) String img, @RequestParam(required = false) MultipartFile attach) throws Exception { User visitor = UserUtils.getCurrentUser(); @@ -90,7 +72,7 @@ public class Post { if (visitor.isAnonymous()) throw new HttpForbiddenException(); - if (body == null || body.length() < 1 || body.length() > 4096) { + if (body.length() > 4096) { throw new HttpBadRequestException(); } body = body.replace("\r", StringUtils.EMPTY); @@ -98,26 +80,27 @@ public class Post { URI attachmentFName = HttpUtils.receiveMultiPartFile(attach, tmpDir); if (StringUtils.isBlank(attachmentFName.toString()) && img != null && img.length() > 10) { - try { - URL imgUrl = new URL(img); - attachmentFName = HttpUtils.downloadImage(imgUrl, tmpDir); - } catch (Exception e) { - logger.error("DOWNLOAD ERROR", e); - throw new HttpBadRequestException(); + URI juickUri = URI.create(img); + if (juickUri.getScheme().equals("juick")) { + attachmentFName = juickUri; + } else { + try { + URL imgUrl = new URL(img); + attachmentFName = HttpUtils.downloadImage(imgUrl, tmpDir); + } catch (Exception e) { + logger.error("DOWNLOAD ERROR", e); + throw new HttpBadRequestException(); + } } } - commandsManager.processCommand(visitor, body, attachmentFName); - } - @PostMapping("/upload") - public String doUploadFile(@RequestParam(required = true) MultipartFile attach) { - return HttpUtils.receiveMultiPartFile(attach, tmpDir).toString(); + return commandsManager.processCommand(visitor, body, attachmentFName); } @RequestMapping(value = "/comment", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_UTF8_VALUE) public com.juick.Message doPostComment( @RequestParam(defaultValue = "0") int mid, @RequestParam(defaultValue = "0") int rid, - @RequestParam String body, + @RequestParam(required = false, defaultValue = StringUtils.EMPTY) String body, @RequestParam(required = false) String img, @RequestParam(required = false) MultipartFile attach) throws Exception { @@ -142,7 +125,7 @@ public class Post { } } - if (body == null || body.length() < 1 || body.length() > 4096) { + if (body.length() > 4096) { throw new HttpBadRequestException(); } body = body.replace("\r", StringUtils.EMPTY); @@ -166,76 +149,6 @@ public class Post { return commandsManager.processCommand(visitor, String.format("#%d/%d %s", mid, rid, body), attachmentFName).getNewMessage().get(); } - Session session = Session.getDefaultInstance(new Properties()); - - @ApiIgnore - @PostMapping("/mail") - @ResponseStatus(value = HttpStatus.OK) - public void processMail(InputStream data) throws Exception { - if (UserUtils.getCurrentUser().getName().equals(serviceUser)) { - MimeMessage msg = new MimeMessage(session, data); - logger.info("got msg {}", msg.toString()); - String from = msg.getFrom() == null || msg.getFrom().length > 1 ? ((InternetAddress) msg.getSender()).getAddress() - : ((InternetAddress) msg.getFrom()[0]).getAddress(); - - User visitor = userService.getUserByEmail(from); - if (!visitor.isAnonymous()) { - MimeMessageParser parser = new MimeMessageParser(msg); - parser.parse(); - final String[] body = {parser.getPlainContent()}; - if (body[0] == null) { - parser.getAttachmentList().stream() - .filter(a -> a.getContentType().equals("text/plain")).findFirst() - .ifPresent(a -> { - try { - body[0] = IOUtils.toString(a.getInputStream(), StandardCharsets.UTF_8); - logger.info("got text: {}", body[0]); - } catch (IOException e) { - logger.info("attachment error: {}", e); - } - }); - } - final String[] attachmentFName = new String[1]; - parser.getAttachmentList().stream().filter(a -> - a.getContentType().equals("image/jpeg") || a.getContentType().equals("image/png")) - .findFirst().ifPresent(a -> { - logger.info("got attachment: {}", a.getContentType()); - String attachmentType; - if (a.getContentType().equals("image/jpeg")) { - attachmentType = "jpg"; - } else { - attachmentType = "png"; - } - attachmentFName[0] = DigestUtils.md5Hex(UUID.randomUUID().toString()) + "." + attachmentType; - try { - logger.info("got inputstream: {}", a.getInputStream()); - FileOutputStream fos = new FileOutputStream(Paths.get(tmpDir, attachmentFName[0]).toString()); - IOUtils.copy(a.getInputStream(), fos); - fos.close(); - } catch (IOException e) { - logger.info("attachment error: {}", e); - } - }); - String[] inReplyToHeaders = msg.getHeader("In-Reply-To"); - if (inReplyToHeaders != null && inReplyToHeaders.length > 0) { - Scanner inReplyToScanner = new Scanner(inReplyToHeaders[0].trim()).useDelimiter(EmailManager.MSGID_PATTERN); - int mid = Integer.parseInt(inReplyToScanner.next()); - int rid = Integer.parseInt(inReplyToScanner.next()); - logger.info("Message is reply to #{}/{}", mid, rid); - body[0] = rid > 0 ? String.format("#%d/%d %s", mid, rid, body[0]) - : String.format("#%d %s", mid, body[0]); - } - URI attachmentUri = StringUtils.isNotEmpty(attachmentFName[0]) ? URI.create(String.format("juick://%s", attachmentFName[0])) - : URI.create(StringUtils.EMPTY); - commandsManager.processCommand(visitor, body[0], attachmentUri); - } else { - logger.info("not registered: {}", from); - } - } else { - throw new HttpForbiddenException(); - } - } - @PostMapping("/like") @ResponseStatus(value = HttpStatus.OK) public Status doPostRecomm(@RequestParam Integer mid) throws Exception { diff --git a/juick-server/src/main/java/com/juick/server/configuration/ApiSecurityConfig.java b/juick-api/src/main/java/com/juick/server/configuration/ApiSecurityConfig.java index a065f79e..3809090e 100644 --- a/juick-server/src/main/java/com/juick/server/configuration/ApiSecurityConfig.java +++ b/juick-api/src/main/java/com/juick/server/configuration/ApiSecurityConfig.java @@ -94,7 +94,7 @@ public class ApiSecurityConfig extends WebSecurityConfigurerAdapter { } @Bean - public RememberMeServices rememberMeServices() throws Exception { + public RememberMeServices rememberMeServices() { return new RequestParamHashRememberMeServices(rememberMeKey, userService); } diff --git a/juick-api/src/main/java/com/juick/server/configuration/PostConfig.java b/juick-api/src/main/java/com/juick/server/configuration/PostConfig.java new file mode 100644 index 00000000..598a7435 --- /dev/null +++ b/juick-api/src/main/java/com/juick/server/configuration/PostConfig.java @@ -0,0 +1,9 @@ +package com.juick.server.configuration; + +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.context.annotation.ComponentScan; + +@EnableAutoConfiguration +@ComponentScan({"com.juick.server", "com.juick.service"}) +public class PostConfig { +} diff --git a/juick-common/build.gradle b/juick-common/build.gradle index 39061697..bb21aee7 100644 --- a/juick-common/build.gradle +++ b/juick-common/build.gradle @@ -5,8 +5,10 @@ dependencies { compile("org.springframework.boot:spring-boot-starter-security") compile("org.springframework.boot:spring-boot-starter-web") compile("org.springframework.boot:spring-boot-starter-websocket") + compile("org.springframework.boot:spring-boot-starter-json") compile "org.apache.commons:commons-lang3:3.7" compile "org.apache.commons:commons-collections4:4.1" + compile 'org.apache.commons:commons-text:1.3' compile "commons-codec:commons-codec:1.11" compile "commons-io:commons-io:2.6" compile 'com.google.code.findbugs:jsr305:3.0.2' @@ -15,14 +17,6 @@ dependencies { compile "org.apache.commons:commons-imaging:1.0-SNAPSHOT" runtime "commons-fileupload:commons-fileupload:1.3.3" - compile ('com.github.juick:com.juick.xmpp:658f8cf751') { - exclude group: 'xmlpull' - } - compile 'xpp3:xpp3:1.1.4c' - - compile "rocks.xmpp:xmpp-core-client:0.7.5" - compile "rocks.xmpp:xmpp-extensions-client:0.7.5" - compile "javax.inject:javax.inject:1" compile "javax.xml.bind:jaxb-api:2.3.0" compile 'org.glassfish.jaxb:jaxb-runtime:2.3.0' diff --git a/juick-common/src/main/java/com/juick/server/configuration/BaseWebConfiguration.java b/juick-common/src/main/java/com/juick/server/configuration/BaseWebConfiguration.java index 5880fd5c..9063e665 100644 --- a/juick-common/src/main/java/com/juick/server/configuration/BaseWebConfiguration.java +++ b/juick-common/src/main/java/com/juick/server/configuration/BaseWebConfiguration.java @@ -21,22 +21,13 @@ import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.datatype.jdk8.Jdk8Module; import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; -import com.juick.server.xmpp.JidConverter; -import com.juick.server.xmpp.iq.MessageQuery; -import com.juick.server.xmpp.s2s.BasicXmppSession; -import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.core.convert.ConversionService; -import org.springframework.format.support.DefaultFormattingConversionService; import org.springframework.scheduling.annotation.SchedulingConfigurer; import org.springframework.scheduling.config.ScheduledTaskRegistrar; import org.springframework.web.servlet.config.annotation.PathMatchConfigurer; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; import org.springframework.web.servlet.resource.ResourceUrlEncodingFilter; -import rocks.xmpp.core.session.Extension; -import rocks.xmpp.core.session.XmppSessionConfiguration; -import rocks.xmpp.core.session.debug.LogbackDebugger; import java.util.concurrent.Executor; import java.util.concurrent.ExecutorService; @@ -78,25 +69,9 @@ public class BaseWebConfiguration implements WebMvcConfigurer, SchedulingConfigu public Executor taskExecutor() { return Executors.newScheduledThreadPool(100); } - @Value("${hostname:localhost}") - private String hostname; @Bean public ExecutorService executorService() { return Executors.newCachedThreadPool(); } - @Bean - public BasicXmppSession session() { - XmppSessionConfiguration configuration = XmppSessionConfiguration.builder() - .extensions(Extension.of(com.juick.Message.class), Extension.of(MessageQuery.class)) - .debugger(LogbackDebugger.class) - .build(); - return BasicXmppSession.create(hostname, configuration); - } - @Bean - public static ConversionService conversionService() { - DefaultFormattingConversionService cs = new DefaultFormattingConversionService(); - cs.addConverter(new JidConverter()); - return cs; - } } diff --git a/juick-common/src/main/java/com/juick/server/helpers/CommandResult.java b/juick-common/src/main/java/com/juick/server/helpers/CommandResult.java index a772153b..a5baaee0 100644 --- a/juick-common/src/main/java/com/juick/server/helpers/CommandResult.java +++ b/juick-common/src/main/java/com/juick/server/helpers/CommandResult.java @@ -1,5 +1,6 @@ package com.juick.server.helpers; +import com.fasterxml.jackson.annotation.JsonInclude; import com.juick.Message; import java.util.Optional; @@ -17,7 +18,7 @@ public class CommandResult { } public Optional<Message> getNewMessage() { - return Optional.of(newMessage); + return Optional.ofNullable(newMessage); } public static CommandResult build(Message newMessage, String text, String markdown) { CommandResult result = new CommandResult(); diff --git a/juick-common/src/main/java/com/juick/server/util/HttpBadRequestException.java b/juick-common/src/main/java/com/juick/server/util/HttpBadRequestException.java index 1c3b4e66..242f2b09 100644 --- a/juick-common/src/main/java/com/juick/server/util/HttpBadRequestException.java +++ b/juick-common/src/main/java/com/juick/server/util/HttpBadRequestException.java @@ -27,6 +27,6 @@ import org.springframework.web.bind.annotation.ResponseStatus; @ResponseStatus(value = HttpStatus.BAD_REQUEST) public class HttpBadRequestException extends RuntimeException { public HttpBadRequestException() { - super(StringUtils.EMPTY, null, false, false); + super("the request was bad", null, false, false); } } diff --git a/juick-common/src/main/java/com/juick/service/BaseRestService.java b/juick-common/src/main/java/com/juick/service/BaseRestService.java deleted file mode 100644 index 13604a89..00000000 --- a/juick-common/src/main/java/com/juick/service/BaseRestService.java +++ /dev/null @@ -1,35 +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 <http://www.gnu.org/licenses/>. - */ - -package com.juick.service; - -import org.springframework.web.client.RestTemplate; - -/** - * Created by vitalyster on 15.12.2016. - */ -public abstract class BaseRestService { - private RestTemplate rest; - - public BaseRestService(RestTemplate rest) { - this.rest = rest; - } - - public RestTemplate getRest() { - return rest; - } -} diff --git a/juick-common/src/test/java/com/juick/MessageTest.java b/juick-common/src/test/java/com/juick/MessageTest.java index d3205876..7d11503d 100644 --- a/juick-common/src/test/java/com/juick/MessageTest.java +++ b/juick-common/src/test/java/com/juick/MessageTest.java @@ -17,42 +17,13 @@ package com.juick; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.datatype.jdk8.Jdk8Module; -import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; -import com.juick.util.DateFormattersHolder; import com.juick.util.MessageUtils; -import org.apache.commons.codec.CharEncoding; import org.apache.commons.lang3.RandomUtils; import org.apache.commons.lang3.StringUtils; -import org.json.JSONObject; import org.junit.Test; -import org.w3c.dom.Document; -import org.w3c.dom.NamedNodeMap; -import org.w3c.dom.Node; -import org.xml.sax.SAXException; -import rocks.xmpp.addr.Jid; -import rocks.xmpp.core.session.Extension; -import rocks.xmpp.core.session.XmppSession; -import rocks.xmpp.core.session.XmppSessionConfiguration; - -import javax.xml.bind.JAXBContext; -import javax.xml.bind.JAXBException; -import javax.xml.bind.Marshaller; -import javax.xml.bind.Unmarshaller; -import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; -import javax.xml.parsers.ParserConfigurationException; -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.io.StringReader; -import java.io.StringWriter; -import java.text.ParseException; -import java.time.Instant; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.*; -import static org.junit.Assert.assertEquals; /** * Created by aalexeev on 12/7/16. @@ -185,63 +156,4 @@ public class MessageTest { assertThat(StringUtils.countMatches(MessageUtils.getTagsString(message), "*test"), equalTo(1)); assertThat(StringUtils.countMatches(MessageUtils.getTagsString(message), "*ab"), equalTo(1)); } - @Test - public void tagsShouldBeDeserializedFromXml() throws JAXBException { - XmppSessionConfiguration configuration = XmppSessionConfiguration.builder() - .extensions(Extension.of(com.juick.Message.class)) - .build(); - XmppSession xmpp = new XmppSession("juick.com", configuration) { - @Override - public void connect(Jid from) { - - } - - @Override - public Jid getConnectedResource() { - return null; - } - }; - String tag = "<tag xmlns='http://juick.com/message'>yo</tag>"; - String xml = "<message xmlns='jabber:client' from='juick@juick.com' type='chat'><body>yo</body><juick mid='1' ts='2017-09-14' uid='1' uname='ugnich' xmlns='http://juick.com/message'><body>yo</body><user uid='1' uname='ugnich' xmlns='http://juick.com/user'/><tag>yo</tag><tag>people</tag></juick></message>"; - Unmarshaller unmarshaller = xmpp.createUnmarshaller(); - rocks.xmpp.core.stanza.model.Message xmppMessage = (rocks.xmpp.core.stanza.model.Message) unmarshaller.unmarshal(new StringReader(xml)); - Tag xmlTag = (Tag) unmarshaller.unmarshal(new StringReader(tag)); - assertThat(xmlTag.getName(), equalTo("yo")); - Message juickMessage = xmppMessage.getExtension(Message.class); - assertThat(juickMessage.getTags().get(0).getName(), equalTo("yo")); - } - @Test - public void messageParserSerializer() throws ParseException, ParserConfigurationException, - IOException, SAXException, JAXBException { - Message msg = new Message(); - msg.setTags(MessageUtils.parseTags("test test" + (char) 0xA0 + "2 test3")); - assertEquals("First tag must be", "test", msg.getTags().get(0).getName()); - assertEquals("Third tag must be", "test3", msg.getTags().get(2).getName()); - assertEquals("Count of tags must be", 3, msg.getTags().size()); - Instant currentDate = Instant.now(); - msg.setTimestamp(currentDate); - ObjectMapper serializer = new ObjectMapper(); - serializer.registerModule(new Jdk8Module()); - serializer.registerModule(new JavaTimeModule()); - String jsonMessage = serializer.writeValueAsString(msg); - JSONObject jsonObject = new JSONObject(jsonMessage); - assertEquals("date should be in timestamp field", DateFormattersHolder.getMessageFormatterInstance().format(currentDate), - jsonObject.getString("timestamp")); - - - JAXBContext context = JAXBContext - .newInstance(Message.class); - Marshaller m = context.createMarshaller(); - - StringWriter sw = new StringWriter(); - m.marshal(msg, sw); - - DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); - DocumentBuilder db = dbf.newDocumentBuilder(); - Document doc = db.parse(new ByteArrayInputStream(sw.toString().getBytes(CharEncoding.UTF_8))); - Node juickNode = doc.getElementsByTagName("juick").item(0); - NamedNodeMap attrs = juickNode.getAttributes(); - assertEquals("date should be in ts field", DateFormattersHolder.getMessageFormatterInstance().format(currentDate), - attrs.getNamedItem("ts").getNodeValue()); - } } diff --git a/juick-server-xmpp/build.gradle b/juick-server-xmpp/build.gradle deleted file mode 100644 index e1e96723..00000000 --- a/juick-server-xmpp/build.gradle +++ /dev/null @@ -1,5 +0,0 @@ -apply plugin: 'java' - -dependencies { - compile project(':juick-common') -}
\ No newline at end of file diff --git a/juick-server/build.gradle b/juick-server/build.gradle index d496ec69..71b2f866 100644 --- a/juick-server/build.gradle +++ b/juick-server/build.gradle @@ -3,7 +3,7 @@ apply plugin: 'org.springframework.boot' dependencies { compile project(':juick-server-jdbc') - compile project(':juick-server-xmpp') + compile project(':juick-api') compile ('org.springframework.boot:spring-boot-starter-security') providedRuntime("org.springframework.boot:spring-boot-starter-tomcat") providedRuntime 'com.h2database:h2:1.4.196' @@ -14,10 +14,21 @@ dependencies { compile 'com.github.pengrad:java-telegram-bot-api:3.6.0' compile 'com.github.messenger4j:messenger4j:1.0.0-M3' compile 'org.springframework.social:spring-social-twitter:1.1.2.RELEASE' - compile 'org.apache.commons:commons-email:1.5' compile 'org.imgscalr:imgscalr-lib:4.2' compile 'org.twitter4j:twitter4j-core:4.0.6' + compile ('com.github.juick:com.juick.xmpp:658f8cf751') { + exclude group: 'xmlpull' + } + compile 'xpp3:xpp3:1.1.4c' + + compile "rocks.xmpp:xmpp-core-client:0.7.5" + compile "rocks.xmpp:xmpp-extensions-client:0.7.5" + + compile "javax.inject:javax.inject:1" + compile "javax.xml.bind:jaxb-api:2.3.0" + compile 'org.glassfish.jaxb:jaxb-runtime:2.3.0' + compile 'com.rometools:rome:1.9.0' compile 'com.rometools:rome-modules:1.9.0' diff --git a/juick-server-xmpp/src/main/java/com/juick/server/NotificationListener.java b/juick-server/src/main/java/com/juick/server/NotificationListener.java index f6330570..f6330570 100644 --- a/juick-server-xmpp/src/main/java/com/juick/server/NotificationListener.java +++ b/juick-server/src/main/java/com/juick/server/NotificationListener.java diff --git a/juick-server-xmpp/src/main/java/com/juick/server/XMPPConnection.java b/juick-server/src/main/java/com/juick/server/XMPPConnection.java index 59b33aba..59b33aba 100644 --- a/juick-server-xmpp/src/main/java/com/juick/server/XMPPConnection.java +++ b/juick-server/src/main/java/com/juick/server/XMPPConnection.java diff --git a/juick-server-xmpp/src/main/java/com/juick/server/XMPPServer.java b/juick-server/src/main/java/com/juick/server/XMPPServer.java index bf8ed228..bf8ed228 100644 --- a/juick-server-xmpp/src/main/java/com/juick/server/XMPPServer.java +++ b/juick-server/src/main/java/com/juick/server/XMPPServer.java diff --git a/juick-server/src/main/java/com/juick/server/api/Messages.java b/juick-server/src/main/java/com/juick/server/api/Messages.java index c6600e2b..7eb86284 100644 --- a/juick-server/src/main/java/com/juick/server/api/Messages.java +++ b/juick-server/src/main/java/com/juick/server/api/Messages.java @@ -18,11 +18,9 @@ package com.juick.server.api; import com.juick.Message; -import com.juick.Status; import com.juick.Tag; import com.juick.User; import com.juick.server.util.HttpBadRequestException; -import com.juick.server.util.HttpForbiddenException; import com.juick.server.util.UserUtils; import com.juick.service.MessagesService; import com.juick.service.TagService; @@ -33,7 +31,6 @@ import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import org.springframework.util.StringUtils; import org.springframework.web.bind.annotation.*; -import springfox.documentation.annotations.ApiIgnore; import javax.inject.Inject; import java.io.IOException; @@ -167,20 +164,4 @@ public class Messages { } throw new HttpBadRequestException(); } - @ApiIgnore - @RequestMapping("/messages/set_privacy") - @ResponseBody - public ResponseEntity<Status> doSetPrivacy( - @RequestParam(defaultValue = "0") int mid) { - User visitor = UserUtils.getCurrentUser(); - int vuid = visitor.getUid(); - if (vuid == 0) { - throw new HttpForbiddenException(); - } - com.juick.User user = messagesService.getMessageAuthor(mid); - if (user != null && user.getUid() == vuid && messagesService.setMessagePrivacy(mid)) { - return ResponseEntity.ok(Status.OK); - } - throw new HttpForbiddenException(); - } } diff --git a/juick-server/src/main/java/com/juick/server/api/PM.java b/juick-server/src/main/java/com/juick/server/api/PM.java index a09ecc2d..3649bb5e 100644 --- a/juick-server/src/main/java/com/juick/server/api/PM.java +++ b/juick-server/src/main/java/com/juick/server/api/PM.java @@ -18,7 +18,6 @@ package com.juick.server.api; import com.juick.User; -import com.juick.server.ServerManager; import com.juick.server.component.MessageEvent; import com.juick.server.helpers.AnonymousUser; import com.juick.server.helpers.PrivateChats; @@ -31,8 +30,6 @@ import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; -import rocks.xmpp.addr.Jid; -import rocks.xmpp.core.stanza.model.Message; import javax.inject.Inject; import java.util.Collections; @@ -48,8 +45,6 @@ public class PM { @Inject private PMQueriesService pmQueriesService; @Inject - private ServerManager serverManager; - @Inject private ApplicationEventPublisher applicationEventPublisher; @RequestMapping(value = "/pm", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_UTF8_VALUE) diff --git a/juick-server/src/main/java/com/juick/server/api/Service.java b/juick-server/src/main/java/com/juick/server/api/Service.java new file mode 100644 index 00000000..f67f6986 --- /dev/null +++ b/juick-server/src/main/java/com/juick/server/api/Service.java @@ -0,0 +1,117 @@ +package com.juick.server.api; + +import com.juick.User; +import com.juick.server.CommandsManager; +import com.juick.server.EmailManager; +import com.juick.server.util.HttpForbiddenException; +import com.juick.server.util.UserUtils; +import com.juick.service.UserService; +import org.apache.commons.codec.digest.DigestUtils; +import org.apache.commons.io.IOUtils; +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.mail.util.MimeMessageParser; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.http.HttpStatus; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.ResponseStatus; +import springfox.documentation.annotations.ApiIgnore; + +import javax.inject.Inject; +import javax.mail.Session; +import javax.mail.internet.InternetAddress; +import javax.mail.internet.MimeMessage; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.net.URI; +import java.nio.charset.StandardCharsets; +import java.nio.file.Paths; +import java.util.Properties; +import java.util.Scanner; +import java.util.UUID; + +@Controller +public class Service { + private static Logger logger = LoggerFactory.getLogger(Post.class); + @Inject + private UserService userService; + + @Inject + CommandsManager commandsManager; + @Value("${api_user:juick}") + private String serviceUser; + @Value("${upload_tmp_dir:#{systemEnvironment['TEMP'] ?: '/tmp'}}") + private String tmpDir; + Session session = Session.getDefaultInstance(new Properties()); + + @ApiIgnore + @PostMapping("/mail") + @ResponseStatus(value = HttpStatus.OK) + public void processMail(InputStream data) throws Exception { + if (UserUtils.getCurrentUser().getName().equals(serviceUser)) { + MimeMessage msg = new MimeMessage(session, data); + logger.info("got msg {}", msg.toString()); + String from = msg.getFrom() == null || msg.getFrom().length > 1 ? ((InternetAddress) msg.getSender()).getAddress() + : ((InternetAddress) msg.getFrom()[0]).getAddress(); + + User visitor = userService.getUserByEmail(from); + if (!visitor.isAnonymous()) { + MimeMessageParser parser = new MimeMessageParser(msg); + parser.parse(); + final String[] body = {parser.getPlainContent()}; + if (body[0] == null) { + parser.getAttachmentList().stream() + .filter(a -> a.getContentType().equals("text/plain")).findFirst() + .ifPresent(a -> { + try { + body[0] = IOUtils.toString(a.getInputStream(), StandardCharsets.UTF_8); + logger.info("got text: {}", body[0]); + } catch (IOException e) { + logger.info("attachment error: {}", e); + } + }); + } + final String[] attachmentFName = new String[1]; + parser.getAttachmentList().stream().filter(a -> + a.getContentType().equals("image/jpeg") || a.getContentType().equals("image/png")) + .findFirst().ifPresent(a -> { + logger.info("got attachment: {}", a.getContentType()); + String attachmentType; + if (a.getContentType().equals("image/jpeg")) { + attachmentType = "jpg"; + } else { + attachmentType = "png"; + } + attachmentFName[0] = DigestUtils.md5Hex(UUID.randomUUID().toString()) + "." + attachmentType; + try { + logger.info("got inputstream: {}", a.getInputStream()); + FileOutputStream fos = new FileOutputStream(Paths.get(tmpDir, attachmentFName[0]).toString()); + IOUtils.copy(a.getInputStream(), fos); + fos.close(); + } catch (IOException e) { + logger.info("attachment error: {}", e); + } + }); + String[] inReplyToHeaders = msg.getHeader("In-Reply-To"); + if (inReplyToHeaders != null && inReplyToHeaders.length > 0) { + Scanner inReplyToScanner = new Scanner(inReplyToHeaders[0].trim()).useDelimiter(EmailManager.MSGID_PATTERN); + int mid = Integer.parseInt(inReplyToScanner.next()); + int rid = Integer.parseInt(inReplyToScanner.next()); + logger.info("Message is reply to #{}/{}", mid, rid); + body[0] = rid > 0 ? String.format("#%d/%d %s", mid, rid, body[0]) + : String.format("#%d %s", mid, body[0]); + } + URI attachmentUri = StringUtils.isNotEmpty(attachmentFName[0]) ? URI.create(String.format("juick://%s", attachmentFName[0])) + : URI.create(StringUtils.EMPTY); + commandsManager.processCommand(visitor, body[0], attachmentUri); + } else { + logger.info("not registered: {}", from); + } + } else { + throw new HttpForbiddenException(); + } + } +} diff --git a/juick-server/src/main/java/com/juick/server/configuration/ApiAppConfiguration.java b/juick-server/src/main/java/com/juick/server/configuration/ApiAppConfiguration.java index 973c31fd..91f5446a 100644 --- a/juick-server/src/main/java/com/juick/server/configuration/ApiAppConfiguration.java +++ b/juick-server/src/main/java/com/juick/server/configuration/ApiAppConfiguration.java @@ -21,7 +21,13 @@ import com.google.common.base.Predicates; import com.juick.server.WebsocketManager; import com.juick.server.api.rss.MessagesView; import com.juick.server.api.rss.RepliesView; +import com.juick.server.xmpp.JidConverter; +import com.juick.server.xmpp.iq.MessageQuery; +import com.juick.server.xmpp.s2s.BasicXmppSession; +import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.*; +import org.springframework.core.convert.ConversionService; +import org.springframework.format.support.DefaultFormattingConversionService; import org.springframework.scheduling.annotation.EnableAsync; import org.springframework.scheduling.annotation.EnableScheduling; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; @@ -31,6 +37,9 @@ import org.springframework.web.socket.config.annotation.EnableWebSocket; import org.springframework.web.socket.config.annotation.WebSocketConfigurer; import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry; import org.springframework.web.socket.server.standard.ServletServerContainerFactoryBean; +import rocks.xmpp.core.session.Extension; +import rocks.xmpp.core.session.XmppSessionConfiguration; +import rocks.xmpp.core.session.debug.LogbackDebugger; import springfox.documentation.builders.PathSelectors; import springfox.documentation.builders.RequestHandlerSelectors; import springfox.documentation.service.ApiInfo; @@ -88,4 +97,20 @@ public class ApiAppConfiguration implements WebMvcConfigurer, WebSocketConfigure AbstractRssFeedView repliesView() { return new RepliesView(); } + @Value("${hostname:localhost}") + private String hostname; + @Bean + public BasicXmppSession session() { + XmppSessionConfiguration configuration = XmppSessionConfiguration.builder() + .extensions(Extension.of(com.juick.Message.class), Extension.of(MessageQuery.class)) + .debugger(LogbackDebugger.class) + .build(); + return BasicXmppSession.create(hostname, configuration); + } + @Bean + public static ConversionService conversionService() { + DefaultFormattingConversionService cs = new DefaultFormattingConversionService(); + cs.addConverter(new JidConverter()); + return cs; + } } diff --git a/juick-common/src/main/java/com/juick/server/xmpp/JidConverter.java b/juick-server/src/main/java/com/juick/server/xmpp/JidConverter.java index e9a9707e..e9a9707e 100644 --- a/juick-common/src/main/java/com/juick/server/xmpp/JidConverter.java +++ b/juick-server/src/main/java/com/juick/server/xmpp/JidConverter.java diff --git a/juick-server-xmpp/src/main/java/com/juick/server/xmpp/helpers/XMPPStatus.java b/juick-server/src/main/java/com/juick/server/xmpp/helpers/XMPPStatus.java index 7978ceb3..7978ceb3 100644 --- a/juick-server-xmpp/src/main/java/com/juick/server/xmpp/helpers/XMPPStatus.java +++ b/juick-server/src/main/java/com/juick/server/xmpp/helpers/XMPPStatus.java diff --git a/juick-common/src/main/java/com/juick/server/xmpp/iq/MessageQuery.java b/juick-server/src/main/java/com/juick/server/xmpp/iq/MessageQuery.java index 7500cbf8..7500cbf8 100644 --- a/juick-common/src/main/java/com/juick/server/xmpp/iq/MessageQuery.java +++ b/juick-server/src/main/java/com/juick/server/xmpp/iq/MessageQuery.java diff --git a/juick-common/src/main/java/com/juick/server/xmpp/iq/package-info.java b/juick-server/src/main/java/com/juick/server/xmpp/iq/package-info.java index dada8289..dada8289 100644 --- a/juick-common/src/main/java/com/juick/server/xmpp/iq/package-info.java +++ b/juick-server/src/main/java/com/juick/server/xmpp/iq/package-info.java diff --git a/juick-server-xmpp/src/main/java/com/juick/server/xmpp/router/Stream.java b/juick-server/src/main/java/com/juick/server/xmpp/router/Stream.java index 7532443c..7532443c 100644 --- a/juick-server-xmpp/src/main/java/com/juick/server/xmpp/router/Stream.java +++ b/juick-server/src/main/java/com/juick/server/xmpp/router/Stream.java diff --git a/juick-server-xmpp/src/main/java/com/juick/server/xmpp/router/StreamComponentServer.java b/juick-server/src/main/java/com/juick/server/xmpp/router/StreamComponentServer.java index 5e2f6f82..5e2f6f82 100644 --- a/juick-server-xmpp/src/main/java/com/juick/server/xmpp/router/StreamComponentServer.java +++ b/juick-server/src/main/java/com/juick/server/xmpp/router/StreamComponentServer.java diff --git a/juick-server-xmpp/src/main/java/com/juick/server/xmpp/router/StreamError.java b/juick-server/src/main/java/com/juick/server/xmpp/router/StreamError.java index 7eacfc94..7eacfc94 100644 --- a/juick-server-xmpp/src/main/java/com/juick/server/xmpp/router/StreamError.java +++ b/juick-server/src/main/java/com/juick/server/xmpp/router/StreamError.java diff --git a/juick-server-xmpp/src/main/java/com/juick/server/xmpp/router/StreamHandler.java b/juick-server/src/main/java/com/juick/server/xmpp/router/StreamHandler.java index 43836c2d..43836c2d 100644 --- a/juick-server-xmpp/src/main/java/com/juick/server/xmpp/router/StreamHandler.java +++ b/juick-server/src/main/java/com/juick/server/xmpp/router/StreamHandler.java diff --git a/juick-server-xmpp/src/main/java/com/juick/server/xmpp/router/StreamNamespaces.java b/juick-server/src/main/java/com/juick/server/xmpp/router/StreamNamespaces.java index 1b9b1965..1b9b1965 100644 --- a/juick-server-xmpp/src/main/java/com/juick/server/xmpp/router/StreamNamespaces.java +++ b/juick-server/src/main/java/com/juick/server/xmpp/router/StreamNamespaces.java diff --git a/juick-server-xmpp/src/main/java/com/juick/server/xmpp/router/XMPPError.java b/juick-server/src/main/java/com/juick/server/xmpp/router/XMPPError.java index 0cf9a3bc..0cf9a3bc 100644 --- a/juick-server-xmpp/src/main/java/com/juick/server/xmpp/router/XMPPError.java +++ b/juick-server/src/main/java/com/juick/server/xmpp/router/XMPPError.java diff --git a/juick-server-xmpp/src/main/java/com/juick/server/xmpp/router/XMPPRouter.java b/juick-server/src/main/java/com/juick/server/xmpp/router/XMPPRouter.java index 6edecf05..6edecf05 100644 --- a/juick-server-xmpp/src/main/java/com/juick/server/xmpp/router/XMPPRouter.java +++ b/juick-server/src/main/java/com/juick/server/xmpp/router/XMPPRouter.java diff --git a/juick-server-xmpp/src/main/java/com/juick/server/xmpp/router/XmlUtils.java b/juick-server/src/main/java/com/juick/server/xmpp/router/XmlUtils.java index 7579489f..7579489f 100644 --- a/juick-server-xmpp/src/main/java/com/juick/server/xmpp/router/XmlUtils.java +++ b/juick-server/src/main/java/com/juick/server/xmpp/router/XmlUtils.java diff --git a/juick-common/src/main/java/com/juick/server/xmpp/s2s/BasicXmppSession.java b/juick-server/src/main/java/com/juick/server/xmpp/s2s/BasicXmppSession.java index 647f2717..647f2717 100644 --- a/juick-common/src/main/java/com/juick/server/xmpp/s2s/BasicXmppSession.java +++ b/juick-server/src/main/java/com/juick/server/xmpp/s2s/BasicXmppSession.java diff --git a/juick-server-xmpp/src/main/java/com/juick/server/xmpp/s2s/CacheEntry.java b/juick-server/src/main/java/com/juick/server/xmpp/s2s/CacheEntry.java index 33e875bd..33e875bd 100644 --- a/juick-server-xmpp/src/main/java/com/juick/server/xmpp/s2s/CacheEntry.java +++ b/juick-server/src/main/java/com/juick/server/xmpp/s2s/CacheEntry.java diff --git a/juick-server-xmpp/src/main/java/com/juick/server/xmpp/s2s/Connection.java b/juick-server/src/main/java/com/juick/server/xmpp/s2s/Connection.java index 6bf61169..6bf61169 100644 --- a/juick-server-xmpp/src/main/java/com/juick/server/xmpp/s2s/Connection.java +++ b/juick-server/src/main/java/com/juick/server/xmpp/s2s/Connection.java diff --git a/juick-server-xmpp/src/main/java/com/juick/server/xmpp/s2s/ConnectionIn.java b/juick-server/src/main/java/com/juick/server/xmpp/s2s/ConnectionIn.java index 9ee81d4d..9ee81d4d 100644 --- a/juick-server-xmpp/src/main/java/com/juick/server/xmpp/s2s/ConnectionIn.java +++ b/juick-server/src/main/java/com/juick/server/xmpp/s2s/ConnectionIn.java diff --git a/juick-server-xmpp/src/main/java/com/juick/server/xmpp/s2s/ConnectionListener.java b/juick-server/src/main/java/com/juick/server/xmpp/s2s/ConnectionListener.java index fde7a0e7..fde7a0e7 100644 --- a/juick-server-xmpp/src/main/java/com/juick/server/xmpp/s2s/ConnectionListener.java +++ b/juick-server/src/main/java/com/juick/server/xmpp/s2s/ConnectionListener.java diff --git a/juick-server-xmpp/src/main/java/com/juick/server/xmpp/s2s/ConnectionOut.java b/juick-server/src/main/java/com/juick/server/xmpp/s2s/ConnectionOut.java index e3bd53e9..e3bd53e9 100644 --- a/juick-server-xmpp/src/main/java/com/juick/server/xmpp/s2s/ConnectionOut.java +++ b/juick-server/src/main/java/com/juick/server/xmpp/s2s/ConnectionOut.java diff --git a/juick-server-xmpp/src/main/java/com/juick/server/xmpp/s2s/DNSQueries.java b/juick-server/src/main/java/com/juick/server/xmpp/s2s/DNSQueries.java index 1367d333..1367d333 100644 --- a/juick-server-xmpp/src/main/java/com/juick/server/xmpp/s2s/DNSQueries.java +++ b/juick-server/src/main/java/com/juick/server/xmpp/s2s/DNSQueries.java diff --git a/juick-server-xmpp/src/main/java/com/juick/server/xmpp/s2s/StanzaListener.java b/juick-server/src/main/java/com/juick/server/xmpp/s2s/StanzaListener.java index 6932298f..6932298f 100644 --- a/juick-server-xmpp/src/main/java/com/juick/server/xmpp/s2s/StanzaListener.java +++ b/juick-server/src/main/java/com/juick/server/xmpp/s2s/StanzaListener.java diff --git a/juick-server-xmpp/src/main/java/com/juick/server/xmpp/s2s/util/DialbackUtils.java b/juick-server/src/main/java/com/juick/server/xmpp/s2s/util/DialbackUtils.java index d25dbad8..d25dbad8 100644 --- a/juick-server-xmpp/src/main/java/com/juick/server/xmpp/s2s/util/DialbackUtils.java +++ b/juick-server/src/main/java/com/juick/server/xmpp/s2s/util/DialbackUtils.java diff --git a/juick-common/src/main/java/rocks/xmpp/core/session/debug/LogbackDebugger.java b/juick-server/src/main/java/rocks/xmpp/core/session/debug/LogbackDebugger.java index aae49bc7..aae49bc7 100644 --- a/juick-common/src/main/java/rocks/xmpp/core/session/debug/LogbackDebugger.java +++ b/juick-server/src/main/java/rocks/xmpp/core/session/debug/LogbackDebugger.java diff --git a/juick-server-xmpp/src/main/resources/juick.png b/juick-server/src/main/resources/juick.png Binary files differindex a7b0e901..a7b0e901 100644 --- a/juick-server-xmpp/src/main/resources/juick.png +++ b/juick-server/src/main/resources/juick.png diff --git a/juick-server/src/test/java/com/juick/server/tests/ServerTests.java b/juick-server/src/test/java/com/juick/server/tests/ServerTests.java index 4ea212f1..9b9722b2 100644 --- a/juick-server/src/test/java/com/juick/server/tests/ServerTests.java +++ b/juick-server/src/test/java/com/juick/server/tests/ServerTests.java @@ -19,7 +19,12 @@ package com.juick.server.tests; import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.ObjectMapper; -import com.juick.*; +import com.fasterxml.jackson.datatype.jdk8.Jdk8Module; +import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; +import com.juick.ExternalToken; +import com.juick.Message; +import com.juick.Tag; +import com.juick.User; import com.juick.server.*; import com.juick.server.component.MessageEvent; import com.juick.server.helpers.AnonymousUser; @@ -29,10 +34,15 @@ import com.juick.server.util.HttpUtils; import com.juick.service.*; import com.juick.util.DateFormattersHolder; import com.juick.util.MessageUtils; +import org.apache.commons.codec.CharEncoding; import org.apache.commons.io.IOUtils; import org.apache.commons.lang3.StringUtils; -import org.hamcrest.Matchers; -import org.junit.*; +import org.json.JSONException; +import org.json.JSONObject; +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; import org.junit.rules.ExpectedException; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Value; @@ -41,23 +51,44 @@ import org.springframework.boot.builder.SpringApplicationBuilder; import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.context.ConfigurableApplicationContext; -import org.springframework.http.MediaType; +import org.springframework.http.*; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.test.context.TestPropertySource; import org.springframework.test.context.junit4.SpringRunner; import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.MvcResult; import org.springframework.util.FileSystemUtils; +import org.springframework.util.LinkedMultiValueMap; +import org.springframework.util.MultiValueMap; +import org.springframework.web.client.HttpClientErrorException; +import org.springframework.web.client.RestTemplate; import org.springframework.web.context.WebApplicationContext; import org.springframework.web.util.UriComponents; import org.springframework.web.util.UriComponentsBuilder; +import org.w3c.dom.Document; +import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.Node; +import org.xml.sax.SAXException; import rocks.xmpp.addr.Jid; +import rocks.xmpp.core.session.Extension; +import rocks.xmpp.core.session.XmppSession; +import rocks.xmpp.core.session.XmppSessionConfiguration; import rocks.xmpp.core.stanza.model.StanzaError; import rocks.xmpp.core.stanza.model.client.ClientMessage; import rocks.xmpp.core.stanza.model.errors.Condition; import javax.inject.Inject; +import javax.xml.bind.JAXBContext; +import javax.xml.bind.JAXBException; +import javax.xml.bind.Marshaller; +import javax.xml.bind.Unmarshaller; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; +import java.io.ByteArrayInputStream; import java.io.IOException; +import java.io.StringReader; +import java.io.StringWriter; import java.net.URI; import java.nio.file.Files; import java.nio.file.Paths; @@ -898,4 +929,78 @@ public class ServerTests { .stream().noneMatch(m -> m.getTags().contains(banned))); } + @Test + public void tagsShouldBeDeserializedFromXml() throws JAXBException { + XmppSessionConfiguration configuration = XmppSessionConfiguration.builder() + .extensions(Extension.of(com.juick.Message.class)) + .build(); + XmppSession xmpp = new XmppSession("juick.com", configuration) { + @Override + public void connect(Jid from) { + + } + + @Override + public Jid getConnectedResource() { + return null; + } + }; + String tag = "<tag xmlns='http://juick.com/message'>yo</tag>"; + String xml = "<message xmlns='jabber:client' from='juick@juick.com' type='chat'><body>yo</body><juick mid='1' ts='2017-09-14' uid='1' uname='ugnich' xmlns='http://juick.com/message'><body>yo</body><user uid='1' uname='ugnich' xmlns='http://juick.com/user'/><tag>yo</tag><tag>people</tag></juick></message>"; + Unmarshaller unmarshaller = xmpp.createUnmarshaller(); + rocks.xmpp.core.stanza.model.Message xmppMessage = (rocks.xmpp.core.stanza.model.Message) unmarshaller.unmarshal(new StringReader(xml)); + Tag xmlTag = (Tag) unmarshaller.unmarshal(new StringReader(tag)); + assertThat(xmlTag.getName(), equalTo("yo")); + Message juickMessage = xmppMessage.getExtension(Message.class); + assertThat(juickMessage.getTags().get(0).getName(), equalTo("yo")); + } + @Test + public void messageParserSerializer() throws ParserConfigurationException, + IOException, SAXException, JAXBException, JSONException { + Message msg = new Message(); + msg.setTags(MessageUtils.parseTags("test test" + (char) 0xA0 + "2 test3")); + assertEquals("First tag must be", "test", msg.getTags().get(0).getName()); + assertEquals("Third tag must be", "test3", msg.getTags().get(2).getName()); + assertEquals("Count of tags must be", 3, msg.getTags().size()); + Instant currentDate = Instant.now(); + msg.setTimestamp(currentDate); + ObjectMapper serializer = new ObjectMapper(); + serializer.registerModule(new Jdk8Module()); + serializer.registerModule(new JavaTimeModule()); + String jsonMessage = serializer.writeValueAsString(msg); + JSONObject jsonObject = new JSONObject(jsonMessage); + assertEquals("date should be in timestamp field", DateFormattersHolder.getMessageFormatterInstance().format(currentDate), + jsonObject.getString("timestamp")); + + + JAXBContext context = JAXBContext + .newInstance(Message.class); + Marshaller m = context.createMarshaller(); + + StringWriter sw = new StringWriter(); + m.marshal(msg, sw); + + DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); + DocumentBuilder db = dbf.newDocumentBuilder(); + Document doc = db.parse(new ByteArrayInputStream(sw.toString().getBytes(CharEncoding.UTF_8))); + Node juickNode = doc.getElementsByTagName("juick").item(0); + NamedNodeMap attrs = juickNode.getAttributes(); + assertEquals("date should be in ts field", DateFormattersHolder.getMessageFormatterInstance().format(currentDate), + attrs.getNamedItem("ts").getNodeValue()); + } + @Test + public void restTemplateTests() { + HttpHeaders headers = new HttpHeaders(); + headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED); + MultiValueMap<String, String> map= new LinkedMultiValueMap<>(); + HttpEntity<MultiValueMap<String, String>> request = new HttpEntity<>(map, headers); + + map.add("body", "yo"); + map.add("hash", userService.getHashByUID(ugnich.getUid())); + RestTemplate rest = new RestTemplate(); + ResponseEntity<CommandResult> result = rest.postForEntity( + "http://localhost:8080/post", + request, CommandResult.class); + assertThat(result.getStatusCode(), is(HttpStatus.OK)); + } } diff --git a/juick-www/build.gradle b/juick-www/build.gradle index 1b7e4132..f211149b 100644 --- a/juick-www/build.gradle +++ b/juick-www/build.gradle @@ -24,7 +24,7 @@ apply plugin: 'org.springframework.boot' dependencies { compile project(':juick-common') compile project(':juick-server-jdbc') - providedCompile (project(':juick-server-xmpp')) { + providedCompile (project(':juick-api')) { transitive = false } compile 'com.github.ben-manes.caffeine:caffeine:2.6.2' @@ -32,7 +32,7 @@ dependencies { compile("org.springframework.boot:spring-boot-starter-web") compile ('org.springframework.boot:spring-boot-starter-security') providedRuntime("org.springframework.boot:spring-boot-devtools") - providedRuntime("org.springframework.boot:spring-boot-starter-tomcat") + providedCompile("org.springframework.boot:spring-boot-starter-tomcat") providedRuntime 'com.h2database:h2:1.4.196' providedRuntime 'mysql:mysql-connector-java:5.1.45' runtime "commons-fileupload:commons-fileupload:1.3.3" diff --git a/juick-www/src/main/java/com/juick/Application.java b/juick-www/src/main/java/com/juick/Application.java index cb132ae9..47c16754 100644 --- a/juick-www/src/main/java/com/juick/Application.java +++ b/juick-www/src/main/java/com/juick/Application.java @@ -5,6 +5,7 @@ import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.builder.SpringApplicationBuilder; import org.springframework.boot.web.servlet.support.SpringBootServletInitializer; import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.PropertySource; import org.springframework.transaction.annotation.EnableTransactionManagement; @SpringBootApplication diff --git a/juick-www/src/main/java/com/juick/www/configuration/EmbeddedAPIConfig.java b/juick-www/src/main/java/com/juick/www/configuration/EmbeddedAPIConfig.java new file mode 100644 index 00000000..6ceb140b --- /dev/null +++ b/juick-www/src/main/java/com/juick/www/configuration/EmbeddedAPIConfig.java @@ -0,0 +1,19 @@ +package com.juick.www.configuration; + +import com.juick.server.configuration.PostConfig; +import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; +import org.springframework.boot.builder.SpringApplicationBuilder; +import org.springframework.context.ConfigurableApplicationContext; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +@ConditionalOnClass(name = "com.juick.server.api.Post") +public class EmbeddedAPIConfig { + @Bean + public ConfigurableApplicationContext apiContext() { + return new SpringApplicationBuilder() + .sources(PostConfig.class) + .run("--server.port=8081"); + } +} diff --git a/juick-www/src/main/java/com/juick/www/configuration/EmbeddedXMPPConfig.java b/juick-www/src/main/java/com/juick/www/configuration/EmbeddedXMPPConfig.java deleted file mode 100644 index a54b76a1..00000000 --- a/juick-www/src/main/java/com/juick/www/configuration/EmbeddedXMPPConfig.java +++ /dev/null @@ -1,22 +0,0 @@ -package com.juick.www.configuration; - -import com.juick.server.XMPPConnection; -import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.ComponentScan; -import org.springframework.context.annotation.Configuration; -import rocks.xmpp.extensions.component.accept.ExternalComponent; - -import javax.inject.Inject; - -@Configuration -@ConditionalOnClass(name = "com.juick.server.xmpp.router.XMPPRouter") -@ComponentScan(basePackages = "com.juick.server") -public class EmbeddedXMPPConfig { - @Inject - private XMPPConnection xmppConnection; - @Bean - public ExternalComponent xmpp() { - return xmppConnection.getRouter(); - } -} diff --git a/juick-www/src/main/java/com/juick/www/configuration/WwwAppConfiguration.java b/juick-www/src/main/java/com/juick/www/configuration/WwwAppConfiguration.java index 13a394cb..edee3b87 100644 --- a/juick-www/src/main/java/com/juick/www/configuration/WwwAppConfiguration.java +++ b/juick-www/src/main/java/com/juick/www/configuration/WwwAppConfiguration.java @@ -51,7 +51,7 @@ import java.util.Collections; @Configuration @EnableCaching @Import({ BaseWebConfiguration.class, WebSecurityConfig.class, SapeConfiguration.class, - StorageConfiguration.class, XMPPConfiguration.class}) + StorageConfiguration.class}) public class WwwAppConfiguration implements WebMvcConfigurer { @Inject private UserService userService; diff --git a/juick-www/src/main/java/com/juick/www/configuration/XMPPConfiguration.java b/juick-www/src/main/java/com/juick/www/configuration/XMPPConfiguration.java deleted file mode 100644 index 8afddf2d..00000000 --- a/juick-www/src/main/java/com/juick/www/configuration/XMPPConfiguration.java +++ /dev/null @@ -1,43 +0,0 @@ -package com.juick.www.configuration; - -import com.juick.Message; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import rocks.xmpp.core.XmppException; -import rocks.xmpp.core.session.Extension; -import rocks.xmpp.core.session.XmppSessionConfiguration; -import rocks.xmpp.core.session.debug.LogbackDebugger; -import rocks.xmpp.extensions.component.accept.ExternalComponent; - -@Configuration -public class XMPPConfiguration { - private static Logger logger = LoggerFactory.getLogger(XMPPConfiguration.class); - @Value("${xmpp_host:localhost}") - private String xmppHost; - @Value("${xmpp_password:secret}") - private String xmppPassword; - @Value("${www_xmpp_jid:www.juick.local}") - private String xmppJid; - @Value("${xmpp_port:5347}") - private int xmppPort; - @Bean - @ConditionalOnMissingBean(type = "rocks.xmpp.extensions.component.accept.ExternalComponent") - public ExternalComponent xmpp() { - XmppSessionConfiguration configuration = XmppSessionConfiguration.builder() - .extensions(Extension.of(Message.class)) - .debugger(LogbackDebugger.class) - .build(); - ExternalComponent xmpp = ExternalComponent.create(xmppJid, xmppPassword, configuration, xmppHost, xmppPort); - xmpp.addConnectionListener(e -> logger.error(e.toString(), e.getCause())); - try { - xmpp.connect(); - } catch (XmppException e) { - logger.error("xmpp extension", e); - } - return xmpp; - } -} diff --git a/juick-www/src/main/java/com/juick/www/controllers/NewMessage.java b/juick-www/src/main/java/com/juick/www/controllers/NewMessage.java index c26d7c0c..3d6bc8cf 100644 --- a/juick-www/src/main/java/com/juick/www/controllers/NewMessage.java +++ b/juick-www/src/main/java/com/juick/www/controllers/NewMessage.java @@ -16,8 +16,11 @@ */ package com.juick.www.controllers; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; import com.juick.User; import com.juick.server.helpers.AnonymousUser; +import com.juick.server.helpers.CommandResult; import com.juick.server.util.*; import com.juick.service.*; import com.juick.www.WebApp; @@ -26,23 +29,29 @@ import org.apache.commons.text.StringEscapeUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Value; +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpHeaders; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.http.converter.FormHttpMessageConverter; import org.springframework.stereotype.Controller; import org.springframework.ui.ModelMap; +import org.springframework.util.LinkedMultiValueMap; +import org.springframework.util.MultiValueMap; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.client.HttpClientErrorException; +import org.springframework.web.client.RestTemplate; import org.springframework.web.multipart.MultipartFile; -import rocks.xmpp.addr.Jid; -import rocks.xmpp.core.stanza.model.Message; -import rocks.xmpp.extensions.component.accept.ExternalComponent; -import rocks.xmpp.extensions.nick.model.Nickname; -import rocks.xmpp.extensions.oob.model.x.OobX; import javax.inject.Inject; import java.io.IOException; import java.net.URI; -import java.net.URISyntaxException; import java.net.URL; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; import java.util.stream.Collectors; /** @@ -66,20 +75,19 @@ public class NewMessage { @Inject private WebApp webApp; @Inject - private ExternalComponent xmpp; + private ObjectMapper jsonMapper; @Inject private ImagesService imagesService; @Value("${img_path:#{systemEnvironment['TEMP'] ?: '/tmp'}}") private String imgDir; @Value("${upload_tmp_dir:#{systemEnvironment['TEMP'] ?: '/tmp'}}") private String tmpDir; - @Value("${xmppbot_jid:juick@localhost}") - private Jid botJid; + private RestTemplate rest = new RestTemplate(); private static final Logger logger = LoggerFactory.getLogger(NewMessage.class); @GetMapping("/post") - protected String postAction(@RequestParam(required = false) String body, ModelMap model) throws IOException { + protected String postAction(@RequestParam(required = false) String body, ModelMap model) { com.juick.User visitor = UserUtils.getCurrentUser(); model.addAttribute("title", "Написать"); model.addAttribute("headers", ""); @@ -146,51 +154,22 @@ public class NewMessage { } } - String attachmentType = StringUtils.isNotEmpty(attachmentFName.toString()) ? attachmentFName.toString().substring(attachmentFName.toString().length() - 3) : null; - int ridnew = messagesService.createReply(mid, rid, visitor, body, attachmentType); - subscriptionService.subscribeMessage(msg, visitor); + HttpHeaders headers = new HttpHeaders(); + headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED); + MultiValueMap<String, String> params = new LinkedMultiValueMap<>(); + HttpEntity<MultiValueMap<String, String>> request = new HttpEntity<>(params, headers); - Message xmsg = new Message(); - xmsg.setFrom(botJid); - xmsg.setType(Message.Type.CHAT); - xmsg.setThread("juick-" + mid); - - com.juick.Message jmsg = messagesService.getReply(mid, ridnew); - xmsg.addExtension(jmsg); - - String quote = reply != null ? StringUtils.defaultString(reply.getText()) - : StringUtils.defaultString(msg.getText()); - if (quote.length() >= 50) { - quote = quote.substring(0, 47) + "..."; - } - xmsg.addExtension(new Nickname("@" + jmsg.getUser().getName())); + params.add("body", rid == 0 ? String.format("#%d %s", mid, body) : String.format("#%d/%d %s", mid, rid, body)); + params.add("hash", userService.getHashByUID(visitor.getUid())); if (StringUtils.isNotEmpty(attachmentFName.toString())) { - String fname = mid + "-" + ridnew + "." + attachmentType; - String attachmentURL = "http://i.juick.com/photos-1024/" + fname; - - imagesService.saveImageWithPreviews(attachmentFName.getHost(), fname); - - body = attachmentURL + "\n" + body; - try { - xmsg.addExtension(new OobX(new URI(attachmentURL))); - } catch (URISyntaxException e) { - logger.warn("invalid uri: {}, exception {}", attachmentURL, e); - } - } - - if (xmpp.isConnected()) { - - xmsg.setBody("Reply by @" + jmsg.getUser().getName() + ":\n>" + quote + "\n" + body + "\n\n#" + - mid + "/" + ridnew + " http://juick.com/" + mid + "#" + ridnew); - - xmsg.setTo(botJid); - xmpp.send(xmsg); - } else { - logger.warn("XMPP unavailable"); + params.add("img", attachmentFName.toASCIIString()); } - - return "redirect:/" + msg.getUser().getName() + "/" + mid + "#" + ridnew; + ResponseEntity<CommandResult> result = rest.postForEntity( + "http://localhost:8081/post", + request, CommandResult.class); + logger.info("/comment: {}", jsonMapper.writeValueAsString(result.getBody())); + return "redirect:/" + msg.getUser().getName() + "/" + mid + "#" + result.getBody().getNewMessage().get().getRid(); } @PostMapping("/pm/send") @@ -217,30 +196,25 @@ public class NewMessage { throw new HttpForbiddenException(); } - if (pmQueriesService.createPM(visitor.getUid(), userTo.getUid(), body)) { - if (xmpp.isConnected()) { - Message msg = new Message(); - msg.setFrom(botJid); - msg.setTo(botJid.withLocal("pm")); - com.juick.Message jmsg = new com.juick.Message(); - jmsg.setUser(visitor); - jmsg.setText(body); - jmsg.setTo(userTo); - msg.addExtension(jmsg); - xmpp.send(msg); - } else { - logger.warn("XMPP unavailable"); - } - return "redirect:/pm/sent"; - } else { - throw new HttpBadRequestException(); - } + HttpHeaders headers = new HttpHeaders(); + headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED); + MultiValueMap<String, String> params = new LinkedMultiValueMap<>(); + HttpEntity<MultiValueMap<String, String>> request = new HttpEntity<>(params, headers); + + params.add("body", String.format("@%s %s", userTo.getName(), body)); + params.add("hash", userService.getHashByUID(visitor.getUid())); + ResponseEntity<CommandResult> result = rest.postForEntity( + "http://localhost:8081/post", + request, CommandResult.class); + logger.info("/pm: {}", jsonMapper.writeValueAsString(result.getBody())); + return "redirect:/pm/sent"; + } @PostMapping("/post2") public String doPostMessage(@RequestParam(name = "body", required = false) String bodyParam, @RequestParam(required = false) String img, @RequestParam(required = false) String referer, - @RequestParam(required = false) MultipartFile attach) throws IOException { + @RequestParam(required = false) MultipartFile attach) throws JsonProcessingException { com.juick.User visitor = UserUtils.getCurrentUser(); if (visitor.getUid() == 0 || visitor.isBanned()) { @@ -259,18 +233,31 @@ public class NewMessage { throw new HttpBadRequestException(); } } - Message msg = new Message(); - msg.setType(Message.Type.CHAT); - msg.setFrom(Jid.of(String.valueOf(visitor.getUid()), "uid.juick.com", "perl")); - msg.setTo(botJid); - msg.setBody(body); + HttpHeaders headers = new HttpHeaders(); + headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED); + MultiValueMap<String, String> params = new LinkedMultiValueMap<>(); + HttpEntity<MultiValueMap<String, String>> request = new HttpEntity<>(params, headers); + + params.add("body", body); + params.add("hash", userService.getHashByUID(visitor.getUid())); if (StringUtils.isNotEmpty(attachmentFName.toString())) { - msg.addExtension(new OobX(attachmentFName, "!!!!Juick!!")); + params.add("img", attachmentFName.toASCIIString()); } - xmpp.sendMessage(msg); - if (StringUtils.isBlank(referer) || referer.substring(0, 21).equals("http://juick.com/post") - || referer.substring(0, 22).equals("https://juick.com/post")) { - return "redirect:/?show=my"; + try { + ResponseEntity<CommandResult> result = rest.postForEntity( + "http://localhost:8081/post", + request, CommandResult.class); + if (result.getBody().getNewMessage().isPresent()) { + logger.info("/post: {}", jsonMapper.writeValueAsString(result.getBody())); + } else { + logger.info("{} : {}", body, result.getBody().getText()); + } + if (StringUtils.isBlank(referer) || referer.substring(0, 21).equals("http://juick.com/post") + || referer.substring(0, 22).equals("https://juick.com/post")) { + return "redirect:/?show=my"; + } + } catch (HttpClientErrorException e) { + logger.error("post error", e); } return "redirect:" + referer; } diff --git a/juick-www/src/test/java/com/juick/WebAppTests.java b/juick-www/src/test/java/com/juick/WebAppTests.java index a0ec9737..39e2b70e 100644 --- a/juick-www/src/test/java/com/juick/WebAppTests.java +++ b/juick-www/src/test/java/com/juick/WebAppTests.java @@ -248,13 +248,11 @@ public class WebAppTests { mockMvc.perform(post("/post2") .cookie(loginResult.getResponse().getCookies()) .param("body", msgText)).andExpect(status().isFound()); - Thread.sleep(5000); Message lastMessage = messagesService.getMessage(messagesService.getMyFeed(ugnich.getUid(), 0, false).get(0)); assertThat(lastMessage.getText(), equalTo(msgText)); mockMvc.perform(post("/post2") .cookie(loginResult.getResponse().getCookies()) .param("img", "http://static.juick.com/settings/facebook.png")).andExpect(status().isFound()); - Thread.sleep(5000); lastMessage = messagesService.getMessage(messagesService.getMyFeed(ugnich.getUid(), 0, false).get(0)); assertThat(lastMessage.getAttachmentType(), equalTo("png")); mockMvc.perform(post("/post2") @@ -292,7 +290,6 @@ public class WebAppTests { .cookie(loginResult.getResponse().getCookies()) .param("body", String.format("D #%d/%d", mid, 3))) .andExpect(status().isFound()); - Thread.sleep(5000); assertThat(messagesService.getReplies(ugnich, mid).size(), equalTo(2)); } @Test diff --git a/settings.gradle b/settings.gradle index 515091f3..dc9123cf 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,4 +1,4 @@ rootProject.name = "Juick" -include ':juick-common', ':juick-server-jdbc', ':juick-server-xmpp', ':juick-server', ':juick-www', ':juick-notifications' +include ':juick-common', ':juick-server-jdbc', ':juick-api', ':juick-server', ':juick-www', ':juick-notifications' |