aboutsummaryrefslogtreecommitdiff
path: root/juick-www/src/main/java/com/juick/www/controllers
diff options
context:
space:
mode:
authorGravatar Vitaly Takmazov2016-12-28 22:38:21 +0300
committerGravatar Vitaly Takmazov2017-01-10 12:08:35 +0300
commit2f682b5e3cfc3fc5f961b60129be7bc90e0d6a03 (patch)
tree840aea9eb94d5c1f667a710d3298135854bc5002 /juick-www/src/main/java/com/juick/www/controllers
parenteb440ea4f120115613880e340b010eed5397e72c (diff)
juick-www: now on spring-webmvc
Diffstat (limited to 'juick-www/src/main/java/com/juick/www/controllers')
-rw-r--r--juick-www/src/main/java/com/juick/www/controllers/Discover.java138
-rw-r--r--juick-www/src/main/java/com/juick/www/controllers/FacebookLogin.java153
-rw-r--r--juick-www/src/main/java/com/juick/www/controllers/Help.java74
-rw-r--r--juick-www/src/main/java/com/juick/www/controllers/Home.java232
-rw-r--r--juick-www/src/main/java/com/juick/www/controllers/Login.java258
-rw-r--r--juick-www/src/main/java/com/juick/www/controllers/NewMessage.java468
-rw-r--r--juick-www/src/main/java/com/juick/www/controllers/PM.java163
-rw-r--r--juick-www/src/main/java/com/juick/www/controllers/PageTemplates.java381
-rw-r--r--juick-www/src/main/java/com/juick/www/controllers/RSS.java66
-rw-r--r--juick-www/src/main/java/com/juick/www/controllers/Settings.java287
-rw-r--r--juick-www/src/main/java/com/juick/www/controllers/SignUp.java170
-rw-r--r--juick-www/src/main/java/com/juick/www/controllers/TwitterAuth.java103
-rw-r--r--juick-www/src/main/java/com/juick/www/controllers/User.java368
-rw-r--r--juick-www/src/main/java/com/juick/www/controllers/UserThread.java374
-rw-r--r--juick-www/src/main/java/com/juick/www/controllers/VKontakteLogin.java130
-rw-r--r--juick-www/src/main/java/com/juick/www/controllers/XMPPPost.java84
16 files changed, 3449 insertions, 0 deletions
diff --git a/juick-www/src/main/java/com/juick/www/controllers/Discover.java b/juick-www/src/main/java/com/juick/www/controllers/Discover.java
new file mode 100644
index 00000000..e5d17501
--- /dev/null
+++ b/juick-www/src/main/java/com/juick/www/controllers/Discover.java
@@ -0,0 +1,138 @@
+/*
+ * Juick
+ * Copyright (C) 2008-2011, Ugnich Anton
+ *
+ * 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.www.controllers;
+
+import com.juick.service.AdsService;
+import com.juick.service.MessagesService;
+import com.juick.service.TagService;
+import com.juick.www.Utils;
+import com.juick.www.WebApp;
+import org.apache.commons.lang3.CharEncoding;
+import org.apache.commons.lang3.StringEscapeUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+
+import javax.inject.Inject;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.net.URLDecoder;
+import java.net.URLEncoder;
+import java.util.List;
+
+/**
+ *
+ * @author Ugnich Anton
+ */
+@Controller
+public class Discover {
+ @Inject
+ WebApp webApp;
+ @Inject
+ MessagesService messagesService;
+ @Inject
+ TagService tagService;
+ @Inject
+ AdsService adsService;
+ @Inject
+ PageTemplates templates;
+
+ @RequestMapping(value = "/tag/{tagName}", method = RequestMethod.GET)
+ protected void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {
+ com.juick.User visitor = webApp.getVisitorUser(request, response);
+
+ String paramTagStr = URLDecoder.decode(request.getRequestURI().substring(5), CharEncoding.UTF_8);
+ com.juick.Tag paramTag = tagService.getTag(paramTagStr, false);
+ if (paramTag == null) {
+ response.sendError(HttpServletResponse.SC_NOT_FOUND);
+ return;
+ } else if (paramTag.SynonymID > 0 && paramTag.TID != paramTag.SynonymID) {
+ com.juick.Tag synTag = tagService.getTag(paramTag.SynonymID);
+ String url = "/tag/" + URLEncoder.encode(synTag.getName(), CharEncoding.UTF_8);
+ if (request.getQueryString() != null) {
+ url += "?" + request.getQueryString();
+ }
+ Utils.sendPermanentRedirect(response, url);
+ return;
+ } else if (!paramTag.getName().equals(paramTagStr)) {
+ String url = "/tag/" + URLEncoder.encode(paramTag.getName(), CharEncoding.UTF_8);
+ if (request.getQueryString() != null) {
+ url += "?" + request.getQueryString();
+ }
+ Utils.sendPermanentRedirect(response, url);
+ return;
+ }
+
+ int paramBefore = 0;
+ String paramBeforeStr = request.getParameter("before");
+ if (paramBeforeStr != null) {
+ try {
+ paramBefore = Integer.parseInt(paramBeforeStr);
+ } catch (NumberFormatException e) {
+ }
+ }
+
+ int visitor_uid = visitor.getUid();
+
+ String title = "*" + StringEscapeUtils.escapeHtml4(paramTag.getName());
+ List<Integer> mids = messagesService.getTag(paramTag.TID, visitor_uid, paramBefore, (visitor_uid == 0) ? 40 : 20);
+
+ response.setContentType("text/html; charset=UTF-8");
+ try (PrintWriter out = response.getWriter()) {
+ String head = StringUtils.EMPTY;
+ if (tagService.getTagNoIndex(paramTag.TID)) {
+ head = "<meta name=\"robots\" content=\"noindex,nofollow\"/>";
+ } else if (paramBefore > 0 || mids.size() < 5) {
+ head = "<meta name=\"robots\" content=\"noindex\"/>";
+ }
+ templates.pageHead(out, visitor, title, head);
+ templates.pageNavigation(out, visitor, null);
+
+ out.println("<section id=\"content\">");
+
+ if (mids.size() > 0) {
+ int vuid = visitor.getUid();
+ int ad_mid = adsService.getAdMid(vuid);
+ if (ad_mid > 0 && mids.indexOf(ad_mid) == -1) {
+ mids.add(0, ad_mid);
+ adsService.logAdMid(vuid, ad_mid);
+ } else {
+ ad_mid = 0;
+ }
+
+ templates.printMessages(out, null, mids, visitor, visitor_uid == 0 ? 2 : 3, ad_mid);
+ }
+
+ if (mids.size() >= 20) {
+ String nextpage = "/tag/" + URLEncoder.encode(paramTag.getName(), CharEncoding.UTF_8) + "?before=" + mids.get(mids.size() - 1);
+ out.println("<p class=\"page\"><a href=\"" + nextpage + "\" rel=\"prev\">Читать дальше →</a></p>");
+ }
+
+ out.println("</section>");
+
+ templates.pageHomeColumn(out, visitor);
+
+ templates.pageFooter(request, out, visitor, true);
+
+ templates.pageEnd(out);
+ }
+ }
+}
diff --git a/juick-www/src/main/java/com/juick/www/controllers/FacebookLogin.java b/juick-www/src/main/java/com/juick/www/controllers/FacebookLogin.java
new file mode 100644
index 00000000..cc11f99a
--- /dev/null
+++ b/juick-www/src/main/java/com/juick/www/controllers/FacebookLogin.java
@@ -0,0 +1,153 @@
+/*
+ * Juick
+ * Copyright (C) 2008-2013, Ugnich Anton
+ *
+ * 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.www.controllers;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.juick.service.CrosspostService;
+import com.juick.service.UserService;
+import com.juick.www.Utils;
+import com.juick.www.facebook.Graph;
+import org.apache.commons.lang3.CharEncoding;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.commons.lang3.math.NumberUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.core.env.Environment;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+
+import javax.inject.Inject;
+import javax.servlet.http.Cookie;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.UnsupportedEncodingException;
+import java.net.URLEncoder;
+import java.util.UUID;
+
+/**
+ *
+ * @author Ugnich Anton
+ */
+@Controller
+public class FacebookLogin {
+
+ private static final Logger logger = LoggerFactory.getLogger(FacebookLogin.class);
+
+ private final String FACEBOOK_APPID;
+ private final String FACEBOOK_SECRET;
+ private final String FACEBOOK_REDIRECT = "http://juick.com/_fblogin";
+ private final ObjectMapper mapper;
+
+ @Inject
+ CrosspostService crosspostService;
+ @Inject
+ UserService userService;
+
+ @Inject
+ public FacebookLogin(Environment env) {
+ FACEBOOK_APPID = env.getProperty("facebook_appid");
+ FACEBOOK_SECRET = env.getProperty("facebook_secret");
+
+ mapper = new ObjectMapper();
+ mapper.setSerializationInclusion(JsonInclude.Include.NON_EMPTY);
+ mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
+ mapper.setSerializationInclusion(JsonInclude.Include.NON_DEFAULT);
+ }
+
+ @RequestMapping(value = "/_fblogin", method = RequestMethod.GET)
+ protected void doGet(HttpServletRequest request, HttpServletResponse response) throws UnsupportedEncodingException {
+ String fbstate;
+
+ String code = request.getParameter("code");
+ if (StringUtils.isBlank(code)) {
+ fbstate = UUID.randomUUID().toString();
+
+ Cookie c = new Cookie("fbstate", fbstate);
+ response.addCookie(c);
+
+ response.setStatus(HttpServletResponse.SC_MOVED_TEMPORARILY);
+ response.setHeader("Location", "https://www.facebook.com/dialog/oauth?scope=publish_stream&client_id=" + FACEBOOK_APPID + "&redirect_uri=" + URLEncoder.encode(FACEBOOK_REDIRECT, CharEncoding.UTF_8) + "&state=" + fbstate);
+ return;
+ }
+
+ fbstate = Utils.getCookie(request, "fbstate");
+ if (fbstate == null || fbstate.isEmpty() || !fbstate.equals(request.getParameter("state"))) {
+ response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
+ return;
+ } else {
+ Cookie c = new Cookie("fbstate", "-");
+ c.setMaxAge(0);
+ response.addCookie(c);
+ }
+
+ String token = Utils.fetchURL("https://graph.facebook.com/oauth/access_token?client_id=" + FACEBOOK_APPID + "&redirect_uri=" + URLEncoder.encode(FACEBOOK_REDIRECT, CharEncoding.UTF_8) + "&client_secret=" + FACEBOOK_SECRET + "&code=" + URLEncoder.encode(code, CharEncoding.UTF_8));
+ if (token == null || token.isEmpty() || !token.startsWith("access_token=")) {
+ logger.error("FACEBOOK TOKEN ERROR: {}", token);
+ response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
+ return;
+ }
+ token = token.substring(13); // access_token=...
+ int tokenamp = token.indexOf('&'); // &expires=
+ if (tokenamp > 0) {
+ token = token.substring(0, tokenamp);
+ }
+
+ String graph = Utils.fetchURL("https://graph.facebook.com/me?access_token=" + token);
+ if (graph == null || graph.isEmpty()) {
+ logger.error("FACEBOOK GRAPH ERROR");
+ response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
+ return;
+ }
+
+ try {
+ Graph fb = mapper.readValue(graph, Graph.class);
+
+ long fbID = NumberUtils.toLong(fb.getId(), 0);
+ if (fbID == 0 || StringUtils.isBlank(fb.getName()) || StringUtils.isBlank(fb.getLink())) {
+ throw new Exception();
+ }
+
+ int uid = crosspostService.getUIDbyFBID(fbID);
+ if (uid > 0) {
+ if (!crosspostService.updateFacebookUser(fbID, token, fb.getName(), fb.getLink())) {
+ throw new Exception();
+ }
+ Cookie c = new Cookie("hash", userService.getHashByUID(uid));
+ c.setMaxAge(50 * 24 * 60 * 60);
+ response.addCookie(c);
+ response.setStatus(HttpServletResponse.SC_MOVED_TEMPORARILY);
+ response.setHeader("Location", "/");
+ } else if (fb.getVerified()) {
+ String loginhash = UUID.randomUUID().toString();
+ if (!crosspostService.createFacebookUser(fbID, loginhash, token, fb.getName(), fb.getLink())) {
+ throw new Exception();
+ }
+ response.setStatus(HttpServletResponse.SC_MOVED_TEMPORARILY);
+ response.setHeader("Location", "/signup?type=fb&hash=" + loginhash);
+ } else {
+ throw new Exception();
+ }
+ } catch (Exception e) {
+ logger.error("fb error", e);
+ response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
+ return;
+ }
+ }
+}
diff --git a/juick-www/src/main/java/com/juick/www/controllers/Help.java b/juick-www/src/main/java/com/juick/www/controllers/Help.java
new file mode 100644
index 00000000..58949827
--- /dev/null
+++ b/juick-www/src/main/java/com/juick/www/controllers/Help.java
@@ -0,0 +1,74 @@
+package com.juick.www.controllers;
+
+import com.juick.server.util.HttpNotFoundException;
+import com.juick.www.HelpService;
+import com.juick.www.WebApp;
+import org.springframework.stereotype.Controller;
+import org.springframework.ui.Model;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestMapping;
+
+import javax.inject.Inject;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.net.URISyntaxException;
+import java.util.Locale;
+import java.util.Objects;
+import java.util.Optional;
+
+/**
+ * Created by aalexeev on 11/21/16.
+ */
+@Controller
+public class Help {
+ @Inject
+ private HelpService helpService;
+ @Inject
+ private WebApp webApp;
+
+ @RequestMapping({"/help/", "/help", "/help/{langOrPage}", "/help/{lang}/{page}"})
+ public String showHelp(
+ HttpServletRequest request,
+ HttpServletResponse response,
+ Locale locale,
+ @PathVariable("lang") Optional<String> langParam,
+ @PathVariable("page") Optional<String> pageParam,
+ @PathVariable("langOrPage") Optional<String> langOrPageParam,
+ Model model) throws IOException, URISyntaxException {
+ com.juick.User visitor = webApp.getVisitorUser(request, response);
+ String page = pageParam.orElse("index");
+ String lang = langParam.orElse(locale.getLanguage());
+
+ String navigation = null;
+
+ if (langOrPageParam.isPresent()) {
+ String langOrPage = langOrPageParam.get();
+
+ if (helpService.canBeLang(langOrPage)) {
+ navigation = helpService.getHelp("navigation", langOrPage);
+ if (navigation != null)
+ lang = langOrPage;
+ }
+
+ if (navigation == null && helpService.canBePage(langOrPage))
+ page = langOrPage;
+ }
+
+ String content = helpService.getHelp(page, lang);
+ if (content == null && !Objects.equals("index", page))
+ content = helpService.getHelp("index", lang);
+
+ if (navigation == null)
+ navigation = helpService.getHelp("navigation", lang);
+
+ if (content == null || navigation == null)
+ throw new HttpNotFoundException();
+
+ model.addAttribute("navigation", navigation);
+ model.addAttribute("content", content);
+ model.addAttribute("visitor", visitor);
+
+ return "views/help";
+ }
+}
diff --git a/juick-www/src/main/java/com/juick/www/controllers/Home.java b/juick-www/src/main/java/com/juick/www/controllers/Home.java
new file mode 100644
index 00000000..2f9dc903
--- /dev/null
+++ b/juick-www/src/main/java/com/juick/www/controllers/Home.java
@@ -0,0 +1,232 @@
+/*
+ * Juick
+ * Copyright (C) 2008-2011, Ugnich Anton
+ *
+ * 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.www.controllers;
+
+import com.juick.service.AdsService;
+import com.juick.service.MessagesService;
+import com.juick.service.UserService;
+import com.juick.util.WebUtils;
+import com.juick.www.Utils;
+import com.juick.www.WebApp;
+import org.apache.commons.lang3.CharEncoding;
+import org.apache.commons.lang3.StringEscapeUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.commons.lang3.math.NumberUtils;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.RequestParam;
+
+import javax.inject.Inject;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.net.URLEncoder;
+import java.util.List;
+
+/**
+ *
+ * @author Ugnich Anton
+ */
+@Controller
+public class Home {
+ @Inject
+ UserService userService;
+ @Inject
+ MessagesService messagesService;
+ @Inject
+ AdsService adsService;
+ @Inject
+ PageTemplates templates;
+ @Inject
+ WebApp webApp;
+
+ @RequestMapping(value = "/{anything}/**", method = RequestMethod.GET)
+ protected void parseAnyThing(HttpServletResponse response, @PathVariable String anything,
+ @RequestParam(required = false, defaultValue = "0") int before) throws IOException {
+ if (before == 0) {
+ boolean isPostNumber = WebUtils.isPostNumber(anything);
+ int messageId = isPostNumber ?
+ NumberUtils.toInt(anything) : 0;
+
+ if (isPostNumber && anything.equals(Integer.toString(messageId))) {
+ if (messageId > 0) {
+ com.juick.User author = messagesService.getMessageAuthor(messageId);
+
+ if (author != null) {
+ Utils.sendPermanentRedirect(response, "/" + author.getName() + "/" + anything);
+ return;
+ }
+ }
+ }
+ com.juick.User user = userService.getUserByName(anything);
+ if (user.getUid() > 0) {
+ Utils.sendPermanentRedirect(response, "/" + user.getName() + "/");
+ return;
+ }
+ response.sendError(HttpServletResponse.SC_NOT_FOUND);
+ return;
+ }
+ com.juick.User user = userService.getUserByName(anything);
+ if (user.getUid() > 0) {
+ Utils.sendPermanentRedirect(response, "/" + user.getName() + "/?before=" + before);
+ return;
+ } else {
+ response.sendError(HttpServletResponse.SC_NOT_FOUND);
+ return;
+ }
+ }
+
+ @RequestMapping(value = "/", method = RequestMethod.GET)
+ protected void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {
+ String tag = request.getParameter("tag");
+ if (tag != null) {
+ Utils.sendPermanentRedirect(response, "/tag/" + URLEncoder.encode(tag, CharEncoding.UTF_8));
+ }
+ com.juick.User visitor = webApp.getVisitorUser(request, response);
+ int paramBefore = NumberUtils.toInt(request.getParameter("before"), 0);
+
+ String paramSearch = request.getParameter("search");
+ if (paramSearch != null && paramSearch.length() > 64) {
+ paramSearch = null;
+ }
+
+ String title;
+ List<Integer> mids;
+
+ String paramShow = request.getParameter("show");
+ if (paramSearch != null) {
+ title = "Поиск: " + StringEscapeUtils.escapeHtml4(paramSearch);
+ mids = messagesService.getSearch(Utils.encodeSphinx(paramSearch), paramBefore);
+ } else if (paramShow == null) {
+ if (visitor.getUid() > 0) {
+ title = "Популярные";
+ mids = messagesService.getPopular(visitor.getUid(), paramBefore);
+ } else {
+ title = "Микроблоги Juick: популярные записи";
+ mids = messagesService.getPopular(0, paramBefore);
+ }
+
+ } else if (paramShow.equals("top")) {
+ Utils.sendPermanentRedirect(response, "/");
+ return;
+ } else if (paramShow.equals("my") && visitor != null) {
+ title = "Моя лента";
+ mids = messagesService.getMyFeed(visitor.getUid(), paramBefore);
+ } else if (paramShow.equals("private") && visitor != null) {
+ title = "Приватные";
+ mids = messagesService.getPrivate(visitor.getUid(), paramBefore);
+ } else if (paramShow.equals("discuss") && visitor != null) {
+ title = "Обсуждения";
+ mids = messagesService.getDiscussions(visitor.getUid(), paramBefore);
+ } else if (paramShow.equals("recommended") && visitor != null) {
+ title = "Рекомендации";
+ mids = messagesService.getRecommended(visitor.getUid(), paramBefore);
+ } else if (paramShow.equals("photos")) {
+ title = "Фотографии";
+ if (visitor != null) {
+ mids = messagesService.getPhotos(visitor.getUid(), paramBefore);
+ } else {
+ mids = messagesService.getPhotos(0, paramBefore);
+ }
+ } else if (paramShow.equals("all")) {
+ title = "Все сообщения";
+ if (visitor != null) {
+ mids = messagesService.getAll(visitor.getUid(), paramBefore);
+ } else {
+ mids = messagesService.getAll(0, paramBefore);
+ }
+ } else {
+ response.sendError(HttpServletResponse.SC_NOT_FOUND);
+ return;
+ }
+
+ response.setContentType("text/html; charset=UTF-8");
+ try (PrintWriter out = response.getWriter()) {
+ String head = StringUtils.EMPTY;
+ if (paramBefore > 0 || paramShow != null) {
+ head = "<meta name=\"robots\" content=\"noindex\"/>";
+ }
+ templates.pageHead(out, visitor, title, head);
+ templates.pageNavigation(out, visitor, paramSearch);
+
+ out.println("<section id=\"content\">");
+
+ if (paramShow == null && paramBefore == 0) {
+ out.println("<!--noindex-->");
+ }
+
+ if (visitor.getUid() > 0) {
+ out.println("<form action=\"/post\" method=\"post\" enctype=\"multipart/form-data\">");
+ out.println("<section id=\"newmessage\">");
+ out.println(" <textarea name=\"body\" placeholder=\"Новое сообщение...\"></textarea>");
+ out.println(" <div>");
+ out.println(" <input type=\"text\" class=\"img\" name=\"img\" " +
+ "placeholder=\"Ссылка на изображение (JPG/PNG, до 10Мб)\"/> " +
+ "или <a href=\"#\">загрузить</a><br/>");
+ out.println(" <input type=\"text\" class=\"tags\" name=\"tags\" " +
+ "placeholder=\"Теги (через пробел)\"/><br/>");
+ out.println(" <input type=\"submit\" class=\"subm\" value=\"Отправить\"/>");
+ out.println(" </div>");
+ out.println("</section>");
+ out.println("</form>");
+ }
+
+ if (mids.size() > 0) {
+ int ad_mid = 0;
+ if (paramShow == null || paramShow.equals("top") || paramShow.equals("all")) {
+ int vuid = visitor.getUid();
+ ad_mid = adsService.getAdMid(vuid);
+ if (ad_mid > 0 && mids.indexOf(ad_mid) == -1) {
+ mids.add(0, ad_mid);
+ adsService.logAdMid(vuid, ad_mid);
+ } else {
+ ad_mid = 0;
+ }
+ }
+
+ templates.printMessages(out, null, mids, visitor, visitor.getUid() == 0 ? 2 : 3, ad_mid);
+ }
+
+ if (mids.size() >= 20) {
+ String nextpage = "?before=" + mids.get(mids.size() - 1);
+ if (paramShow != null) {
+ nextpage += "&amp;show=" + paramShow;
+ }
+ if (paramSearch != null) {
+ nextpage += "&amp;search=" + URLEncoder.encode(paramSearch, CharEncoding.UTF_8);
+ }
+
+ out.println("<p class=\"page\"><a href=\"" + nextpage + "\" rel=\"prev\">Читать дальше →</a></p>");
+ }
+
+ if (paramShow == null && paramBefore == 0) {
+ out.println("<!--/noindex-->");
+ }
+
+ out.println("</section>");
+
+ templates.pageHomeColumn(out, visitor, paramShow == null && paramBefore == 0 && paramSearch == null && visitor.getUid() == 0);
+
+ templates.pageFooter(request, out, visitor, true);
+ templates.pageEnd(out);
+ }
+ }
+}
diff --git a/juick-www/src/main/java/com/juick/www/controllers/Login.java b/juick-www/src/main/java/com/juick/www/controllers/Login.java
new file mode 100644
index 00000000..bce3e000
--- /dev/null
+++ b/juick-www/src/main/java/com/juick/www/controllers/Login.java
@@ -0,0 +1,258 @@
+/*
+ * Juick
+ * Copyright (C) 2008-2011, Ugnich Anton
+ *
+ * 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.www.controllers;
+
+import com.juick.service.UserService;
+import com.juick.www.Utils;
+import com.juick.www.WebApp;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+
+import javax.inject.Inject;
+import javax.servlet.http.Cookie;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.io.PrintWriter;
+
+/**
+ *
+ * @author Ugnich Anton
+ */
+@Controller
+public class Login {
+ @Inject
+ UserService userService;
+ @Inject
+ WebApp webApp;
+
+ @RequestMapping(value = "/login", method = RequestMethod.GET)
+ protected void doGetLoginForm(HttpServletRequest request, HttpServletResponse response) throws IOException {
+ String hash = request.getQueryString();
+ if (hash != null) {
+ if (hash.length() > 32) {
+ response.sendError(HttpServletResponse.SC_BAD_REQUEST);
+ return;
+ }
+
+ if (userService.getUIDbyHash(hash) > 0) {
+ Cookie c = new Cookie("hash", hash);
+ c.setMaxAge(365 * 24 * 60 * 60);
+ response.addCookie(c);
+ response.sendRedirect("/");
+ } else {
+ response.sendError(HttpServletResponse.SC_FORBIDDEN);
+ }
+ }
+ com.juick.User visitor = webApp.getVisitorUser(request, response);
+ if (visitor.getUid() > 0) {
+ Utils.sendTemporaryRedirect(response, "/");
+ return;
+ }
+
+ response.setContentType("text/html; charset=UTF-8");
+ try (PrintWriter out = response.getWriter()) {
+ out.println("<!DOCTYPE html>");
+ out.println("<html>");
+ out.println("<head>");
+ out.println("<title>Juick</title>");
+ out.println("<script type=\"text/javascript\" src=\"//ajax.googleapis.com/ajax/libs/jquery/1.8.2/jquery.min.js\" defer=\"defer\"></script>");
+ out.println("<style>");
+ out.println("* { margin: 0; padding: 0; }");
+ out.println("html { font-family: sans-serif; font-size: 12pt; }");
+ out.println("html { background: #eeeee5; }");
+ out.println("body { margin: 100px auto 0 auto; width: 1000px; }");
+ out.println("a { color: #069; }");
+ out.println("ul { float: left; width: 700px; height: 350px; list-style-type: none; background: url(/tagscloud.png) no-repeat; position: relative; }");
+ out.println("ul a { position: absolute; display: block; text-indent: 100%; white-space: nowrap; overflow: hidden; }");
+
+ out.println("#bottom1 { position: absolute; left: 0px; bottom: 10px; width: 100%; text-align: center; color: #555; }");
+ out.println("#bottom2 { position: absolute; left: 0px; bottom: -50px; width: 100%; padding-bottom: 20px; text-align: center; font-size: small; color: #777; }");
+
+ out.println("#signup,#signin { margin-left: 730px; width: 250px; }");
+ out.println("#signup { padding-top: 25px; }");
+ out.println("#signup>div { width: 100%; margin: 15px 0; }");
+ out.println("#signup>div>a { display: block; width: 100%; height: 32px; line-height: 32px; text-indent: 37px; text-decoration: none; overflow: hidden; }");
+
+ out.println("#facebook a { color: #FFF; background: url(\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAMAAABEpIrGAAAAAXNSR0IArs4c6QAAADNQTFRFO1edX3ewl6bLnKrOoK3QrrrYvMXe2N7r3OLu3+Tv5urz7O/29vf6+Pn7+vv9/Pz9////ykQjsQAAAEZJREFUOMtjYBgFuAATO68ADxdOaUYuATDAqYBbAL8CFgECCjiBcqz4XMiPz3oQEKCtAgEkwEdIAQchBWyEFDAPkDdHsAIAhZkIwz/VK/UAAAAASUVORK5CYII=\") no-repeat #3A569C; }");
+ out.println("#vk a { color: #FFF; background: url(\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAMAAABEpIrGAAAAAXNSR0IArs4c6QAAAHJQTFRFbY+zbo+zbpCzb5C0cpO1c5O2dZW3dpa4e5m6gJ29gZ69lq/In7bNo7jPrcDUs8XXvs3dv87dy9fkztnlz9rm0Nrm093o1N7o1+Dq3OTt3ubu4Ofv5Orw7fH27vL28PP38vX49Pb5+vv8+/z9/Pz9////2jSYlQAAAG5JREFUOMvtkEcOgDAMBE3vvXdIyP+/iMMRKfYHmMtcRtE6AD8f1Is8pyKgAs0RGYO2HSWqMQaoBHVRgYsS3AsrtyFlrqgdJlCLb95gxQO6IkZCqL+KCjz0TQU5ejOf2a3aJXPF7BOB2PvMhp8PDzGRFgEe7xvEAAAAAElFTkSuQmCC\") no-repeat #6d8fb3; }");
+ out.println("#xmpp>a { color: #333; background: url(\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAMAAABEpIrGAAAAAXNSR0IArs4c6QAAAt9QTFRFBj5rCUFoFz5mDEFuDUNqGUJkGUNgAEprEkVtGkRhHURnHEZjAE+BIElmEEx/HEx0PUdTHE5wMEtfO0laJk5sFlN6Nk1cKFBuIlJ1R0pYRExTGF2KMVh1OFhxDGSQT1deNlx6TVhkIGKPUlphKWOFU1tiOmB+Vl1kmlAuNmaDQGpaIG6ba2Q2SGeBN2uUNW+LF3mGRmyLV3BAL3xWgmVJ2VAa2lEb0VYX11UafWlmam9mam5xy1km3lUea29y2VccvF8obHBz21gd4VcXS3ebPoVG1lwl5FkaU3iYYHaH2F0ejHFIx2Iv4V0aP4o+02As218g4l4bPYtFX351KZFaymU43mIrVYoz5mEfT4w0xGsrSo82eXqDw2s+z2k1OZVAT4SoPZU5RZM4NJVYbYc8VoSiWY43WItbuXBK52gYOI20TpM6YYSYfX98T5Q7foB9aYSZSZc8Ro21cYxH7GwdT46e0HFGeopO2HA8V5ZEf4s8528l1HM7UJs5UI+xXoyrWZhGY4ylyHdMwXhXQZS7XpdNU5tH4XJBYJZZcIuhbpJk0HdPU588kohqOZ2pVZS30XpX6XcxSaFrz4FIUqVWWqVCYZm23YBGxYRrZZ2QXpy/5YFC7IA+6oBRb6ZUcKZn44ZSgKJu54hHmJqXbbBNfKh3cq5nYqrMpJyVdrBjx5WCo56diamAjaWdyZeE8JFV8ZJWnqOlaK/Sd7Zh7pVdgbN6x52N8JdfwqCU8ZhgZLbXb7a5grtTmK+UxKKWtqahq6qhd7bHqauop6yvqqyp755pbbzRrK6rwamgib53qq+xra+sobSg86Jza8PJsLKujMVctrGwqLapv7Crr7Wr8ad1srSxj8R9uLOys7WyubSztLazkcZ/sre6tbe0r7m0tri1t7m2vri3uLq3v7m4ubu4nc9mpNBvos2UptJxtNWXtteFuNmbuNyQud2Rut6SwN+aweCbwuGdw+KeweKkF4OfHQAAAadJREFUOMtjeEoAMAwfBQ9vYJO68RCu4BYDq1bXmr2XHoMlnlzet2qGpTgX8y2EFWwensEdrW2FbUAlJ2zDKsqaYwo6eZHcIGzoor/s5IdPSfefPt3nf3Xn3HZpPU8xJAXWIvU88VOffcm78vTptrijJe4OfAmy1kgKzjMlaIfUPvvQcObp03U120ucTZQaGc8je1NZrd8g8cL7eUufPp0wfX2mvVydripKONzkTG1JXvL6TuXTR/Zb5gR6F+Vw30QNqNUss/pqn3/MvrTD7Wy1V9Y0jtXoIZnLv2nSnrfzF3bP3hDRu1wwHzOo1VWOTXn5yi/q7MTJuxTUscTFQyHNc5vfbU1btOCgjNBDbJH1UF5i9/XP6VVrJRUfYo/Nx3YcpS/euOo4Pn6MqeDx44f3LoY2SYnOXBlUfPPug8cwRQxQ6Qf39sda+HqZaQiwGydFlx+4eQ+qAqrg4b3bPqbmNhkrNm5cbGUUHply7d6Dh8hWPH744Oa186eOHDl06NDh46fP33zwEMUEiCMe3L13GwjuPbj38PHTx9jT5OPHj5G9MFQyDgA8riWAv9eLFAAAAABJRU5ErkJggg==\") no-repeat #BBB; }");
+ out.println("#xmppinfo { background: #FFF; padding: 10px; display: none; }");
+
+ out.println("#signin { text-align: center; font-size: small; }");
+ out.println("#signinform { background: #FFF; padding: 10px 15px; margin-top: 15px; display: none; }");
+ out.println("input.txt { width: 212px; border: 1px solid #CCC; margin: 3px 0; padding: 3px; }");
+ out.println("input.submit { width: 70px; border: 1px solid #CCC; margin: 3px 0; padding: 3px; }");
+ out.println("</style>");
+ out.println("<link rel=\"icon\" href=\"//i.juick.com/favicon.png\"/>");
+ out.println("</head>");
+
+ out.println("<body>");
+
+ out.println("<ul id=\"tags\">");
+ out.println(" <li><a href=\"/tag/juick\" style=\"left: 359px; top: 120px; width: 311px; height: 99px\">juick</a></li>");
+ out.println(" <li><a href=\"/tag/linux\" style=\"left: 201px; top: 100px; width: 98px; height: 35px\">linux</a></li>");
+ out.println(" <li><a href=\"/tag/android\" style=\"left: 314px; top: 42px; width: 45px; height: 158px\">android</a></li>");
+ out.println(" <li><a href=\"/tag/работа\" style=\"left: 149px; top: 138px; width: 165px; height: 41px\">работа</a></li>");
+ out.println(" <li><a href=\"/tag/music\" style=\"left: 119px; top: 249px; width: 124px; height: 32px\">music</a></li>");
+ out.println(" <li><a href=\"/tag/windows\" style=\"left: 448px; top: 234px; width: 186px; height: 32px\">windows</a></li>");
+ out.println(" <li><a href=\"/tag/google\" style=\"left: 244px; top: 252px; width: 134px; height: 41px\">google</a></li>");
+ out.println(" <li><a href=\"/tag/кино\" style=\"left: 68px; top: 83px; width: 97px; height: 28px\">кино</a></li>");
+ out.println(" <li><a href=\"/tag/фото\" style=\"left: 400px; top: 266px; width: 101px; height: 29px\">фото</a></li>");
+ out.println(" <li><a href=\"/tag/жизнь\" style=\"left: 554px; top: 266px; width: 125px; height: 27px\">жизнь</a></li>");
+ out.println(" <li><a href=\"/tag/еда\" style=\"left: 46px; top: 196px; width: 71px; height: 32px\">еда</a></li>");
+ out.println(" <li><a href=\"/tag/музыка\" style=\"left: 61px; top: 111px; width: 139px; height: 27px\">музыка</a></li>");
+ out.println(" <li><a href=\"/tag/прекрасное\" style=\"left: 152px; top: 200px; width: 205px; height: 32px\">прекрасное</a></li>");
+ out.println(" <li><a href=\"/tag/книги\" style=\"left: 148px; top: 293px; width: 103px; height: 25px\">книги</a></li>");
+ out.println(" <li><a href=\"/tag/цитата\" style=\"left: 325px; top: 301px; width: 126px; height: 27px\">цитата</a></li> <li><a href=\"/tag/games\" style=\"left: 117px; top: 142px; width: 30px; height: 104px\">games</a></li>");
+ out.println(" <li><a href=\"/tag/ubuntu\" style=\"left: 503px; top: 2px; width: 28px; height: 102px\">ubuntu</a></li>");
+ out.println(" <li><a href=\"/tag/котэ\" style=\"left: 534px; top: 27px; width: 76px; height: 28px\">котэ</a></li>");
+ out.println(" <li><a href=\"/tag/ВНЕЗАПНО\" style=\"left: 501px; top: 293px; width: 146px; height: 23px\">ВНЕЗАПНО</a></li>");
+ out.println(" <li><a href=\"/tag/юмор\" style=\"left: 73px; top: 53px; width: 84px; height: 28px\">юмор</a></li>");
+ out.println(" <li><a href=\"/tag/мысли\" style=\"left: 202px; top: 179px; width: 102px; height: 21px\">мысли</a></li>");
+ out.println(" <li><a href=\"/tag/pic\" style=\"left: 400px; top: 78px; width: 33px; height: 38px\">pic</a></li>");
+ out.println(" <li><a href=\"/tag/политота\" style=\"left: 531px; top: 60px; width: 130px; height: 24px\">политота</a></li>");
+ out.println(" <li><a href=\"/tag/WOT\" style=\"left: 159px; top: 63px; width: 48px; height: 20px\">WOT</a></li>");
+ out.println(" <li><a href=\"/tag/fail\" style=\"left: 8px; top: 170px; width: 34px; height: 27px\">fail</a></li>");
+ out.println(" <li><a href=\"/tag/погода\" style=\"left: 670px; top: 126px; width: 24px; height: 93px\">погода</a></li>");
+ out.println(" <li><a href=\"/tag/apple\" style=\"left: 42px; top: 167px; width: 64px; height: 29px\">apple</a></li>");
+ out.println(" <li><a href=\"/tag/jabber\" style=\"left: 436px; top: 43px; width: 25px; height: 75px\">jabber</a></li>");
+ out.println(" <li><a href=\"/tag/тян\" style=\"left: 532px; top: 94px; width: 47px; height: 21px\">тян</a></li>");
+ out.println(" <li><a href=\"/tag/work\" style=\"left: 359px; top: 55px; width: 58px; height: 23px\">work</a></li>");
+ out.println(" <li><a href=\"/tag/Python\" style=\"left: 240px; top: 63px; width: 74px; height: 23px\">Python</a></li>");
+ out.println(" <li><a href=\"/tag/Видео\" style=\"left: 266px; top: 232px; width: 76px; height: 20px\">Видео</a></li>");
+ out.println(" <li><a href=\"/tag/авто\" style=\"left: 359px; top: 30px; width: 58px; height: 24px\">авто</a></li>");
+ out.println(" <li><a href=\"/tag/Anime\" style=\"left: 360px; top: 328px; width: 66px; height: 21px\">Anime</a></li>");
+ out.println(" <li><a href=\"/tag/игры\" style=\"left: 378px; top: 242px; width: 22px; height: 58px\">игры</a></li>");
+ out.println(" <li><a href=\"/tag/вело\" style=\"left: 176px; top: 9px; width: 18px; height: 54px\">вело</a></li>");
+ out.println(" <li><a href=\"/tag/web\" style=\"left: 661px; top: 219px; width: 22px; height: 47px\">web</a></li>");
+ out.println(" <li><a href=\"/tag/YouTube\" style=\"left: 498px; top: 316px; width: 81px; height: 24px\">YouTube</a></li>");
+ out.println(" <li><a href=\"/tag/Вопрос\" style=\"left: 208px; top: 18px; width: 22px; height: 72px\">Вопрос</a></li>");
+ out.println(" <li><a href=\"/tag/железо\" style=\"left: 159px; top: 318px; width: 75px; height: 16px\">железо</a></li>");
+ out.println(" <li><a href=\"/tag/Microsoft\" style=\"left: 20px; top: 146px; width: 86px; height: 21px\">Microsoft</a></li>");
+ out.println(" <li><a href=\"/tag/video\" style=\"left: 616px; top: 101px; width: 51px; height: 19px\">video</a></li>");
+ out.println(" <li><a href=\"/tag/Россия\" style=\"left: 32px; top: 242px; width: 68px; height: 16px\">Россия</a></li>");
+ out.println(" <li><a href=\"/tag/java\" style=\"left: 409px; top: 226px; width: 39px; height: 22px\">java</a></li>");
+ out.println(" <li><a href=\"/tag/новости\" style=\"left: 39px; top: 67px; width: 21px; height: 79px\">новости</a></li>");
+ out.println(" <li><a href=\"/tag/интернет\" style=\"left: 100px; top: 233px; width: 17px; height: 85px\">интернет</a></li>");
+ out.println(" <li><a href=\"/tag/steam\" style=\"left: 14px; top: 228px; width: 52px; height: 13px\">steam</a></li>");
+ out.println(" <li><a href=\"/tag/слова\" style=\"left: 501px; top: 272px; width: 51px; height: 18px\">слова</a></li>");
+ out.println(" <li><a href=\"/tag/почта\" style=\"left: 477px; top: 27px; width: 17px; height: 56px\">почта</a></li>");
+ out.println(" <li><a href=\"/tag/help\" style=\"left: 123px; top: 281px; width: 21px; height: 35px\">help</a></li>");
+ out.println(" <li><a href=\"/tag/skype\" style=\"left: 110px; top: 320px; width: 49px; height: 20px\">skype</a></li>");
+ out.println(" <li><a href=\"/tag/debian\" style=\"left: 461px; top: 47px; width: 16px; height: 51px\">debian</a></li>");
+ out.println(" <li><a href=\"/tag/win\" style=\"left: 505px; top: 104px; width: 27px; height: 16px\">win</a></li>");
+ out.println(" <li><a href=\"/tag/Религия\" style=\"left: 33px; top: 281px; width: 67px; height: 17px\">Религия</a></li>");
+ out.println(" <li><a href=\"/tag/soft\" style=\"left: 286px; top: 86px; width: 28px; height: 14px\">soft</a></li>");
+ out.println(" <li><a href=\"/tag/Политика\" style=\"left: 144px; top: 281px; width: 75px; height: 12px\">Политика</a></li>");
+ out.println(" <li><a href=\"/tag/сны\" style=\"left: 426px; top: 328px; width: 33px; height: 13px\">сны</a></li>");
+ out.println(" <li><a href=\"/tag/Питер\" style=\"left: 146px; top: 233px; width: 50px; height: 16px\">Питер</a></li>");
+ out.println(" <li><a href=\"/tag/bash\" style=\"left: 451px; top: 311px; width: 38px; height: 16px\">bash</a></li>");
+ out.println(" <li><a href=\"/tag/code\" style=\"left: 279px; top: 310px; width: 39px; height: 16px\">code</a></li>");
+ out.println(" <li><a href=\"/tag/yandex\" style=\"left: 19px; top: 263px; width: 56px; height: 18px\">yandex</a></li>");
+ out.println(" <li><a href=\"/tag/firefox\" style=\"left: 452px; top: 295px; width: 48px; height: 16px\">firefox</a></li>");
+ out.println(" <li><a href=\"/tag/hardware\" style=\"left: 230px; top: 40px; width: 67px; height: 18px\">hardware</a></li>");
+ out.println(" <li><a href=\"/tag/git\" style=\"left: 78px; top: 258px; width: 20px; height: 19px\">git</a></li>");
+ out.println(" <li><a href=\"/tag/dev\" style=\"left: 165px; top: 88px; width: 31px; height: 19px\">dev</a></li>");
+ out.println(" <li><a href=\"/tag/mobile\" style=\"left: 421px; top: 24px; width: 15px; height: 47px\">mobile</a></li>");
+ out.println(" <li><a href=\"/tag/люди\" style=\"left: 151px; top: 184px; width: 43px; height: 15px\">люди</a></li>");
+ out.println(" <li><a href=\"/tag/php\" style=\"left: 149px; top: 24px; width: 27px; height: 18px\">php</a></li>");
+ out.println(" <li><a href=\"/tag/haskell\" style=\"left: 271px; top: 293px; width: 48px; height: 16px\">haskell</a></li>");
+ out.println(" <li><a href=\"/tag/стихи\" style=\"left: 135px; top: 42px; width: 41px; height: 11px\">стихи</a></li>");
+ out.println(" <li><a href=\"/tag/photo\" style=\"left: 639px; top: 219px; width: 20px; height: 39px\">photo</a></li>");
+ out.println(" <li><a href=\"/tag/чай\" style=\"left: 448px; top: 220px; width: 27px; height: 14px\">чай</a></li>");
+ out.println(" <li><a href=\"/tag/Опрос\" style=\"left: 297px; top: 22px; width: 14px; height: 41px\">Опрос</a></li>");
+ out.println(" <li><a href=\"/tag/Chrome\" style=\"left: 311px; top: 25px; width: 48px; height: 17px\">Chrome</a></li>");
+ out.println(" <li><a href=\"/tag/life\" style=\"left: 255px; top: 311px; width: 23px; height: 16px\">life</a></li>");
+ out.println(" <li><a href=\"/tag/opera\" style=\"left: 226px; top: 232px; width: 38px; height: 14px\">opera</a></li>");
+ out.println(" <li><a href=\"/tag/programming\" style=\"left: 234px; top: 327px; width: 81px; height: 14px\">programming</a></li>");
+ out.println(" <li><a href=\"/tag/дети\" style=\"left: 15px; top: 197px; width: 31px; height: 13px\">дети</a></li>");
+ out.println(" <li><a href=\"/tag/сериалы\" style=\"left: 575px; top: 219px; width: 61px; height: 13px\">сериалы</a></li>");
+ out.println(" <li><a href=\"/tag/учеба\" style=\"left: 616px; top: 84px; width: 43px; height: 17px\">учеба</a></li>");
+ out.println("</ul>");
+
+ out.println("<div id=\"bottom1\">juick.com &copy; 2008-2014 &nbsp; <a href=\"/help/ru/contacts\" rel=\"nofollow\">Контакты</a> &#183; <a href=\"/help/\" rel=\"nofollow\">Помощь</a></div>");
+
+ out.println("<div id=\"signup\">");
+ out.println(" Зарегистрироваться:");
+ out.println(" <div id=\"facebook\"><a href=\"/_fblogin\" rel=\"nofollow\">Facebook</a></div>");
+ out.println(" <div id=\"vk\"><a href=\"/_vklogin\" rel=\"nofollow\">ВКонтакте</a></div>");
+ out.println(" <div id=\"xmpp\"><a href=\"#\" onclick=\"$('#xmppinfo').toggle(); return false\">XMPP</a>");
+ out.println(" <div id=\"xmppinfo\">Отправьте <b>LOGIN</b> на <a href=\"xmpp:juick@juick.com?message;body=LOGIN\">juick@juick.com</a></div>");
+ out.println(" </div>");
+ out.println("</div>");
+ out.println("<div id=\"signin\"><a href=\"#\" onclick=\"$('#signinform').toggle(); $('#nickinput').focus(); return false\">Уже зарегистрированы?</a>");
+ out.println("<div id=\"signinform\"><form action=\"/login\" method=\"POST\">");
+ out.println("<input class=\"txt\" type=\"text\" name=\"username\" placeholder=\"Имя пользователя\" id=\"nickinput\"/>");
+ out.println("<input class=\"txt\" type=\"password\" name=\"password\" placeholder=\"Пароль\"/>");
+ out.println("<input class=\"submit\" type=\"submit\" value=\"OK\"/>");
+ out.println("</form></div>");
+ out.println("</div>");
+
+ out.println("</body>");
+ out.println("</html>");
+ }
+ }
+
+ @RequestMapping(value = "/login", method = RequestMethod.POST)
+ protected void doPostLogin(HttpServletRequest request, HttpServletResponse response) throws IOException {
+ String username = request.getParameter("username");
+ String password = request.getParameter("password");
+ if (username == null || password == null || username.length() > 32 || password.isEmpty()) {
+ response.sendError(HttpServletResponse.SC_BAD_REQUEST);
+ return;
+ }
+
+ int uid = userService.checkPassword(username, password);
+ if (uid > 0) {
+ String hash = userService.getHashByUID(uid);
+ Cookie c = new Cookie("hash", hash);
+ c.setMaxAge(365 * 24 * 60 * 60);
+ response.addCookie(c);
+
+ String referer = request.getHeader("Referer");
+ if (referer != null && referer.startsWith("http://juick.com/") && !referer.equals("http://juick.com/login")) {
+ response.sendRedirect(referer);
+ } else {
+ response.sendRedirect("/");
+ }
+ } else {
+ response.sendError(HttpServletResponse.SC_FORBIDDEN);
+ }
+ }
+
+ @RequestMapping(value = "/logout", method = RequestMethod.GET)
+ protected void doGetLogout(HttpServletRequest request, HttpServletResponse response) throws IOException {
+ com.juick.User visitor = webApp.getVisitorUser(request, response);
+ if (visitor.getUid() > 0) {
+ userService.logout(visitor.getUid());
+ }
+
+ Cookie c = new Cookie("hash", "-");
+ c.setDomain(".juick.com");
+ c.setMaxAge(0);
+ response.addCookie(c);
+
+ Cookie c2 = new Cookie("hash", "-");
+ c2.setMaxAge(0);
+ response.addCookie(c2);
+
+ response.sendRedirect("/");
+ }
+}
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
new file mode 100644
index 00000000..dacd54a3
--- /dev/null
+++ b/juick-www/src/main/java/com/juick/www/controllers/NewMessage.java
@@ -0,0 +1,468 @@
+/*
+ * Juick
+ * Copyright (C) 2008-2011, Ugnich Anton
+ *
+ * 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.www.controllers;
+
+import com.juick.Tag;
+import com.juick.server.helpers.TagStats;
+import com.juick.server.util.HttpBadRequestException;
+import com.juick.server.util.HttpUtils;
+import com.juick.service.*;
+import com.juick.www.Utils;
+import com.juick.www.WebApp;
+import net.coobird.thumbnailator.Thumbnails;
+import org.apache.commons.lang3.CharEncoding;
+import org.apache.commons.lang3.StringEscapeUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.commons.lang3.math.NumberUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.core.env.Environment;
+import org.springframework.stereotype.Controller;
+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 javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.io.UnsupportedEncodingException;
+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;
+
+/**
+ * @author Ugnich Anton
+ */
+@Controller
+public class NewMessage {
+
+ @Inject
+ Environment env;
+ @Inject
+ TagService tagService;
+ @Inject
+ MessagesService messagesService;
+ @Inject
+ UserService userService;
+ @Inject
+ SubscriptionService subscriptionService;
+ @Inject
+ CrosspostService crosspostService;
+ @Inject
+ WebApp webApp;
+ @Inject
+ PageTemplates templates;
+
+ private static final Logger logger = LoggerFactory.getLogger(NewMessage.class);
+
+ @RequestMapping(value = "/post", method = RequestMethod.GET)
+ protected void doGetNewMessage(HttpServletRequest request, HttpServletResponse response) throws IOException {
+ com.juick.User visitor = webApp.getVisitorUser(request, response);
+ if (visitor.getUid() == 0) {
+ Utils.sendTemporaryRedirect(response, "/login");
+ return;
+ }
+ response.setContentType("text/html; charset=UTF-8");
+ try (PrintWriter out = response.getWriter()) {
+ templates.pageHead(out, visitor, "Написать", "<script src=\"//maps.google.com/maps?file=api&amp;v=2&amp;sensor=false&amp;key=ABQIAAAAVVtPtxkw4soCEHg44FsNChRB4OFYjAXt73He16Zkp6a_0tPs2RTU6i6UlcMs4QvPBYvIY8rWvcxqOg\" type=\"text/javascript\"></script>"
+ + "<script src=\"//static.juick.com/mc.js\" type=\"text/javascript\" defer=\"defer\"></script>"
+ + "<script src=\"//static.juick.com/maps.js?2010111500\" type=\"text/javascript\" defer=\"defer\"></script>"
+ + "<script src=\"//static.juick.com/post3.js\" type=\"text/javascript\" defer=\"defer\"></script>");
+ templates.pageNavigation(out, visitor, null);
+
+ out.println("<section id=\"content\" class=\"pagetext\">");
+ out.println("<form action=\"/post2\" method=\"post\" id=\"postmsg\" enctype=\"multipart/form-data\">");
+ out.println("<p style=\"text-align: left\"><b>Место: <span id=\"location\"></span></b> <span id=\"locationclear\">&mdash; <a href=\"#\" onclick=\"clearLocation()\">Отменить</a></span></p>");
+ out.println("<p style=\"text-align: left\"><b>Фото:</b> <span id=\"attachmentfile\"><input type=\"file\" name=\"attach\"/> <i>(JPG, PNG, до 10Мб)</i></span></p>");
+
+ String body = request.getParameter("body");
+ if (body == null) {
+ body = StringUtils.EMPTY;
+ } else {
+ if (body.length() > 4096) {
+ body = body.substring(0, 4096);
+ }
+ body = StringEscapeUtils.escapeHtml4(body);
+ }
+ out.println("<p><textarea name=\"body\" class=\"newmessage\" rows=\"7\" cols=\"10\">" + body + "</textarea><br/>");
+
+ out.println("<input type=\"hidden\" name=\"place_id\"/>" + "" + "<input type=\"submit\" class=\"subm\" value=\" Отправить \"/></p>");
+ out.println("</form>");
+ out.println("<div id=\"geomap\"></div>");
+ out.println("<p style=\"text-align: left\"><b>Теги:</b></p>");
+ printUserTags(out, visitor);
+ out.println("</section>");
+
+ templates.pageFooter(request, out, visitor, false);
+ templates.pageEnd(out);
+ }
+ }
+
+ void printUserTags(PrintWriter out, com.juick.User visitor) {
+ List<TagStats> tags = tagService.getUserTagStats(visitor.getUid());
+
+ if (tags.isEmpty()) {
+ return;
+ }
+
+ int min = tags.get(0).getUsageCount();
+ int max = tags.get(0).getUsageCount();
+ for (int i = 1; i < tags.size(); i++) {
+ int usagecnt = tags.get(i).getUsageCount();
+ if (usagecnt < min) {
+ min = usagecnt;
+ }
+ if (usagecnt > max) {
+ max = usagecnt;
+ }
+ }
+ max -= min;
+
+ out.print("<p style=\"text-align: justify\">");
+ for (int i = 0; i < tags.size(); i++) {
+ if (i > 0) {
+ out.print(" ");
+ }
+ String taglink = StringUtils.EMPTY;
+ try {
+ taglink = "<a onclick=\"return addTag('" + StringEscapeUtils.escapeHtml4(tags.get(i).getTag().getName()) + "')\" href=\"/" +
+ visitor.getName() + "/?tag=" + URLEncoder.encode(tags.get(i).getTag().getName(), CharEncoding.UTF_8) +
+ "\" title=\"" + tags.get(i).getUsageCount() + "\">" + StringEscapeUtils.escapeHtml4(tags.get(i).getTag().getName()) + "</a>";
+ } catch (UnsupportedEncodingException e) {
+ }
+ int usagecnt = tags.get(i).getUsageCount();
+ if (usagecnt <= max / 5 + min) {
+ out.print("<span style=\"font-size: small\">" + taglink + "</span>");
+ } else if (usagecnt <= max / 5 * 2 + min) {
+ out.print(taglink);
+ } else if (usagecnt <= max / 5 * 3 + min) {
+ out.print("<span style=\"font-size: large\">" + taglink + "</span>");
+ } else if (usagecnt <= max / 5 * 4 + min) {
+ out.print("<span style=\"font-size: x-large\">" + taglink + "</span>");
+ } else {
+ out.print("<span style=\"font-size: xx-large\">" + taglink + "</span>");
+ }
+ }
+ out.println("</p>");
+ }
+
+ @RequestMapping(value = "/post", method = RequestMethod.POST)
+ public void doPostMessage(HttpServletRequest request, HttpServletResponse response,
+ @RequestParam(required = false) String img,
+ @RequestParam(required = false) MultipartFile attach) throws IOException {
+ com.juick.User visitor = webApp.getVisitorUser(request, response);
+ if (visitor.getUid() == 0) {
+ response.sendError(HttpServletResponse.SC_FORBIDDEN);
+ return;
+ }
+ String body = request.getParameter("body");
+ if (body == null || body.length() < 1 || body.length() > 4096) {
+ response.sendError(HttpServletResponse.SC_BAD_REQUEST);
+ return;
+ }
+ body = body.replace("\r", StringUtils.EMPTY);
+
+ List<Tag> tags = webApp.parseTags(request.getParameter("tags"));
+
+ 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);
+ } 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;
+
+ Path origName = Paths.get(webApp.getImgDir(), "p", fname);
+ Files.move(Paths.get(webApp.getTmpDir(), attachmentFName), origName);
+ Thumbnails.of(origName.toFile()).size(1024, 1024).outputQuality(0.9)
+ .toFile(Paths.get(webApp.getImgDir(), "photos-1024", fname).toFile());
+ Thumbnails.of(origName.toFile()).size(512, 512).outputQuality(0.9)
+ .toFile(Paths.get(webApp.getImgDir(), "photos-512", fname).toFile());
+ Thumbnails.of(origName.toFile()).size(160, 120).outputQuality(0.9)
+ .toFile(Paths.get(webApp.getImgDir(), "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");
+ }
+
+ //
+
+ response.setContentType("text/html; charset=UTF-8");
+ try (PrintWriter out = response.getWriter()) {
+ templates.pageHead(out, visitor, "Сообщение опубликовано", null);
+ templates.pageNavigation(out, visitor, null);
+
+ 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);
+ }
+
+ 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;
+
+ out.println("<section id=\"content\">");
+ out.println("<h1>Сообщение опубликовано</h1>");
+ out.println("<p>Поделитесь своим новым постом в социальных сетях:</p>");
+ if (crosspostService.getTwitterTokens(visitor.getUid()).isPresent()) {
+ out.println("<p class=\"social\"><a href=\"https://twitter.com/intent/tweet?text=" + URLEncoder.encode(sharetwi, CharEncoding.UTF_8) + "\" class=\"ico32-twi sharenew\">Отправить в Twitter</a></p>");
+ }
+ out.println("<p class=\"social\"><a href=\"http://www.livejournal.com/update.bml?subject=" + URLEncoder.encode(hashtags, CharEncoding.UTF_8) + "&event=" + sharelj + "&prop_taglist=" + URLEncoder.encode(tagscomma, CharEncoding.UTF_8) + "\" target=\"_blank\" class=\"ico32-lj sharenew\">Отправить в LiveJournal</a></p>");
+ out.println("<p class=\"social\"><a href=\"https://vk.com/share.php?url=" + url + "\" class=\"ico32-vk sharenew\">Отправить в ВКонтакте</a></p>");
+ if (crosspostService.getFacebookToken(visitor.getUid()).isPresent()) {
+ out.println("<p class=\"social\"><a href=\"https://www.facebook.com/sharer/sharer.php?u=" + url + "\" class=\"ico32-fb sharenew\">Отправить в Facebook</a></p>");
+ }
+ out.println("<p class=\"social\"><a href=\"https://plus.google.com/share?url=" + url + "\" class=\"ico32-gp sharenew\">Отправить в Google+</a></p>");
+ out.println("<p>Ссылка на сообщение: <a href=\"http://juick.com/" + mid + "\">http://juick.com/" + mid + "</a></p>");
+ out.println("</section>");
+
+ templates.pageHomeColumn(out, visitor);
+
+ templates.pageFooter(request, out, visitor, false);
+ templates.pageEnd(out);
+ }
+ }
+
+ @RequestMapping(value = "/comment", method = RequestMethod.POST)
+ public void doPostComment(HttpServletRequest request, HttpServletResponse response,
+ @RequestParam(required = false) String img,
+ @RequestParam(required = false) MultipartFile attach) throws IOException {
+ com.juick.User visitor = webApp.getVisitorUser(request, response);
+ if (visitor.getUid() == 0) {
+ response.sendError(HttpServletResponse.SC_FORBIDDEN);
+ return;
+ }
+ int mid = NumberUtils.toInt(request.getParameter("mid"), 0);
+ if (mid == 0) {
+ response.sendError(HttpServletResponse.SC_BAD_REQUEST);
+ return;
+ }
+ com.juick.Message msg = messagesService.getMessage(mid);
+ if (msg == null) {
+ response.sendError(HttpServletResponse.SC_NOT_FOUND);
+ return;
+ }
+
+ int rid = NumberUtils.toInt(request.getParameter("rid"), 0);
+ com.juick.Message reply = null;
+ if (rid > 0) {
+ reply = messagesService.getReply(mid, rid);
+ if (reply == null) {
+ response.sendError(HttpServletResponse.SC_NOT_FOUND);
+ return;
+ }
+ }
+
+ String body = request.getParameter("body");
+ if (body == null || body.length() < 1 || body.length() > 4096) {
+ response.sendError(HttpServletResponse.SC_BAD_REQUEST);
+ return;
+ }
+ 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()))) {
+ response.sendError(HttpServletResponse.SC_FORBIDDEN);
+ return;
+ }
+
+ 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);
+ } 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;
+
+ Path origName = Paths.get(webApp.getImgDir(), "p", fname);
+ Files.move(Paths.get(webApp.getTmpDir(), attachmentFName), origName);
+ Thumbnails.of(origName.toFile()).size(1024, 1024).outputQuality(0.9)
+ .toFile(Paths.get(webApp.getImgDir(), "photos-1024", fname).toFile());
+ Thumbnails.of(origName.toFile()).size(512, 512).outputQuality(0.9)
+ .toFile(Paths.get(webApp.getImgDir(), "photos-512", fname).toFile());
+ Thumbnails.of(origName.toFile()).size(160, 120).outputQuality(0.9)
+ .toFile(Paths.get(webApp.getImgDir(), "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");
+ }
+
+ Utils.sendTemporaryRedirect(response, "/" + msg.getUser().getName() + "/" + mid + "#" + ridnew);
+ }
+
+ @RequestMapping(value = "/like", method = RequestMethod.POST)
+ public void doPostRecomm(HttpServletRequest request, HttpServletResponse response) throws IOException {
+ com.juick.User visitor = webApp.getVisitorUser(request, response);
+ if (visitor.getUid() == 0) {
+ response.sendError(HttpServletResponse.SC_FORBIDDEN);
+ return;
+ }
+ int mid = NumberUtils.toInt(request.getParameter("mid"), 0);
+ if (mid == 0) {
+ response.sendError(HttpServletResponse.SC_BAD_REQUEST);
+ return;
+ }
+ com.juick.Message msg = messagesService.getMessage(mid);
+ if (msg == null) {
+ response.sendError(HttpServletResponse.SC_NOT_FOUND);
+ return;
+ }
+ if (msg.getUser().getUid() == visitor.getUid()) {
+ response.sendError(HttpServletResponse.SC_FORBIDDEN);
+ return;
+ }
+
+ 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");
+ }
+
+ Utils.replyJSON(request, response, "{\"status\":\"ok\"}");
+ } else {
+ response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
+ }
+ }
+}
diff --git a/juick-www/src/main/java/com/juick/www/controllers/PM.java b/juick-www/src/main/java/com/juick/www/controllers/PM.java
new file mode 100644
index 00000000..56b688cf
--- /dev/null
+++ b/juick-www/src/main/java/com/juick/www/controllers/PM.java
@@ -0,0 +1,163 @@
+/*
+ * Juick
+ * Copyright (C) 2008-2011, Ugnich Anton
+ *
+ * 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.www.controllers;
+
+import com.juick.service.PMQueriesService;
+import com.juick.service.TagService;
+import com.juick.service.UserService;
+import com.juick.util.MessageUtils;
+import com.juick.util.WebUtils;
+import com.juick.www.Utils;
+import com.juick.www.WebApp;
+import org.apache.commons.lang3.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+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 rocks.xmpp.addr.Jid;
+import rocks.xmpp.core.stanza.model.Message;
+
+import javax.inject.Inject;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.util.List;
+
+/**
+ *
+ * @author Ugnich Anton
+ */
+@Controller
+public class PM {
+ private static final Logger logger = LoggerFactory.getLogger(PM.class);
+
+ @Inject
+ PMQueriesService pmQueriesService;
+ @Inject
+ TagService tagService;
+ @Inject
+ UserService userService;
+ @Inject
+ WebApp webApp;
+
+ @RequestMapping(value = "/pm/inbox", method = RequestMethod.GET)
+ protected String doGetInbox(HttpServletRequest request, HttpServletResponse response, ModelMap model) {
+ com.juick.User visitor = webApp.getVisitorUser(request, response);
+ if (visitor.getUid() == 0) {
+ Utils.sendTemporaryRedirect(response, "/login");
+ }
+ String title = "PM: Inbox";
+ List<com.juick.Message> msgs = pmQueriesService.getLastPMInbox(visitor.getUid());
+ msgs.forEach(m -> m.setText(MessageUtils.formatMessage(m.getText())));
+ model.addAttribute("title", title);
+ model.addAttribute("visitor", visitor);
+ model.addAttribute("msgs", msgs);
+ model.addAttribute("tags", tagService.getPopularTags());
+ return "views/pm_inbox";
+ }
+
+ @RequestMapping(value = "/pm/sent", method = RequestMethod.GET)
+ protected String doGetSent(HttpServletRequest request, HttpServletResponse response, ModelMap model) {
+ com.juick.User visitor = webApp.getVisitorUser(request, response);
+ if (visitor.getUid() == 0) {
+ Utils.sendTemporaryRedirect(response, "/login");
+ }
+ String title = "PM: Sent";
+ List<com.juick.Message> msgs = pmQueriesService.getLastPMSent(visitor.getUid());
+
+ String uname = request.getParameter("uname");
+ if (WebUtils.isNotUserName(uname)) {
+ uname = StringUtils.EMPTY;
+ }
+
+ model.addAttribute("title", title);
+ model.addAttribute("visitor", visitor);
+ model.addAttribute("msgs", msgs);
+ model.addAttribute("tags", tagService.getPopularTags());
+ model.addAttribute("uname", uname);
+ return "views/pm_sent";
+ }
+
+ @RequestMapping(value = "/pm/send", method = RequestMethod.POST)
+ public void doPostPM(HttpServletRequest request, HttpServletResponse response) throws IOException {
+ com.juick.User visitor = webApp.getVisitorUser(request, response);
+ if (visitor.getUid() == 0 || visitor.isBanned()) {
+ response.sendError(HttpServletResponse.SC_FORBIDDEN);
+ return;
+ }
+ String uname = request.getParameter("uname");
+ if (uname.startsWith("@")) {
+ uname = uname.substring(1);
+ }
+ int uid = 0;
+ if (WebUtils.isUserName(uname)) {
+ uid = userService.getUIDbyName(uname);
+ }
+
+ String body = request.getParameter("body");
+ if (uid == 0 || body == null || body.length() < 1 || body.length() > 10240) {
+ response.sendError(HttpServletResponse.SC_BAD_REQUEST);
+ return;
+ }
+
+ if (userService.isInBLAny(uid, visitor.getUid())) {
+ response.sendError(HttpServletResponse.SC_FORBIDDEN);
+ return;
+ }
+
+ 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<String> 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");
+ }
+
+ Utils.sendTemporaryRedirect(response, "/pm/sent");
+
+ } else {
+ response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
+ }
+ }
+}
diff --git a/juick-www/src/main/java/com/juick/www/controllers/PageTemplates.java b/juick-www/src/main/java/com/juick/www/controllers/PageTemplates.java
new file mode 100644
index 00000000..3152d5fc
--- /dev/null
+++ b/juick-www/src/main/java/com/juick/www/controllers/PageTemplates.java
@@ -0,0 +1,381 @@
+/*
+ * Juick
+ * Copyright (C) 2008-2011, Ugnich Anton
+ *
+ * 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.www.controllers;
+
+import com.juick.Message;
+import com.juick.server.helpers.TagStats;
+import com.juick.service.MessagesService;
+import com.juick.service.TagService;
+import com.juick.service.UserService;
+import com.juick.util.MessageUtils;
+import org.apache.commons.lang3.CharEncoding;
+import org.apache.commons.lang3.StringEscapeUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.util.StringUtils;
+import ru.sape.Sape;
+
+import javax.inject.Inject;
+import javax.servlet.http.HttpServletRequest;
+import java.io.PrintWriter;
+import java.io.UnsupportedEncodingException;
+import java.net.URLEncoder;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.List;
+import java.util.stream.Collectors;
+
+/**
+ * @author Ugnich Anton
+ */
+public class PageTemplates {
+
+ private static final Logger logger = LoggerFactory.getLogger(PageTemplates.class);
+
+ public Sape sape = null;
+ protected static final SimpleDateFormat sdfSQL = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+ private static SimpleDateFormat sdfSimple = new SimpleDateFormat("d MMM");
+ private static SimpleDateFormat sdfFull = new SimpleDateFormat("d MMM yyyy");
+ private static String tagsHTML = null;
+
+ @Inject
+ TagService tagService;
+ @Inject
+ MessagesService messagesService;
+ @Inject
+ UserService userService;
+
+ public void pageHead(PrintWriter out, com.juick.User visitor, String title, String headers) {
+ out.println("<!DOCTYPE html>");
+ out.print("<html>");
+ out.print("<head>");
+ out.println("<meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">");
+ out.print("<link rel=\"stylesheet\" href=\"/style.css?v=2\"/>");
+ out.print("<script type=\"text/javascript\" src=\"/scripts.js\"></script>");
+ if (headers != null) {
+ out.print(headers);
+ }
+ out.print("<title>" + title + "</title>");
+ out.println("<meta name=\"viewport\" content=\"width=device-width,initial-scale=1,user-scalable=no\"/>");
+ out.println("<link rel=\"icon\" href=\"//i.juick.com/favicon.png\"/>");
+ out.println("<!--[if lt IE 9 & (!IEMobile 7)]>");
+ out.println("<script src=\"//cdnjs.cloudflare.com/ajax/libs/html5shiv/3.7.3/html5shiv.min.js\"></script>");
+ out.println("<![endif]-->");
+ out.println("</head>");
+ out.flush();
+ if (visitor.getUid() > 0) {
+ out.println("<body id=\"body\" data-hash=\"" + visitor.getAuthHash() + "\">");
+ } else {
+ out.println("<body id=\"body\">");
+ }
+ }
+
+ public void pageNavigation(PrintWriter out, com.juick.User visitor, String search) {
+ out.println("<header>");
+ out.println(" <div id=\"logo\"><a href=\"/\">Juick</a></div>");
+ out.print(" <nav id=\"global\"><ul>");
+ out.print("<li><a href=\"/\">Популярные</a></li>");
+ out.print("<li><a href=\"/?show=all\" rel=\"nofollow\">Все сообщения</a></li>");
+ out.print("<li><a href=\"/?show=photos\" rel=\"nofollow\">Фотографии</a></li>");
+ out.println("</ul></nav>");
+ out.print(" <div id=\"search\"><form action=\"/\"><input type=\"text\" name=\"search\" class=\"text\" placeholder=\"Поиск\"");
+ if (search != null) {
+ out.print(" value=\"" + StringEscapeUtils.escapeHtml4(search) + "\"");
+ }
+ out.println("/></form></div>");
+ out.println(" <section id=\"headdiv\">");
+ if (visitor.getUid() > 0) {
+ out.print(" <nav id=\"user\"><ul>");
+ out.print("<li><a href=\"/?show=my\">Моя лента</a></li>");
+ out.print("<li><a href=\"/pm/inbox\">Приватные</a></li>");
+ out.print("<li><a href=\"/?show=discuss\">Обсуждения</a></li>");
+ out.print("<li><a href=\"/?show=recommended\">Рекомендации</a></li>");
+ out.println("</ul></nav>");
+ out.print(" <nav id=\"actions\"><ul>");
+ out.print("<li><a href=\"/#post\">Написать</a></li>");
+ out.print("<li><a href=\"/" + visitor.getName() + "\">@" + visitor.getName() + "</a></li>");
+ out.print("<li><a href=\"/logout\">Выйти</a></li>");
+ out.println("</ul></nav>");
+ } else {
+ out.println("<p>Чтобы добавлять сообщения и комментарии, <a href=\"#\" class=\"a-login\">представьтесь</a>.</p>");
+ }
+ out.println(" </section>");
+ out.println("</header>");
+ }
+
+ public void pageHomeColumn(PrintWriter out, com.juick.User visitor) {
+ pageHomeColumn(out, visitor, false);
+ }
+
+ public void pageHomeColumn(PrintWriter out, com.juick.User visitor, boolean showAdv) {
+ if (tagsHTML == null) {
+ tagsHTML = formatPopularTags(80);
+ }
+
+ out.println("<aside id=\"column\">");
+ out.print(" <p class=\"tags\">" + tagsHTML);
+ if (showAdv) {
+ out.print(" <a href=\"http://ru.wix.com/\">конструктор сайтов</a>");
+ }
+ out.println("</p>");
+// if (visitor != null) {
+// printContestRating(out, sql);
+// }
+ out.println("</aside>");
+ }
+
+ public String formatPopularTags(int cnt) {
+ List<String> popularTags = tagService.getPopularTags().stream()
+ .map(t -> "<a href=\"/tag/" + URLEncoder.encode(t) + "\">" + StringEscapeUtils.escapeHtml4(t) + "</a>").collect(Collectors.toList());
+ return StringUtils.collectionToDelimitedString(popularTags, " ");
+ }
+
+ public void pageFooter(HttpServletRequest request, PrintWriter out, com.juick.User visitor, boolean sapeon) {
+ out.println("<div id=\"footer\">");
+ out.println(" <div id=\"footer-right\"><a href=\"/settings\" rel=\"nofollow\">Настройки</a> &#183; <a href=\"/help/ru/contacts\" rel=\"nofollow\">Контакты</a> &#183; <a href=\"/help/\" rel=\"nofollow\">Справка</a> &#183; <a href=\"/help/ru/adv\" rel=\"nofollow\">Реклама</a></div>");
+ out.print(" <div id=\"footer-social\">");
+ out.print("<a href=\"https://twitter.com/Juick\" rel=\"nofollow\" class=\"ico32-twi\">Twitter</a>");
+ out.print("<a href=\"https://vk.com/juick\" rel=\"nofollow\" class=\"ico32-vk\">ВКонтакте</a>");
+ out.print("<a href=\"https://www.facebook.com/JuickCom\" rel=\"nofollow\" class=\"ico32-fb\">Facebook</a>");
+ out.println("</div>");
+ out.print(" <div id=\"footer-left\">juick.com &copy; 2008-2016");
+
+ String queryString = request.getQueryString();
+ String requestURI = request.getRequestURI();
+ if (sapeon && sape != null && (visitor.getUid() == 0 || visitor.getUid() == 1) && queryString == null) {
+ String links = sape.getPageLinks(requestURI, request.getCookies()).render();
+ if (links != null && !links.isEmpty()) {
+ out.print("<br/>Спонсоры: " + links);
+ }
+ }
+
+ out.println("</div>");
+ out.println("</div>");
+
+ out.println("<script>");
+ out.println("(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){");
+ out.println("(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),");
+ out.println("m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)");
+ out.println("})(window,document,'script','//www.google-analytics.com/analytics.js','ga');");
+ out.println("ga('create','UA-385578-4','juick.com');");
+ out.println("ga('require','displayfeatures');");
+ out.println("ga('send','pageview');");
+
+ if (sapeon) {
+ out.println("var _acic={dataProvider:10};");
+ out.println("(function(){");
+ out.println("var e=document.createElement('script');e.type='text/javascript';e.async=true;e.src='//www2.aci'+'nt.net/aci.js';");
+ out.println("var t=document.getElementsByTagName('script')[0];t.parentNode.insertBefore(e,t);");
+ out.println("})();");
+ }
+
+ out.println("</script>");
+ }
+
+ public void pageEnd(PrintWriter out) {
+ out.println("</body></html>");
+ }
+
+ public String formatTags(List<TagStats> tags) {
+ String ret = org.apache.commons.lang3.StringUtils.EMPTY;
+ for (TagStats tag : tags) {
+ String tagName = StringEscapeUtils.escapeHtml4(tag.getTag().getName());
+ try {
+ ret += "<a href=\"/tag/" + URLEncoder.encode(tag.getTag().getName(), CharEncoding.UTF_8) + "\"";
+ if (tag.getUsageCount() < 2) {
+ ret += " rel=\"nofollow\"";
+ }
+ ret += ">" + tagName + "</a>";
+ } catch (UnsupportedEncodingException e) {
+ }
+ }
+
+ return ret;
+ }
+
+ public String formatDate(int minutes, Date fulldate) {
+ if (minutes < 1) {
+ return "сейчас";
+ } else if (minutes < 60) {
+ String unit;
+ int ld = minutes % 10;
+ if ((minutes < 10 || minutes > 20) && ld == 1) {
+ unit = "минуту";
+ } else if ((minutes < 10 || minutes > 20) && ld > 1 && ld < 5) {
+ unit = "минуты";
+ } else {
+ unit = "минут";
+ }
+ return minutes + " " + unit + " назад";
+ } else if (minutes < 1440) {
+ int hours = (minutes / 60);
+ String unit;
+ int ld = hours % 10;
+ if ((hours < 10 || hours > 20) && ld == 1) {
+ unit = "час";
+ } else if ((hours < 10 || hours > 20) && ld > 1 && ld < 5) {
+ unit = "часа";
+ } else {
+ unit = "часов";
+ }
+ return hours + " " + unit + " назад";
+ } else if (minutes < 20160) {
+ int days = (minutes / 1440);
+ String unit;
+ int ld = days % 10;
+ if ((days < 10 || days > 20) && ld == 1) {
+ unit = "день";
+ } else if ((days < 10 || days > 20) && ld > 1 && ld < 5) {
+ unit = "дня";
+ } else {
+ unit = "дней";
+ }
+ return days + " " + unit + " назад";
+ } else {
+ String ret = sdfFull.format(fulldate);
+ synchronized (sdfSQL) {
+ try {
+ Calendar c = Calendar.getInstance();
+ int curyear = c.get(Calendar.YEAR);
+ c.setTime(fulldate);
+ if (c.get(Calendar.YEAR) == curyear) {
+ ret = sdfSimple.format(fulldate);
+ } else {
+ ret = sdfFull.format(fulldate);
+ }
+ } catch (Exception e) {
+ logger.error("PARSE EXCEPTION: {}, exception {}", fulldate, e);
+ }
+ }
+ return ret;
+ }
+ }
+
+ public String formatJSLocalTime(Date ts) {
+ return "<script type=\"text/javascript\">"
+ + "var d=new Date(" + ts.getTime() + ");"
+ + "document.write((d.getDate()<10?'0':'')+d.getDate()+'.'+(d.getMonth()<9?'0':'')+(d.getMonth()+1)+'.'+d.getFullYear()+' '+(d.getHours()<10?'0':'')+d.getHours()+':'+(d.getMinutes()<10?'0':'')+d.getMinutes());"
+ + "</script>";
+ }
+
+ public String formatReplies(int replies) {
+ int ld = replies % 10;
+ int lh = replies % 100;
+ if ((lh < 10 || lh > 20) && ld == 1) {
+ return replies + " ответ";
+ } else if ((lh < 10 || lh > 20) && ld > 1 && ld < 5) {
+ return replies + " ответа";
+ } else {
+ return replies + " ответов";
+ }
+ }
+
+ public void printMessages(PrintWriter out, com.juick.User user, List<Integer> mids, com.juick.User visitor, int YandexID, int ad_mid) {
+ List<com.juick.Message> msgs = messagesService.getMessages(mids);
+
+ for (int i = 0; i < msgs.size(); i++) {
+ com.juick.Message msg = msgs.get(i);
+ if (msg.getMid() == ad_mid) {
+ msgs.remove(i);
+ msgs.add(0, msg);
+ break;
+ }
+ }
+
+ List<Integer> blUIDs = new ArrayList<Integer>(20);
+ if (visitor != null) {
+ for (Message msg : msgs) {
+ blUIDs.add(msg.getUser().getUid());
+ }
+ blUIDs = userService.checkBL(visitor.getUid(), blUIDs);
+ }
+
+ for (Message msg : msgs) {
+
+ List<TagStats> tags = tagService.getMessageTags(msg.getMid());
+ String tagsStr = formatTags(tags);
+ if (msg.ReadOnly) {
+ tagsStr += "<a>readonly</a>";
+ }
+ if (msg.getPrivacy() < 0) {
+ tagsStr += "<a>friends</a>";
+ }
+ if (msg.getMid() == ad_mid) {
+ tagsStr += "<a>реклама</a>";
+ }
+
+ String txt;
+ if (msg.getTags().stream().anyMatch(t -> t.getName().equals("code"))) {
+ txt = MessageUtils.formatMessageCode(msg.getText());
+ } else {
+ txt = MessageUtils.formatMessage(msg.getText());
+ }
+
+ out.println("<article data-mid=\"" + msg.getMid() + "\">");
+ out.println(" <header class=\"u\">");
+ out.println(" @<a href=\"/" + msg.getUser().getName() + "/\">" + msg.getUser().getName() + "</a>:");
+ out.println(" <div class=\"msg-avatar\"><a href=\"/" + msg.getUser().getName() + "/\"><img src=\"//i.juick.com/a/" + msg.getUser().getUid() + ".png\" alt=\"" + msg.getUser().getName() + "\"/></a></div>");
+ out.println(" <div class=\"msg-ts\"><a href=\"/" + msg.getUser().getName() + "/" + msg.getMid() + "\"><time datetime=\"" + sdfSQL.format(msg.getDate()) + "Z\" title=\"" + sdfSQL.format(msg.getDate()) + " GMT\">" + formatDate(msg.TimeAgo, msg.getDate()) + "</time></a></div>");
+
+ out.println(" <div class=\"msg-tags\">" + tagsStr + "</div>");
+ out.println(" </header>");
+
+ if (msg.getAttachmentType() != null) {
+ String fname = msg.getMid() + "." + msg.getAttachmentType();
+ out.println(" <p class=\"ir\"><a href=\"//i.juick.com/photos-512/" + fname + "\" data-fname=\"" + fname + "\"><img src=\"//i.juick.com/photos-512/" + fname + "\" alt=\"\"/></a></p>");
+ }
+ out.println(" <p>" + txt + "</p>");
+ if (msg.getAttachmentType() != null) {
+ out.println(" <div class=\"irbr\"></div>");
+ }
+ out.print(" <nav class=\"l\">");
+ msg.ReadOnly |= blUIDs.contains(msg.getUser().getUid());
+ if (visitor.getUid() == 0) {
+ out.print("<a href=\"#\" class=\"a-login\">Рекомендовать</a>");
+ } else {
+ out.print("<a href=\"/post?body=!+%23" + msg.getMid() + "\" class=\"a-like\">Рекомендовать</a>");
+ }
+ if (visitor.getUid() == 0 && !msg.ReadOnly) {
+ out.print("<a href=\"/" + msg.getMid() + "\" class=\"a-login\">Комментировать</a> ");
+ } else if (visitor.getUid() > 0 && (!msg.ReadOnly || visitor.getUid() == msg.getUser().getUid())) {
+ out.print("<a class=\"a-comment\" href=\"/" + msg.getMid() + "\">Комментировать</a> ");
+ }
+ if (visitor.getUid() > 0 && msg.getPrivacy() < 0 && msg.getUser().getUid() == visitor.getUid()) {
+ out.print(" <a href=\"#\" class=\"a-privacy\">Открыть доступ</a>");
+ }
+ if (visitor.getUid() > 0 && visitor.getUid() == 3694) {
+ out.print(" <a href=\"#\" class=\"a-popular-plus\">+</a>");
+ out.print(" <a href=\"#\" class=\"a-popular-minus\">-</a>");
+ out.print(" <a href=\"#\" class=\"a-popular-delete\">x</a>");
+ }
+ out.println("</nav>");
+
+ out.print(" <nav class=\"s\">");
+ if (msg.getLikes() > 0) {
+ out.print("<a href=\"/" + msg.getUser().getName() + "/" + msg.getMid() + "\" class=\"likes\"><i data-icon=\"ei-heart\" data-size=\"s\"></i>&nbsp;" + msg.getLikes() + "</a>");
+ }
+ if (msg.getReplies() > 0) {
+ out.print("<a href=\"/" + msg.getUser().getName() + "/" + msg.getMid() + "\" class=\"replies\"><i data-icon=\"ei-comment\" data-size=\"s\"></i>&nbsp;&nbsp;" + msg.getReplies() + "</a>");
+ }
+ out.println("</nav>");
+ out.print("</article>");
+ }
+ }
+}
diff --git a/juick-www/src/main/java/com/juick/www/controllers/RSS.java b/juick-www/src/main/java/com/juick/www/controllers/RSS.java
new file mode 100644
index 00000000..79fd8e67
--- /dev/null
+++ b/juick-www/src/main/java/com/juick/www/controllers/RSS.java
@@ -0,0 +1,66 @@
+/*
+ * Juick
+ * Copyright (C) 2008-2013, ugnich
+ *
+ * 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.www.controllers;
+
+import com.juick.Message;
+import com.juick.server.util.HttpNotFoundException;
+import com.juick.service.MessagesService;
+import com.juick.service.UserService;
+import com.juick.util.DateFormattersHolder;
+import com.juick.util.MessageUtils;
+import org.springframework.jdbc.core.JdbcTemplate;
+import org.springframework.stereotype.Controller;
+import org.springframework.ui.ModelMap;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+
+import javax.inject.Inject;
+import javax.servlet.http.HttpServletResponse;
+import java.util.List;
+
+/**
+ *
+ * @author ugnich
+ */
+@Controller
+public class RSS {
+ @Inject
+ UserService userService;
+ @Inject
+ MessagesService messagesService;
+
+ @RequestMapping(value = "/rss/{uname}", method = RequestMethod.GET)
+ protected String doGet(JdbcTemplate sql, HttpServletResponse response,
+ @PathVariable String uname, ModelMap model) {
+ int uid = userService.getUIDbyName(uname);
+ List<Integer> mids = messagesService.getUserBlog(uid, 0, 0);
+ if (mids.isEmpty()) {
+ throw new HttpNotFoundException();
+ }
+
+ List<Message> msgs = messagesService.getMessages(mids);
+
+ msgs.forEach(m -> MessageUtils.formatMessage(m.getText()));
+
+ model.addAttribute("user", msgs.stream().findFirst().get().getUser());
+ model.addAttribute("msgs", msgs);
+ model.addAttribute("sdfRSS", DateFormattersHolder.getRssFormatterInstance());
+ return "webapp/WEB-INF/layouts/rss";
+ }
+}
diff --git a/juick-www/src/main/java/com/juick/www/controllers/Settings.java b/juick-www/src/main/java/com/juick/www/controllers/Settings.java
new file mode 100644
index 00000000..63cf99e6
--- /dev/null
+++ b/juick-www/src/main/java/com/juick/www/controllers/Settings.java
@@ -0,0 +1,287 @@
+/*
+ * Juick
+ * Copyright (C) 2008-2013, Ugnich Anton
+ *
+ * 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.www.controllers;
+
+import com.juick.server.helpers.NotifyOpts;
+import com.juick.server.helpers.UserInfo;
+import com.juick.server.util.HttpBadRequestException;
+import com.juick.server.util.HttpUtils;
+import com.juick.service.*;
+import com.juick.util.UserUtils;
+import com.juick.www.WebApp;
+import net.coobird.thumbnailator.Thumbnails;
+import org.apache.commons.io.FilenameUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.dao.EmptyResultDataAccessException;
+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 javax.inject.Inject;
+import javax.mail.Message;
+import javax.mail.MessagingException;
+import javax.mail.Session;
+import javax.mail.Transport;
+import javax.mail.internet.InternetAddress;
+import javax.mail.internet.MimeMessage;
+import javax.servlet.ServletException;
+import javax.servlet.http.Cookie;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.nio.file.StandardCopyOption;
+import java.util.Arrays;
+import java.util.List;
+import java.util.stream.Collectors;
+import java.util.stream.IntStream;
+
+/**
+ *
+ * @author Ugnich Anton
+ */
+@Controller
+public class Settings {
+ private static final Logger logger = LoggerFactory.getLogger(Settings.class);
+
+ @Inject
+ WebApp webApp;
+ @Inject
+ TagService tagService;
+ @Inject
+ UserService userService;
+ @Inject
+ CrosspostService crosspostService;
+ @Inject
+ SubscriptionService subscriptionService;
+ @Inject
+ EmailService emailService;
+ @Inject
+ TelegramService telegramService;
+
+ @RequestMapping(value = "/settings", method = RequestMethod.GET)
+ protected String doGet(HttpServletRequest request, HttpServletResponse response, ModelMap model) throws IOException {
+ com.juick.User visitor = webApp.getVisitorUser(request, response);
+ if (visitor.getUid() == 0) {
+ response.sendRedirect("/login");
+ }
+ List<String> pages = Arrays.asList("main", "password", "about", "auth-email", "privacy");
+ String page = request.getParameter("page");
+ if (StringUtils.isEmpty(page) || !pages.contains(page)) {
+ page = "main";
+ }
+
+ model.addAttribute("title", "Настройки");
+ model.addAttribute("visitor", visitor);
+ model.addAttribute("tags", tagService.getPopularTags());
+ model.addAttribute("auths", userService.getAuthCodes(visitor));
+ model.addAttribute("eopts", userService.getEmailOpts(visitor));
+ model.addAttribute("ehash", userService.getEmailHash(visitor));
+ model.addAttribute("emails", userService.getEmails(visitor));
+ model.addAttribute("jids", userService.getAllJIDs(visitor));
+ List<String> hours = IntStream.rangeClosed(0, 23).boxed()
+ .map(i -> StringUtils.leftPad(String.format("%d", i), 2, "0")).collect(Collectors.toList());
+ model.addAttribute("hours", hours);
+ model.addAttribute("fbstatus", crosspostService.getFbCrossPostStatus(visitor.getUid()).isCrosspostEnabled());
+ model.addAttribute("twitter_name", crosspostService.getTwitterName(visitor.getUid()));
+ model.addAttribute("telegram_name", crosspostService.getTelegramName(visitor.getUid()));
+ model.addAttribute("notify_options", subscriptionService.getNotifyOptions(visitor));
+ model.addAttribute("userinfo", userService.getUserInfo(visitor));
+ if (page.equals("auth-email")) {
+ if (emailService.verifyAddressByCode(visitor.getUid(), request.getParameter("code"))) {
+ ;
+ model.addAttribute("result", "OK!");
+ } else {
+ model.addAttribute("result", "Sorry, code unknown.");
+ }
+ }
+ return String.format("views/settings_%s", page);
+ }
+
+ @RequestMapping(value = "/settings", method = RequestMethod.POST)
+ protected String doPost(HttpServletRequest request, HttpServletResponse response,
+ @RequestParam(required = false) MultipartFile avatar,
+ ModelMap model)
+ throws IOException, ServletException {
+ com.juick.User visitor = webApp.getVisitorUser(request, response);
+ if (visitor.getUid() == 0) {
+ throw new HttpBadRequestException();
+ }
+ List<String> pages = Arrays.asList("main", "password", "about", "email", "email-add", "email-del",
+ "email-subscr", "auth-email", "privacy", "jid-del", "twitter-del", "telegram-del", "facebook-disable",
+ "facebook-enable", "vk-del");
+ String page = request.getParameter("page");
+ if (StringUtils.isEmpty(page) || !pages.contains(page)) {
+ throw new HttpBadRequestException();
+ }
+ String result = StringUtils.EMPTY;
+ switch (page) {
+ case "password":
+ if (userService.updatePassword(visitor, request.getParameter("password"))) {
+ result = "<p>Password has been changed.</p>";
+ String hash = userService.getHashByUID(visitor.getUid());
+ Cookie c = new Cookie("hash", hash);
+ c.setMaxAge(365 * 24 * 60 * 60);
+ response.addCookie(c);
+ }
+ break;
+ case "main":
+ NotifyOpts opts = new NotifyOpts();
+ opts.setRepliesEnabled(StringUtils.isNotEmpty(request.getParameter("jnotify")));
+ opts.setSubscriptionsEnabled(StringUtils.isNotEmpty(request.getParameter("subscr_notify")));
+ opts.setRecommendationsEnabled(StringUtils.isNotEmpty(request.getParameter("recomm")));
+ if (subscriptionService.setNotifyOptions(visitor, opts)) {
+ result = "<p>Notification options has been updated</p>";
+ }
+ break;
+ case "about":
+ UserInfo info = new UserInfo();
+ info.setFullName(request.getParameter("fullname"));
+ info.setCountry(request.getParameter("country"));
+ info.setUrl(request.getParameter("url"));
+ info.setDescription(request.getParameter("descr"));
+ String avatarTmpPath = HttpUtils.receiveMultiPartFile(avatar, webApp.getTmpDir());
+ if (StringUtils.isNotEmpty(avatarTmpPath)) {
+ String originalExtension = FilenameUtils.getExtension(avatarTmpPath);
+ String originalName = String.format("%s.%s", visitor.getUid(), originalExtension);
+ String targetName = String.format("%s.png", visitor.getUid());
+ Path ao = Paths.get(webApp.getImgDir(), "ao", originalName);
+ Path a = Paths.get(webApp.getImgDir(), "a", targetName);
+ Path as = Paths.get(webApp.getImgDir(), "as", targetName);
+ Files.move(Paths.get(webApp.getTmpDir(), avatarTmpPath), ao, StandardCopyOption.REPLACE_EXISTING);
+ Thumbnails.of(ao.toFile()).size(96, 96).toFile(a.toFile());
+ Thumbnails.of(ao.toFile()).size(32, 32).toFile(as.toFile());
+ }
+ if (userService.updateUserInfo(visitor, info)) {
+ result = String.format("<p>Your info is updated.</p><p><a href='/%s/'>Back to blog</a>.</p>", visitor.getName());
+ }
+ break;
+ case "jid-del":
+ // FIXME: stop using ugnich-csv in parameters
+ String[] params = request.getParameter("delete").split(";", 2);
+ boolean res = false;
+ if (params[0].equals("xmpp")) {
+ res = userService.deleteJID(visitor.getUid(), params[1]);
+ } else if (params[0].equals("xmpp-unauth")) {
+ res = userService.unauthJID(visitor.getUid(), params[1]);
+ }
+ if (res) {
+ result = "<p>Deleted. <a href=\"/settings\">Back</a>.</p>";
+ } else {
+ result = "<p>Error</p>";
+ }
+ break;
+ case "email":
+ String newHash = userService.updateSecretEmail(visitor);
+ if (StringUtils.isNotEmpty(newHash)) {
+ result = String.format("<p>New secret email: <strong>%s@mail.juick.com</strong></p>" +
+ "<p><a href=\"/settings\">Back</a>.</p>", newHash);
+ } else {
+ throw new HttpBadRequestException();
+ }
+ break;
+ case "email-add":
+ try {
+ emailService.verifyAddressByCode(visitor.getUid(), request.getParameter("account"));
+ } catch (EmptyResultDataAccessException e) {
+ String authCode = UserUtils.generateHash(8);
+ if (emailService.addVerificationCode(visitor.getUid(), request.getParameter("account"), authCode)) {
+ Session session = Session.getDefaultInstance(System.getProperties());
+ try {
+ MimeMessage message = new MimeMessage(session);
+ message.setFrom(new InternetAddress("noreply@mail.juick.com"));
+ message.addRecipient(Message.RecipientType.TO, new InternetAddress(request.getParameter("account")));
+ message.setSubject("Juick authorization link");
+ message.setText(String.format("Follow link to attach this email to Juick account:\n" +
+ "http://juick.com/settings?page=auth-email&code=%s\n\n" +
+ "If you don't know, what this mean - just ignore this mail.\n", authCode));
+ Transport.send(message);
+ result = "<p>Authorization link has been sent to your email. Follow it to proceed.</p>" +
+ "<p><a href=\"/settings\">Back</a></p>";
+
+ } catch (MessagingException ex) {
+ logger.error("mail exception", ex);
+ throw new HttpBadRequestException();
+ }
+ }
+ }
+ break;
+ case "email-del":
+ if (emailService.deleteEmail(visitor.getUid(), request.getParameter("account"))) {
+ result = "<p>Deleted. <a href=\"/settings\">Back</a>.</p>";
+ } else {
+ result = "<p>An error occured while deleting.</p>";
+ }
+ break;
+ case "email-subscr":
+ if (emailService.setSubscriptionHour(visitor.getUid(), request.getParameter("account"),
+ request.getParameter("time"))) {
+ result = String.format("<p>Saved! Will send to <strong>%s</strong> at <strong>%s:00 GMT</strong>." +
+ "</p><p><a href=\"/settings\">Back</a></p>", request.getParameter("account"),
+ request.getParameter("time"));
+ } else {
+ result = "<p>Disabled.</p><p><a href=\"/settings\">Back</a></p>";
+ }
+ break;
+ case "twitter-del":
+ crosspostService.deleteTwitterToken(visitor.getUid());
+ for (Cookie cookie : request.getCookies()) {
+ if (cookie.getName().equals("request_token")) {
+ cookie.setMaxAge(0);
+ response.addCookie(cookie);
+ }
+ if (cookie.getName().equals("request_token_secret")) {
+ cookie.setMaxAge(0);
+ response.addCookie(cookie);
+ }
+ }
+ result = "<p><a href=\"/settings\">Back</a></p>";
+ break;
+ case "telegram-del":
+ telegramService.deleteTelegramUser(visitor.getUid());
+ result = "<p><a href=\"/settings\">Back</a></p>";
+ break;
+ case "facebook-disable":
+ crosspostService.disableFBCrosspost(visitor.getUid());
+ result = "<p><a href=\"/settings\">Back</a></p>";
+ break;
+ case "facebook-enable":
+ crosspostService.enableFBCrosspost(visitor.getUid());
+ result = "<p><a href=\"/settings\">Back</a></p>";
+ break;
+ case "vk-del":
+ crosspostService.deleteVKUser(visitor.getUid());
+ result = "<p><a href=\"/settings\">Back</a></p>";
+ break;
+ default:
+ throw new HttpBadRequestException();
+ }
+
+ model.addAttribute("title", "Настройки");
+ model.addAttribute("visitor", visitor);
+ model.addAttribute("result", result);
+ return "views/settings_result";
+ }
+}
diff --git a/juick-www/src/main/java/com/juick/www/controllers/SignUp.java b/juick-www/src/main/java/com/juick/www/controllers/SignUp.java
new file mode 100644
index 00000000..937a3242
--- /dev/null
+++ b/juick-www/src/main/java/com/juick/www/controllers/SignUp.java
@@ -0,0 +1,170 @@
+/*
+ * Juick
+ * Copyright (C) 2008-2013, Ugnich Anton
+ *
+ * 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.www.controllers;
+
+import com.juick.server.util.HttpBadRequestException;
+import com.juick.server.util.HttpForbiddenException;
+import com.juick.service.CrosspostService;
+import com.juick.service.UserService;
+import com.juick.www.Utils;
+import com.juick.www.WebApp;
+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 javax.inject.Inject;
+import javax.servlet.http.Cookie;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+/**
+ *
+ * @author Ugnich Anton
+ */
+@Controller
+public class SignUp {
+
+ @Inject
+ WebApp webApp;
+ @Inject
+ UserService userService;
+ @Inject
+ CrosspostService crosspostService;
+
+
+ @RequestMapping(value = "/signup", method = RequestMethod.GET)
+ protected String doGet(HttpServletRequest request, HttpServletResponse response, ModelMap model) {
+ com.juick.User visitor = webApp.getVisitorUser(request, response);
+
+ String type = request.getParameter("type");
+ String hash = request.getParameter("hash");
+ if (type == null || type.isEmpty() || hash == null || hash.isEmpty() || hash.length() > 36
+ || !type.matches("^[a-zA-Z0-9\\-]+$") || !hash.matches("^[a-zA-Z0-9\\-]+$")) {
+ throw new HttpBadRequestException();
+ }
+
+ String account = null;
+ switch (type) {
+ case "fb":
+ account = crosspostService.getFacebookNameByHash(hash);
+ break;
+ case "vk":
+ account = crosspostService.getVKNameByHash(hash);
+ break;
+ case "xmpp":
+ account = crosspostService.getJIDByHash(hash);
+ break;
+ case "durov":
+ account = crosspostService.getTelegramNameByHash(hash);
+ break;
+ }
+ if (account == null) {
+ throw new HttpBadRequestException();
+ }
+
+ model.addAttribute("title", "Новый пользователь");
+ model.addAttribute("visitor", visitor);
+ model.addAttribute("account", account);
+ model.addAttribute("type", type);
+ model.addAttribute("hash", hash);
+ return "views/signup";
+ }
+
+ @RequestMapping(value = "/signup", method = RequestMethod.POST)
+ protected String doPost(HttpServletRequest request, HttpServletResponse response) {
+ com.juick.User visitor = webApp.getVisitorUser(request, response);
+ int uid = 0;
+
+ String type = request.getParameter("type");
+ String hash = request.getParameter("hash");
+ if (type == null || type.isEmpty() || hash == null || hash.isEmpty() || hash.length() > 36 || !type.matches("^[a-zA-Z0-9\\-]+$") || !hash.matches("^[a-zA-Z0-9\\-]+$")) {
+ throw new HttpBadRequestException();
+ }
+
+ String action = request.getParameter("action");
+ if (action.charAt(0) == 'l') {
+
+ if (visitor.getUid() == 0) {
+ String username = request.getParameter("username");
+ String password = request.getParameter("password");
+ if (username == null || password == null || username.length() > 32 || password.isEmpty()) {
+ throw new HttpBadRequestException();
+ }
+ uid = userService.checkPassword(username, password);
+ } else {
+ uid = visitor.getUid();
+ }
+
+ if (uid <= 0) {
+ throw new HttpForbiddenException();
+ }
+
+ if (!(type.charAt(0) == 'f' && crosspostService.setFacebookUser(hash, uid))
+ && !(type.charAt(0) == 'v' && crosspostService.setVKUser(hash, uid))
+ && !(type.charAt(0) == 'd' && crosspostService.setTelegramUser(hash, uid))
+ && !(type.charAt(0) == 'x' && crosspostService.setJIDUser(hash, uid))) {
+ throw new HttpBadRequestException();
+ }
+
+ } else { // Create new account
+ String username = request.getParameter("username");
+ String password = request.getParameter("password");
+ if (username == null || password == null || username.length() < 2 || username.length() > 16 || !username.matches("^[a-zA-Z0-9\\-]+$") || password.length() < 6 || password.length() > 32) {
+ throw new HttpBadRequestException();
+ }
+
+ // CHECK USERNAME
+
+ uid = userService.createUser(username, password);
+ if (uid <= 0) {
+ throw new HttpBadRequestException();
+ }
+
+ if (!(type.charAt(0) == 'f' && crosspostService.setFacebookUser(hash, uid))
+ && !(type.charAt(0) == 'v' && crosspostService.setVKUser(hash, uid))
+ && !(type.charAt(0) == 'd' && crosspostService.setTelegramUser(hash, uid))
+ && !(type.charAt(0) == 'x' && crosspostService.setJIDUser(hash, uid))) {
+ throw new HttpBadRequestException();
+ }
+
+ int ref = 0;
+ String sRef = Utils.getCookie(request, "ref");
+ if (sRef != null) {
+ try {
+ ref = Integer.parseInt(sRef);
+ } catch (Exception e) {
+ }
+ }
+
+ if (ref > 0) {
+ crosspostService.setUserRef(uid, ref);
+ }
+
+ visitor = null;
+ }
+
+ if (visitor == null) {
+ hash = userService.getHashByUID(uid);
+ Cookie c = new Cookie("hash", hash);
+ c.setMaxAge(365 * 24 * 60 * 60);
+ response.addCookie(c);
+ }
+ return "redirect:/";
+ }
+}
diff --git a/juick-www/src/main/java/com/juick/www/controllers/TwitterAuth.java b/juick-www/src/main/java/com/juick/www/controllers/TwitterAuth.java
new file mode 100644
index 00000000..901a8362
--- /dev/null
+++ b/juick-www/src/main/java/com/juick/www/controllers/TwitterAuth.java
@@ -0,0 +1,103 @@
+package com.juick.www.controllers;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.github.scribejava.apis.TwitterApi;
+import com.github.scribejava.core.builder.ServiceBuilder;
+import com.github.scribejava.core.model.OAuth1AccessToken;
+import com.github.scribejava.core.model.OAuth1RequestToken;
+import com.github.scribejava.core.model.OAuthRequest;
+import com.github.scribejava.core.model.Verb;
+import com.github.scribejava.core.oauth.OAuth10aService;
+import com.juick.service.UserService;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.core.env.Environment;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+
+import javax.inject.Inject;
+import javax.servlet.http.Cookie;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+
+/**
+ * Created by vt on 01.12.2015.
+ */
+@Controller
+public class TwitterAuth {
+
+ private final static String VERIFY_URL = "https://api.twitter.com/1.1/account/verify_credentials.json";
+
+ private String consumerKey, consumerSecret;
+
+ private final ObjectMapper mapper;
+
+ @Inject
+ UserService userService;
+
+ @Inject
+ public TwitterAuth(Environment env) {
+ this.consumerKey = env.getProperty("twitter_consumer_key");
+ this.consumerSecret = env.getProperty("twitter_consumer_secret");
+ mapper = new ObjectMapper();
+ mapper.setSerializationInclusion(JsonInclude.Include.NON_EMPTY);
+ mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
+ mapper.setSerializationInclusion(JsonInclude.Include.NON_DEFAULT);
+ }
+
+ @RequestMapping(value = "/_twitter", method = RequestMethod.GET)
+ protected void doGet(HttpServletRequest request, HttpServletResponse response)
+ throws IOException {
+ String hash = StringUtils.EMPTY, request_token = StringUtils.EMPTY, request_token_secret = StringUtils.EMPTY;
+ String verifier = request.getParameter("oauth_verifier");
+ Cookie[] cookies = request.getCookies();
+ for (Cookie cookie : cookies) {
+ if (cookie.getName().equals("hash")) {
+ hash = cookie.getValue();
+ }
+ if (cookie.getName().equals("request_token")) {
+ request_token = cookie.getValue();
+ }
+ if (cookie.getName().equals("request_token_secret")) {
+ request_token_secret = cookie.getValue();
+ }
+ }
+ com.juick.User user = userService.getUserByHash(hash);
+ if ( user == null || user.getUid() == 0) {
+ response.sendError(HttpServletResponse.SC_FORBIDDEN);
+ return;
+ }
+ OAuth10aService oAuthService = new ServiceBuilder()
+ .apiKey(consumerKey)
+ .apiSecret(consumerSecret)
+ .callback("http://juick.com/_twitter")
+ .build(TwitterApi.instance());
+
+ if (request_token.isEmpty() && request_token_secret.isEmpty()
+ && (verifier == null || verifier.isEmpty())) {
+ OAuth1RequestToken requestToken = oAuthService.getRequestToken();
+ String authUrl = oAuthService.getAuthorizationUrl(requestToken);
+ response.addCookie(new Cookie("request_token", requestToken.getToken()));
+ response.addCookie(new Cookie("request_token_secret", requestToken.getTokenSecret()));
+ response.setStatus(HttpServletResponse.SC_FOUND);
+ response.setHeader("Location", authUrl);
+ } else {
+ if (verifier != null && verifier.length() > 0) {
+ OAuth1RequestToken requestToken = new OAuth1RequestToken(request_token, request_token_secret);
+ OAuth1AccessToken accessToken = oAuthService.getAccessToken(requestToken, verifier);
+ OAuthRequest oAuthRequest = new OAuthRequest(Verb.GET, VERIFY_URL, oAuthService.getConfig());
+ oAuthService.signRequest(accessToken, oAuthRequest);
+ com.juick.www.twitter.User twitterUser = mapper.readValue(oAuthRequest.send().getBody(), com.juick.www.twitter.User.class);
+ if (userService.linkTwitterAccount(user, accessToken.getToken(), accessToken.getTokenSecret(),
+ twitterUser.getScreenName())) {
+ response.setStatus(HttpServletResponse.SC_FOUND);
+ response.setHeader("Location", "http://juick.com/settings");
+ } else {
+ response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
+ }
+ }
+ }
+ }
+}
diff --git a/juick-www/src/main/java/com/juick/www/controllers/User.java b/juick-www/src/main/java/com/juick/www/controllers/User.java
new file mode 100644
index 00000000..d3406f4e
--- /dev/null
+++ b/juick-www/src/main/java/com/juick/www/controllers/User.java
@@ -0,0 +1,368 @@
+/*
+ * Juick
+ * Copyright (C) 2008-2011, Ugnich Anton
+ *
+ * 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.www.controllers;
+
+import com.juick.server.helpers.TagStats;
+import com.juick.service.MessagesService;
+import com.juick.service.TagService;
+import com.juick.service.UserService;
+import com.juick.www.Utils;
+import com.juick.www.WebApp;
+import org.apache.commons.lang3.CharEncoding;
+import org.apache.commons.lang3.StringEscapeUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+
+import javax.inject.Inject;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.io.UnsupportedEncodingException;
+import java.net.URLEncoder;
+import java.util.Comparator;
+import java.util.List;
+import java.util.stream.Collectors;
+
+/**
+ *
+ * @author Ugnich Anton
+ */
+@Controller
+public class User {
+ @Inject
+ WebApp webApp;
+ @Inject
+ UserService userService;
+ @Inject
+ TagService tagService;
+ @Inject
+ MessagesService messagesService;
+ @Inject
+ PageTemplates templates;
+
+ @RequestMapping("/{uname}/")
+ protected void doGetBlog(HttpServletRequest request, HttpServletResponse response,
+ @PathVariable String uname) throws IOException {
+ com.juick.User user = userService.getUserByName(uname);
+ com.juick.User visitor = webApp.getVisitorUser(request, response);
+ if (visitor.isBanned()) {
+ response.sendError(HttpServletResponse.SC_NOT_FOUND);
+ return;
+ }
+
+ List<Integer> mids;
+
+ String paramShow = request.getParameter("show");
+
+ com.juick.Tag paramTag = null;
+ String paramTagStr = request.getParameter("tag");
+ if (paramTagStr != null) {
+ if (paramTagStr.length() < 64) {
+ paramTag = tagService.getTag(paramTagStr, false);
+ }
+ if (paramTag == null) {
+ response.sendError(HttpServletResponse.SC_NOT_FOUND);
+ return;
+ } else if (!paramTag.getName().equals(paramTagStr)) {
+ String url = "/" + user.getName() + "/?tag=" + URLEncoder.encode(paramTag.getName(), CharEncoding.UTF_8);
+ Utils.sendPermanentRedirect(response, url);
+ return;
+ }
+ }
+
+ int paramBefore = 0;
+ String paramBeforeStr = request.getParameter("before");
+ if (paramBeforeStr != null) {
+ try {
+ paramBefore = Integer.parseInt(paramBeforeStr);
+ } catch (NumberFormatException e) {
+ }
+ }
+
+ String paramSearch = request.getParameter("search");
+ if (paramSearch != null && paramSearch.length() > 64) {
+ paramSearch = null;
+ }
+
+ int privacy = 0;
+ if (visitor.getUid() > 0) {
+ if (user.getUid() == visitor.getUid() || visitor.getUid() == 1) {
+ privacy = -3;
+ } else if (userService.isInWL(user.getUid(), visitor.getUid())) {
+ privacy = -2;
+ }
+ }
+
+ String title;
+ if (paramShow == null) {
+ if (paramTag != null) {
+ title = "Блог " + user.getName() + ": *" + StringEscapeUtils.escapeHtml4(paramTag.getName());
+ mids = messagesService.getUserTag(user.getUid(), paramTag.TID, privacy, paramBefore);
+ } else if (paramSearch != null) {
+ title = "Блог " + user.getName() + ": " + StringEscapeUtils.escapeHtml4(paramSearch);
+ mids = messagesService.getUserSearch(user.getUid(), Utils.encodeSphinx(paramSearch), privacy, paramBefore);
+ } else {
+ title = "Блог " + user.getName();
+ mids = messagesService.getUserBlog(user.getUid(), privacy, paramBefore);
+ }
+ } else if (paramShow.equals("recomm")) {
+ title = "Рекомендации " + user.getName();
+ mids = messagesService.getUserRecommendations(user.getUid(), paramBefore);
+ } else if (paramShow.equals("photos")) {
+ title = "Фотографии " + user.getName();
+ mids = messagesService.getUserPhotos(user.getUid(), privacy, paramBefore);
+ } else {
+ response.sendError(HttpServletResponse.SC_NOT_FOUND);
+ return;
+ }
+
+ response.setContentType("text/html; charset=UTF-8");
+ try (PrintWriter out = response.getWriter()) {
+ String head = "<link rel=\"alternate\" type=\"application/rss+xml\" title=\"@" +
+ user.getName() + "\" href=\"//rss.juick.com/" + user.getName() + "/blog\"/>";
+ if (paramTag != null && tagService.getTagNoIndex(paramTag.TID)) {
+ head += "<meta name=\"robots\" content=\"noindex,nofollow\"/>";
+ } else if (paramBefore > 0 || paramShow != null) {
+ head += "<meta name=\"robots\" content=\"noindex\"/>";
+ }
+ templates.pageHead(out, visitor, title, head);
+ templates.pageNavigation(out, visitor, null);
+ pageUserColumn(out, user, visitor);
+
+ if (mids.size() > 0) {
+ out.println("<section id=\"content\">");
+
+ if (paramTag != null) {
+ out.println("<p class=\"page\"><a href=\"/tag/" +
+ URLEncoder.encode(paramTag.getName(), CharEncoding.UTF_8) + "\">← Все записи с тегом <b>" +
+ StringEscapeUtils.escapeHtml4(paramTag.getName()) + "</b></a></p>");
+ }
+
+ templates.printMessages(out, user, mids, visitor, visitor.getUid() == 0 ? 4 : 5, 0);
+
+ if (mids.size() >= 20) {
+ String nextpage = "?before=" + mids.get(mids.size() - 1);
+ if (paramShow != null) {
+ nextpage += "&amp;show=" + paramShow;
+ }
+ if (paramTag != null) {
+ nextpage += "&amp;tag=" + URLEncoder.encode(paramTag.getName(), CharEncoding.UTF_8);
+ }
+ if (paramSearch != null) {
+ nextpage += "&amp;search=" + URLEncoder.encode(paramSearch, CharEncoding.UTF_8);
+ }
+ out.println("<p class=\"page\"><a href=\"" + nextpage + "\" rel=\"prev\">Читать дальше →</a></p>");
+ }
+
+ out.println("</section>");
+ }
+
+ templates.pageFooter(request, out, visitor, true);
+ templates.pageEnd(out);
+ }
+ }
+
+ @RequestMapping(value = "/{uname}/tags", method = RequestMethod.GET)
+ protected void doGetTags(HttpServletRequest request, HttpServletResponse response,
+ @PathVariable String uname) throws IOException {
+ com.juick.User user = userService.getUserByName(uname);
+ com.juick.User visitor = webApp.getVisitorUser(request, response);
+ if (visitor.isBanned()) {
+ response.sendError(HttpServletResponse.SC_NOT_FOUND);
+ return;
+ }
+
+ response.setContentType("text/html; charset=UTF-8");
+ try (PrintWriter out = response.getWriter()) {
+ String head = "<meta name=\"robots\" content=\"noindex,nofollow\"/>";
+ templates.pageHead(out, visitor, "Теги " + user.getName(), head);
+ templates.pageNavigation(out, visitor, null);
+ pageUserColumn(out, user, visitor);
+
+ out.println("<section id=\"content\">");
+ out.println("<p>" + pageUserTags(user, visitor, 0) + "</p>");
+ out.println("</section>");
+
+ templates.pageFooter(request, out, visitor, false);
+ templates.pageEnd(out);
+ }
+ }
+
+ @RequestMapping(value = "/{uname}/friends", method = RequestMethod.GET)
+ protected void doGetFriends(HttpServletRequest request, HttpServletResponse response,
+ @PathVariable String uname) throws ServletException, IOException {
+ com.juick.User user = userService.getUserByName(uname);
+ com.juick.User visitor = webApp.getVisitorUser(request, response);
+ if (visitor.isBanned()) {
+ response.sendError(HttpServletResponse.SC_NOT_FOUND);
+ return;
+ }
+
+ response.setContentType("text/html; charset=UTF-8");
+ try (PrintWriter out = response.getWriter()) {
+ String head = "<meta name=\"robots\" content=\"noindex\"/>";
+ templates.pageHead(out, visitor, "Подписки " + user.getName(), head);
+ templates.pageNavigation(out, visitor, null);
+ pageUserColumn(out, user, visitor);
+
+ out.println("<section id=\"content\">");
+ out.println("<table class=\"users\"><tr>");
+
+ List<com.juick.User> friends = userService.getUserFriends(user.getUid());
+ for (int i = 0; i < friends.size(); i++) {
+ if (i % 3 == 0 && i > 0) {
+ out.print("</tr><tr>");
+ }
+ out.print("<td><a href=\"/" + friends.get(i).getName()
+ + "/\"><img src=\"//i.juick.com/as/" + friends.get(i).getUid() + ".png\"/>"
+ + friends.get(i).getName() + "</a></td>");
+ }
+
+ out.println("</tr></table>");
+ out.println("</section>");
+
+ templates.pageFooter(request, out, visitor, false);
+ templates.pageEnd(out);
+ }
+ }
+
+ @RequestMapping(value = "/{uname}/readers", method = RequestMethod.GET)
+ protected void doGetReaders(HttpServletRequest request, HttpServletResponse response,
+ @PathVariable String uname) throws ServletException, IOException {
+ com.juick.User user = userService.getUserByName(uname);
+ com.juick.User visitor = webApp.getVisitorUser(request, response);
+ if (visitor.isBanned()) {
+ response.sendError(HttpServletResponse.SC_NOT_FOUND);
+ return;
+ }
+
+ response.setContentType("text/html; charset=UTF-8");
+ try (PrintWriter out = response.getWriter()) {
+ String head = "<meta name=\"robots\" content=\"noindex\"/>";
+ templates.pageHead(out, visitor, "Читатели " + user.getName(), head);
+ templates.pageNavigation(out, visitor, null);
+ pageUserColumn(out, user, visitor);
+
+ out.println("<section id=\"content\">");
+ out.println("<table class=\"users\"><tr>");
+
+ List<com.juick.User> readers = userService.getUserReaders(user.getUid());
+ for (int i = 0; i < readers.size(); i++) {
+ if (i % 3 == 0 && i > 0) {
+ out.print("</tr><tr>");
+ }
+ out.print("<td><a href=\"/" + readers.get(i).getName()
+ + "/\"><img src=\"//i.juick.com/as/" + readers.get(i).getUid() + ".png\"/>"
+ + readers.get(i).getName() + "</a></td>");
+ }
+
+ out.println("</tr></table>");
+ out.println("</section>");
+
+ templates.pageFooter(request, out, visitor, false);
+ templates.pageEnd(out);
+ }
+ }
+
+ public void pageUserColumn(PrintWriter out, com.juick.User user, com.juick.User visitor) {
+ out.println("<aside id=\"column\">");
+ out.println(" <div id=\"ctitle\"><a href=\"./\"><img src=\"//i.juick.com/as/" + user.getUid() + ".png\" alt=\"\"/>" + user.getName() + "</a></div>");
+ if (visitor.getUid() > 0 && visitor.getUid() != user.getUid()) {
+ out.println(" <ul id=\"ctoolbar\">");
+ if (userService.isSubscribed(visitor.getUid(), user.getUid())) {
+ out.println(" <li><a href=\"/post?body=U+%40" + user.getName() + "\" title=\"Подписан\"><div style=\"background-position: -48px 0\"></div></a></li>");
+ } else {
+ out.println(" <li><a href=\"/post?body=S+%40" + user.getName() + "\" title=\"Подписаться\"><div style=\"background-position: -16px 0\"></div></a></li>");
+ }
+ if (userService.isInBL(visitor.getUid(), user.getUid())) {
+ out.println(" <li><a href=\"/post?body=BL+%40" + user.getName() + "\" title=\"Разблокировать\"><div style=\"background-position: -96px 0\"></div></a></li>");
+ } else {
+ out.println(" <li><a href=\"/post?body=BL+%40" + user.getName() + "\" title=\"Заблокировать\"><div style=\"background-position: -80px 0\"></div></a></li>");
+ }
+ if (!userService.isInBLAny(user.getUid(), visitor.getUid())) {
+ out.println(" <li><a href=\"/pm/sent?uname=" + user.getName() + "\" title=\"Написать приватное сообщение\"><div style=\"background-position: -112px 0\"></div></a></li>");
+ }
+ out.println(" </ul>");
+ } else {
+ out.println(" <hr/>");
+ }
+ out.println(" <ul>");
+ out.println(" <li><a href=\"./\">Блог</a></li>");
+ out.println(" <li><a href=\"./?show=recomm\" rel=\"nofollow\">Рекомендации</a></li>");
+ out.println(" <li><a href=\"./?show=photos\" rel=\"nofollow\">Фотографии</a></li>");
+ out.println(" </ul>");
+ out.println(" <hr/>");
+ out.println(" <form action=\"./\">");
+ out.println(" <p><input type=\"text\" name=\"search\" class=\"inp\" placeholder=\"Поиск\"/></p>");
+ out.println(" </form>");
+ out.println(" <p class=\"tags\">" + pageUserTags(user, visitor, 20) + "<a href=\"./tags\" rel=\"nofollow\">...</a></p>");
+ out.println(" <hr/>");
+ out.println(" <div id=\"ustats\"><ul>");
+ out.println(" <li><a href=\"./friends\">Я читаю: " + userService.getStatsIRead(user.getUid()) + "</a></li>");
+ out.println(" <li><a href=\"./readers\">Мои подписчики: " + userService.getStatsMyReaders(user.getUid()) + "</a></li>");
+ out.println(" <li>Сообщений: " + userService.getStatsMessages(user.getUid()) + "</li>");
+ out.println(" <li>Комментариев: " + userService.getStatsReplies(user.getUid()) + "</li>");
+ out.println(" </ul>");
+
+ List<com.juick.User> iread = userService.getUserReadLeastPopular(user.getUid(), 8);
+ if (!iread.isEmpty()) {
+ out.println("<table class=\"iread\"><tr>");
+ for (int i = 0; i < iread.size(); i++) {
+ if (i == 4) {
+ out.println("</tr><tr>");
+ }
+ com.juick.User u = iread.get(i);
+ out.println("<td><a href=\"/" + u.getName() + "/\"><img src=\"//i.juick.com/a/" + u.getUid() + ".png\" alt=\"" + u.getName() + "\"/></a></td>");
+ }
+ out.println("</tr></table>");
+ }
+
+ out.println(" </div>");
+ out.println("</aside>");
+ }
+
+ public String pageUserTags(com.juick.User user, com.juick.User visitor, int cnt) {
+ List<TagStats> tags = tagService.getUserTagStats(user.getUid()).stream()
+ .sorted((e1, e2) -> Integer.compare(e2.getUsageCount(), e1.getUsageCount())).collect(Collectors.toList());
+ int maxUsageCnt = tags.stream().map(TagStats::getUsageCount).max(Comparator.naturalOrder()).orElse(0);
+ String ret = StringUtils.EMPTY;
+ int count = cnt > 0 ? Math.min(tags.size(), cnt) : tags.size();
+ for (int i = 0; i < count; i++) {
+ String tag = StringEscapeUtils.escapeHtml4(tags.get(i).getTag().getName());
+ try {
+ tag = "<a href=\"./?tag=" + URLEncoder.encode(tags.get(i).getTag().getName(), CharEncoding.UTF_8) + "\" title=\""
+ + tags.get(i).getUsageCount() + "\" rel=\"nofollow\">" + tag + "</a>";
+ } catch (UnsupportedEncodingException e) {
+ }
+
+ if (tags.get(i).getUsageCount() > maxUsageCnt / 3 * 2) {
+ ret += "<big>" + tag + "</big> ";
+ } else if (tags.get(i).getUsageCount() > maxUsageCnt / 3) {
+ ret += "<small>" + tag + "</small> ";
+ } else {
+ ret += tag + " ";
+ }
+ }
+ return ret;
+ }
+}
diff --git a/juick-www/src/main/java/com/juick/www/controllers/UserThread.java b/juick-www/src/main/java/com/juick/www/controllers/UserThread.java
new file mode 100644
index 00000000..4020e149
--- /dev/null
+++ b/juick-www/src/main/java/com/juick/www/controllers/UserThread.java
@@ -0,0 +1,374 @@
+/*
+ * Juick
+ * Copyright (C) 2008-2011, Ugnich Anton
+ *
+ * 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.www.controllers;
+
+import com.juick.Message;
+import com.juick.server.helpers.TagStats;
+import com.juick.service.MessagesService;
+import com.juick.service.TagService;
+import com.juick.service.UserService;
+import com.juick.util.MessageUtils;
+import com.juick.www.WebApp;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+
+import javax.inject.Inject;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ *
+ * @author Ugnich Anton
+ */
+@Controller
+public class UserThread {
+
+ @Inject
+ WebApp webApp;
+ @Inject
+ MessagesService messagesService;
+ @Inject
+ UserService userService;
+ @Inject
+ TagService tagService;
+ @Inject
+ PageTemplates templates;
+
+ @RequestMapping(value = "/{uname}/{mid}", method = RequestMethod.GET)
+ protected void doGetThread(HttpServletRequest request, HttpServletResponse response,
+ @PathVariable int mid) throws ServletException, IOException {
+ com.juick.User visitor = webApp.getVisitorUser(request, response);
+
+ if (!messagesService.canViewThread(mid, visitor.getUid())) {
+ response.sendError(HttpServletResponse.SC_FORBIDDEN);
+ return;
+ }
+
+ com.juick.Message msg = messagesService.getMessage(mid);
+
+ boolean listview = false;
+ String paramView = request.getParameter("view");
+ if (paramView != null) {
+ if (paramView.equals("list")) {
+ listview = true;
+ if (visitor.getUid() > 0) {
+ userService.setUserOptionInt(visitor.getUid(), "repliesview", 1);
+ }
+ } else if (paramView.equals("tree") && visitor.getUid() > 0) {
+ userService.setUserOptionInt(visitor.getUid(), "repliesview", 0);
+ }
+ } else if (visitor.getUid() > 0 && userService.getUserOptionInt(visitor.getUid(), "repliesview", 0) == 1) {
+ listview = true;
+ }
+
+ String title = msg.getUser().getName() + ": " + msg.getTagsString();
+
+ response.setContentType("text/html; charset=UTF-8");
+ try (PrintWriter out = response.getWriter()) {
+ String headers = "<link rel=\"alternate\" type=\"application/rss+xml\" title=\"@" + msg.getUser().getName() + "\" href=\"//rss.juick.com/" + msg.getUser().getName() + "/blog\"/>";
+ if (paramView != null) {
+ headers += "<link rel=\"canonical\" href=\"http://juick.com/" + msg.getUser().getName() + "/" + msg.getMid() + "\"/>";
+ }
+ if (msg.Hidden) {
+ headers += "<meta name=\"robots\" content=\"noindex\"/>";
+ }
+ templates.pageHead(out, visitor, title, headers);
+ templates.pageNavigation(out, visitor, null);
+
+ out.println("<section id=\"content\" data-mid=\"" + msg.getMid() + "\" style=\"margin-left: 0; width: 100%\">");
+ printMessage(out, msg, visitor);
+ printReplies(out, msg, visitor, listview);
+ out.println("</section>");
+
+ templates.pageFooter(request, out, visitor, false);
+
+ templates.pageEnd(out);
+ }
+ }
+
+ public com.juick.Message printMessage(PrintWriter out, com.juick.Message msg, com.juick.User visitor) {
+ msg.VisitorCanComment = visitor.getUid() > 0;
+
+ List<TagStats> tags = tagService.getMessageTags(msg.getMid());
+ String tagsStr = templates.formatTags(tags);
+ if (msg.ReadOnly) {
+ tagsStr += "<a>readonly</a>";
+ msg.VisitorCanComment = false;
+ }
+ if (msg.getPrivacy() < 0) {
+ tagsStr += "<a>friends</a>";
+ }
+
+ String txt;
+ if (msg.getTags().stream().anyMatch(t -> t.getName().equals("code"))) {
+ txt = MessageUtils.formatMessageCode(msg.getText());
+ } else {
+ txt = MessageUtils.formatMessage(msg.getText());
+ }
+
+ if (!tags.isEmpty()) {
+ tagsStr = "<div class=\"msg-tags\">" + tagsStr + "</div>";
+ }
+
+ out.println("<ul>");
+ out.println(" <li id=\"msg-" + msg.getMid() + "\" data-mid=\"" + msg.getMid() + "\" class=\"msg msgthread\">");
+ out.println(" <div class=\"msg-cont\">");
+ out.println(" <div class=\"msg-menu\"><a href=\"#\"></a></div>");
+ out.println(" <div class=\"msg-ts\">" + templates.formatJSLocalTime(msg.getDate()) + "</div>");
+ out.println(" <div class=\"msg-avatar\"><a href=\"/" + msg.getUser().getName() + "/\"><img src=\"//i.juick.com/a/" + msg.getUser().getUid() + ".png\" alt=\"" + msg.getUser().getName() + "\"/></a></div>");
+ out.println(" <div class=\"msg-header\">@<a href=\"/" + msg.getUser().getName() + "/\">" + msg.getUser().getName() + "</a>:" + tagsStr + "</div>");
+ out.println(" <div class=\"msg-txt\">" + txt + "</div>");
+
+ if (msg.getAttachmentType() != null) {
+ out.println(" <div class=\"msg-media\"><a href=\"//i.juick.com/p/" + msg.getMid() + "." + msg.getAttachmentType() + "\"><img src=\"//i.juick.com/photos-512/" + msg.getMid() + "." + msg.getAttachmentType() + "\" alt=\"\"/></a></div>");
+ }
+
+ boolean visitorInBL = false;
+ if (visitor.getUid() > 0) {
+ if (visitor.getUid() == msg.getUser().getUid()) {
+ msg.VisitorCanComment = true;
+ } else {
+ visitorInBL = userService.isInBL(msg.getUser().getUid(), visitor.getUid());
+ if (visitorInBL) {
+ msg.VisitorCanComment = false;
+ }
+ }
+ }
+
+ if (msg.VisitorCanComment) {
+ out.println(" <form action=\"/comment\" method=\"POST\" enctype=\"multipart/form-data\"><input type=\"hidden\" name=\"mid\" value=\"" + msg.getMid() + "\"/>");
+ out.println(" <div class=\"msg-comment\"><div class=\"ta-wrapper\"><textarea name=\"body\" rows=\"1\" class=\"reply\" placeholder=\"Написать комментарий\"></textarea></div></div>");
+ out.println(" </form>");
+ }
+
+ List<String> recomm = messagesService.getMessageRecommendations(msg.getMid());
+ if (!recomm.isEmpty()) {
+ out.print(" <div class=\"msg-recomms\">Рекомендовали (" + recomm.size() + "): ");
+ for (int i = 0; i < recomm.size(); i++) {
+ if (i > 0) {
+ out.print(", ");
+ }
+ out.print("<a href=\"/" + recomm.get(i) + "/\">@" + recomm.get(i) + "</a>");
+ }
+ out.println("</div>");
+ }
+ out.println(" </div>");
+ out.println(" </li>");
+
+ out.println(" <li id=\"mtoolbar\"><ul>");
+ out.println(" <li><a href=\"/" + msg.getMid() + "\"><div style=\"background-position: -64px 0\"></div>" + msg.getMid() + "</a></li>");
+ if (visitor.getUid() > 0) {
+ if (visitor.getUid() != msg.getUser().getUid()) {
+ if (messagesService.isSubscribed(visitor.getUid(), msg.getMid())) {
+ out.println(" <li><a href=\"/post?body=U+%23" + msg.getMid() + "\"><div style=\"background-position: -48px 0\"></div>Подписан</a></li>");
+ } else {
+ out.println(" <li><a href=\"/post?body=S+%23" + msg.getMid() + "\"><div style=\"background-position: -16px 0\"></div>Подписаться</a></li>");
+ }
+ if (!visitorInBL) {
+ out.println(" <li><a href=\"/post?body=%21+%23" + msg.getMid() + "\"><div style=\"background-position: -32px 0\"></div>Рекомендовать</a></li>");
+ }
+ } else {
+ out.println(" <li><a href=\"/post?body=D+%23" + msg.getMid() + "\"><div style=\"background-position: 0\"></div>Удалить</a></li>");
+ }
+ }
+ out.println(" </ul></li>");
+ out.println("</ul>");
+
+ return msg;
+ }
+
+ public void printReplies(PrintWriter out, com.juick.Message msg, com.juick.User visitor, boolean listview) {
+ List<com.juick.Message> replies = messagesService.getReplies(msg.getMid());
+
+ List<Integer> blUIDs = new ArrayList<Integer>();
+ for (int i = 0; i < replies.size(); i++) {
+ com.juick.Message reply = replies.get(i);
+ if (reply.getUser().getUid() != msg.getUser().getUid() && !blUIDs.contains(reply.getUser().getUid())) {
+ blUIDs.add(reply.getUser().getUid());
+ }
+ if (reply.getReplyto() > 0) {
+ boolean added = false;
+ for (int n = 0; n < replies.size(); n++) {
+ if (replies.get(n).getRid() == reply.getReplyto()) {
+ replies.get(n).childs.add(reply);
+ added = true;
+ break;
+ }
+ }
+ if (!added) {
+ reply.setReplyto(0);
+ }
+ }
+ }
+
+ if (!replies.isEmpty()) {
+ if (visitor.getUid() > 0 && msg.getUser().getUid() == visitor.getUid()) {
+ for (Message reply : replies) {
+ reply.VisitorCanComment = true;
+ }
+ } else if (visitor.getUid() > 0 && msg.VisitorCanComment) {
+ blUIDs = userService.checkBL(visitor.getUid(), blUIDs);
+ for (Message reply : replies) {
+ reply.VisitorCanComment = reply.getUser().getUid() == visitor.getUid() || !blUIDs.contains(reply.getUser().getUid());
+ }
+ } else {
+ for (Message reply : replies) {
+ reply.VisitorCanComment = false;
+ }
+ }
+
+ boolean foldable = false;
+ if (replies.size() > 10) {
+ for (int i = 0; i < replies.size() - 1; i++) {
+ if (replies.get(i).getChildsCount() > 1) {
+ foldable = true;
+ break;
+ }
+ }
+ }
+
+ out.println("<div class=\"title2\">");
+ out.print(" <div class=\"title2-right\">");
+ if (listview) {
+ out.print("<a href=\"?view=tree\" rel=\"nofollow\">Показать деревом</a>");
+ } else {
+ if (foldable) {
+ out.print("<span id=\"unfoldall\"><a href=\"#\">Раскрыть все</a> &#183; </span>");
+ }
+ out.print("<a href=\"?view=list\" rel=\"nofollow\">Показать списком</a>");
+ }
+ out.print("</div>");
+ out.println(" <h2>Ответы (" + replies.size() + ")</h2>");
+ out.println("</div>");
+
+ out.println("<ul id=\"replies\">");
+ if (listview) {
+ printList(out, replies, visitor);
+ } else {
+ printTree(out, replies, visitor, 0, 0, false);
+ }
+ out.println("</ul>");
+
+ for (Message reply : replies) {
+ reply.cleanupChilds();
+ }
+ replies.clear();
+ }
+ }
+
+ public void printTree(PrintWriter out, List<com.juick.Message> replies, com.juick.User visitor, int ReplyTo, int margin, boolean hidden) {
+ if (margin > 240) {
+ margin = 240;
+ }
+
+ for (int i = 0; i < replies.size(); i++) {
+ com.juick.Message msg = replies.get(i);
+ if (msg.getReplyto() == ReplyTo) {
+
+ out.print(" <li id=\"" + msg.getRid() + "\" class=\"msg\" style=\"");
+ if (margin > 0) {
+ out.print("margin-left: " + margin + "px;");
+ }
+ if (hidden) {
+ out.print("display:none;");
+ }
+ out.println("\">");
+ out.println(" <div class=\"msg-cont\">");
+ out.println(" <div class=\"msg-header\">");
+ if (!msg.getUser().isBanned()) {
+ out.println(" @<a href=\"/" + msg.getUser().getName() + "/\">" + msg.getUser().getName() + "</a>:");
+ out.println(" <div class=\"msg-avatar\"><a href=\"/" + msg.getUser().getName() + "/\"><img src=\"//i.juick.com/a/" + msg.getUser().getUid() + ".png\" alt=\"" + msg.getUser().getName() + "\"/></a></div>");
+ } else {
+ out.println(" [удалено]:");
+ out.println(" <div class=\"msg-avatar\"><img src=\"//i.juick.com/av-96.png\"/></div>");
+ }
+ out.println(" <div class=\"msg-menu\"><a href=\"#\" class=\"a-thread-links\"></a></div>");
+ out.println(" <div class=\"msg-ts\"><a href=\"/" + msg.getMid() + "#" + msg.getRid() + "\" title=\"" + templates.sdfSQL.format(msg.getDate()) + " GMT\">" + templates.formatDate(msg.TimeAgo, msg.getDate()) + "</a></div>");
+ out.println(" </div>");
+ out.println(" <div class=\"msg-txt\">" + MessageUtils.formatMessage(msg.getText()) + "</div>");
+ if (msg.getAttachmentType() != null) {
+ out.println(" <div class=\"msg-media\"><a href=\"//i.juick.com/p/" + msg.getMid() + "-" + msg.getRid() + "." + msg.getAttachmentType() + "\"><img src=\"//i.juick.com/photos-512/" + msg.getMid() + "-" + msg.getRid() + "." + msg.getAttachmentType() + "\" alt=\"\"/></a></div>");
+ }
+ out.print(" <div class=\"msg-links\">/" + msg.getRid());
+ if (msg.getReplyto() > 0) {
+ out.print(" в ответ на <a href=\"#" + msg.getReplyto() + "\">/" + msg.getReplyto() + "</a>");
+ }
+ if (msg.VisitorCanComment) {
+ out.println(" &#183; <a href=\"/post?body=%23" + msg.getMid() + "/" + msg.getRid() + "%20\" class=\"a-thread-comment\">Ответить</a></div>");
+ out.println(" <div class=\"msg-comment\" style=\"display: none\"></div>");
+ } else if (visitor == null) {
+ out.println(" &#183; <a href=\"#\" class=\"a-login\">Ответить</a></div>");
+ }
+
+ int childs = msg.getChildsCount();
+ if (ReplyTo == 0 && childs > 1 && replies.size() > 10) {
+ out.println(" <div class=\"msg-comments\"><a href=\"#\">" + templates.formatReplies(childs) + "</a></div>");
+ }
+ out.println(" </div>");
+ out.println(" </li>");
+
+ if (ReplyTo == 0 && childs > 1 && replies.size() > 10) {
+ printTree(out, msg.childs, visitor, msg.getRid(), margin + 20, true);
+ } else if (childs > 0) {
+ printTree(out, msg.childs, visitor, msg.getRid(), margin + 20, hidden);
+ }
+ }
+ }
+ }
+
+ public void printList(PrintWriter out, List<com.juick.Message> replies, com.juick.User visitor) {
+ for (Message msg : replies) {
+ out.print(" <li id=\"" + msg.getRid() + "\" class=\"msg\">");
+ out.println(" <div class=\"msg-cont\">");
+ out.println(" <div class=\"msg-header\">");
+ if (!msg.getUser().isBanned()) {
+ out.println(" @<a href=\"/" + msg.getUser().getName() + "/\">" + msg.getUser().getName() + "</a>:");
+ out.println(" <div class=\"msg-avatar\"><a href=\"/" + msg.getUser().getName() + "/\"><img src=\"//i.juick.com/a/" + msg.getUser().getUid() + ".png\" alt=\"" + msg.getUser().getName() + "\"/></a></div>");
+ } else {
+ out.println(" [удалено]:");
+ out.println(" <div class=\"msg-avatar\"><img src=\"//i.juick.com/av-96.png\"/></div>");
+ }
+ out.println(" <div class=\"msg-menu\"><a href=\"#\" class=\"a-thread-links\"></a></div>");
+ out.println(" <div class=\"msg-ts\"><a href=\"/" + msg.getMid() + "#" + msg.getRid() + "\" title=\"" + PageTemplates.sdfSQL.format(msg.getDate()) + " GMT\">" + templates.formatDate(msg.TimeAgo, msg.getDate()) + "</a></div>");
+ out.println(" </div>");
+ out.println(" <div class=\"msg-txt\">" + MessageUtils.formatMessage(msg.getText()) + "</div>");
+ if (msg.getAttachmentType() != null) {
+ out.println(" <div class=\"msg-media\"><a href=\"//i.juick.com/p/" + msg.getMid() + "-" + msg.getRid() + "." + msg.getAttachmentType() + "\"><img src=\"//i.juick.com/photos-512/" + msg.getMid() + "-" + msg.getRid() + "." + msg.getAttachmentType() + "\" alt=\"\"/></a></div>");
+ }
+ out.print(" <div class=\"msg-links\">/" + msg.getRid());
+ if (msg.getReplyto() > 0) {
+ out.print(" в ответ на <a href=\"#" + msg.getReplyto() + "\">/" + msg.getReplyto() + "</a>");
+ }
+ if (msg.VisitorCanComment) {
+ out.println(" &#183; <a href=\"#\" class=\"a-thread-comment\">Ответить</a></div>");
+ out.println(" <div class=\"msg-comment\" style=\"display: none\"></div>");
+ } else if (visitor.getUid() == 0) {
+ out.println(" <div class=\"msg-links\"><a href=\"/post?body=%23" + msg.getMid() + "/" + msg.getRid() + "%20\" class=\"a-thread-comment\">Ответить</a></div>");
+ }
+ out.println(" </div>");
+ out.println(" </li>");
+ }
+ }
+}
diff --git a/juick-www/src/main/java/com/juick/www/controllers/VKontakteLogin.java b/juick-www/src/main/java/com/juick/www/controllers/VKontakteLogin.java
new file mode 100644
index 00000000..d860a7bc
--- /dev/null
+++ b/juick-www/src/main/java/com/juick/www/controllers/VKontakteLogin.java
@@ -0,0 +1,130 @@
+/*
+ * Juick
+ * Copyright (C) 2008-2013, Ugnich Anton
+ *
+ * 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.www.controllers;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.juick.service.CrosspostService;
+import com.juick.service.UserService;
+import com.juick.www.Utils;
+import com.juick.www.vk.Token;
+import com.juick.www.vk.UsersResponse;
+import org.apache.commons.lang3.CharEncoding;
+import org.apache.commons.lang3.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+
+import javax.inject.Inject;
+import javax.servlet.http.Cookie;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.net.URLEncoder;
+import java.util.UUID;
+
+/**
+ * @author Ugnich Anton
+ */
+@Controller
+public class VKontakteLogin {
+ private static final Logger logger = LoggerFactory.getLogger(VKontakteLogin.class);
+ private static final String VK_APPID = "3544101";
+ private static final String VK_SECRET = "z2afNI8jA5lIpZ2jsTm1";
+ private static final String VK_REDIRECT = "http://juick.com/_vklogin";
+
+ @Inject
+ CrosspostService crosspostService;
+ @Inject
+ UserService userService;
+
+ public VKontakteLogin() {
+ mapper = new ObjectMapper();
+ mapper.setSerializationInclusion(JsonInclude.Include.NON_EMPTY);
+ mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
+ mapper.setSerializationInclusion(JsonInclude.Include.NON_DEFAULT);
+ }
+
+ private final ObjectMapper mapper;
+
+ @RequestMapping(value = "/_vklogin", method = RequestMethod.GET)
+ protected void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {
+ String code = request.getParameter("code");
+ if (StringUtils.isBlank(code)) {
+ response.setStatus(HttpServletResponse.SC_MOVED_TEMPORARILY);
+ response.setHeader("Location", "https://oauth.vk.com/authorize?client_id=" + VK_APPID + "&redirect_uri=" + URLEncoder.encode(VK_REDIRECT, CharEncoding.UTF_8) + "&scope=friends,wall,offline&response_type=code");
+ return;
+ }
+
+
+ String tokenjson = Utils.fetchURL("https://oauth.vk.com/access_token?client_id=" + VK_APPID + "&redirect_uri=" + URLEncoder.encode(VK_REDIRECT, CharEncoding.UTF_8) + "&client_secret=" + VK_SECRET + "&code=" + URLEncoder.encode(code, CharEncoding.UTF_8));
+ if (tokenjson == null || tokenjson.isEmpty()) {
+ logger.error("VK TOKEN EMPTY");
+ response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
+ return;
+ }
+ String token = null;
+ long vkID = 0;
+ Token json = mapper.readValue(tokenjson, Token.class);
+ token = json.getAccessToken();
+ vkID = json.getUserId();
+ if (token == null || vkID == 0) {
+ logger.error("VK TOKEN EMPTY: {}", tokenjson);
+ response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
+ return;
+ }
+
+ String graph = Utils.fetchURL("https://api.vk.com/method/users.get?uids=" + vkID + "&fields=screen_name&access_token=" + token);
+ if (graph == null || graph.isEmpty()) {
+ logger.error("VK GRAPH ERROR");
+ response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
+ return;
+ }
+
+ try {
+ com.juick.www.vk.User jsonUser = mapper.readValue(graph, UsersResponse.class).getUsers().get(0);
+ String vkName = jsonUser.getFirstName() + " " + jsonUser.getLastName();
+ String vkLink = jsonUser.getScreenName();
+
+ if (vkName == null || vkLink == null || vkName.isEmpty() || vkName.length() == 1 || vkLink.isEmpty()) {
+ throw new Exception();
+ }
+
+ int uid = crosspostService.getUIDbyVKID(vkID);
+ if (uid > 0) {
+ Cookie c = new Cookie("hash", userService.getHashByUID(uid));
+ c.setMaxAge(50 * 24 * 60 * 60);
+ response.addCookie(c);
+ response.setStatus(HttpServletResponse.SC_MOVED_TEMPORARILY);
+ response.setHeader("Location", "/");
+ } else {
+ String loginhash = UUID.randomUUID().toString();
+ if (!crosspostService.createVKUser(vkID, loginhash, token, vkName, vkLink)) {
+ throw new Exception();
+ }
+ response.setStatus(HttpServletResponse.SC_MOVED_TEMPORARILY);
+ response.setHeader("Location", "/signup?type=vk&hash=" + loginhash);
+ }
+ } catch (Exception e) {
+ logger.error("JSON ERROR", e);
+ response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
+ }
+ }
+}
diff --git a/juick-www/src/main/java/com/juick/www/controllers/XMPPPost.java b/juick-www/src/main/java/com/juick/www/controllers/XMPPPost.java
new file mode 100644
index 00000000..f64907b2
--- /dev/null
+++ b/juick-www/src/main/java/com/juick/www/controllers/XMPPPost.java
@@ -0,0 +1,84 @@
+package com.juick.www.controllers;
+
+import com.juick.server.util.HttpBadRequestException;
+import com.juick.server.util.HttpUtils;
+import com.juick.service.TagService;
+import com.juick.www.WebApp;
+import org.apache.commons.lang3.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.stereotype.Controller;
+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.oob.model.x.OobX;
+
+import javax.inject.Inject;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.net.URL;
+
+/**
+ * Created by vitalyster on 08.12.2016.
+ */
+@Controller
+public class XMPPPost {
+ private final static Logger logger = LoggerFactory.getLogger(XMPPPost.class);
+
+ @Inject
+ WebApp webApp;
+ @Inject
+ TagService tagService;
+
+ @RequestMapping(value = "/post2", method = RequestMethod.POST)
+ public void doPostMessage(HttpServletRequest request, HttpServletResponse response,
+ @RequestParam(required = false) String img,
+ @RequestParam(required = false) MultipartFile attach) throws IOException {
+
+ com.juick.User visitor = webApp.getVisitorUser(request, response);
+ if (visitor.getUid() == 0 || visitor.isBanned()) {
+ response.sendError(HttpServletResponse.SC_FORBIDDEN);
+ return;
+ }
+ String body = request.getParameter("body").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);
+ } 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);
+ }
+ String referer = request.getHeader("referer");
+ if (StringUtils.isBlank(referer) || referer.substring(0, 21).equals("http://juick.com/post")
+ || referer.substring(0, 22).equals("https://juick.com/post")) {
+ response.sendRedirect("/?show=my");
+ return;
+ }
+ response.sendRedirect(referer);
+ }
+}