aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Vitaly Takmazov2016-12-20 12:33:51 +0300
committerGravatar Vitaly Takmazov2016-12-20 12:33:51 +0300
commit8b02f969d3a09e39557474eb90ec821d550e3b1b (patch)
tree21dcc4d441cb55f7f83daf38b75c25fac163b88e
parentd2de0b9d8cd2ddc6edb24de9d52ee8ab533c7403 (diff)
juick-spring-www: WIP
-rw-r--r--juick-spring-www/src/main/java/com/juick/www/controllers/PMController.java2
-rw-r--r--juick-spring-www/src/main/java/com/juick/www/controllers/PostController.java280
-rw-r--r--juick-spring-www/src/main/webapp/WEB-INF/templates/views/error.html1
-rw-r--r--juick-spring-www/src/main/webapp/WEB-INF/templates/views/partial/blog_messages.html6
-rw-r--r--juick-spring-www/src/main/webapp/WEB-INF/templates/views/posted.html40
5 files changed, 325 insertions, 4 deletions
diff --git a/juick-spring-www/src/main/java/com/juick/www/controllers/PMController.java b/juick-spring-www/src/main/java/com/juick/www/controllers/PMController.java
index 3228b4c0..9fceb23c 100644
--- a/juick-spring-www/src/main/java/com/juick/www/controllers/PMController.java
+++ b/juick-spring-www/src/main/java/com/juick/www/controllers/PMController.java
@@ -73,7 +73,7 @@ public class PMController {
return "views/pm_sent";
}
- @RequestMapping(value = "/pm/sent", method = RequestMethod.POST)
+ @RequestMapping(value = "/pm/send", method = RequestMethod.POST)
public String doPostPM(
@RequestParam String uname,
@RequestParam String body,
diff --git a/juick-spring-www/src/main/java/com/juick/www/controllers/PostController.java b/juick-spring-www/src/main/java/com/juick/www/controllers/PostController.java
new file mode 100644
index 00000000..1ce2f893
--- /dev/null
+++ b/juick-spring-www/src/main/java/com/juick/www/controllers/PostController.java
@@ -0,0 +1,280 @@
+package com.juick.www.controllers;
+
+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.HttpNotFoundException;
+import com.juick.server.util.HttpUtils;
+import com.juick.service.MessagesService;
+import com.juick.service.SubscriptionService;
+import com.juick.service.TagService;
+import com.juick.service.UserService;
+import com.juick.util.UserUtils;
+import com.juick.www.WebApp;
+import net.coobird.thumbnailator.Thumbnails;
+import org.apache.commons.lang3.CharEncoding;
+import org.apache.commons.lang3.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.core.env.Environment;
+import org.springframework.stereotype.Controller;
+import org.springframework.ui.ModelMap;
+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.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.net.URLEncoder;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.List;
+
+/**
+ * Created by vitalyster on 20.12.2016.
+ */
+@Controller
+public class PostController {
+
+ private static final Logger logger = LoggerFactory.getLogger(PostController.class);
+
+ @Inject
+ MessagesService messagesService;
+ @Inject
+ UserService userService;
+ @Inject
+ SubscriptionService subscriptionService;
+ @Inject
+ TagService tagService;
+ @Inject
+ WebApp webApp;
+ @Inject
+ Environment env;
+
+ @RequestMapping(value = "/post", method = RequestMethod.POST)
+ public String doPost(
+ @RequestParam(required = false, value = "tags") String tagsStr,
+ @RequestParam String body,
+ @RequestParam(required = false) String img,
+ @RequestParam(required = false) MultipartFile attach,
+ ModelMap modelMap
+ ) throws IOException {
+ body = body.replace("\r", "");
+
+ List<Tag> tags = tagService.fromString(tagsStr, true);
+
+ String attachmentFName = HttpUtils.receiveMultiPartFile(attach, env.getProperty("upload_tmp_dir",
+ "/var/www/juick.com/i/tmp/"));
+
+ if (StringUtils.isBlank(attachmentFName) && img != null && img.length() > 10) {
+ try {
+ URL imgUrl = new URL(img);
+ attachmentFName = HttpUtils.downloadImage(imgUrl);
+ } catch (Exception e) {
+ logger.error("DOWNLOAD ERROR", e);
+ throw new HttpBadRequestException();
+ }
+ }
+
+ User visitor = UserUtils.getCurrentUser();
+
+ 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;
+
+ Path origName = Paths.get(webApp.imgDir, "p", fname);
+ Files.move(Paths.get(webApp.tmpDir, attachmentFName), origName);
+ Thumbnails.of(origName.toFile()).size(1024, 1024).outputQuality(0.9)
+ .toFile(Paths.get(webApp.imgDir, "photos-1024", fname).toFile());
+ Thumbnails.of(origName.toFile()).size(512, 512).outputQuality(0.9)
+ .toFile(Paths.get(webApp.imgDir, "photos-512", fname).toFile());
+ Thumbnails.of(origName.toFile()).size(160, 120).outputQuality(0.9)
+ .toFile(Paths.get(webApp.imgDir, "ps", fname).toFile());
+
+ 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("twitter@crosspost.juick.com"));
+ webApp.getXmpp().send(xmsg);
+ xmsg.setTo(Jid.of("fb@crosspost.juick.com"));
+ webApp.getXmpp().send(xmsg);
+
+ xmsg.setTo(Jid.of("jubo@nologin.ru"));
+ webApp.getXmpp().send(xmsg);
+ } else {
+ logger.warn("XMPP unavailable");
+ }
+
+ String hashtags = "";
+ String tagscomma = "";
+ for (int i = 0; i < jmsg.getTags().size(); i++) {
+ if (i > 0) {
+ hashtags += " ";
+ tagscomma += ",";
+ }
+ hashtags += "#" + jmsg.getTags().get(i);
+ tagscomma += jmsg.getTags().get(i);
+ }
+
+ String url = URLEncoder.encode("http://juick.com/" + mid, CharEncoding.UTF_8);
+ String sharetwi = hashtags + " " + body;
+ if (sharetwi.length() > 115) {
+ sharetwi = sharetwi.substring(0, 114) + "…";
+ }
+ sharetwi += " http://juick.com/" + mid;
+ String sharelj = URLEncoder.encode(body + "\n", CharEncoding.UTF_8) + url;
+
+ modelMap.put("title", "Сообщение опубликовано");
+ modelMap.put("url", url);
+ modelMap.put("sharetwi", URLEncoder.encode(sharetwi, CharEncoding.UTF_8));
+ modelMap.put("sharelj", sharelj);
+ modelMap.put("mid", mid);
+
+ return "views/posted";
+ }
+
+ @RequestMapping(value = "/comment", method = RequestMethod.POST)
+ public String doComment(
+ @RequestParam(defaultValue = "0") int mid,
+ @RequestParam(required = false, defaultValue = "0") int rid,
+ @RequestParam String body,
+ @RequestParam(required = false) String img,
+ @RequestParam(required = false) MultipartFile attach) throws IOException {
+ 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 (body.length() < 1 || body.length() > 4096) {
+ throw new HttpBadRequestException();
+ }
+ body = body.replace("\r", "");
+
+ User visitor = UserUtils.getCurrentUser();
+
+ 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, env.getProperty("upload_tmp_dir",
+ "/var/www/juick.com/i/tmp/"));
+
+ if (StringUtils.isBlank(attachmentFName) && img != null && img.length() > 10) {
+ try {
+ URL imgUrl = new URL(img);
+ attachmentFName = HttpUtils.downloadImage(imgUrl);
+ } 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());
+
+ com.juick.Message jmsg = messagesService.getReply(mid, ridnew);
+
+ Message xmsg = new Message();
+ xmsg.setFrom(Jid.of("juick@juick.com"));
+ xmsg.setType(Message.Type.CHAT);
+ xmsg.setThread("juick-" + mid);
+
+ 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;
+
+ Path origName = Paths.get(webApp.imgDir, "p", fname);
+ Files.move(Paths.get(webApp.tmpDir, attachmentFName), origName);
+ Thumbnails.of(origName.toFile()).size(1024, 1024).outputQuality(0.9)
+ .toFile(Paths.get(webApp.imgDir, "photos-1024", fname).toFile());
+ Thumbnails.of(origName.toFile()).size(512, 512).outputQuality(0.9)
+ .toFile(Paths.get(webApp.imgDir, "photos-512", fname).toFile());
+ Thumbnails.of(origName.toFile()).size(160, 120).outputQuality(0.9)
+ .toFile(Paths.get(webApp.imgDir, "ps", fname).toFile());
+
+ 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;
+ }
+}
diff --git a/juick-spring-www/src/main/webapp/WEB-INF/templates/views/error.html b/juick-spring-www/src/main/webapp/WEB-INF/templates/views/error.html
index 0b22deb3..9d763feb 100644
--- a/juick-spring-www/src/main/webapp/WEB-INF/templates/views/error.html
+++ b/juick-spring-www/src/main/webapp/WEB-INF/templates/views/error.html
@@ -11,5 +11,6 @@
<p th:text="#{error.pageNotFound.description}">Probably, user deleted this post, or this page never existed.</p>
</article>
</section>
+<p layout:fragment="column" th:replace="views/partial/homecolumn">Main side column</p>
</body>
</html> \ No newline at end of file
diff --git a/juick-spring-www/src/main/webapp/WEB-INF/templates/views/partial/blog_messages.html b/juick-spring-www/src/main/webapp/WEB-INF/templates/views/partial/blog_messages.html
index 3c7e4238..5d808f98 100644
--- a/juick-spring-www/src/main/webapp/WEB-INF/templates/views/partial/blog_messages.html
+++ b/juick-spring-www/src/main/webapp/WEB-INF/templates/views/partial/blog_messages.html
@@ -28,12 +28,12 @@
<nav class="l">
<th:block th:switch="${#authorization.expression('isAuthenticated()')}">
<a th:case="false" class="a-login" th:href="|/${msg.getMid()}/|" th:text="#{message.recommend}">Recommend</a>
- <a th:case="true" class="a-like" th:href="|/post?body=!+%23${msg.getMid()}/|" th:text="#{message.comment}">Comment</a>
+ <a th:case="true" class="a-like" th:href="|/post?body=!+%23${msg.getMid()}/|" th:text="#{message.recommend}">Recommend</a>
</th:block>
<a th:if="${#authorization.expression('isAuthenticated()') == false && !msg.ReadOnly}" class="a-login"
th:href="|/${msg.getMid()}/|" th:text="#{message.comment}">Comment</a>
<a th:if="${#authorization.expression('isAuthenticated()') == true && !msg.ReadOnly}"
- class="a-comment" th:href="|/${msg.getMid()}/|" th:text="#{message.recommend}">Recommend</a>
+ class="a-comment" th:href="|/${msg.getMid()}/|" th:text="#{message.comment}">Comment</a>
<th:block th:if="${#authorization.expression('hasRole(''ROLE_ADMIN'')')}">
<a href="#" class="a-popular-plus">+</a>
@@ -46,7 +46,7 @@
class="likes"><i data-icon="ei-heart" data-size="s"></i>
<span th:text="${msg.getLikes()}" th:remove="tag">&nbsp;10</span></a>
<a th:if="${msg.getReplies() > 0}" th:href="|/${msg.getUser().getName()}/${msg.getMid()}|"
- class="replies"><i data-icon="ei-heart" data-size="s"></i>
+ class="replies"><i data-icon="ei-comment" data-size="s"></i>
<span th:text="${msg.getReplies()}" th:remove="tag">&nbsp;42</span>
</a>
</nav>
diff --git a/juick-spring-www/src/main/webapp/WEB-INF/templates/views/posted.html b/juick-spring-www/src/main/webapp/WEB-INF/templates/views/posted.html
new file mode 100644
index 00000000..25432c2c
--- /dev/null
+++ b/juick-spring-www/src/main/webapp/WEB-INF/templates/views/posted.html
@@ -0,0 +1,40 @@
+<!DOCTYPE html>
+<html xmlns:th="http://www.thymeleaf.org"
+ xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
+ layout:decorate="~{layout/mainLayout}">
+<head>
+ <title th:if="${#authorization.expression('isAuthenticated()')}" th:text="${title}">Page title</title>
+</head>
+
+<body>
+<article layout:fragment="content">
+ <h1>Сообщение опубликовано</h1>
+ <p>Поделитесь своим новым постом в социальных сетях:</p>
+ <p class="social" th:if="${sharetwi} != null">
+ <a
+ th:href="|https://twitter.com/intent/tweet?text=${sharetwi}|"
+ class="ico32-twi sharenew">Отправить в Twitter</a>
+ </p>
+ <p class="social">
+ <a th:href="|http://www.livejournal.com/update.bml?subject=${hashtags}&event=${sharelj}&prop_taglist=${tagscomma}|"
+ target="_blank" class="ico32-lj sharenew">Отправить в LiveJournal</a>
+ </p>
+ <p class="social">
+ <a th:href="|https://vk.com/share.php?url=${url}|" class="ico32-vk sharenew">Отправить в ВКонтакте</a>
+ </p>
+ <p class="social">
+ <a th:href="|https://www.facebook.com/sharer/sharer.php?u=${url}|"
+ class="ico32-fb sharenew">Отправить в Facebook</a>
+ </p>
+ <p>Ссылка на сообщение:
+ <a th:href="|http://juick.com/${mid}|" th:text="|http://juick.com/${mid}|">http://juick.com/12345
+ </a>
+ </p>
+</article>
+
+<aside id="column">
+ <p layout:fragment="column" th:replace="views/partial/homecolumn">Main side column</p>
+</aside>
+
+</body>
+</html> \ No newline at end of file