From 6f4e181f0a03b4b190922bd5f8bd97fb9fdb206e Mon Sep 17 00:00:00 2001 From: Ugnich Anton Date: Sun, 25 Dec 2011 15:56:30 +0700 Subject: Initial commit --- src/conf/MANIFEST.MF | 2 + src/java/Blogs.properties | 14 + src/java/Blogs_ru.properties | 14 + src/java/Chats.properties | 5 + src/java/Chats_ru.properties | 5 + src/java/Global.properties | 17 ++ src/java/Global_ru.properties | 17 ++ src/java/Login.properties | 6 + src/java/Login_ru.properties | 6 + src/java/Map.properties | 5 + src/java/Map_ru.properties | 5 + src/java/Photos.properties | 4 + src/java/Photos_ru.properties | 4 + src/java/User.properties | 16 ++ src/java/User_ru.properties | 16 ++ src/java/com/juick/http/www/Blogs.java | 217 ++++++++++++++ src/java/com/juick/http/www/Chats.java | 77 +++++ src/java/com/juick/http/www/Login.java | 129 +++++++++ src/java/com/juick/http/www/Main.java | 173 ++++++++++++ src/java/com/juick/http/www/Map.java | 64 +++++ src/java/com/juick/http/www/NewMessage.java | 37 +++ src/java/com/juick/http/www/PageTemplates.java | 377 +++++++++++++++++++++++++ src/java/com/juick/http/www/Photos.java | 100 +++++++ src/java/com/juick/http/www/RootRedirects.java | 53 ++++ src/java/com/juick/http/www/User.java | 198 +++++++++++++ src/java/com/juick/http/www/UserThread.java | 298 +++++++++++++++++++ src/java/com/juick/http/www/Utils.java | 112 ++++++++ 27 files changed, 1971 insertions(+) create mode 100644 src/conf/MANIFEST.MF create mode 100644 src/java/Blogs.properties create mode 100644 src/java/Blogs_ru.properties create mode 100644 src/java/Chats.properties create mode 100644 src/java/Chats_ru.properties create mode 100644 src/java/Global.properties create mode 100644 src/java/Global_ru.properties create mode 100644 src/java/Login.properties create mode 100644 src/java/Login_ru.properties create mode 100644 src/java/Map.properties create mode 100644 src/java/Map_ru.properties create mode 100644 src/java/Photos.properties create mode 100644 src/java/Photos_ru.properties create mode 100644 src/java/User.properties create mode 100644 src/java/User_ru.properties create mode 100644 src/java/com/juick/http/www/Blogs.java create mode 100644 src/java/com/juick/http/www/Chats.java create mode 100644 src/java/com/juick/http/www/Login.java create mode 100644 src/java/com/juick/http/www/Main.java create mode 100644 src/java/com/juick/http/www/Map.java create mode 100644 src/java/com/juick/http/www/NewMessage.java create mode 100644 src/java/com/juick/http/www/PageTemplates.java create mode 100644 src/java/com/juick/http/www/Photos.java create mode 100644 src/java/com/juick/http/www/RootRedirects.java create mode 100644 src/java/com/juick/http/www/User.java create mode 100644 src/java/com/juick/http/www/UserThread.java create mode 100644 src/java/com/juick/http/www/Utils.java (limited to 'src') diff --git a/src/conf/MANIFEST.MF b/src/conf/MANIFEST.MF new file mode 100644 index 00000000..59499bce --- /dev/null +++ b/src/conf/MANIFEST.MF @@ -0,0 +1,2 @@ +Manifest-Version: 1.0 + 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 . + */ +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 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("
"); + out.println("
"); + out.println("
    "); + + if (mids.size() > 0) { + PageTemplates.printMessages(out, sql, mids, locale); + } + + out.println("
"); + out.println(""); + + 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("

Older →

"); + } + + out.println("
"); + + out.println("
"); + out.println("

" + rb.getString("Lists") + "

"); + if (visitor != null) { + out.println(""); + } + out.println(""); + out.println("

" + rb.getString("Tags") + "

"); + out.println("

" + getTags(sql, 30) + "

"); + out.println("

" + rb.getString("Search") + "

"); + out.println("

"); + out.println("
"); + out.println("
"); + + 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 = "" + tag + ""; + } catch (UnsupportedEncodingException e) { + } + + if (tags[i].UsageCnt > maxUsageCnt / 3 * 2) { + ret += "" + tag + " "; + } else if (tags[i].UsageCnt > maxUsageCnt / 3) { + ret += "" + tag + " "; + } 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 . + */ +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("
"); + out.println("
    "); + + 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("
  • " + Utils.encodeHTML(rs.getString(2)) + "
    " + rb.getString("Users online") + ": " + rs.getInt(3) + "
    " + chatid + "@chat.juick.com
  • "); + } + } catch (SQLException e) { + System.err.println(e); + } finally { + Utils.finishSQL(rs, stmt); + } + + out.println("
"); + out.println("
"); + + 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 . + */ +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("
"); + out.println("
"); + out.println("
"); + out.println("

" + rb.getString("Username") + ":

"); + out.println("

" + rb.getString("Password") + ":

"); + out.println("

"); + out.println("
"); + out.println("
"); + out.println("
"); + + 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 . + */ +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 GET 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 POST 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 . + */ +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"), "" + + "" + + ""); + PageTemplates.pageNavigation(out, locale, visitor); + PageTemplates.pageTitle(out, rb.getString("Messages on map")); + + out.println("
"); + out.println("
"); + out.println("
    "); + out.println("

    " + rb.getString("Popular places") + "

      "); + out.println("
      "); + out.println(""); + + 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 . + */ +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 . + */ +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(""); + out.println(""); + out.println(""); + out.println(" "); + out.println(" " + title + ""); + out.println(" "); + out.println(" "); + out.println(" "); + out.println(" "); + out.println(" "); + out.println(" "); + out.println(" "); + if (headers != null) { + out.println(headers); + } + out.println(""); + out.println(); + out.println(""); + } + + public static void pageNavigation(PrintWriter out, Locale loc, com.juick.User user) { + ResourceBundle rb = ResourceBundle.getBundle("Global", loc); + out.println("
      "); + out.println("
      \"Juick\"
      "); + out.println(" "); + out.println(" "); + out.println("
      "); + } + + public static void pageTitle(PrintWriter out, String title) { + out.println("
      "); + out.println("

      " + title + "

      "); + out.println("
      "); + } + + 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("
      "); + out.println("
      \""
      "); + out.println("
        "); + out.println("
      • " + rb.getString("(Stats) I read") + ": " + iread + "
      • "); + out.println("
      • " + rb.getString("(Stats) My readers") + ": " + myreaders + "
      • "); + out.println("
      • " + rb.getString("(Stats) Messages") + ": " + messages + "
      • "); + out.println("
      • " + rb.getString("(Stats) Replies") + ": " + replies + "
      • "); + out.println("
      "); + out.println("

      " + fullname + "

      " + description + "

      "); + out.println("
      "); + out.println(); + } + + public static void pageFooter(PrintWriter out, Locale loc) { + ResourceBundle rb = ResourceBundle.getBundle("Global", loc); + out.println("
      "); + out.println(" "); + out.println("
      juick.com © 2008-2011
      "); + out.println("
      "); + } + + 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("<", "<"); + tag = tag.replaceAll(">", ">"); + try { + ret += " *" + tag + ""; + } 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("&", "&"); + msg = msg.replaceAll("<", "<"); + msg = msg.replaceAll(">", ">"); + + // -- + // — + msg = msg.replaceAll("((?<=\\s)|(?<=\\A))\\-\\-?((?=\\s)|(?=\\Z))", "$1—$2"); + + // http://juick.com/last?page=2 + // juick.com + msg = msg.replaceAll("((?<=\\s)|(?<=\\A))((?:ht|f)tps?://(?:www\\.)?([^\\/\\s\\n\\\"]+)/?[^\\s\\n\\\"]*)", "$1$3"); + + // #12345 + // #12345 + msg = msg.replaceAll("((?<=\\s)|(?<=\\A)|(?<=[[:punct:]]))#(\\d+)((?=\\s)|(?=\\Z)|(?=\\))|(?=\\.)|(?=\\,))", "$1#$2$3"); + + // #12345/65 + // #12345/65 + msg = msg.replaceAll("((?<=\\s)|(?<=\\A)|(?<=[[:punct:]]))#(\\d+)/(\\d+)((?=\\s)|(?=\\Z)|(?=[[:punct:]]))", "$1#$2/$3$4"); + + // *bold* + // bold + msg = msg.replaceAll("((?<=\\s)|(?<=\\A)|(?<=[[:punct:]]))\\*([^\\*\\n<>]+)\\*((?=\\s)|(?=\\Z)|(?=[[:punct:]]))", "$1$2$3"); + + // /italic/ + // italic + msg = msg.replaceAll("((?<=\\s)|(?<=\\A))/([^\\/\\n<>]+)/((?=\\s)|(?=\\Z)|(?=[[:punct:]]))", "$1$2$3"); + + // _underline_ + // underline + msg = msg.replaceAll("((?<=\\s)|(?<=\\A))_([^\\_\\n<>]+)_((?=\\s)|(?=\\Z)|(?=[[:punct:]]))", "$1$2$3"); + + // /12 + // /12 + msg = msg.replaceAll("((?<=\\s)|(?<=\\A))\\/(\\d+)((?=\\s)|(?=\\Z)|(?=[[:punct:]]))", "$1/$2$3"); + + // @username@jabber.org + // @username@jabber.org + msg = msg.replaceAll("((?<=\\s)|(?<=\\A))@([\\w\\-\\|\\.]+@[\\w\\-\\.]+)((?=\\s)|(?=\\Z)|(?=[[:punct:]]))", "$1@$2$3"); + + // @username + // @username@jabber.org + msg = msg.replaceAll("((?<=\\s)|(?<=\\A))@([\\w\\-]+)((?=\\s)|(?=\\Z)|(?=[[:punct:]]))", "$1@$2$3"); + + // (http://juick.com/last?page=2) + // (juick.com) + msg = msg.replaceAll("((?<=\\s)|(?<=\\A))([\\(\\[\\{]|<)((?:ht|f)tps?://(?:www\\.)?([^\\/\\s\\n\\\"\\)\\!]+)/?[^\\s]*)([\\)\\]\\}]|>)", "$1$2$4$5"); + + // > citate + msg = msg.replaceAll("(?:(?<=\\n)|(?<=\\A))>\\s(.*)(\\n|(?=\\Z))", "
      $1
      "); + msg = msg.replaceAll("
      ", "\n"); + + msg = msg.replaceAll("\n", "
      \n"); + return msg; + } + + public static void printMessages(PrintWriter out, Connection sql, ArrayList 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("
    • "); + } else { + out.println("
    • "); + } + + if (rs.getString(12) != null) { + if (rs.getString(12).equals("jpg")) { + out.println("
      \"\"/
      "); + } else { + out.println("
      Attachment: Video
      "); + out.println(" "); + } + } + + out.println("
      "); + out.println(" "); + out.println("
      @" + uname + ":" + tags + "
      "); + out.println("
      " + txt + "
      "); + + if (rs.getInt(10) > 0) { + String repliesby = rs.getString(11); + if (repliesby == null) { + repliesby = "..."; + } + out.println("
      " + formatReplies(rs.getInt(10), locale) + " " + rb.getString("(replies) by") + " " + repliesby + "
      "); + } else { + out.println("
      "); + out.println("
      "); + out.println("
      "); + } + out.println("
    • "); + } + } 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 . + */ +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"), "" + + "" + + "" + + ""); + PageTemplates.pageNavigation(out, locale, visitor); + PageTemplates.pageTitle(out, rb.getString("Last photos and videos")); + + out.println("
      "); + out.println("
      Loading...
      "); + out.println("
        "); + + 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("
      • \"\"
      • "); + } else { + out.println("
      • \"\"
      • "); + } + } + } catch (SQLException e) { + System.err.println(e); + } finally { + Utils.finishSQL(rs, stmt); + } + + out.println("
      "); + out.println("
      "); + out.println(""); + + 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 . + */ +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 . + */ +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 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("
      "); + out.println("
      "); + out.println("
        "); + + if (mids.size() > 0) { + PageTemplates.printMessages(out, sql, mids, locale); + } + + out.println("
      "); + out.println(""); + + 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("

      Older →

      "); + } + + out.println("
      "); + + out.println("
      "); + out.println("

      " + rb.getString("(Menu) Messages") + "

      "); + out.println(""); + out.println("

      " + rb.getString("(Menu) Tags") + "

      "); + pageUserTags(out, sql, user, visitor, 15); + out.println("

      " + rb.getString("(Menu) Search") + "

      "); + out.println("

      "); + out.println("
      "); + out.println("
      "); + + 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 = "" + tag + ""; + } catch (UnsupportedEncodingException e) { + } + + if (tags[i].UsageCnt > maxUsageCnt / 3 * 2) { + out.print("" + tag + " "); + } else if (tags[i].UsageCnt > maxUsageCnt / 3) { + out.print("" + tag + " "); + } 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 . + */ +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("
      "); + out.println("
      "); + + out.println("
        "); + printMessage(out, sql, MID, locale); + out.println("
      "); + + out.println("
      "); + out.print(" "); + out.println("

      Replies

      "); + out.println("
      "); + + out.println("
        "); + printReplies(out, sql, MID, locale, listview); + out.println("
      "); + + out.println(""); + + out.println("
      "); + + out.println("
      "); + + 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("
    • "); + + if (rs.getString(11) != null) { + if (rs.getString(11).equals("jpg")) { + out.println("
      \"\"/
      "); + } else { + out.println("
      Attachment: Video
      "); + out.println(" "); + } + } + + out.println("
      "); + out.println(" "); + out.println("
      @" + uname + ":" + tags + "
      "); + out.println("
      " + txt + "
      "); + out.println("
    • "); + } + } 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 replies = new ArrayList(); + + 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 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("
    • 0) { + out.print("margin-left: " + margin + "px;display:none;"); + } + out.println("\">"); + if (msg.AttachmentType != null) { + if (msg.AttachmentType.equals("jpg")) { + out.println("
      \"\"/
      "); + } else { + out.println("
      Attachment: Video
      "); + out.println(" "); + } + } + out.println("
      "); + out.println(" "); + out.println(" "); + out.println("
      " + msg.Text + "
      "); + if (ReplyTo == 0) { + int childs = msg.getChildsCount() - 1; + if (childs > 0) { + out.println(" "); + } + } + out.println("
    • "); + + printTree(out, replies, msg.RID, margin + 20, locale); + } + } + } + + public static void printList(PrintWriter out, ArrayList replies, Locale locale) { + for (int i = 0; i < replies.size(); i++) { + com.juick.Message msg = replies.get(i); + + out.print("
    • "); + if (msg.AttachmentType != null) { + if (msg.AttachmentType.equals("jpg")) { + out.println("
      \"\"/
      "); + } else { + out.println("
      Attachment: Video
      "); + out.println(" "); + } + } + out.println("
      "); + out.println(" "); + out.println(" "); + out.println("
      " + msg.Text + "
      "); + out.println("
    • "); + } + } +} 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 . + */ +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 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("<", "<"); + ret = ret.replaceAll(">", ">"); + return str; + } + + public static String encodeSphinx(String str) { + String ret = str; + ret = ret.replaceAll("@", "\\\\@"); + return ret; + } +} -- cgit v1.2.3