aboutsummaryrefslogtreecommitdiff
path: root/src/java
diff options
context:
space:
mode:
authorGravatar Ugnich Anton2011-12-25 15:56:30 +0700
committerGravatar Ugnich Anton2011-12-25 15:56:30 +0700
commit6f4e181f0a03b4b190922bd5f8bd97fb9fdb206e (patch)
treec8b5241c84cb24a6c0c8a8b2eaa109f569dfc76c /src/java
Initial commit
Diffstat (limited to 'src/java')
-rw-r--r--src/java/Blogs.properties14
-rw-r--r--src/java/Blogs_ru.properties14
-rw-r--r--src/java/Chats.properties5
-rw-r--r--src/java/Chats_ru.properties5
-rw-r--r--src/java/Global.properties17
-rw-r--r--src/java/Global_ru.properties17
-rw-r--r--src/java/Login.properties6
-rw-r--r--src/java/Login_ru.properties6
-rw-r--r--src/java/Map.properties5
-rw-r--r--src/java/Map_ru.properties5
-rw-r--r--src/java/Photos.properties4
-rw-r--r--src/java/Photos_ru.properties4
-rw-r--r--src/java/User.properties16
-rw-r--r--src/java/User_ru.properties16
-rw-r--r--src/java/com/juick/http/www/Blogs.java217
-rw-r--r--src/java/com/juick/http/www/Chats.java77
-rw-r--r--src/java/com/juick/http/www/Login.java129
-rw-r--r--src/java/com/juick/http/www/Main.java173
-rw-r--r--src/java/com/juick/http/www/Map.java64
-rw-r--r--src/java/com/juick/http/www/NewMessage.java37
-rw-r--r--src/java/com/juick/http/www/PageTemplates.java377
-rw-r--r--src/java/com/juick/http/www/Photos.java100
-rw-r--r--src/java/com/juick/http/www/RootRedirects.java53
-rw-r--r--src/java/com/juick/http/www/User.java198
-rw-r--r--src/java/com/juick/http/www/UserThread.java298
-rw-r--r--src/java/com/juick/http/www/Utils.java112
26 files changed, 1969 insertions, 0 deletions
diff --git a/src/java/Blogs.properties b/src/java/Blogs.properties
new file mode 100644
index 00000000..3b596f77
--- /dev/null
+++ b/src/java/Blogs.properties
@@ -0,0 +1,14 @@
+# To change this template, choose Tools | Templates
+# and open the template in the editor.
+
+Last\ messages=Last messages
+Lists=Lists
+Tags=Tags
+Search=Search
+My\ feed=My feed
+Private=Private
+Incoming=Incoming
+Recommended=Recommended
+All\ messages=All messages
+Popular=Popular
+With\ photos=With photos
diff --git a/src/java/Blogs_ru.properties b/src/java/Blogs_ru.properties
new file mode 100644
index 00000000..f5fe415f
--- /dev/null
+++ b/src/java/Blogs_ru.properties
@@ -0,0 +1,14 @@
+# To change this template, choose Tools | Templates
+# and open the template in the editor.
+
+Last\ messages=\u041f\u043e\u0441\u043b\u0435\u0434\u043d\u0438\u0435 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f
+Lists=\u0421\u043f\u0438\u0441\u043a\u0438
+Tags=\u0422\u0435\u0433\u0438
+Search=\u041f\u043e\u0438\u0441\u043a
+My\ feed=\u041c\u043e\u044f \u043b\u0435\u043d\u0442\u0430
+Private=\u041f\u0440\u0438\u0432\u0430\u0442\u043d\u044b\u0435
+Incoming=\u0412\u0445\u043e\u0434\u044f\u0449\u0438\u0435
+Recommended=\u0420\u0435\u043a\u043e\u043c\u0435\u043d\u0434\u043e\u0432\u0430\u043d\u043d\u043e\u0435
+All\ messages=\u0412\u0441\u0435 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f
+Popular=\u041f\u043e\u043f\u0443\u043b\u044f\u0440\u043d\u044b\u0435
+With\ photos=\u0421 \u0444\u043e\u0442\u043e\u0433\u0440\u0430\u0444\u0438\u044f\u043c\u0438
diff --git a/src/java/Chats.properties b/src/java/Chats.properties
new file mode 100644
index 00000000..e5596bac
--- /dev/null
+++ b/src/java/Chats.properties
@@ -0,0 +1,5 @@
+# To change this template, choose Tools | Templates
+# and open the template in the editor.
+
+Active\ chats=Active chats
+Users\ online=Users online
diff --git a/src/java/Chats_ru.properties b/src/java/Chats_ru.properties
new file mode 100644
index 00000000..6f144f69
--- /dev/null
+++ b/src/java/Chats_ru.properties
@@ -0,0 +1,5 @@
+# To change this template, choose Tools | Templates
+# and open the template in the editor.
+
+Active\ chats=\u0410\u043a\u0442\u0438\u0432\u043d\u044b\u0435 \u0447\u0430\u0442\u044b
+Users\ online=\u041f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439 \u043e\u043d\u043b\u0430\u0439\u043d
diff --git a/src/java/Global.properties b/src/java/Global.properties
new file mode 100644
index 00000000..0883bec5
--- /dev/null
+++ b/src/java/Global.properties
@@ -0,0 +1,17 @@
+# To change this template, choose Tools | Templates
+# and open the template in the editor.
+
+Blogs=Blogs
+Chats=Chats
+Photos=Photos
+Map=Map
+Post=Post
+Blog=Blog
+Settings=Settings
+Logout=Logout
+Login=Login
+Contacts=Contacts
+Help=Help
+Older=Older
+Newer=Newer
+(replies)\ by=by
diff --git a/src/java/Global_ru.properties b/src/java/Global_ru.properties
new file mode 100644
index 00000000..81ba9c4f
--- /dev/null
+++ b/src/java/Global_ru.properties
@@ -0,0 +1,17 @@
+# To change this template, choose Tools | Templates
+# and open the template in the editor.
+
+Blogs=\u0411\u043b\u043e\u0433\u0438
+Chats=\u0427\u0430\u0442\u044b
+Photos=\u0424\u043e\u0442\u043e
+Map=\u041a\u0430\u0440\u0442\u0430
+Post=\u041d\u0430\u043f\u0438\u0441\u0430\u0442\u044c
+Blog=\u0411\u043b\u043e\u0433
+Settings=\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438
+Logout=\u0412\u044b\u0439\u0442\u0438
+Login=\u0412\u043e\u0439\u0442\u0438
+Contacts=\u041a\u043e\u043d\u0442\u0430\u043a\u0442\u044b
+Help=\u0421\u043f\u0440\u0430\u0432\u043a\u0430
+Older=\u0421\u0442\u0430\u0440\u044b\u0435
+Newer=\u041d\u043e\u0432\u044b\u0435
+(replies)\ by=\u043e\u0442
diff --git a/src/java/Login.properties b/src/java/Login.properties
new file mode 100644
index 00000000..820b58f3
--- /dev/null
+++ b/src/java/Login.properties
@@ -0,0 +1,6 @@
+# To change this template, choose Tools | Templates
+# and open the template in the editor.
+
+Login=Login
+Username=Username
+Password=Password
diff --git a/src/java/Login_ru.properties b/src/java/Login_ru.properties
new file mode 100644
index 00000000..402e58eb
--- /dev/null
+++ b/src/java/Login_ru.properties
@@ -0,0 +1,6 @@
+# To change this template, choose Tools | Templates
+# and open the template in the editor.
+
+Login=\u0412\u0445\u043e\u0434
+Username=\u0418\u043c\u044f \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f
+Password=\u041f\u0430\u0440\u043e\u043b\u044c
diff --git a/src/java/Map.properties b/src/java/Map.properties
new file mode 100644
index 00000000..004e4d13
--- /dev/null
+++ b/src/java/Map.properties
@@ -0,0 +1,5 @@
+# To change this template, choose Tools | Templates
+# and open the template in the editor.
+
+Messages\ on\ map=Messages on map
+Popular\ places=Popular places
diff --git a/src/java/Map_ru.properties b/src/java/Map_ru.properties
new file mode 100644
index 00000000..633a1bcc
--- /dev/null
+++ b/src/java/Map_ru.properties
@@ -0,0 +1,5 @@
+# To change this template, choose Tools | Templates
+# and open the template in the editor.
+
+Messages\ on\ map=\u0421\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f \u043d\u0430 \u043a\u0430\u0440\u0442\u0435
+Popular\ places=\u041f\u043e\u043f\u0443\u043b\u044f\u0440\u043d\u044b\u0435 \u043c\u0435\u0441\u0442\u0430
diff --git a/src/java/Photos.properties b/src/java/Photos.properties
new file mode 100644
index 00000000..84624aad
--- /dev/null
+++ b/src/java/Photos.properties
@@ -0,0 +1,4 @@
+# To change this template, choose Tools | Templates
+# and open the template in the editor.
+
+Last\ photos\ and\ videos=Last photos and videos
diff --git a/src/java/Photos_ru.properties b/src/java/Photos_ru.properties
new file mode 100644
index 00000000..1933c3cf
--- /dev/null
+++ b/src/java/Photos_ru.properties
@@ -0,0 +1,4 @@
+# To change this template, choose Tools | Templates
+# and open the template in the editor.
+
+Last\ photos\ and\ videos=\u041f\u043e\u0441\u043b\u0435\u0434\u043d\u0438\u0435 \u0444\u043e\u0442\u043e \u0438 \u0432\u0438\u0434\u0435\u043e
diff --git a/src/java/User.properties b/src/java/User.properties
new file mode 100644
index 00000000..aa2e0bcb
--- /dev/null
+++ b/src/java/User.properties
@@ -0,0 +1,16 @@
+# To change this template, choose Tools | Templates
+# and open the template in the editor.
+
+(Stats)\ I\ read=I read
+(Stats)\ My\ readers=My readers
+(Stats)\ Messages=Messages
+(Stats)\ Replies=Replies
+(Menu)\ Messages=Messages
+(Menu)\ Blog=Blog
+(Menu)\ Recommendations=Recommendations
+(Menu)\ Photos=Photos and videos
+(Menu)\ Tags=Tags
+(Menu)\ Search=Search
+Expand\ all=Expand all
+View\ as\ list=View as list
+View\ as\ tree=View as tree
diff --git a/src/java/User_ru.properties b/src/java/User_ru.properties
new file mode 100644
index 00000000..a5c6f3ef
--- /dev/null
+++ b/src/java/User_ru.properties
@@ -0,0 +1,16 @@
+# To change this template, choose Tools | Templates
+# and open the template in the editor.
+
+(Stats)\ I\ read=\u042f \u0447\u0438\u0442\u0430\u044e
+(Stats)\ My\ readers=\u041c\u0435\u043d\u044f \u0447\u0438\u0442\u0430\u044e\u0442
+(Stats)\ Messages=\u0421\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0439
+(Stats)\ Replies=\u041e\u0442\u0432\u0435\u0442\u043e\u0432
+(Menu)\ Messages=\u0421\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f
+(Menu)\ Blog=\u0411\u043b\u043e\u0433
+(Menu)\ Recommendations=\u0420\u0435\u043a\u043e\u043c\u0435\u043d\u0434\u0430\u0446\u0438\u0438
+(Menu)\ Photos=\u0424\u043e\u0442\u043e \u0438 \u0432\u0438\u0434\u0435\u043e
+(Menu)\ Tags=\u0422\u0435\u0433\u0438
+(Menu)\ Search=\u041f\u043e\u0438\u0441\u043a
+Expand\ all=\u0420\u0430\u0441\u043a\u0440\u044b\u0442\u044c \u0432\u0441\u0435
+View\ as\ list=\u041f\u043e\u043a\u0430\u0437\u0430\u0442\u044c \u0441\u043f\u0438\u0441\u043a\u043e\u043c
+View\ as\ tree=\u041f\u043e\u043a\u0430\u0437\u0430\u0442\u044c \u0434\u0435\u0440\u0435\u0432\u043e\u043c
diff --git a/src/java/com/juick/http/www/Blogs.java b/src/java/com/juick/http/www/Blogs.java
new file mode 100644
index 00000000..3b9b6882
--- /dev/null
+++ b/src/java/com/juick/http/www/Blogs.java
@@ -0,0 +1,217 @@
+/*
+ * 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.http.www;
+
+import com.juick.server.MessagesQueries;
+import com.juick.server.TagQueries;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.io.UnsupportedEncodingException;
+import java.net.URLEncoder;
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Locale;
+import java.util.ResourceBundle;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+/**
+ *
+ * @author Ugnich Anton
+ */
+public class Blogs {
+
+ protected void doGet(Connection sql, Connection sqlSearch, HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
+ com.juick.User visitor = Utils.getVisitorUser(sql, request);
+ Locale locale = request.getLocale();
+ ResourceBundle rb = ResourceBundle.getBundle("Blogs", locale);
+
+ String title;
+ ArrayList<Integer> mids;
+
+ String paramShow = request.getParameter("show");
+
+ int paramTag = 0;
+ String paramTagStr = request.getParameter("tag");
+ if (paramTagStr != null && paramTagStr.length() < 64) {
+ paramTag = TagQueries.getTagID(sql, paramTagStr, false);
+ }
+
+ 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;
+ }
+
+ if (paramShow == null) {
+ if (paramTag > 0) {
+ title = "*" + Utils.encodeHTML(paramTagStr);
+ mids = MessagesQueries.getTag(sql, paramTag, paramBefore);
+ } else if (paramSearch != null) {
+ title = rb.getString("Search") + ": " + Utils.encodeHTML(paramSearch);
+ mids = MessagesQueries.getSearch(sql, sqlSearch, Utils.encodeSphinx(paramSearch), paramBefore);
+ } else {
+ title = rb.getString("Last messages");
+ mids = MessagesQueries.getAll(sql, paramBefore);
+ }
+ } else if (paramShow.equals("my")) {
+ title = rb.getString("My feed");
+ mids = MessagesQueries.getMyFeed(sql, visitor.UID, paramBefore);
+ } else if (paramShow.equals("private")) {
+ title = rb.getString("Private");
+ mids = MessagesQueries.getPrivate(sql, visitor.UID, paramBefore);
+ } else if (paramShow.equals("incoming")) {
+ title = rb.getString("Incoming");
+ mids = MessagesQueries.getIncoming(sql, visitor.UID, paramBefore);
+ } else if (paramShow.equals("recommended")) {
+ title = rb.getString("Recommended");
+ mids = MessagesQueries.getRecommended(sql, visitor.UID, paramBefore);
+ } else if (paramShow.equals("top")) {
+ title = rb.getString("Popular");
+ mids = MessagesQueries.getPopular(sql, paramBefore);
+ } else if (paramShow.equals("photos")) {
+ title = rb.getString("With photos");
+ mids = MessagesQueries.getPhotos(sql, paramBefore);
+ } else {
+ response.sendError(404);
+ return;
+ }
+
+ response.setContentType("text/html; charset=UTF-8");
+ PrintWriter out = response.getWriter();
+ try {
+ PageTemplates.pageHead(out, title, null);
+ PageTemplates.pageNavigation(out, locale, visitor);
+ PageTemplates.pageTitle(out, title);
+
+ out.println("<div id=\"wrapper\">");
+ out.println("<div id=\"content\">");
+ out.println("<ul>");
+
+ if (mids.size() > 0) {
+ PageTemplates.printMessages(out, sql, mids, locale);
+ }
+
+ out.println("</ul>");
+ out.println("<script type=\"text/javascript\">");
+ out.println("$(\"textarea\").autoResize();");
+ out.println("</script>");
+
+ if (mids.size() == 20) {
+ String nextpage = "?before=" + mids.get(mids.size() - 1);
+ if (paramShow != null) {
+ nextpage += "&show=" + paramShow;
+ }
+ if (paramTag > 0) {
+ nextpage += "&tag=" + URLEncoder.encode(paramTagStr, "UTF-8");
+ }
+ out.println("<p class=\"page\"><a href=\"" + nextpage + "\">Older →</a></p>");
+ }
+
+ out.println("</div>");
+
+ out.println("<div id=\"column\">");
+ out.println("<h2>" + rb.getString("Lists") + "</h2>");
+ if (visitor != null) {
+ out.println("<ul>");
+ out.println(" <li><a href=\"?show=my\">" + rb.getString("My feed") + "</a></li>");
+ out.println(" <li><a href=\"?show=private\">" + rb.getString("Private") + "</a></li>");
+ out.println(" <li><a href=\"?show=incoming\">" + rb.getString("Incoming") + "</a></li>");
+ out.println(" <li><a href=\"?show=recommended\">" + rb.getString("Recommended") + "</a></li>");
+ out.println("</ul>");
+ }
+ out.println("<ul>");
+ out.println(" <li><a href=\"?\">" + rb.getString("All messages") + "</a></li>");
+ out.println(" <li><a href=\"?show=top\">" + rb.getString("Popular") + "</a></li>");
+ out.println(" <li><a href=\"?show=photos\">" + rb.getString("With photos") + "</a></li>");
+ out.println("</ul>");
+ out.println("<h2>" + rb.getString("Tags") + "</h2>");
+ out.println("<p style=\"text-align: justify\">" + getTags(sql, 30) + "</p>");
+ out.println("<h2>" + rb.getString("Search") + "</h2>");
+ out.println("<form action=\"/\" id=\"search\"><p><input type=\"text\" name=\"search\" class=\"inp\"/></p></form>");
+ out.println("</div>");
+ out.println("</div>");
+
+ PageTemplates.pageFooter(out, locale);
+ } finally {
+ out.close();
+ }
+ }
+
+ private String getTags(Connection sql, int cnt) {
+ String ret = "";
+ com.juick.Tag tags[] = new com.juick.Tag[cnt];
+
+ int maxUsageCnt = 0;
+ PreparedStatement stmt = null;
+ ResultSet rs = null;
+ try {
+ stmt = sql.prepareStatement("SELECT tags.name AS name,COUNT(DISTINCT messages.user_id) AS cnt FROM (messages INNER JOIN messages_tags ON (messages.ts>TIMESTAMPADD(DAY,-3,NOW()) AND messages.message_id=messages_tags.message_id)) INNER JOIN tags ON messages_tags.tag_id=tags.tag_id GROUP BY tags.tag_id ORDER BY cnt DESC LIMIT ?");
+ stmt.setInt(1, cnt);
+ rs = stmt.executeQuery();
+ rs.beforeFirst();
+ cnt = 0;
+ while (rs.next()) {
+ tags[cnt] = new com.juick.Tag();
+ tags[cnt].Name = rs.getString(1);
+ tags[cnt].UsageCnt = rs.getInt(2);
+ if (tags[cnt].UsageCnt > maxUsageCnt) {
+ maxUsageCnt = tags[cnt].UsageCnt;
+ }
+ cnt++;
+ }
+ } catch (SQLException e) {
+ System.err.println(e);
+ } finally {
+ Utils.finishSQL(rs, stmt);
+ }
+
+ Arrays.sort(tags, 0, cnt);
+
+ for (int i = 0; i < cnt; i++) {
+ String tag = Utils.encodeHTML(tags[i].Name);
+ try {
+ tag = "<a href=\"/?tag=" + URLEncoder.encode(tags[i].Name, "UTF-8") + "\">" + tag + "</a>";
+ } catch (UnsupportedEncodingException e) {
+ }
+
+ if (tags[i].UsageCnt > maxUsageCnt / 3 * 2) {
+ ret += "<big>" + tag + "</big> ";
+ } else if (tags[i].UsageCnt > maxUsageCnt / 3) {
+ ret += "<small>" + tag + "</small> ";
+ } else {
+ ret += tag + " ";
+ }
+ }
+
+ return ret;
+ }
+}
diff --git a/src/java/com/juick/http/www/Chats.java b/src/java/com/juick/http/www/Chats.java
new file mode 100644
index 00000000..3df37976
--- /dev/null
+++ b/src/java/com/juick/http/www/Chats.java
@@ -0,0 +1,77 @@
+/*
+ * 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.http.www;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.Locale;
+import java.util.ResourceBundle;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+/**
+ *
+ * @author Ugnich Anton
+ */
+public class Chats {
+
+ protected void doGet(Connection sql, HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
+ com.juick.User visitor = Utils.getVisitorUser(sql, request);
+ Locale locale = request.getLocale();
+ ResourceBundle rb = ResourceBundle.getBundle("Chats", locale);
+
+ response.setContentType("text/html; charset=UTF-8");
+ PrintWriter out = response.getWriter();
+ try {
+ PageTemplates.pageHead(out, rb.getString("Active chats"), "");
+ PageTemplates.pageNavigation(out, locale, visitor);
+ PageTemplates.pageTitle(out, rb.getString("Active chats"));
+
+ out.println("<div id=\"wrapper\">");
+ out.println("<div id=\"content\"><ul id=\"chats\">");
+
+ PreparedStatement stmt = null;
+ ResultSet rs = null;
+ try {
+ stmt = sql.prepareStatement("SELECT chats.chat_id,chats.subject,COUNT(chat_users.user_id) AS cnt FROM chats INNER JOIN chat_users USING(chat_id) GROUP BY chat_id ORDER BY cnt DESC");
+ rs = stmt.executeQuery();
+ rs.beforeFirst();
+ while (rs.next()) {
+ String chatid = Integer.toString(rs.getInt(1), Character.MAX_RADIX);
+ out.println("<li><b>" + Utils.encodeHTML(rs.getString(2)) + "</b><br/><i>" + rb.getString("Users online") + ": " + rs.getInt(3) + "</i><br/><a href=\"xmpp:" + chatid + "@chat.juick.com?join\">" + chatid + "@chat.juick.com</a></li>");
+ }
+ } catch (SQLException e) {
+ System.err.println(e);
+ } finally {
+ Utils.finishSQL(rs, stmt);
+ }
+
+ out.println("</ul></div>");
+ out.println("</div>");
+
+ PageTemplates.pageFooter(out, locale);
+ } finally {
+ out.close();
+ }
+ }
+}
diff --git a/src/java/com/juick/http/www/Login.java b/src/java/com/juick/http/www/Login.java
new file mode 100644
index 00000000..d03dd64d
--- /dev/null
+++ b/src/java/com/juick/http/www/Login.java
@@ -0,0 +1,129 @@
+/*
+ * 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.http.www;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.SQLException;
+import java.util.Locale;
+import java.util.ResourceBundle;
+import javax.servlet.ServletException;
+import javax.servlet.http.Cookie;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+/**
+ *
+ * @author Ugnich Anton
+ */
+public class Login {
+
+ protected void doGetLoginForm(Connection sql, HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
+ com.juick.User visitor = Utils.getVisitorUser(sql, request);
+ Locale locale = request.getLocale();
+ ResourceBundle rb = ResourceBundle.getBundle("Login", locale);
+
+ response.setContentType("text/html; charset=UTF-8");
+ PrintWriter out = response.getWriter();
+ try {
+ PageTemplates.pageHead(out, rb.getString("Login"), "");
+ PageTemplates.pageNavigation(out, locale, visitor);
+ PageTemplates.pageTitle(out, rb.getString("Login"));
+
+ out.println("<div id=\"wrapper\">");
+ out.println("<div id=\"content\">");
+ out.println("<form action=\"/login\" method=\"post\">");
+ out.println("<p>" + rb.getString("Username") + ": <input type=\"text\" name=\"username\"/></p>");
+ out.println("<p>" + rb.getString("Password") + ": <input type=\"password\" name=\"password\"/></p>");
+ out.println("<p><input type=\"submit\" value=\" OK \"/></p>");
+ out.println("</form>");
+ out.println("</div>");
+ out.println("</div>");
+
+ PageTemplates.pageFooter(out, locale);
+ } finally {
+ out.close();
+ }
+ }
+
+ protected void doGetLogin(Connection sql, HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
+ String hash = request.getQueryString();
+ if (hash.length() > 32) {
+ response.sendError(400);
+ return;
+ }
+
+ if (com.juick.server.UserQueries.getUIDbyHash(sql, hash) > 0) {
+ Cookie c = new Cookie("hash", hash);
+ c.setDomain(".juick.com");
+ c.setMaxAge(0);
+ response.addCookie(c);
+
+ response.sendRedirect("/");
+ } else {
+ response.sendError(403);
+ }
+ }
+
+ protected void doPostLogin(Connection sql, HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
+ String username = request.getParameter("username");
+ String password = request.getParameter("password");
+ if (username == null || password == null || username.length() > 32) {
+ response.sendError(400);
+ return;
+ }
+
+ int uid = com.juick.server.UserQueries.checkPassword(sql, username, password);
+ if (uid > 0) {
+ String hash = com.juick.server.UserQueries.getHashByUID(sql, uid);
+ Cookie c = new Cookie("hash", hash);
+ c.setDomain(".juick.com");
+ c.setMaxAge(0);
+ response.addCookie(c);
+
+ response.sendRedirect("/");
+ } else {
+ response.sendError(403);
+ }
+ }
+
+ protected void doGetLogout(Connection sql, HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
+ int uid = Utils.getVisitorUID(sql, request);
+ if (uid > 0) {
+ PreparedStatement stmt = null;
+ try {
+ stmt = sql.prepareStatement("DELETE FROM logins WHERE user_id=?");
+ stmt.setInt(1, uid);
+ stmt.executeUpdate();
+ } catch (SQLException e) {
+ System.err.println(e);
+ } finally {
+ Utils.finishSQL(null, stmt);
+ }
+ }
+
+ Cookie c = new Cookie("hash", "-");
+ c.setDomain(".juick.com");
+ c.setMaxAge(0);
+ response.addCookie(c);
+
+ response.sendRedirect("/");
+ }
+}
diff --git a/src/java/com/juick/http/www/Main.java b/src/java/com/juick/http/www/Main.java
new file mode 100644
index 00000000..709c6588
--- /dev/null
+++ b/src/java/com/juick/http/www/Main.java
@@ -0,0 +1,173 @@
+/*
+ * 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.http.www;
+
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.sql.Connection;
+import java.sql.DriverManager;
+import java.sql.SQLException;
+import java.util.Properties;
+import javax.servlet.ServletException;
+import javax.servlet.annotation.WebServlet;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+/**
+ *
+ * @author Ugnich Anton
+ */
+@WebServlet(name = "Main", urlPatterns = {"/"})
+public class Main extends HttpServlet {
+
+ Connection sql;
+ Connection sqlSearch;
+ Blogs blogs = new Blogs();
+ Chats chats = new Chats();
+ Photos photos = new Photos();
+ RootRedirects rootRedirects = new RootRedirects();
+ Map map = new Map();
+ Login login = new Login();
+ User pagesUser = new User();
+ UserThread pagesUserThread = new UserThread();
+ NewMessage pagesNewMessage = new NewMessage();
+
+ @Override
+ public void init() throws ServletException {
+ super.init();
+ try {
+ Properties conf = new Properties();
+ conf.load(new FileInputStream("/etc/juick/www.conf"));
+
+ Class.forName("com.mysql.jdbc.Driver");
+ sql = DriverManager.getConnection("jdbc:mysql://localhost/juick?autoReconnect=true&user=" + conf.getProperty("mysql_username", "") + "&password=" + conf.getProperty("mysql_password", ""));
+ sqlSearch = DriverManager.getConnection("jdbc:mysql://127.0.0.1:9306/juick?autoReconnect=true&characterEncoding=utf8&maxAllowedPacket=512000&relaxAutoCommit=true&user=root&password=");
+ } catch (Exception e) {
+ log(null, e);
+ }
+ }
+
+ @Override
+ public void destroy() {
+ super.destroy();
+ if (sql != null) {
+ try {
+ sql.close();
+ } catch (SQLException e) {
+ log(null, e);
+ }
+ }
+ }
+
+ /**
+ * Handles the HTTP <code>GET</code> method.
+ * @param request servlet request
+ * @param response servlet response
+ * @throws ServletException if a servlet-specific error occurs
+ * @throws IOException if an I/O error occurs
+ */
+ @Override
+ protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
+ if (request.getCharacterEncoding() == null) {
+ request.setCharacterEncoding("UTF-8");
+ }
+ String uri = request.getRequestURI();
+ if (uri.equals("/")) {
+ blogs.doGet(sql, sqlSearch, request, response);
+ } else if (uri.equals("/chats")) {
+ chats.doGet(sql, request, response);
+ } else if (uri.equals("/photos")) {
+ photos.doGet(sql, request, response);
+ } else if (uri.equals("/map")) {
+ map.doGet(sql, request, response);
+ } else if (uri.equals("/post")) {
+ pagesNewMessage.doGetNewMessage(sql, request, response);
+ } else if (uri.equals("/login")) {
+ if (request.getQueryString() == null) {
+ login.doGetLoginForm(sql, request, response);
+ } else {
+ login.doGetLogin(sql, request, response);
+ }
+ } else if (uri.equals("/logout")) {
+ login.doGetLogout(sql, request, response);
+ } else if (uri.equals("/settings")) {
+ //TODO settings
+ } else if (uri.matches("^/\\d+$")) {
+ rootRedirects.doGetPostID(sql, request, response);
+ } else if (uri.matches("^/[^/]$")) {
+ rootRedirects.doGetUsername(sql, request, response);
+ } else if (uri.matches("^/.+/.*")) {
+ String uriparts[] = uri.split("/");
+ com.juick.User user = com.juick.server.UserQueries.getUserByNick(sql, uriparts[1]);
+ if (user != null && user.UName.equals(uriparts[1])) {
+ if (uriparts.length == 2) { // http://juick.com/username/
+ pagesUser.doGetBlog(sql, sqlSearch, request, response, user);
+ } else if (uriparts[2].equals("info")) {
+ pagesUser.doGetInfo(sql, request, response, user);
+ } else {
+ int mid = 0;
+ try {
+ mid = Integer.parseInt(uriparts[2]);
+ } catch (NumberFormatException e) {
+ }
+ if (mid > 0) {
+ com.juick.User author = com.juick.server.MessagesQueries.getMessageAuthor(sql, mid);
+ if (author != null) {
+ if (!author.UName.equals(user.UName)) {
+ Utils.sendPermanentRedirect(response, "/" + author.UName + "/" + mid);
+ } else {
+ pagesUserThread.doGetThread(sql, request, response, user, mid);
+ }
+ } else {
+ response.sendError(404);
+ }
+ } else {
+ response.sendError(404);
+ }
+ }
+ } else if (user != null) {
+ Utils.sendPermanentRedirect(response, "/" + user.UName + "/" + (uriparts.length > 2 ? uriparts[2] : ""));
+ } else {
+ response.sendError(404);
+ }
+ } else {
+ response.sendError(404);
+ }
+ }
+
+ /**
+ * Handles the HTTP <code>POST</code> method.
+ * @param request servlet request
+ * @param response servlet response
+ * @throws ServletException if a servlet-specific error occurs
+ * @throws IOException if an I/O error occurs
+ */
+ @Override
+ protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
+ String uri = request.getRequestURI();
+ if (uri.equals("/post")) {
+ pagesNewMessage.doPostNewMessage(sql, request, response);
+ } else if (uri.equals("/login")) {
+ login.doPostLogin(sql, request, response);
+ } else if (uri.equals("/settings")) {
+ } else {
+ response.sendError(405);
+ }
+ }
+}
diff --git a/src/java/com/juick/http/www/Map.java b/src/java/com/juick/http/www/Map.java
new file mode 100644
index 00000000..1bc625b8
--- /dev/null
+++ b/src/java/com/juick/http/www/Map.java
@@ -0,0 +1,64 @@
+/*
+ * 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.http.www;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.sql.Connection;
+import java.util.Locale;
+import java.util.ResourceBundle;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+/**
+ *
+ * @author Ugnich Anton
+ */
+public class Map {
+
+ protected void doGet(Connection sql, HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
+ com.juick.User visitor = Utils.getVisitorUser(sql, request);
+ Locale locale = request.getLocale();
+ ResourceBundle rb = ResourceBundle.getBundle("Map", locale);
+
+ response.setContentType("text/html; charset=UTF-8");
+ PrintWriter out = response.getWriter();
+ try {
+ PageTemplates.pageHead(out, rb.getString("Messages on map"), "<script src=\"http://maps.google.com/maps?file=api&amp;v=2&amp;sensor=false&amp;key=ABQIAAAAVVtPtxkw4soCEHg44FsNChRB4OFYjAXt73He16Zkp6a_0tPs2RTU6i6UlcMs4QvPBYvIY8rWvcxqOg\" type=\"text/javascript\"></script>"
+ + "<script src=\"http://static.juick.com/mc.js\" type=\"text/javascript\"></script>"
+ + "<script src=\"http://static.juick.com/map.js?2010111500\" type=\"text/javascript\"></script>");
+ PageTemplates.pageNavigation(out, locale, visitor);
+ PageTemplates.pageTitle(out, rb.getString("Messages on map"));
+
+ out.println("<div id=\"wrapper\">");
+ out.println("<div id=\"geomap\" style=\"height: 400px; margin: 1em 0.5em\"></div>");
+ out.println("<div id=\"content\"><ul id=\"messages\"></ul></div>");
+ out.println("<div id=\"column\"><h2>" + rb.getString("Popular places") + "</h2><ul id=\"places\"></ul></div>");
+ out.println("</div>");
+ out.println("<script type=\"text/javascript\">");
+ out.println("$(document).ready(mapInit);");
+ out.println("$(window).unload(GUnload);");
+ out.println("</script>");
+
+ PageTemplates.pageFooter(out, locale);
+ } finally {
+ out.close();
+ }
+ }
+}
diff --git a/src/java/com/juick/http/www/NewMessage.java b/src/java/com/juick/http/www/NewMessage.java
new file mode 100644
index 00000000..8a92b475
--- /dev/null
+++ b/src/java/com/juick/http/www/NewMessage.java
@@ -0,0 +1,37 @@
+/*
+ * 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.http.www;
+
+import java.io.IOException;
+import java.sql.Connection;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+/**
+ *
+ * @author Ugnich Anton
+ */
+public class NewMessage {
+
+ protected void doGetNewMessage(Connection sql, HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
+ }
+
+ protected void doPostNewMessage(Connection sql, HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
+ }
+}
diff --git a/src/java/com/juick/http/www/PageTemplates.java b/src/java/com/juick/http/www/PageTemplates.java
new file mode 100644
index 00000000..94561dfd
--- /dev/null
+++ b/src/java/com/juick/http/www/PageTemplates.java
@@ -0,0 +1,377 @@
+/*
+ * 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.http.www;
+
+import java.io.PrintWriter;
+import java.io.UnsupportedEncodingException;
+import java.net.URLEncoder;
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.Locale;
+import java.util.ResourceBundle;
+
+/**
+ *
+ * @author Ugnich Anton
+ */
+public class PageTemplates {
+
+ public static void pageHead(PrintWriter out, String title, String headers) {
+ out.println("<!DOCTYPE html>");
+ out.println("<html>");
+ out.println("<head>");
+ out.println(" <meta charset=\"utf-8\"/>");
+ out.println(" <title>" + title + "</title>");
+ out.println(" <link rel=\"stylesheet\" href=\"http://static.juick.com/style3.css\"/>");
+ out.println(" <link rel=\"icon\" type=\"image/png\" href=\"http://static.juick.com/favicon.png\"/>");
+ out.println(" <script type=\"text/javascript\" src=\"https://ajax.googleapis.com/ajax/libs/jquery/1.6.4/jquery.min.js\"></script>");
+ out.println(" <script type=\"text/javascript\" src=\"https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.16/jquery-ui.min.js\"></script>");
+ out.println(" <script type=\"text/javascript\" src=\"https://ajax.googleapis.com/ajax/libs/swfobject/2.2/swfobject.js\"></script>");
+ out.println(" <script type=\"text/javascript\" src=\"http://static.juick.com/scripts3.js\"></script>");
+ out.println(" <script type=\"text/javascript\" src=\"http://static.juick.com/js/jquery.autoresize.js\"></script>");
+ if (headers != null) {
+ out.println(headers);
+ }
+ out.println("</head>");
+ out.println();
+ out.println("<body>");
+ }
+
+ public static void pageNavigation(PrintWriter out, Locale loc, com.juick.User user) {
+ ResourceBundle rb = ResourceBundle.getBundle("Global", loc);
+ out.println("<div id=\"header\">");
+ out.println("<div id=\"logo\"><a href=\"/?show=my\"><img src=\"http://static.juick.com/logo3.png\" width=\"120\" height=\"40\" alt=\"Juick\" border=\"0\"/></a></div>");
+ out.println(" <ul id=\"nav\">");
+ out.println(" <li><a href=\"/\">" + rb.getString("Blogs") + "</a></li>");
+ out.println(" <li><a href=\"/chats\">" + rb.getString("Chats") + "</a></li>");
+ out.println(" <li><a href=\"/photos\">" + rb.getString("Photos") + "</a></li>");
+ out.println(" <li><a href=\"/map\">" + rb.getString("Map") + "</a></li>");
+ out.println(" </ul>");
+ out.println(" <ul id=\"nav-right\">");
+ if (user != null) {
+ out.println(" <li><a href=\"/post\">" + rb.getString("Post") + "</a></li>");
+ out.println(" <li><a href=\"#\" onclick=\"$('#nav-menu').toggle('blind'); return false\"><img src=\"http://i.juick.com/as/" + user.UID + ".png\" alt=\"@\"/>" + user.UName + "</a><ul id=\"nav-menu\">");
+ out.println(" <li><a href=\"/" + user.UName + "/\">" + rb.getString("Blog") + "</a></li>");
+ out.println(" <li><a href=\"/settings\">" + rb.getString("Settings") + "</a></li>");
+ out.println(" <li><a href=\"/logout\">" + rb.getString("Logout") + "</a></li>");
+ out.println(" </ul></li>");
+ } else {
+ out.println(" <li><a href=\"/login\">" + rb.getString("Login") + "</a></li>");
+ }
+ out.println(" </ul>");
+ out.println("</div>");
+ }
+
+ public static void pageTitle(PrintWriter out, String title) {
+ out.println("<div id=\"title\">");
+ out.println(" <h1>" + title + "</h1>");
+ out.println("</div>");
+ }
+
+ public static void pageUserTitle(PrintWriter out, Connection sql, Locale loc, com.juick.User user, com.juick.User visitor) {
+ ResourceBundle rb = ResourceBundle.getBundle("User", loc);
+
+ // Full name and description
+ String fullname = null;
+ String description = null;
+ PreparedStatement stmt = null;
+ ResultSet rs = null;
+ try {
+ stmt = sql.prepareStatement("SELECT fullname,descr FROM usersinfo WHERE user_id=?");
+ stmt.setInt(1, user.UID);
+ rs = stmt.executeQuery();
+ if (rs.first()) {
+ fullname = rs.getString(1) + " (" + user.UName + ")";
+ description = rs.getString(2);
+ }
+ } catch (SQLException e) {
+ System.err.println(e);
+ } finally {
+ Utils.finishSQL(rs, stmt);
+ }
+ if (fullname == null) {
+ fullname = user.UName;
+ }
+ if (description == null) {
+ description = "";
+ }
+
+ // I read
+ int iread = 0;
+ try {
+ stmt = sql.prepareStatement("SELECT COUNT(*) FROM subscr_users WHERE suser_id=?");
+ stmt.setInt(1, user.UID);
+ rs = stmt.executeQuery();
+ if (rs.first()) {
+ iread = rs.getInt(1);
+ }
+ } catch (SQLException e) {
+ System.err.println(e);
+ } finally {
+ Utils.finishSQL(rs, stmt);
+ }
+
+ // My readers
+ int myreaders = 0;
+ try {
+ stmt = sql.prepareStatement("SELECT COUNT(*) FROM subscr_users WHERE user_id=?");
+ stmt.setInt(1, user.UID);
+ rs = stmt.executeQuery();
+ if (rs.first()) {
+ myreaders = rs.getInt(1);
+ }
+ } catch (SQLException e) {
+ System.err.println(e);
+ } finally {
+ Utils.finishSQL(rs, stmt);
+ }
+
+ // Messages
+ int messages = 0;
+ try {
+ stmt = sql.prepareStatement("SELECT COUNT(*) FROM messages WHERE user_id=?");
+ stmt.setInt(1, user.UID);
+ rs = stmt.executeQuery();
+ if (rs.first()) {
+ messages = rs.getInt(1);
+ }
+ } catch (SQLException e) {
+ System.err.println(e);
+ } finally {
+ Utils.finishSQL(rs, stmt);
+ }
+
+ // Replies
+ int replies = 0;
+ try {
+ stmt = sql.prepareStatement("SELECT COUNT(*) FROM replies WHERE user_id=?");
+ stmt.setInt(1, user.UID);
+ rs = stmt.executeQuery();
+ if (rs.first()) {
+ replies = rs.getInt(1);
+ }
+ } catch (SQLException e) {
+ System.err.println(e);
+ } finally {
+ Utils.finishSQL(rs, stmt);
+ }
+
+ out.println("<div id=\"title\"><div id=\"title-container\">");
+ out.println(" <div id=\"title-av\"><a href=\"/" + user.UName + "/\"><img src=\"http://i.juick.com/a/" + user.UID + ".png\" width=\"96\" height=\"96\" alt=\"" + user.UName + "\"/></a></div>");
+ out.println(" <div id=\"title-stats\"><ul>");
+ out.println(" <li>" + rb.getString("(Stats) I read") + ": " + iread + "</li>");
+ out.println(" <li>" + rb.getString("(Stats) My readers") + ": " + myreaders + "</li>");
+ out.println(" <li>" + rb.getString("(Stats) Messages") + ": " + messages + "</li>");
+ out.println(" <li>" + rb.getString("(Stats) Replies") + ": " + replies + "</li>");
+ out.println(" </ul></div>");
+ out.println(" <div id=\"title-username\"><h1>" + fullname + "</h1><p>" + description + "</p></div>");
+ out.println("</div></div>");
+ out.println();
+ }
+
+ public static void pageFooter(PrintWriter out, Locale loc) {
+ ResourceBundle rb = ResourceBundle.getBundle("Global", loc);
+ out.println("<div id=\"fwrapper\"><div id=\"footer\">");
+ out.println(" <div id=\"footer-right\"><a href=\"/help/contacts\">" + rb.getString("Contacts") + "</a> &#183; <a href=\"/help/\">" + rb.getString("Help") + "</a></div>");
+ out.println(" <div id=\"footer-left\">juick.com &copy; 2008-2011</div>");
+ out.println("</div>");
+ }
+
+ public static String formatTags(String tags) {
+ String ret = "";
+ String tagsarr[] = tags.split(" ");
+ for (int i = 0; i < tagsarr.length; i++) {
+ String tag = tagsarr[i];
+ tag = tag.replaceAll("<", "&lt;");
+ tag = tag.replaceAll(">", "&gt;");
+ try {
+ ret += " *<a href=\"/?tag=" + URLEncoder.encode(tagsarr[i], "utf-8") + "\">" + tag + "</a>";
+ } catch (UnsupportedEncodingException e) {
+ }
+ }
+
+ return ret;
+ }
+
+ public static String formatDate(int minsago, String fulldate, Locale loc) {
+ if (minsago < 1) {
+ return "now";
+ } else if (minsago < 60) {
+ return minsago + " minute" + ((minsago % 10 == 1) ? "" : "s") + " ago";
+ } else if (minsago < 1440) {
+ int hours = (minsago / 60);
+ return hours + " hour" + ((hours % 10 == 1) ? "" : "s") + " ago";
+ } else if (minsago < 20160) {
+ int days = (minsago / 1440);
+ return days + " day" + ((days % 10 == 1) ? "" : "s") + " ago";
+ } else {
+ return fulldate;
+ }
+ }
+
+ public static String formatReplies(int replies, Locale loc) {
+ return replies + " repl" + (replies % 10 == 1 ? "y" : "ies");
+ }
+
+ public static String formatMessage(String msg) {
+ msg = msg.replaceAll("&", "&amp;");
+ msg = msg.replaceAll("<", "&lt;");
+ msg = msg.replaceAll(">", "&gt;");
+
+ // --
+ // &mdash;
+ msg = msg.replaceAll("((?<=\\s)|(?<=\\A))\\-\\-?((?=\\s)|(?=\\Z))", "$1&mdash;$2");
+
+ // http://juick.com/last?page=2
+ // <a href="http://juick.com/last?page=2" rel="nofollow">juick.com</a>
+ msg = msg.replaceAll("((?<=\\s)|(?<=\\A))((?:ht|f)tps?://(?:www\\.)?([^\\/\\s\\n\\\"]+)/?[^\\s\\n\\\"]*)", "$1<a href=\"$2\" rel=\"nofollow\">$3</a>");
+
+ // #12345
+ // <a href="http://juick.com/12345">#12345</a>
+ msg = msg.replaceAll("((?<=\\s)|(?<=\\A)|(?<=[[:punct:]]))#(\\d+)((?=\\s)|(?=\\Z)|(?=\\))|(?=\\.)|(?=\\,))", "$1<a href=\"http://juick.com/$2\">#$2</a>$3");
+
+ // #12345/65
+ // <a href="http://juick.com/12345#65">#12345/65</a>
+ msg = msg.replaceAll("((?<=\\s)|(?<=\\A)|(?<=[[:punct:]]))#(\\d+)/(\\d+)((?=\\s)|(?=\\Z)|(?=[[:punct:]]))", "$1<a href=\"http://juick.com/$2#$3\">#$2/$3</a>$4");
+
+ // *bold*
+ // <b>bold</b>
+ msg = msg.replaceAll("((?<=\\s)|(?<=\\A)|(?<=[[:punct:]]))\\*([^\\*\\n<>]+)\\*((?=\\s)|(?=\\Z)|(?=[[:punct:]]))", "$1<b>$2</b>$3");
+
+ // /italic/
+ // <i>italic</i>
+ msg = msg.replaceAll("((?<=\\s)|(?<=\\A))/([^\\/\\n<>]+)/((?=\\s)|(?=\\Z)|(?=[[:punct:]]))", "$1<i>$2</i>$3");
+
+ // _underline_
+ // <span class="u">underline</span>
+ msg = msg.replaceAll("((?<=\\s)|(?<=\\A))_([^\\_\\n<>]+)_((?=\\s)|(?=\\Z)|(?=[[:punct:]]))", "$1<span class=\"u\">$2</span>$3");
+
+ // /12
+ // <a href="#12">/12</a>
+ msg = msg.replaceAll("((?<=\\s)|(?<=\\A))\\/(\\d+)((?=\\s)|(?=\\Z)|(?=[[:punct:]]))", "$1<a href=\"#$2\">/$2</a>$3");
+
+ // @username@jabber.org
+ // <a href="http://juick.com/username@jabber.org/">@username@jabber.org</a>
+ msg = msg.replaceAll("((?<=\\s)|(?<=\\A))@([\\w\\-\\|\\.]+@[\\w\\-\\.]+)((?=\\s)|(?=\\Z)|(?=[[:punct:]]))", "$1<a href=\"http://juick.com/$2/\">@$2</a>$3");
+
+ // @username
+ // <a href="http://juick.com/username@jabber.org/">@username@jabber.org</a>
+ msg = msg.replaceAll("((?<=\\s)|(?<=\\A))@([\\w\\-]+)((?=\\s)|(?=\\Z)|(?=[[:punct:]]))", "$1<a href=\"http://juick.com/$2/\">@$2</a>$3");
+
+ // (http://juick.com/last?page=2)
+ // (<a href="http://juick.com/last?page=2" rel="nofollow">juick.com</a>)
+ msg = msg.replaceAll("((?<=\\s)|(?<=\\A))([\\(\\[\\{]|&lt;)((?:ht|f)tps?://(?:www\\.)?([^\\/\\s\\n\\\"\\)\\!]+)/?[^\\s]*)([\\)\\]\\}]|&gt;)", "$1$2<a href=\"$3\" rel=\"nofollow\">$4</a>$5");
+
+ // > citate
+ msg = msg.replaceAll("(?:(?<=\\n)|(?<=\\A))&gt;\\s(.*)(\\n|(?=\\Z))", "<blockquote>$1</blockquote>");
+ msg = msg.replaceAll("</blockquote><blockquote>", "\n");
+
+ msg = msg.replaceAll("\n", "<br/>\n");
+ return msg;
+ }
+
+ public static void printMessages(PrintWriter out, Connection sql, ArrayList<Integer> mids, Locale locale) {
+ ResourceBundle rb = ResourceBundle.getBundle("Global", locale);
+
+ PreparedStatement stmt = null;
+ ResultSet rs = null;
+ try {
+ stmt = sql.prepareStatement("SELECT STRAIGHT_JOIN messages.message_id,messages.user_id,users.nick,messages_txt.tags,messages.readonly,messages.privacy,messages_txt.txt,TIMESTAMPDIFF(MINUTE,messages.ts,NOW()),messages.ts,messages.replies,messages_txt.repliesby,messages.attach,messages.place_id,places.name,messages.lat,messages.lon FROM ((messages INNER JOIN messages_txt ON messages.message_id=messages_txt.message_id) INNER JOIN users ON messages.user_id=users.id) LEFT JOIN places ON messages.place_id=places.place_id WHERE messages.message_id IN (" + Utils.convertArray2String(mids) + ") ORDER BY messages.message_id DESC");
+ rs = stmt.executeQuery();
+ rs.beforeFirst();
+ while (rs.next()) {
+ int mid = rs.getInt(1);
+ int uid = rs.getInt(2);
+ String uname = rs.getString(3);
+ String tags = rs.getString(4);
+ String txt = rs.getString(7);
+ // timediff
+ // timestamp
+ // replies
+ // 11 repliesby
+ // attach
+ // pid
+ // pname
+ // lat
+ // lon
+
+ tags = (tags != null) ? formatTags(tags) : "";
+ if (rs.getInt(5) == 1) {
+ tags += " *readonly";
+ }
+ switch (rs.getInt(6)) {
+ case 2:
+ tags += " *public";
+ break;
+ case -1:
+ tags += " *friends";
+ break;
+ case -2:
+ tags += " *private";
+ break;
+ }
+
+ txt = formatMessage(txt);
+
+ if (mid == mids.get(0)) {
+ out.println(" <li class=\"msg\" style=\"border: 0\">");
+ } else {
+ out.println(" <li class=\"msg\">");
+ }
+
+ if (rs.getString(12) != null) {
+ if (rs.getString(12).equals("jpg")) {
+ out.println(" <div class=\"msg-media\"><img src=\"http://i.juick.com/photos-512/" + mid + ".jpg\" alt=\"\"/></div>");
+ } else {
+ out.println(" <div class=\"msg-media\"><div id=\"video-" + mid + "\"><b>Attachment: <a href=\"http://i.juick.com/video/" + mid + ".mp4\">Video</a></b></div></div>");
+ out.println(" <script type=\"text/javascript\">");
+ out.println(" inlinevideo(" + mid + ");");
+ out.println(" </script>");
+ }
+ }
+
+ out.println(" <div class=\"msg-avatar\"><a href=\"/" + uname + "/\"><img src=\"http://i.juick.com/a/" + uid + ".png\"></a></div>");
+ out.println(" <div class=\"msg-ts\"><a href=\"/" + uname + "/" + mid + "\">" + formatDate(rs.getInt(8), rs.getString(9), locale) + "</a><div class=\"msg-menu\"><a href=\"#\" onclick=\"$('#msg-menu-" + mid + "').toggle('blind'); return false\"><img src=\"http://static.juick.com/message-menu-icon.png\"></a><ul id=\"msg-menu-" + mid + "\">");
+ out.println(" <li><a href=\"#\" onclick=\"return false\">Under construction</a></li>");
+ out.println(" </ul></div></div>");
+ out.println(" <div class=\"msg-header\"><a href=\"/" + uname + "/\">@" + uname + "</a>:" + tags + "</div>");
+ out.println(" <div class=\"msg-txt\">" + txt + "</div>");
+
+ if (rs.getInt(10) > 0) {
+ String repliesby = rs.getString(11);
+ if (repliesby == null) {
+ repliesby = "...";
+ }
+ out.println(" <div class=\"msg-comments\"><a href=\"/" + uname + "/" + mid + "\">" + formatReplies(rs.getInt(10), locale) + "</a> " + rb.getString("(replies) by") + " " + repliesby + "</div>");
+ } else {
+ out.println(" <form action=\"/post\" method=\"POST\" enctype=\"multipart/form-data\"><input type=\"hidden\" name=\"mid\" value=\"" + mid + "\"/>");
+ out.println(" <div class=\"msg-comment\"><textarea name=\"body\" rows=\"1\" placeholder=\"Add a comment...\" onkeypress=\"postformListener(this.form,event)\"></textarea></div>");
+ out.println(" </form>");
+ }
+ out.println(" </li>");
+ }
+ } catch (SQLException e) {
+ System.err.println(e);
+ } finally {
+ Utils.finishSQL(rs, stmt);
+ }
+ }
+}
diff --git a/src/java/com/juick/http/www/Photos.java b/src/java/com/juick/http/www/Photos.java
new file mode 100644
index 00000000..7a202625
--- /dev/null
+++ b/src/java/com/juick/http/www/Photos.java
@@ -0,0 +1,100 @@
+/*
+ * 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.http.www;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.Locale;
+import java.util.ResourceBundle;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+/**
+ *
+ * @author Ugnich Anton
+ */
+public class Photos {
+
+ protected void doGet(Connection sql, HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
+ com.juick.User visitor = Utils.getVisitorUser(sql, request);
+ Locale locale = request.getLocale();
+ ResourceBundle rb = ResourceBundle.getBundle("Photos", locale);
+
+ response.setContentType("text/html; charset=UTF-8");
+ PrintWriter out = response.getWriter();
+ try {
+ PageTemplates.pageHead(out, rb.getString("Last photos and videos"), "<script type=\"text/javascript\" src=\"http://static.juick.com/js/jquery.onImagesLoad.min.js\"></script>"
+ + "<script type=\"text/javascript\" src=\"http://static.juick.com/js/gallery.js\"></script>"
+ + "<script type=\"text/javascript\" src=\"http://static.juick.com/js/jquery.fancybox-1.3.4.js\"></script>"
+ + "<link rel=\"stylesheet\" href=\"http://static.juick.com/fancybox/jquery.fancybox-1.3.4.css\"/>");
+ PageTemplates.pageNavigation(out, locale, visitor);
+ PageTemplates.pageTitle(out, rb.getString("Last photos and videos"));
+
+ out.println("<div id=\"wrapper\">");
+ out.println("<div id=\"spinner\" style=\"text-align: center\">Loading...</div>");
+ out.println("<ul id=\"gallery\" style=\"display: none\">");
+
+ PreparedStatement stmt = null;
+ ResultSet rs = null;
+ try {
+ stmt = sql.prepareStatement("SELECT messages.message_id,messages.attach,users.nick FROM messages INNER JOIN users ON messages.user_id=users.id WHERE messages.attach IS NOT NULL ORDER BY message_id DESC LIMIT 20");
+ rs = stmt.executeQuery();
+ rs.beforeFirst();
+ while (rs.next()) {
+ if (rs.getString(2).equals("jpg")) {
+ out.println("<li class=\"galleryitem\"><a href=\"/" + rs.getString(3) + "/" + rs.getInt(1) + "\" title=\"@" + rs.getString(3) + "\"><img src=\"http://i.juick.com/photos-512/" + rs.getInt(1) + ".jpg\" alt=\"\"></a></li>");
+ } else {
+ out.println("<li class=\"galleryitem\"><a href=\"/" + rs.getString(3) + "/" + rs.getInt(1) + "\" title=\"@" + rs.getString(3) + "\"><img src=\"http://i.juick.com/thumbs/" + rs.getInt(1) + ".jpg\" alt=\"\"></a></li>");
+ }
+ }
+ } catch (SQLException e) {
+ System.err.println(e);
+ } finally {
+ Utils.finishSQL(rs, stmt);
+ }
+
+ out.println("</ul>");
+ out.println("</div>");
+ out.println("<script type=\"text/javascript\">");
+ out.println("$('#gallery').onImagesLoad({selectorCallback: galleryResize});");
+ out.println("$('.galleryitem a').click(function() {");
+ out.println(" $.fancybox({");
+ out.println(" 'href': $(this).children('img').attr('src'),");
+ out.println(" 'link': this.href,");
+ out.println(" 'title': this.title,");
+ out.println(" 'orig': this,");
+ out.println(" 'transitionIn': 'elastic',");
+ out.println(" 'transitionOut': 'none',");
+ out.println(" 'easingIn': 'easeOutBack',");
+ out.println(" 'easingOut': 'easeInBack'");
+ out.println(" });");
+ out.println(" return false;");
+ out.println("});");
+ out.println("</script>");
+
+ PageTemplates.pageFooter(out, locale);
+ } finally {
+ out.close();
+ }
+ }
+}
diff --git a/src/java/com/juick/http/www/RootRedirects.java b/src/java/com/juick/http/www/RootRedirects.java
new file mode 100644
index 00000000..d4e17972
--- /dev/null
+++ b/src/java/com/juick/http/www/RootRedirects.java
@@ -0,0 +1,53 @@
+/*
+ * 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.http.www;
+
+import java.io.IOException;
+import java.sql.Connection;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+/**
+ *
+ * @author Ugnich Anton
+ */
+public class RootRedirects {
+
+ protected void doGetPostID(Connection sql, HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
+ String strID = request.getRequestURI().substring(1);
+ int mid = Integer.parseInt(strID);
+ if (mid > 0) {
+ com.juick.User author = com.juick.server.MessagesQueries.getMessageAuthor(sql, mid);
+ if (author != null) {
+ Utils.sendPermanentRedirect(response, "/" + author.UName + "/" + mid);
+ return;
+ }
+ }
+ response.sendError(404);
+ }
+
+ protected void doGetUsername(Connection sql, HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
+ com.juick.User user = com.juick.server.UserQueries.getUserByNick(sql, request.getRequestURI().substring(1));
+ if (user != null) {
+ Utils.sendPermanentRedirect(response, "/" + user.UName + "/");
+ } else {
+ response.sendError(404);
+ }
+ }
+}
diff --git a/src/java/com/juick/http/www/User.java b/src/java/com/juick/http/www/User.java
new file mode 100644
index 00000000..fefe1174
--- /dev/null
+++ b/src/java/com/juick/http/www/User.java
@@ -0,0 +1,198 @@
+/*
+ * 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.http.www;
+
+import com.juick.server.MessagesQueries;
+import com.juick.server.TagQueries;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.io.UnsupportedEncodingException;
+import java.net.URLEncoder;
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Locale;
+import java.util.ResourceBundle;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+/**
+ *
+ * @author Ugnich Anton
+ */
+public class User {
+
+ protected void doGetBlog(Connection sql, Connection sqlSearch, HttpServletRequest request, HttpServletResponse response, com.juick.User user) throws ServletException, IOException {
+ com.juick.User visitor = Utils.getVisitorUser(sql, request);
+ Locale locale = request.getLocale();
+ ResourceBundle rb = ResourceBundle.getBundle("User", locale);
+
+ String title = "@" + user.UName + " - ";
+ ArrayList<Integer> mids;
+
+ String paramShow = request.getParameter("show");
+
+ int paramTag = 0;
+ String paramTagStr = request.getParameter("tag");
+ if (paramTagStr != null && paramTagStr.length() < 64) {
+ paramTag = TagQueries.getTagID(sql, paramTagStr, false);
+ }
+
+ 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;
+ }
+
+ if (paramShow == null) {
+ if (paramTag > 0) {
+ title += "*" + Utils.encodeHTML(paramTagStr);
+ mids = MessagesQueries.getUserTag(sql, user.UID, paramTag, paramBefore);
+ } else if (paramSearch != null) {
+ title += rb.getString("(Menu) Search") + ": " + Utils.encodeHTML(paramSearch);
+ mids = MessagesQueries.getUserSearch(sql, sqlSearch, user.UID, Utils.encodeSphinx(paramSearch), paramBefore);
+ } else {
+ title += rb.getString("(Menu) Blog");
+ mids = MessagesQueries.getUserBlog(sql, user.UID, paramBefore);
+ }
+ } else if (paramShow.equals("recomm")) {
+ title += rb.getString("(Menu) Recommendations");
+ mids = MessagesQueries.getUserRecommendations(sql, user.UID, paramBefore);
+ } else if (paramShow.equals("photos")) {
+ title += rb.getString("(Menu) Photos");
+ mids = MessagesQueries.getUserPhotos(sql, user.UID, paramBefore);
+ } else {
+ response.sendError(404);
+ return;
+ }
+
+ response.setContentType("text/html; charset=UTF-8");
+ PrintWriter out = response.getWriter();
+ try {
+ PageTemplates.pageHead(out, title, null);
+ PageTemplates.pageNavigation(out, locale, visitor);
+ PageTemplates.pageUserTitle(out, sql, locale, user, visitor);
+
+ out.println("<div id=\"wrapper\">");
+ out.println("<div id=\"content\">");
+ out.println("<ul>");
+
+ if (mids.size() > 0) {
+ PageTemplates.printMessages(out, sql, mids, locale);
+ }
+
+ out.println("</ul>");
+ out.println("<script type=\"text/javascript\">");
+ out.println("$(\"textarea\").autoResize();");
+ out.println("</script>");
+
+ if (mids.size() == 20) {
+ String nextpage = "?before=" + mids.get(19);
+ if (paramShow != null) {
+ nextpage += "&show=" + paramShow;
+ }
+ if (paramTag > 0) {
+ nextpage += "&tag=" + URLEncoder.encode(paramTagStr, "UTF-8");
+ }
+ out.println("<p class=\"page\"><a href=\"" + nextpage + "\">Older →</a></p>");
+ }
+
+ out.println("</div>");
+
+ out.println("<div id=\"column\">");
+ out.println("<h2>" + rb.getString("(Menu) Messages") + "</h2>");
+ out.println("<ul>");
+ out.println(" <li><a href=\"?\">" + rb.getString("(Menu) Blog") + "</a></li>");
+ out.println(" <li><a href=\"?show=recomm\">" + rb.getString("(Menu) Recommendations") + "</a></li>");
+ out.println(" <li><a href=\"?show=photos\">" + rb.getString("(Menu) Photos") + "</a></li>");
+ out.println("</ul>");
+ out.println("<h2>" + rb.getString("(Menu) Tags") + "</h2>");
+ pageUserTags(out, sql, user, visitor, 15);
+ out.println("<h2>" + rb.getString("(Menu) Search") + "</h2>");
+ out.println("<form action=\"./\" id=\"search\"><p><input type=\"text\" name=\"search\" class=\"inp\"/></p></form>");
+ out.println("</div>");
+ out.println("</div>");
+
+ PageTemplates.pageFooter(out, locale);
+ } finally {
+ out.close();
+ }
+ }
+
+ protected void doGetInfo(Connection sql, HttpServletRequest request, HttpServletResponse response, com.juick.User user) throws ServletException, IOException {
+ }
+
+ public static void pageUserTags(PrintWriter out, Connection sql, com.juick.User user, com.juick.User visitor, int cnt) {
+ com.juick.Tag tags[] = new com.juick.Tag[cnt];
+
+ int maxUsageCnt = 0;
+ PreparedStatement stmt = null;
+ ResultSet rs = null;
+ try {
+ stmt = sql.prepareStatement("SELECT tags.name AS name,COUNT(DISTINCT messages_tags.message_id) AS cnt FROM (messages INNER JOIN messages_tags ON (messages.message_id=messages_tags.message_id)) INNER JOIN tags ON messages_tags.tag_id=tags.tag_id WHERE messages.user_id=? GROUP BY messages_tags.tag_id ORDER BY cnt DESC LIMIT ?");
+ stmt.setInt(1, user.UID);
+ stmt.setInt(2, cnt);
+ rs = stmt.executeQuery();
+ rs.beforeFirst();
+ cnt = 0;
+ while (rs.next()) {
+ tags[cnt] = new com.juick.Tag();
+ tags[cnt].Name = rs.getString(1);
+ tags[cnt].UsageCnt = rs.getInt(2);
+ if (tags[cnt].UsageCnt > maxUsageCnt) {
+ maxUsageCnt = tags[cnt].UsageCnt;
+ }
+ cnt++;
+ }
+ } catch (SQLException e) {
+ System.err.println(e);
+ } finally {
+ Utils.finishSQL(rs, stmt);
+ }
+
+ Arrays.sort(tags, 0, cnt);
+
+ for (int i = 0; i < cnt; i++) {
+ String tag = Utils.encodeHTML(tags[i].Name);
+ try {
+ tag = "<a href=\"?tag=" + URLEncoder.encode(tags[i].Name, "UTF-8") + "\" title=\"" + tags[i].UsageCnt + "\">" + tag + "</a>";
+ } catch (UnsupportedEncodingException e) {
+ }
+
+ if (tags[i].UsageCnt > maxUsageCnt / 3 * 2) {
+ out.print("<big>" + tag + "</big> ");
+ } else if (tags[i].UsageCnt > maxUsageCnt / 3) {
+ out.print("<small>" + tag + "</small> ");
+ } else {
+ out.print(tag + " ");
+ }
+ }
+ }
+}
diff --git a/src/java/com/juick/http/www/UserThread.java b/src/java/com/juick/http/www/UserThread.java
new file mode 100644
index 00000000..6688e964
--- /dev/null
+++ b/src/java/com/juick/http/www/UserThread.java
@@ -0,0 +1,298 @@
+/*
+ * 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.http.www;
+
+import com.juick.server.UserQueries;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.Locale;
+import java.util.ResourceBundle;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+/**
+ *
+ * @author Ugnich Anton
+ */
+public class UserThread {
+
+ protected void doGetThread(Connection sql, HttpServletRequest request, HttpServletResponse response, com.juick.User user, int MID) throws ServletException, IOException {
+ com.juick.User visitor = Utils.getVisitorUser(sql, request);
+ Locale locale = request.getLocale();
+ ResourceBundle rb = ResourceBundle.getBundle("User", locale);
+
+ boolean listview = false;
+ String paramView = request.getParameter("view");
+ if (paramView != null) {
+ if (paramView.equals("list")) {
+ listview = true;
+ if (visitor != null) {
+ UserQueries.setUserOptionInt(sql, visitor.UID, "repliesview", 1);
+ }
+ } else if (paramView.equals("tree") && visitor != null) {
+ UserQueries.setUserOptionInt(sql, visitor.UID, "repliesview", 0);
+ }
+ } else if (visitor != null && UserQueries.getUserOptionInt(sql, visitor.UID, "repliesview", 0) == 1) {
+ listview = true;
+ }
+
+ String title = "@" + user.UName + " - #" + MID;
+
+ response.setContentType("text/html; charset=UTF-8");
+ PrintWriter out = response.getWriter();
+ try {
+ PageTemplates.pageHead(out, title, null);
+ PageTemplates.pageNavigation(out, locale, visitor);
+ PageTemplates.pageUserTitle(out, sql, locale, user, visitor);
+
+ out.println("<div id=\"wrapper\">");
+ out.println("<div id=\"content\" style=\"margin-left: 0; width: 100%\">");
+
+ out.println("<ul>");
+ printMessage(out, sql, MID, locale);
+ out.println("</ul>");
+
+ out.println("<div class=\"title2\">");
+ out.print(" <div class=\"title2-right\">");
+ if (listview) {
+ out.print("<a href=\"?view=tree\">" + rb.getString("View as tree") + "</a>");
+ } else {
+ out.print("<a href=\"#\" onclick=\"$('#replies>li').show(); $('#replies .msg-comments').hide(); return false\">" + rb.getString("Expand all") + "</a> &#183; <a href=\"?view=list\">" + rb.getString("View as list") + "</a>");
+ }
+ out.print("</div>");
+ out.println(" <h2>Replies</h2>");
+ out.println("</div>");
+
+ out.println("<ul id=\"replies\">");
+ printReplies(out, sql, MID, locale, listview);
+ out.println("</ul>");
+
+ out.println("<script type=\"text/javascript\">");
+ out.println("$(\"textarea\").autoResize();");
+ out.println("</script>");
+
+ out.println("</div>");
+
+ out.println("</div>");
+
+ PageTemplates.pageFooter(out, locale);
+ } finally {
+ out.close();
+ }
+ }
+
+ public static void printMessage(PrintWriter out, Connection sql, int mid, Locale locale) {
+ ResourceBundle rb = ResourceBundle.getBundle("Global", locale);
+
+ PreparedStatement stmt = null;
+ ResultSet rs = null;
+ try {
+ stmt = sql.prepareStatement("SELECT STRAIGHT_JOIN messages.message_id,messages.user_id,users.nick,messages_txt.tags,messages.readonly,messages.privacy,messages_txt.txt,TIMESTAMPDIFF(MINUTE,messages.ts,NOW()),messages.ts,messages.replies,messages.attach,messages.place_id,places.name,messages.lat,messages.lon FROM ((messages INNER JOIN messages_txt ON messages.message_id=messages_txt.message_id) INNER JOIN users ON messages.user_id=users.id) LEFT JOIN places ON messages.place_id=places.place_id WHERE messages.message_id=?");
+ stmt.setInt(1, mid);
+ rs = stmt.executeQuery();
+ if (rs.first()) {
+ int uid = rs.getInt(2);
+ String uname = rs.getString(3);
+ String tags = rs.getString(4);
+ String txt = rs.getString(7);
+ // timediff
+ // timestamp
+ // replies
+ // attach
+ // pid
+ // pname
+ // lat
+ // lon
+
+ tags = (tags != null) ? PageTemplates.formatTags(tags) : "";
+ if (rs.getInt(5) == 1) {
+ tags += " *readonly";
+ }
+ switch (rs.getInt(6)) {
+ case 2:
+ tags += " *public";
+ break;
+ case -1:
+ tags += " *friends";
+ break;
+ case -2:
+ tags += " *private";
+ break;
+ }
+
+ txt = PageTemplates.formatMessage(txt);
+
+ out.println(" <li class=\"msg\" style=\"border: 0\">");
+
+ if (rs.getString(11) != null) {
+ if (rs.getString(11).equals("jpg")) {
+ out.println(" <div class=\"msg-media\"><img src=\"http://i.juick.com/photos-512/" + mid + ".jpg\" alt=\"\"/></div>");
+ } else {
+ out.println(" <div class=\"msg-media\"><div id=\"video-" + mid + "\"><b>Attachment: <a href=\"http://i.juick.com/video/" + mid + ".mp4\">Video</a></b></div></div>");
+ out.println(" <script type=\"text/javascript\">");
+ out.println(" inlinevideo(" + mid + ");");
+ out.println(" </script>");
+ }
+ }
+
+ out.println(" <div class=\"msg-avatar\"><a href=\"/" + uname + "/\"><img src=\"http://i.juick.com/a/" + uid + ".png\"></a></div>");
+ out.println(" <div class=\"msg-ts\"><a href=\"/" + uname + "/" + mid + "\">" + PageTemplates.formatDate(rs.getInt(8), rs.getString(9), locale) + "</a><div class=\"msg-menu\"><a href=\"#\" onclick=\"$('#msg-menu-" + mid + "').toggle('blind'); return false\"><img src=\"http://static.juick.com/message-menu-icon.png\"></a><ul id=\"msg-menu-" + mid + "\">");
+ out.println(" <li><a href=\"#\" onclick=\"return false\">Under construction</a></li>");
+ out.println(" </ul></div></div>");
+ out.println(" <div class=\"msg-header\"><a href=\"/" + uname + "/\">@" + uname + "</a>:" + tags + "</div>");
+ out.println(" <div class=\"msg-txt\">" + txt + "</div>");
+ out.println(" </li>");
+ }
+ } catch (SQLException e) {
+ System.err.println(e);
+ } finally {
+ Utils.finishSQL(rs, stmt);
+ }
+
+ }
+
+ public static void printReplies(PrintWriter out, Connection sql, int mid, Locale locale, boolean listview) {
+ ArrayList<com.juick.Message> replies = new ArrayList<com.juick.Message>();
+
+ PreparedStatement stmt = null;
+ ResultSet rs = null;
+ try {
+ stmt = sql.prepareStatement("SELECT replies.reply_id,replies.replyto,replies.user_id,users.nick,replies.txt,TIMESTAMPDIFF(MINUTE,replies.ts,NOW()),replies.ts,replies.attach FROM replies INNER JOIN users ON replies.user_id=users.id WHERE replies.message_id=? ORDER BY replies.reply_id ASC");
+ stmt.setInt(1, mid);
+ rs = stmt.executeQuery();
+ rs.beforeFirst();
+ while (rs.next()) {
+ com.juick.Message msg = new com.juick.Message();
+ msg.MID = mid;
+ msg.RID = rs.getInt(1);
+ msg.ReplyTo = rs.getInt(2);
+ msg.User = new com.juick.User();
+ msg.User.UID = rs.getInt(3);
+ msg.User.UName = rs.getString(4);
+ msg.Text = PageTemplates.formatMessage(rs.getString(5));
+ msg.MinutesAgo = rs.getInt(6);
+ msg.TimestampString = rs.getString(7);
+ msg.AttachmentType = rs.getString(8);
+
+ replies.add(msg);
+
+ if (msg.ReplyTo > 0) {
+ boolean added = false;
+ for (int i = 0; i < replies.size(); i++) {
+ if (replies.get(i).RID == msg.ReplyTo) {
+ replies.get(i).childs.add(msg);
+ added = true;
+ break;
+ }
+ }
+ if (!added) {
+ msg.ReplyTo = 0;
+ }
+ }
+ }
+ } catch (SQLException e) {
+ System.err.println(e);
+ } finally {
+ Utils.finishSQL(rs, stmt);
+ }
+
+ if (listview) {
+ printList(out, replies, locale);
+ } else {
+ printTree(out, replies, 0, 0, locale);
+ }
+
+ for (int i = 0; i < replies.size(); i++) {
+ replies.get(i).cleanupChilds();
+ }
+ replies.clear();
+ }
+
+ public static void printTree(PrintWriter out, ArrayList<com.juick.Message> replies, int ReplyTo, int margin, Locale locale) {
+ for (int i = 0; i < replies.size(); i++) {
+ com.juick.Message msg = replies.get(i);
+ if (msg.ReplyTo == ReplyTo) {
+
+ out.print(" <li id=\"" + msg.RID + "\" class=\"msg\" style=\"");
+ if (i == 0) {
+ out.print("border: 0;");
+ }
+ if (margin > 0) {
+ out.print("margin-left: " + margin + "px;display:none;");
+ }
+ out.println("\">");
+ if (msg.AttachmentType != null) {
+ if (msg.AttachmentType.equals("jpg")) {
+ out.println(" <div class=\"msg-media\"><img src=\"http://i.juick.com/photos-512/" + msg.MID + "-" + msg.RID + ".jpg\" alt=\"\"/></div>");
+ } else {
+ out.println(" <div class=\"msg-media\"><div id=\"video-" + msg.MID + "-" + msg.RID + "\"><b>Attachment: <a href=\"http://i.juick.com/video/" + msg.MID + "-" + msg.RID + ".mp4\">Video</a></b></div></div>");
+ out.println(" <script type=\"text/javascript\">");
+ out.println(" inlinevideo('" + msg.MID + "-" + msg.RID + "');");
+ out.println(" </script>");
+ }
+ }
+ out.println(" <div class=\"msg-avatar\"><a href=\"/" + msg.User.UName + "/\"><img src=\"http://i.juick.com/a/" + msg.User.UID + ".png\"></a></div>");
+ out.println(" <div class=\"msg-ts\"><a href=\"/" + msg.User.UName + "/" + msg.MID + "#" + msg.RID + "\">" + PageTemplates.formatDate(msg.MinutesAgo, msg.TimestampString, locale) + "</a><div class=\"msg-menu\"><a href=\"#\" onclick=\"return msgMenu(" + msg.MID + ")\"><img src=\"http://static.juick.com/message-menu-icon.png\"></a><ul id=\"msg-menu-" + msg.MID + "\">");
+ out.println(" <li><a href=\"#\" onclick=\"return false\">Under construction</a></li>");
+ out.println(" </ul></div></div>");
+ out.println(" <div class=\"msg-header\"><a href=\"/" + msg.User.UName + "/\">@" + msg.User.UName + "</a>:</div>");
+ out.println(" <div class=\"msg-txt\">" + msg.Text + "</div>");
+ if (ReplyTo == 0) {
+ int childs = msg.getChildsCount() - 1;
+ if (childs > 0) {
+ out.println(" <div class=\"msg-comments\"><a href=\"#\" onclick=\"return showMoreReplies(" + msg.RID + ")\">" + PageTemplates.formatReplies(childs, locale) + " more</a></div>");
+ }
+ }
+ out.println(" </li>");
+
+ printTree(out, replies, msg.RID, margin + 20, locale);
+ }
+ }
+ }
+
+ public static void printList(PrintWriter out, ArrayList<com.juick.Message> replies, Locale locale) {
+ for (int i = 0; i < replies.size(); i++) {
+ com.juick.Message msg = replies.get(i);
+
+ out.print(" <li id=\"" + msg.RID + "\" class=\"msg\"" + (i == 0 ? " style=\"border: 0\"" : "") + ">");
+ if (msg.AttachmentType != null) {
+ if (msg.AttachmentType.equals("jpg")) {
+ out.println(" <div class=\"msg-media\"><img src=\"http://i.juick.com/photos-512/" + msg.MID + "-" + msg.RID + ".jpg\" alt=\"\"/></div>");
+ } else {
+ out.println(" <div class=\"msg-media\"><div id=\"video-" + msg.MID + "-" + msg.RID + "\"><b>Attachment: <a href=\"http://i.juick.com/video/" + msg.MID + "-" + msg.RID + ".mp4\">Video</a></b></div></div>");
+ out.println(" <script type=\"text/javascript\">");
+ out.println(" inlinevideo('" + msg.MID + "-" + msg.RID + "');");
+ out.println(" </script>");
+ }
+ }
+ out.println(" <div class=\"msg-avatar\"><a href=\"/" + msg.User.UName + "/\"><img src=\"http://i.juick.com/a/" + msg.User.UID + ".png\"></a></div>");
+ out.println(" <div class=\"msg-ts\"><a href=\"/" + msg.User.UName + "/" + msg.MID + "#" + msg.RID + "\">" + PageTemplates.formatDate(msg.MinutesAgo, msg.TimestampString, locale) + "</a><div class=\"msg-menu\"><a href=\"#\" onclick=\"return msgMenu(" + msg.MID + ")\"><img src=\"http://static.juick.com/message-menu-icon.png\"></a><ul id=\"msg-menu-" + msg.MID + "\">");
+ out.println(" <li><a href=\"#\" onclick=\"return false\">Under construction</a></li>");
+ out.println(" </ul></div></div>");
+ out.println(" <div class=\"msg-header\"><a href=\"/" + msg.User.UName + "/\">@" + msg.User.UName + "</a>:</div>");
+ out.println(" <div class=\"msg-txt\">" + msg.Text + "</div>");
+ out.println(" </li>");
+ }
+ }
+}
diff --git a/src/java/com/juick/http/www/Utils.java b/src/java/com/juick/http/www/Utils.java
new file mode 100644
index 00000000..cfa4484d
--- /dev/null
+++ b/src/java/com/juick/http/www/Utils.java
@@ -0,0 +1,112 @@
+/*
+ * 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.http.www;
+
+import java.sql.Connection;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.util.ArrayList;
+import javax.servlet.http.Cookie;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+/**
+ *
+ * @author Ugnich Anton
+ */
+public class Utils {
+
+ public static String getCookie(HttpServletRequest request, String name) {
+ Cookie cookies[] = request.getCookies();
+ if (cookies != null) {
+ for (int i = 0; i < cookies.length; i++) {
+ if (cookies[i].getName().equals(name)) {
+ return cookies[i].getValue();
+ }
+ }
+ }
+ return null;
+ }
+
+ public static com.juick.User getVisitorUser(Connection sql, HttpServletRequest request) {
+ String hash = getCookie(request, "hash");
+ if (hash != null) {
+ return com.juick.server.UserQueries.getUserByHash(sql, hash);
+ } else {
+ return null;
+ }
+ }
+
+ public static int getVisitorUID(Connection sql, HttpServletRequest request) {
+ Cookie cookies[] = request.getCookies();
+ if (cookies != null) {
+ for (int i = 0; i < cookies.length; i++) {
+ if (cookies[i].getName().equals("hash")) {
+ String hash = cookies[i].getValue();
+ return com.juick.server.UserQueries.getUIDbyHash(sql, hash);
+ }
+ }
+ }
+ return 0;
+ }
+
+ public static void sendPermanentRedirect(HttpServletResponse response, String location) {
+ response.setStatus(HttpServletResponse.SC_MOVED_PERMANENTLY);
+ response.setHeader("Location", location);
+ }
+
+ public static void finishSQL(ResultSet rs, Statement stmt) {
+ if (rs != null) {
+ try {
+ rs.close();
+ } catch (SQLException e) {
+ }
+ }
+ if (stmt != null) {
+ try {
+ stmt.close();
+ } catch (SQLException e) {
+ }
+ }
+ }
+
+ public static String convertArray2String(ArrayList<Integer> mids) {
+ String q = "";
+ for (int i = 0; i < mids.size(); i++) {
+ if (i > 0) {
+ q += ",";
+ }
+ q += mids.get(i);
+ }
+ return q;
+ }
+
+ public static String encodeHTML(String str) {
+ String ret = str;
+ ret = ret.replaceAll("<", "&lt;");
+ ret = ret.replaceAll(">", "&gt;");
+ return str;
+ }
+
+ public static String encodeSphinx(String str) {
+ String ret = str;
+ ret = ret.replaceAll("@", "\\\\@");
+ return ret;
+ }
+}