/* * 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.www.controllers; import com.juick.Status; import com.juick.Tag; import com.juick.server.util.*; import com.juick.service.*; import com.juick.www.WebApp; import org.apache.commons.lang3.StringUtils; import org.apache.commons.text.StringEscapeUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Controller; import org.springframework.ui.ModelMap; 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.bind.annotation.ResponseBody; import org.springframework.web.multipart.MultipartFile; import rocks.xmpp.addr.Jid; import rocks.xmpp.core.stanza.model.Message; 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.List; import java.util.stream.Collectors; /** * @author Ugnich Anton */ @Controller public class NewMessage { @Inject private TagService tagService; @Inject private MessagesService messagesService; @Inject private UserService userService; @Inject private SubscriptionService subscriptionService; @Inject private CrosspostService crosspostService; @Inject private PMQueriesService pmQueriesService; @Inject private WebApp webApp; private static final Logger logger = LoggerFactory.getLogger(NewMessage.class); @GetMapping("/post") protected String postAction(@RequestParam(required = false) String body, ModelMap model) throws IOException { com.juick.User visitor = UserUtils.getCurrentUser(); model.addAttribute("title", "Написать"); model.addAttribute("headers", ""); model.addAttribute("visitor", visitor); if (body == null) { body = StringUtils.EMPTY; } else { if (body.length() > 4096) { body = body.substring(0, 4096); } body = StringEscapeUtils.escapeHtml4(body); } model.addAttribute("body", body); model.addAttribute("visitor", visitor); model.addAttribute("tags", tagService.getUserTagStats(visitor.getUid()).stream() .sorted((e1, e2) -> Integer.compare(e2.getUsageCount(), e1.getUsageCount())).map(t -> t.getTag().getName()).collect(Collectors.toList())); return "views/post"; } @PostMapping("/post") public String postResult(@RequestParam(required = false) String img, @RequestParam(required = false, defaultValue = StringUtils.EMPTY) String body, @RequestParam(required = false, name = "tags") String tagsStr, @RequestParam(required = false) MultipartFile attach, ModelMap model) throws IOException { com.juick.User visitor = UserUtils.getCurrentUser(); if ((StringUtils.isEmpty(body) || body.length() > 4096) && StringUtils.isEmpty(img) && attach == null) { throw new HttpBadRequestException(); } body = body.replace("\r", StringUtils.EMPTY); List tags = webApp.parseTags(tagsStr); String attachmentFName = HttpUtils.receiveMultiPartFile(attach, webApp.getTmpDir()); if (StringUtils.isBlank(attachmentFName) && StringUtils.isNotBlank(img)) { try { URL imgUrl = new URL(img); attachmentFName = HttpUtils.downloadImage(imgUrl, webApp.getTmpDir()); } catch (Exception e) { logger.error("DOWNLOAD ERROR", e); throw new HttpBadRequestException(); } } String attachmentType = StringUtils.isNotEmpty(attachmentFName) ? attachmentFName.substring(attachmentFName.length() - 3) : null; int mid = messagesService.createMessage(visitor.getUid(), body, attachmentType, tags); subscriptionService.subscribeMessage(mid, visitor.getUid()); Message xmsg = new Message(); xmsg.setFrom(Jid.of("juick@juick.com")); xmsg.setType(Message.Type.CHAT); xmsg.setThread("juick-" + mid); com.juick.Message jmsg = messagesService.getMessage(mid); xmsg.addExtension(jmsg); xmsg.addExtension(new Nickname("@" + jmsg.getUser().getName())); if (StringUtils.isNotEmpty(attachmentFName)) { String fname = mid + "." + attachmentType; String attachmentURL = "http://i.juick.com/photos-1024/" + fname; ImageUtils.saveImageWithPreviews(attachmentFName, fname, webApp.getTmpDir(), webApp.getImgDir()); body = attachmentURL + "\n" + body; try { xmsg.addExtension(new OobX(new URI(attachmentURL))); } catch (URISyntaxException e) { logger.warn("invalid uri: {} exception {}", attachmentURL, e); } } if (webApp.getXmpp() != null) { xmsg.setBody("@" + jmsg.getUser().getName() + ":" + jmsg.getTagsString() + "\n" + body + "\n\n#" + mid + " http://juick.com/" + mid); xmsg.setTo(Jid.of("juick@s2s.juick.com")); webApp.getXmpp().send(xmsg); xmsg.setTo(Jid.of("juick@ws.juick.com")); webApp.getXmpp().send(xmsg); xmsg.setTo(Jid.of("juick@push.juick.com")); webApp.getXmpp().send(xmsg); xmsg.setTo(Jid.of("jubo@nologin.ru")); webApp.getXmpp().send(xmsg); } else { logger.warn("XMPP unavailable"); } // model.addAttribute("title", "Сообщение опубликовано"); model.addAttribute("visitor", visitor); model.addAttribute("user", visitor); String hashtags = StringUtils.EMPTY; String tagscomma = StringUtils.EMPTY; for (int i = 0; i < jmsg.getTags().size(); i++) { if (i > 0) { hashtags += " "; tagscomma += ","; } hashtags += "#" + jmsg.getTags().get(i); tagscomma += jmsg.getTags().get(i); } model.addAttribute("url", "http://juick.com/" + mid); if (!crosspostService.getTwitterToken(visitor.getUid()).isPresent()) { String sharetwi = hashtags + " " + body; if (sharetwi.length() > 115) { sharetwi = sharetwi.substring(0, 114) + "…"; } sharetwi += " http://juick.com/" + mid; model.addAttribute("sharetwi", sharetwi); } if (!crosspostService.getFacebookToken(visitor.getUid()).isPresent()) { model.addAttribute("facebook", 1); } model.addAttribute("tags", tagService.getUserTagStats(visitor.getUid()).stream() .sorted((e1, e2) -> Integer.compare(e2.getUsageCount(), e1.getUsageCount())).map(t -> t.getTag().getName()).collect(Collectors.toList())); return "views/post_success"; } @PostMapping("/comment") public String doPostComment( @RequestParam(required = false, defaultValue = "0") Integer mid, @RequestParam(required = false, defaultValue = "0") Integer rid, @RequestParam(required = false, defaultValue = StringUtils.EMPTY) String body, @RequestParam(required = false) String img, @RequestParam(required = false) MultipartFile attach) throws IOException { com.juick.User visitor = UserUtils.getCurrentUser(); if (mid == 0) { throw new HttpBadRequestException(); } com.juick.Message msg = messagesService.getMessage(mid); if (msg == null) { throw new HttpNotFoundException(); } com.juick.Message reply = null; if (rid > 0) { reply = messagesService.getReply(mid, rid); if (reply == null) { throw new HttpNotFoundException(); } } if ((StringUtils.isEmpty(body) || body.length() > 4096) && StringUtils.isEmpty(img)) { throw new HttpBadRequestException(); } body = body.replace("\r", StringUtils.EMPTY); if ((msg.ReadOnly && msg.getUser().getUid() != visitor.getUid()) || userService.isInBLAny(msg.getUser().getUid(), visitor.getUid()) || (reply != null && userService.isInBLAny(reply.getUser().getUid(), visitor.getUid()))) { throw new HttpForbiddenException(); } String attachmentFName = HttpUtils.receiveMultiPartFile(attach, webApp.getTmpDir()); if (StringUtils.isBlank(attachmentFName) && img != null && img.length() > 10) { try { URL imgUrl = new URL(img); attachmentFName = HttpUtils.downloadImage(imgUrl, webApp.getTmpDir()); } catch (Exception e) { logger.error("DOWNLOAD ERROR", e); throw new HttpBadRequestException(); } } String attachmentType = StringUtils.isNotEmpty(attachmentFName) ? attachmentFName.substring(attachmentFName.length() - 3) : null; int ridnew = messagesService.createReply(mid, rid, visitor.getUid(), body, attachmentType); subscriptionService.subscribeMessage(mid, visitor.getUid()); Message xmsg = new Message(); xmsg.setFrom(Jid.of("juick@juick.com")); xmsg.setType(Message.Type.CHAT); xmsg.setThread("juick-" + mid); com.juick.Message jmsg = messagesService.getReply(mid, ridnew); xmsg.addExtension(jmsg); String quote = reply != null ? reply.getText() : msg.getText(); if (quote.length() >= 50) { quote = quote.substring(0, 47) + "..."; } xmsg.addExtension(new Nickname("@" + jmsg.getUser().getName())); if (StringUtils.isNotEmpty(attachmentFName)) { String fname = mid + "-" + ridnew + "." + attachmentType; String attachmentURL = "http://i.juick.com/photos-1024/" + fname; ImageUtils.saveImageWithPreviews(attachmentFName, fname, webApp.getTmpDir(), webApp.getImgDir()); body = attachmentURL + "\n" + body; try { xmsg.addExtension(new OobX(new URI(attachmentURL))); } catch (URISyntaxException e) { logger.warn("invalid uri: {}, exception {}", attachmentURL, e); } } if (webApp.getXmpp() != null) { xmsg.setBody("Reply by @" + jmsg.getUser().getName() + ":\n>" + quote + "\n" + body + "\n\n#" + mid + "/" + ridnew + " http://juick.com/" + mid + "#" + ridnew); xmsg.setTo(Jid.of("juick@s2s.juick.com")); webApp.getXmpp().send(xmsg); xmsg.setTo(Jid.of("juick@ws.juick.com")); webApp.getXmpp().send(xmsg); xmsg.setTo(Jid.of("juick@push.juick.com")); webApp.getXmpp().send(xmsg); } else { logger.warn("XMPP unavailable"); } return "redirect:/" + msg.getUser().getName() + "/" + mid + "#" + ridnew; } @PostMapping("/like") @ResponseBody public Status doPostRecomm(@RequestParam Integer mid) throws IOException { com.juick.User visitor = UserUtils.getCurrentUser(); if (visitor.getUid() == 0) { throw new HttpForbiddenException(); } com.juick.Message msg = messagesService.getMessage(mid); if (msg == null) { throw new HttpNotFoundException(); } if (msg.getUser().getUid() == visitor.getUid()) { throw new HttpForbiddenException(); } boolean res = messagesService.recommendMessage(mid, visitor.getUid()); if (res) { if (webApp.getXmpp() != null) { Message xmsg = new Message(); xmsg.setFrom(Jid.of("juick@juick.com")); xmsg.setTo(Jid.of("recomm@s2s.juick.com")); com.juick.Message jmsg = new com.juick.Message(); jmsg.setMid(mid); jmsg.setUser(visitor); xmsg.addExtension(jmsg); webApp.getXmpp().send(xmsg); } else { logger.warn("XMPP unavailable"); } return Status.OK; } else { throw new HttpBadRequestException(); } } @PostMapping("/pm/send") public String doPostPM(@RequestParam(name = "uname", required = false) String unameParam, @RequestParam String body) throws IOException { com.juick.User visitor = UserUtils.getCurrentUser(); if (visitor.getUid() == 0 || visitor.isBanned()) { throw new HttpForbiddenException(); } String uname = unameParam; if (uname.startsWith("@")) { uname = uname.substring(1); } int uid = 0; if (WebUtils.isUserName(uname)) { uid = userService.getUIDbyName(uname); } if (uid == 0 || body.length() > 10240) { throw new HttpBadRequestException(); } if (userService.isInBLAny(uid, visitor.getUid())) { throw new HttpForbiddenException(); } if (pmQueriesService.createPM(visitor.getUid(), uid, body)) { if (webApp.getXmpp() != null) { Message msg = new Message(); msg.setFrom(Jid.of("juick@juick.com")); msg.setTo(Jid.of(String.format("%d@push.juick.com", uid))); com.juick.Message jmsg = new com.juick.Message(); jmsg.setUser(visitor); jmsg.setText(body); msg.addExtension(jmsg); webApp.getXmpp().send(msg); msg.setTo(Jid.of(String.format("%d@ws.juick.com", uid))); webApp.getXmpp().send(msg); List jids = userService.getJIDsbyUID(uid); for (String jid : jids) { Message mm = new Message(); mm.setTo(Jid.of(jid)); mm.setType(Message.Type.CHAT); if (pmQueriesService.havePMinRoster(visitor.getUid(), jid)) { mm.setFrom(Jid.of(jmsg.getUser().getName(), "juick.com", "Juick")); mm.setBody(body); } else { mm.setFrom(Jid.of("juick", "juick.com", "Juick")); mm.setBody("Private message from @" + jmsg.getUser().getName() + ":\n" + body); } webApp.getXmpp().send(mm); } } else { logger.warn("XMPP unavailable"); } return "redirect:/pm/sent"; } else { throw new HttpBadRequestException(); } } @PostMapping("/post2") public String doPostMessage(@RequestParam(name = "body") String bodyParam, @RequestParam(required = false) String img, @RequestParam(required = false) String referer, @RequestParam(required = false) MultipartFile attach) throws IOException { com.juick.User visitor = UserUtils.getCurrentUser(); if (visitor.getUid() == 0 || visitor.isBanned()) { throw new HttpForbiddenException(); } String body = bodyParam.replace("\r", StringUtils.EMPTY); String attachmentFName = HttpUtils.receiveMultiPartFile(attach, webApp.getTmpDir()); if (StringUtils.isBlank(attachmentFName) && img != null && img.length() > 10) { try { URL imgUrl = new URL(img); attachmentFName = HttpUtils.downloadImage(imgUrl, webApp.getTmpDir()); } catch (Exception e) { logger.error("DOWNLOAD ERROR", e); 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(Jid.of("juick@juick.com/Juick")); msg.setBody(body); try { if (StringUtils.isNotEmpty(attachmentFName)) { String attachmentUrl = String.format("juick://%s", attachmentFName); msg.addExtension(new OobX(new URI(attachmentUrl), "!!!!Juick!!")); } webApp.getXmpp().sendMessage(msg); } catch (URISyntaxException e1) { logger.warn("attachment error", e1); } 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"; } return "redirect:" + referer; } }