aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--juick-core/src/main/java/com/juick/server/CrosspostQueries.java37
-rw-r--r--juick-core/src/main/java/com/juick/server/SubscriptionsQueries.java25
-rw-r--r--juick-core/src/main/java/com/juick/server/UserQueries.java66
-rw-r--r--juick-core/src/main/java/com/juick/server/helpers/ApplicationStatus.java25
-rw-r--r--juick-core/src/main/java/com/juick/server/helpers/Auth.java22
-rw-r--r--juick-core/src/main/java/com/juick/server/helpers/EmailOpts.java24
-rw-r--r--juick-core/src/main/java/com/juick/server/helpers/NotifyOpts.java34
-rw-r--r--juick-core/src/main/java/com/juick/server/helpers/UserInfo.java43
-rw-r--r--juick-www/build.gradle3
-rw-r--r--juick-www/src/main/java/com/juick/www/Main.java15
-rw-r--r--juick-www/src/main/java/com/juick/www/PageTemplates.java3
-rw-r--r--juick-www/src/main/java/com/juick/www/Settings.java264
-rw-r--r--juick-www/src/main/resources/views/partial/settings_tabs.html5
-rw-r--r--juick-www/src/main/resources/views/settings_about.html20
-rw-r--r--juick-www/src/main/resources/views/settings_auth-email.html9
-rw-r--r--juick-www/src/main/resources/views/settings_main.html156
-rw-r--r--juick-www/src/main/resources/views/settings_password.html17
-rw-r--r--juick-www/src/main/resources/views/settings_privacy.html9
-rw-r--r--juick-www/src/main/resources/views/settings_result.html9
-rw-r--r--juick-www/src/main/static/style.css4
20 files changed, 734 insertions, 56 deletions
diff --git a/juick-core/src/main/java/com/juick/server/CrosspostQueries.java b/juick-core/src/main/java/com/juick/server/CrosspostQueries.java
index 04898d0a..827dad09 100644
--- a/juick-core/src/main/java/com/juick/server/CrosspostQueries.java
+++ b/juick-core/src/main/java/com/juick/server/CrosspostQueries.java
@@ -17,6 +17,7 @@
*/
package com.juick.server;
+import com.juick.server.helpers.ApplicationStatus;
import org.apache.commons.lang3.tuple.Pair;
import org.springframework.dao.EmptyResultDataAccessException;
import org.springframework.jdbc.core.JdbcTemplate;
@@ -32,9 +33,7 @@ public class CrosspostQueries {
public static Optional<Pair<String, String>> getTwitterTokens(JdbcTemplate sql, int uid) {
try {
return sql.queryForObject("SELECT access_token,access_token_secret FROM twitter WHERE user_id=? AND crosspost=1",
- (rs, num) -> {
- return Optional.of(Pair.of(rs.getString(1), rs.getString(2)));
- }, uid);
+ (rs, num) -> Optional.of(Pair.of(rs.getString(1), rs.getString(2))), uid);
} catch (EmptyResultDataAccessException e) {
return Optional.empty();
}
@@ -48,13 +47,39 @@ public class CrosspostQueries {
return Optional.empty();
}
}
+ public static ApplicationStatus isFBCrossPostEnabled(JdbcTemplate sql, int uid) {
+ try {
+ return sql.queryForObject("SELECT 1, crosspost FROM facebook WHERE user_id=? LIMIT 1", (rs, num) -> {
+ ApplicationStatus status = new ApplicationStatus();
+ status.setConnected(rs.getInt(1) > 0);
+ status.setCrosspostEnabled(rs.getBoolean(2));
+ return status;
+ }, uid);
+ } catch (EmptyResultDataAccessException e) {
+ return new ApplicationStatus();
+ }
+ }
+
+ public static String getTwitterName(JdbcTemplate sql, int uid) {
+ try {
+ return sql.queryForObject("SELECT uname FROM twitter WHERE user_id=?", String.class, uid);
+ } catch (EmptyResultDataAccessException e) {
+ return "";
+ }
+ }
+
+ public static String getTelegramName(JdbcTemplate sql, int uid) {
+ try {
+ return sql.queryForObject("SELECT tg_name FROM telegram WHERE user_id=?", String.class, uid);
+ } catch (EmptyResultDataAccessException e) {
+ return "";
+ }
+ }
public static Optional<Pair<String, String>> getVKTokens(JdbcTemplate sql, int uid) {
try {
return sql.queryForObject("SELECT vk_id,access_token FROM vk WHERE user_id=? AND crosspost=1",
- (rs, num) -> {
- return Optional.of(Pair.of(rs.getString(1), rs.getString(2)));
- }, uid);
+ (rs, num) -> Optional.of(Pair.of(rs.getString(1), rs.getString(2))), uid);
} catch (EmptyResultDataAccessException e) {
return Optional.empty();
}
diff --git a/juick-core/src/main/java/com/juick/server/SubscriptionsQueries.java b/juick-core/src/main/java/com/juick/server/SubscriptionsQueries.java
index cedd2fd4..9a09a5cd 100644
--- a/juick-core/src/main/java/com/juick/server/SubscriptionsQueries.java
+++ b/juick-core/src/main/java/com/juick/server/SubscriptionsQueries.java
@@ -6,6 +6,8 @@ package com.juick.server;
import com.juick.Tag;
import com.juick.User;
+import com.juick.server.helpers.NotifyOpts;
+import org.springframework.dao.EmptyResultDataAccessException;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.util.StringUtils;
@@ -97,4 +99,27 @@ public class SubscriptionsQueries {
toTag.TID, user.getUID()) > 0;
}
+ public static NotifyOpts getNotifyOptions(JdbcTemplate sql, User user) {
+ try {
+ return sql.queryForObject("SELECT jnotify,subscr_notify,recommendations FROM useroptions WHERE user_id=?",
+ (rs, num) -> {
+ NotifyOpts options = new NotifyOpts();
+ options.setRepliesEnabled(rs.getInt(1) > 0);
+ options.setSubscriptionsEnabled(rs.getInt(2) > 0);
+ options.setRecommendationsEnabled(rs.getInt(3) > 0);
+ return options;
+ }, user.getUID());
+ } catch (EmptyResultDataAccessException e) {
+ return new NotifyOpts();
+ }
+ }
+
+ public static boolean setNotifyOptions(JdbcTemplate sql, User user, NotifyOpts options) {
+ return sql.update("UPDATE useroptions SET jnotify=? WHERE user_id=?", options.isRepliesEnabled() ? 1 : 0,
+ user.getUID()) > 0 &&
+ sql.update("UPDATE useroptions SET subscr_notify=? WHERE user_id=?", options.isSubscriptionsEnabled() ? 1 : 0,
+ user.getUID()) > 0 &&
+ sql.update("UPDATE useroptions SET recommendations=? WHERE user_id=?", options.isRecommendationsEnabled() ? 1 : 0,
+ user.getUID()) > 0;
+ }
}
diff --git a/juick-core/src/main/java/com/juick/server/UserQueries.java b/juick-core/src/main/java/com/juick/server/UserQueries.java
index b79f179c..50e3562f 100644
--- a/juick-core/src/main/java/com/juick/server/UserQueries.java
+++ b/juick-core/src/main/java/com/juick/server/UserQueries.java
@@ -18,6 +18,9 @@
package com.juick.server;
import com.juick.User;
+import com.juick.server.helpers.Auth;
+import com.juick.server.helpers.EmailOpts;
+import com.juick.server.helpers.UserInfo;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.dao.EmptyResultDataAccessException;
import org.springframework.jdbc.core.JdbcTemplate;
@@ -31,7 +34,6 @@ import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.*;
-import java.util.stream.Collectors;
/**
*
@@ -242,6 +244,18 @@ public class UserQueries {
}
}
+ public static boolean updatePassword(JdbcTemplate sql, User user, String newPassword) {
+ return user.getUID() > 0 && sql.update("UPDATE users SET passw=? WHERE id=?", newPassword, user.getUID()) > 0;
+ }
+
+ public static String updateSecretEmail(JdbcTemplate sql, User user) {
+ String newHash = generateHash(16);
+ if (sql.update("INSERT INTO mail(user_id,hash) VALUES (?,?) ON DUPLICATE KEY UPDATE hash=?", user.getUID(), newHash, newHash) > 0) {
+ return newHash;
+ }
+ return "";
+ }
+
public static int getUserOptionInt(JdbcTemplate sql, int uid, String option, int defaultValue) {
try {
return sql.queryForObject("SELECT " + option + " FROM useroptions WHERE user_id=?", Integer.class, uid);
@@ -254,6 +268,28 @@ public class UserQueries {
sql.update("UPDATE useroptions SET " + option + "=? WHERE user_id=?", value, uid);
}
+ public static UserInfo getUserInfo(JdbcTemplate sql, User user) {
+ try {
+ return sql.queryForObject("SELECT fullname,country,url,descr FROM usersinfo WHERE user_id=?", ((rs, rowNum) -> {
+ UserInfo info = new UserInfo();
+ info.setFullName(rs.getString(1));
+ info.setCountry(rs.getString(2));
+ info.setUrl(rs.getString(3));
+ info.setDescription(rs.getString(4));
+ return info;
+ }), user.getUID());
+ } catch (EmptyResultDataAccessException e) {
+ return new UserInfo();
+ }
+ }
+
+ public static boolean updateUserInfo(JdbcTemplate sql, User user, UserInfo info) {
+ return sql.update("INSERT INTO usersinfo(user_id,fullname,country,url,descr) VALUES (?,?,?,?,?) " +
+ "ON DUPLICATE KEY UPDATE fullname=?,country=?,url=?,descr=?", user.getUID(), info.getFullName(),
+ info.getCountry(), info.getUrl(), info.getDescription(), info.getFullName(),
+ info.getCountry(), info.getUrl(), info.getDescription()) > 0;
+ }
+
public static boolean getCanMedia(JdbcTemplate sql, int uid) {
try {
int res = sql.queryForObject("SELECT users.lastphoto-UNIX_TIMESTAMP() FROM users WHERE id=?",
@@ -429,4 +465,32 @@ public class UserQueries {
}
return false;
}
+ public static List<String> getAllJIDs(JdbcTemplate sql, User user) {
+ return sql.queryForList("SELECT jid FROM jids WHERE user_id=?", String.class, user.getUID());
+ }
+ public static List<Auth> getAuthCodes(JdbcTemplate sql, User user) {
+ return sql.query("SELECT account,authcode FROM auth WHERE user_id=? AND protocol='xmpp'",
+ (rs, num) -> new Auth(rs.getString(1), rs.getString(2)), user.getUID());
+ }
+
+ public static List<String> getEmails(JdbcTemplate sql, User user) {
+ return sql.queryForList("SELECT email FROM emails WHERE user_id=?", String.class, user.getUID());
+ }
+
+ public static EmailOpts getEmailOpts(JdbcTemplate sql, User user) {
+ try {
+ return sql.queryForObject("SELECT email,subscr_hour FROM emails WHERE user_id=? AND subscr_hour IS NOT NULL",
+ (rs, num) ->new EmailOpts(rs.getString(1), rs.getInt(2)), user.getUID());
+ } catch (EmptyResultDataAccessException e) {
+ return null;
+ }
+ }
+ public static String getEmailHash(JdbcTemplate sql, User user) {
+ try {
+ return sql.queryForObject("SELECT hash FROM mail WHERE user_id=?", String.class, user.getUID())
+ + "@mail.juick.com";
+ } catch (EmptyResultDataAccessException e) {
+ return "";
+ }
+ }
}
diff --git a/juick-core/src/main/java/com/juick/server/helpers/ApplicationStatus.java b/juick-core/src/main/java/com/juick/server/helpers/ApplicationStatus.java
new file mode 100644
index 00000000..986c8275
--- /dev/null
+++ b/juick-core/src/main/java/com/juick/server/helpers/ApplicationStatus.java
@@ -0,0 +1,25 @@
+package com.juick.server.helpers;
+
+/**
+ * Created by vt on 03/09/16.
+ */
+public class ApplicationStatus {
+ private boolean connected;
+ private boolean crosspostEnabled;
+
+ public boolean isConnected() {
+ return connected;
+ }
+
+ public void setConnected(boolean connected) {
+ this.connected = connected;
+ }
+
+ public boolean isCrosspostEnabled() {
+ return crosspostEnabled;
+ }
+
+ public void setCrosspostEnabled(boolean crosspostEnabled) {
+ this.crosspostEnabled = crosspostEnabled;
+ }
+}
diff --git a/juick-core/src/main/java/com/juick/server/helpers/Auth.java b/juick-core/src/main/java/com/juick/server/helpers/Auth.java
new file mode 100644
index 00000000..3e1f0bd9
--- /dev/null
+++ b/juick-core/src/main/java/com/juick/server/helpers/Auth.java
@@ -0,0 +1,22 @@
+package com.juick.server.helpers;
+
+/**
+ * Created by vt on 09/02/16.
+ */
+public class Auth {
+ private String account;
+ private String authCode;
+
+ public Auth(String account, String authCode) {
+ this.account = account;
+ this.authCode = authCode;
+ }
+
+ public String getAccount() {
+ return account;
+ }
+
+ public String getAuthCode() {
+ return authCode;
+ }
+} \ No newline at end of file
diff --git a/juick-core/src/main/java/com/juick/server/helpers/EmailOpts.java b/juick-core/src/main/java/com/juick/server/helpers/EmailOpts.java
new file mode 100644
index 00000000..679d1a8d
--- /dev/null
+++ b/juick-core/src/main/java/com/juick/server/helpers/EmailOpts.java
@@ -0,0 +1,24 @@
+package com.juick.server.helpers;
+
+import org.apache.commons.lang3.StringUtils;
+
+/**
+ * Created by vitalyster on 09.02.2016.
+ */
+public class EmailOpts {
+ private String email;
+ private String subscriptionHour;
+
+ public EmailOpts(String email, int subscriptionHour) {
+ this.email = email;
+ this.subscriptionHour = StringUtils.leftPad(String.format("%d", subscriptionHour), 2, "0");
+ }
+
+ public String getSubscriptionHour() {
+ return subscriptionHour;
+ }
+
+ public String getEmail() {
+ return email;
+ }
+} \ No newline at end of file
diff --git a/juick-core/src/main/java/com/juick/server/helpers/NotifyOpts.java b/juick-core/src/main/java/com/juick/server/helpers/NotifyOpts.java
new file mode 100644
index 00000000..377b0a50
--- /dev/null
+++ b/juick-core/src/main/java/com/juick/server/helpers/NotifyOpts.java
@@ -0,0 +1,34 @@
+package com.juick.server.helpers;
+
+/**
+ * Created by vt on 03/09/16.
+ */
+public class NotifyOpts {
+ private boolean repliesEnabled;
+ private boolean subscriptionsEnabled;
+ private boolean recommendationsEnabled;
+
+ public boolean isRepliesEnabled() {
+ return repliesEnabled;
+ }
+
+ public void setRepliesEnabled(boolean repliesEnabled) {
+ this.repliesEnabled = repliesEnabled;
+ }
+
+ public boolean isSubscriptionsEnabled() {
+ return subscriptionsEnabled;
+ }
+
+ public void setSubscriptionsEnabled(boolean subscriptionsEnabled) {
+ this.subscriptionsEnabled = subscriptionsEnabled;
+ }
+
+ public boolean isRecommendationsEnabled() {
+ return recommendationsEnabled;
+ }
+
+ public void setRecommendationsEnabled(boolean recommendationsEnabled) {
+ this.recommendationsEnabled = recommendationsEnabled;
+ }
+}
diff --git a/juick-core/src/main/java/com/juick/server/helpers/UserInfo.java b/juick-core/src/main/java/com/juick/server/helpers/UserInfo.java
new file mode 100644
index 00000000..5a4b6894
--- /dev/null
+++ b/juick-core/src/main/java/com/juick/server/helpers/UserInfo.java
@@ -0,0 +1,43 @@
+package com.juick.server.helpers;
+
+/**
+ * Created by vt on 03/09/16.
+ */
+public class UserInfo {
+ private String fullName;
+ private String country;
+ private String url;
+ private String description;
+
+ public String getFullName() {
+ return fullName;
+ }
+
+ public void setFullName(String fullName) {
+ this.fullName = fullName;
+ }
+
+ public String getCountry() {
+ return country;
+ }
+
+ public void setCountry(String country) {
+ this.country = country;
+ }
+
+ public String getUrl() {
+ return url;
+ }
+
+ public void setUrl(String url) {
+ this.url = url;
+ }
+
+ public String getDescription() {
+ return description;
+ }
+
+ public void setDescription(String description) {
+ this.description = description;
+ }
+}
diff --git a/juick-www/build.gradle b/juick-www/build.gradle
index 891ee8f6..bebfaddc 100644
--- a/juick-www/build.gradle
+++ b/juick-www/build.gradle
@@ -38,6 +38,7 @@ dependencies {
compile 'com.github.ooxi:serialized-php-parser:0.5.0'
compile 'net.jodah:failsafe:0.9.2'
compile 'com.mitchellbosecke:pebble:2.2.2'
+ compile 'com.sun.mail:javax.mail:1.5.6'
providedCompile 'javax.servlet:javax.servlet-api:3.1.0'
providedRuntime 'mysql:mysql-connector-java:5.1.39'
}
@@ -50,4 +51,4 @@ gretty {
httpPort = 8080
contextPath = ''
servletContainer = 'tomcat8'
-} \ No newline at end of file
+}
diff --git a/juick-www/src/main/java/com/juick/www/Main.java b/juick-www/src/main/java/com/juick/www/Main.java
index c67eced0..231c7f89 100644
--- a/juick-www/src/main/java/com/juick/www/Main.java
+++ b/juick-www/src/main/java/com/juick/www/Main.java
@@ -194,6 +194,7 @@ public class Main extends HttpServlet implements Stream.StreamListener {
pm.doGetSent(sql, request, response, visitor);
} catch (PebbleException e) {
log("pebble exception", e);
+ response.sendError(500);
}
break;
default:
@@ -212,7 +213,12 @@ public class Main extends HttpServlet implements Stream.StreamListener {
} else if (uri.equals("/logout")) {
login.doGetLogout(sql, request, response);
} else if (uri.equals("/settings")) {
- settings.doGet(sql, request, response);
+ try {
+ settings.doGet(sql, request, response);
+ } catch (PebbleException e) {
+ log("pebble exception", e);
+ response.sendError(500);
+ }
} else if (uri.equals("/_fblogin")) {
loginFacebook.doGet(sql, request, response);
} else if (uri.equals("/_vklogin")) {
@@ -350,7 +356,12 @@ public class Main extends HttpServlet implements Stream.StreamListener {
signup.doPost(sql, request, response);
break;
case "/settings":
- settings.doPost(sql, request, response);
+ try {
+ settings.doPost(sql, request, response);
+ } catch (PebbleException e) {
+ log("pebble exception", e);
+ response.sendError(500);
+ }
break;
default:
response.sendError(405);
diff --git a/juick-www/src/main/java/com/juick/www/PageTemplates.java b/juick-www/src/main/java/com/juick/www/PageTemplates.java
index c3b0d6f8..a036ecba 100644
--- a/juick-www/src/main/java/com/juick/www/PageTemplates.java
+++ b/juick-www/src/main/java/com/juick/www/PageTemplates.java
@@ -23,7 +23,6 @@ import com.juick.server.MessagesQueries;
import com.juick.server.TagQueries;
import com.juick.server.UserQueries;
import org.apache.commons.lang3.StringEscapeUtils;
-import com.mitchellbosecke.pebble.PebbleEngine;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.util.StringUtils;
import ru.sape.Sape;
@@ -39,8 +38,6 @@ import java.util.Date;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
import java.util.stream.Collectors;
/**
diff --git a/juick-www/src/main/java/com/juick/www/Settings.java b/juick-www/src/main/java/com/juick/www/Settings.java
index 6364c869..c04a63fb 100644
--- a/juick-www/src/main/java/com/juick/www/Settings.java
+++ b/juick-www/src/main/java/com/juick/www/Settings.java
@@ -17,75 +17,253 @@
*/
package com.juick.www;
+import com.juick.server.CrosspostQueries;
+import com.juick.server.SubscriptionsQueries;
+import com.juick.server.TagQueries;
+import com.juick.server.UserQueries;
+import com.juick.server.helpers.NotifyOpts;
+import com.juick.server.helpers.UserInfo;
+import com.mitchellbosecke.pebble.error.PebbleException;
+import com.mitchellbosecke.pebble.template.PebbleTemplate;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.dao.EmptyResultDataAccessException;
import org.springframework.jdbc.core.JdbcTemplate;
+import javax.mail.Message;
+import javax.mail.MessagingException;
+import javax.mail.Session;
+import javax.mail.Transport;
+import javax.mail.internet.InternetAddress;
+import javax.mail.internet.MimeMessage;
import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import java.util.stream.Collectors;
+import java.util.stream.IntStream;
/**
*
* @author Ugnich Anton
*/
public class Settings {
+ private static final Logger logger = Logger.getLogger(Settings.class.getName());
- protected void doGet(JdbcTemplate sql, HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
+ protected void doGet(JdbcTemplate sql, HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException, PebbleException {
com.juick.User visitor = Utils.getVisitorUser(sql, request, response);
+ if (visitor.getUID() == 0) {
+ response.sendRedirect("/login");
+ }
+ List<String> pages = Arrays.asList("main", "password", "about", "auth-email", "privacy");
+ String page = request.getParameter("page");
+ if (StringUtils.isEmpty(page) || !pages.contains(page)) {
+ page = "main";
+ }
response.setContentType("text/html; charset=UTF-8");
try (PrintWriter out = response.getWriter()) {
- PageTemplates.pageHead(out, visitor, "Логин", "");
- PageTemplates.pageNavigation(out, visitor, null);
-
- out.println("<div id=\"topwrapper\">");
- out.println("<div id=\"wrapper\">");
- out.println("<div id=\"content\">");
- out.println("<form action=\"/login\" method=\"post\">");
- out.println("<p>Имя пользователя: <input type=\"text\" name=\"username\"/></p>");
- out.println("<p>Пароль: <input type=\"password\" name=\"password\"/></p>");
- out.println("<p><input type=\"submit\" value=\" OK \"/></p>");
- out.println("</form>");
- out.println("</div>");
- out.println("</div>");
- out.println("</div>"); // topwrapper
-
- PageTemplates.pageFooter(request, out, visitor, false);
- PageTemplates.pageEnd(out);
+ PebbleTemplate template = Utils.getEngine().getTemplate(String.format("views/settings_%s.html", page));
+ Map<String, Object> context = new HashMap<>();
+ context.put("title", "Настройки");
+ context.put("visitor", visitor);
+ context.put("tags", TagQueries.getPopularTags(sql));
+ context.put("auths", UserQueries.getAuthCodes(sql, visitor));
+ context.put("eopts", UserQueries.getEmailOpts(sql, visitor));
+ context.put("ehash", UserQueries.getEmailHash(sql, visitor));
+ context.put("emails", UserQueries.getEmails(sql, visitor));
+ context.put("jids", UserQueries.getAllJIDs(sql, visitor));
+ List<String> hours = IntStream.rangeClosed(0, 23).boxed()
+ .map(i -> StringUtils.leftPad(String.format("%d", i), 2, "0")).collect(Collectors.toList());
+ context.put("hours", hours);
+ context.put("fbstatus", CrosspostQueries.isFBCrossPostEnabled(sql, visitor.getUID()));
+ context.put("twitter_name", CrosspostQueries.getTwitterName(sql, visitor.getUID()));
+ context.put("telegram_name", CrosspostQueries.getTelegramName(sql, visitor.getUID()));
+ context.put("notify_options", SubscriptionsQueries.getNotifyOptions(sql, visitor));
+ context.put("userinfo", UserQueries.getUserInfo(sql, visitor));
+ if (page.equals("auth-email")) {
+ try {
+ String account = sql.queryForObject("SELECT account FROM auth WHERE user_id=? AND protocol='email' AND authcode=?",
+ String.class, visitor.getUID(), request.getParameter("code"));
+ sql.update("INSERT INTO emails(user_id,email) VALUES (?,?)", visitor.getUID(), account);
+ sql.update("DELETE FROM auth WHERE user_id=? AND authcode=?", visitor.getUID(), request.getParameter("code"));
+ context.put("result", "OK!");
+ } catch (EmptyResultDataAccessException e) {
+ context.put("result", "Sorry, code unknown.");
+ }
+ }
+ template.evaluate(out, context);
}
}
- protected void doPost(JdbcTemplate 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 || password.isEmpty()) {
+ protected void doPost(JdbcTemplate sql, HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException, PebbleException {
+ com.juick.User visitor = Utils.getVisitorUser(sql, request, response);
+ if (visitor.getUID() == 0) {
response.sendError(400);
return;
}
+ List<String> pages = Arrays.asList("main", "password", "about", "email", "email-add", "email-del",
+ "email-subscr", "auth-email", "privacy", "jid-del", "twitter-del", "telegram-del", "facebook-disable",
+ "facebook-enable", "vk-del");
+ String page = request.getParameter("page");
+ if (StringUtils.isEmpty(page) || !pages.contains(page)) {
+ response.sendError(400);
+ return;
+ }
+ String result = "";
+ switch (page) {
+ case "password":
+ if (UserQueries.updatePassword(sql, visitor, request.getParameter("password"))) {
+ result = "<p>Password has been changed.</p>";
+ String hash = com.juick.server.UserQueries.getHashByUID(sql, visitor.getUID());
+ Cookie c = new Cookie("hash", hash);
+ c.setMaxAge(365 * 24 * 60 * 60);
+ response.addCookie(c);
+ }
+ break;
+ case "main":
+ NotifyOpts opts = new NotifyOpts();
+ opts.setRepliesEnabled(StringUtils.isNotEmpty(request.getParameter("jnotify")));
+ opts.setSubscriptionsEnabled(StringUtils.isNotEmpty(request.getParameter("subscr_notify")));
+ opts.setRecommendationsEnabled(StringUtils.isNotEmpty(request.getParameter("recomm")));
+ if (SubscriptionsQueries.setNotifyOptions(sql, visitor, opts)) {
+ result = "<p>Notification options has been updated</p>";
+ }
+ break;
+ case "about":
+ UserInfo info = new UserInfo();
+ info.setFullName(request.getParameter("fullname"));
+ info.setCountry(request.getParameter("country"));
+ info.setUrl(request.getParameter("url"));
+ info.setDescription(request.getParameter("descr"));
+ if (UserQueries.updateUserInfo(sql, visitor, info)) {
+ result = String.format("<p>Your info is updated.</p><p><a href='/%s/'>Back to blog</a>.</p>", visitor.getUName());
+ }
+ break;
+ case "jid-del":
+ String[] params = request.getParameter("delete").split(";", 2);
+ int res = -1;
+ if (params[0].equals("xmpp")) {
+ res = sql.update("DELETE FROM jids WHERE user_id=? AND jid=?", visitor.getUID(), params[1]);
+ } else if (params[0].equals("xmpp-unauth")) {
+ res = sql.update("DELETE FROM auth WHERE user_id=? AND protocol='xmpp' AND account=?", visitor.getUID(), params[1]);
+ }
+ if (res == 1) {
+ result = "<p>Deleted. <a href=\"/settings\">Back</a>.</p>";
+ } else {
+ result = "<p>Error</p>";
+ }
+ break;
+ case "email":
+ String newHash = UserQueries.updateSecretEmail(sql, visitor);
+ if (StringUtils.isNotEmpty(newHash)) {
+ result = String.format("<p>New secret email: <strong>%s@mail.juick.com</strong></p>" +
+ "<p><a href=\"/settings\">Back</a>.</p>", newHash);
+ } else {
+ response.sendError(500);
+ return;
+ }
+ break;
+ case "email-add":
+ try {
+ sql.queryForObject("SELECT authcode FROM auth WHERE user_id=? AND protocol='email' " +
+ "AND account=?", String.class, visitor.getUID(), request.getParameter("account"));
+ } catch (EmptyResultDataAccessException e) {
+ String authCode = UserQueries.generateHash(8);
+ if (sql.update("INSERT INTO auth(user_id,protocol,account,authcode) VALUES (?,'email',?,?)",
+ visitor.getUID(), request.getParameter("account"), authCode) > 0) {
+ Session session = Session.getDefaultInstance(System.getProperties());
+ try {
+ MimeMessage message = new MimeMessage(session);
+ message.setFrom(new InternetAddress("noreply@mail.juick.com"));
+ message.addRecipient(Message.RecipientType.TO, new InternetAddress(request.getParameter("account")));
+ message.setSubject("Juick authorization link");
+ message.setText(String.format("Follow link to attach this email to Juick account:\n" +
+ "http://juick.com/settings?page=auth-email&code=%s\n\n" +
+ "If you don't know, what this mean - just ignore this mail.\n", authCode));
+ Transport.send(message);
+ result = "<p>Authorization link has been sent to your email. Follow it to proceed.</p>" +
+ "<p><a href=\"/settings\">Back</a></p>";
- 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(365 * 24 * 60 * 60);
- response.addCookie(c);
-
-
- if (uid > 0) {
- throw new IOException("Settings");
- }
-
- String referer = request.getHeader("Referer");
- if (referer != null && referer.startsWith("http://juick.com/") && !referer.equals("http://juick.com/login")) {
- response.sendRedirect(referer);
- } else {
- response.sendRedirect("/");
- }
- } else {
- response.sendError(403);
+ } catch (MessagingException ex) {
+ logger.log(Level.SEVERE, "mail exception", ex);
+ response.sendError(500);
+ return;
+ }
+ }
+ }
+ break;
+ case "email-del":
+ if (sql.update("DELETE FROM emails WHERE user_id=? AND email=?", visitor.getUID(), request.getParameter("account")) > 0) {
+ result = "<p>Deleted. <a href=\"/settings\">Back</a>.</p>";
+ } else {
+ result = "<p>An error occured while deleting.</p>";
+ }
+ break;
+ case "email-subscr":
+ sql.update("UPDATE emails SET subscr_hour=NULL WHERE user_id=?", visitor.getUID());
+ String email = request.getParameter("account");
+ if (StringUtils.isNotEmpty(email)) {
+ sql.update("UPDATE emails SET subscr_hour=? WHERE user_id=? AND email=?",
+ request.getParameter("time"), visitor.getUID(), email);
+ result = String.format("<p>Saved! Will send to <strong>%s</strong> at <strong>%s:00 GMT</strong>." +
+ "</p><p><a href=\"/settings\">Back</a></p>", email, request.getParameter("time"));
+ } else {
+ result = "<p>Disabled.</p><p><a href=\"/settings\">Back</a></p>";
+ }
+ break;
+ case "twitter-del":
+ sql.update("DELETE FROM twitter WHERE user_id=?", visitor.getUID());
+ sql.update("DELETE FROM subscr_users WHERE user_id=? AND suser_id=1741", visitor.getUID());
+ for (Cookie cookie : request.getCookies()) {
+ if (cookie.getName().equals("request_token")) {
+ cookie.setMaxAge(0);
+ response.addCookie(cookie);
+ }
+ if (cookie.getName().equals("request_token_secret")) {
+ cookie.setMaxAge(0);
+ response.addCookie(cookie);
+ }
+ }
+ result = "<p><a href=\"/settings\">Back</a></p>";
+ break;
+ case "telegram-del":
+ sql.update("DELETE FROM telegram WHERE user_id=?", visitor.getUID());
+ result = "<p><a href=\"/settings\">Back</a></p>";
+ break;
+ case "facebook-disable":
+ sql.update("UPDATE facebook SET crosspost=0 WHERE user_id=?", visitor.getUID());
+ sql.update("DELETE FROM subscr_users WHERE user_id=? AND suser_id=5863", visitor.getUID());
+ result = "<p><a href=\"/settings\">Back</a></p>";
+ break;
+ case "facebook-enable":
+ sql.update("UPDATE facebook SET crosspost=1 WHERE user_id=?", visitor.getUID());
+ sql.update("INSERT INTO subscr_users(user_id,suser_id,jid,active) VALUES (?,5863,'juick@facebook.juick.com',1)", visitor.getUID());
+ result = "<p><a href=\"/settings\">Back</a></p>";
+ break;
+ case "vk-del":
+ sql.update("DELETE FROM vk WHERE user_id=?", visitor.getUID());
+ result = "<p><a href=\"/settings\">Back</a></p>";
+ break;
+ default:
+ response.sendError(400);
+ return;
+ }
+ response.setContentType("text/html; charset=UTF-8");
+ try (PrintWriter out = response.getWriter()) {
+ PebbleTemplate template = Utils.getEngine().getTemplate("views/settings_result.html");
+ Map<String, Object> context = new HashMap<>();
+ context.put("title", "Настройки");
+ context.put("visitor", visitor);
+ context.put("result", result);
+ template.evaluate(out, context);
}
}
}
diff --git a/juick-www/src/main/resources/views/partial/settings_tabs.html b/juick-www/src/main/resources/views/partial/settings_tabs.html
new file mode 100644
index 00000000..d7901d5e
--- /dev/null
+++ b/juick-www/src/main/resources/views/partial/settings_tabs.html
@@ -0,0 +1,5 @@
+<div id="pagetabs"><ul>
+ <li><a href="/settings">Main</a></li>
+ <li><a href="/settings?page=password">Password</a></li>
+ <li><a href="/settings?page=about">About</a></li>
+</ul></div> \ No newline at end of file
diff --git a/juick-www/src/main/resources/views/settings_about.html b/juick-www/src/main/resources/views/settings_about.html
new file mode 100644
index 00000000..0252af35
--- /dev/null
+++ b/juick-www/src/main/resources/views/settings_about.html
@@ -0,0 +1,20 @@
+{% extends "layouts/content.html" %}
+{% block content %}
+<article>
+ <form action="/settings" method="POST" enctype="multipart/form-data">
+ <p>Full name: <input type="text" name="fullname" value="{{ userinfo.getFullName() }}"/></p>
+ <p>Country: <input type="text" name="country" value="{{ userinfo.getCountry() }}"/></p>
+ <p>URL: <input type="text" name="url" value="{{ userinfo.getUrl() }}" size="32"/><br/>
+ <small>Please, start with &quot;http://&quot;</small></p>
+ <p>About:<br/>
+ <input type="text" name="descr" value="{{ userinfo.getDescription() }}" style="width: 100%"/><br/>
+ <small>Max. 255 symbols</small></p>
+ <p>Avatar: <input type="file" name="avatar"/><br/>
+ <small>Recommendations: PNG, 96x96, &lt;50Kb. Also, JPG and GIF supported.</small></p>
+ <p><input type="hidden" name="page" value="about"/><input type="submit" value=" OK "/></p>
+ </form>
+</article>
+{% endblock %}
+{% block "column" %}
+{% include "views/partial/settings_tabs.html" %}
+{% endblock %} \ No newline at end of file
diff --git a/juick-www/src/main/resources/views/settings_auth-email.html b/juick-www/src/main/resources/views/settings_auth-email.html
new file mode 100644
index 00000000..79691083
--- /dev/null
+++ b/juick-www/src/main/resources/views/settings_auth-email.html
@@ -0,0 +1,9 @@
+{% extends "layouts/content.html" %}
+{% block content %}
+<article>
+ <p>{{ result }}</p><p><a href="/settings">Settings</a>.</p>
+</article>
+{% endblock %}
+{% block "column" %}
+{% include "views/partial/settings_tabs.html" %}
+{% endblock %} \ No newline at end of file
diff --git a/juick-www/src/main/resources/views/settings_main.html b/juick-www/src/main/resources/views/settings_main.html
new file mode 100644
index 00000000..f4630be2
--- /dev/null
+++ b/juick-www/src/main/resources/views/settings_main.html
@@ -0,0 +1,156 @@
+{% extends "layouts/content.html" %}
+{% block content %}
+<article>
+ <h1>Настройки</h1>
+ <form action="/settings" method="POST" enctype="multipart/form-data">
+ <fieldset>
+ <legend>Notification options</legend>
+ <p><input type="checkbox" name="jnotify" value="1" {% if notify_options.isRepliesEnabled() %}
+ checked="checked" {% endif %}/> Reply notifications (&quot;Message posted&quot;)</p>
+ <p><input type="checkbox" name="subscr_notify" value="1" {% if notify_options.isSubscriptionsEnabled() %}
+ checked="checked" {% endif %}/> Subscriptions notifications (&quot;@user subscribed...&quot;)</p>
+ <p><input type="checkbox" name="recomm" value="1" {% if notify_options.isRecommendationsEnabled() %}
+ checked="checked" {% endif %}/> Posts recommendations (&quot;Recommended by @user&quot;)</p>
+ <p><input type="hidden" name="page" value="main"/><input type="submit" value=" OK "/></p>
+ </fieldset>
+ </form>
+ <fieldset>
+ <legend style="background: url(//telegram.org/favicon.ico?3) no-repeat; padding-left: 58px; line-height: 48px;">
+ Telegram</legend>
+ {% if telegram_name is not empty %}
+ <form action="/settings" method="post">
+ <div>Telegram: <b>{{ telegram_name }}</b> &mdash;
+ <input type="hidden" name="page" value="telegram-del"/>
+ <input type="submit" value=" Disable "/>
+ </div>
+ </form>
+ {% else %}
+ <p>To connect Telegram account: send any text message to <a href="https://telegram.me/Juick_bot">@Juick_bot</a>
+ </p>
+ {% endif %}
+ </fieldset>
+ <form action="/settings" method="POST" enctype="multipart/form-data">
+ <fieldset>
+ <legend style="background: url(//static.juick.com/settings/xmpp.png) no-repeat; padding-left: 58px; line-height: 48px;">
+ XMPP accounts
+ </legend>
+ <p>Your accounts:</p>
+ <p>
+ {% for jid in jids %}
+ <label><input type="radio" name="delete" value="xmpp;{{ jid }}">{{ jid }}</label><br/>
+ {% endfor %}
+ {% for auth in auths %}
+ <label><input type="radio" name="delete"
+ value="xmpp-unauth;{{ auth.getAccount() }}">{{ auth.getAccount() }}</label>
+ &mdash; <a href="#"
+ onclick="alert(\'To confirm, please send &quot;AUTH {{ auth.getAuthCode() }}&quot; (without quotes) from this account to &quot;juick@juick.com&quot;.\'); return false;">Confirm</a><br/>
+ {% endfor %}
+ </p>
+ {% if jids is not empty %}
+ <p><input type="hidden" name="page" value="jid-del"/><input type="submit" value=" Delete "/></p>
+ {% endif %}
+ <p>To add new jabber account: send any text message to <a href="xmpp:juick@juick.com?message;body=login">juick@juick.com</a>
+ </p>
+ </fieldset>
+ </form>
+ <fieldset>
+ <legend style="background: url(//static.juick.com/settings/email.png) no-repeat; padding-left: 58px; line-height: 48px;">
+ E-mail
+ </legend>
+ <form action="/settings" method="POST" enctype="multipart/form-data">
+ <p>Add account:<br/>
+ <input type="text" name="account"/>
+ <input type="hidden" name="page" value="email-add"/>
+ <input type="submit" value=" Add "/>
+ </p>
+ </form>
+ <form action="/settings" method="POST" enctype="multipart/form-data">
+ <p>Your accounts:</p>
+ <p>
+ {% for email in emails %}
+ <label><input type="radio" name="account" value="{{ email }}">{{ email }}</label><br/>
+ {% endfor %}
+ {% if emails is empty %}
+ - </p>
+ {% else %}
+ </p>
+ <p><input type="hidden" name="page" value="email-del"/><input type="submit" value=" Delete "/></p>
+ {% endif %}
+ </form>
+ {% if emails is not empty %}
+ <form action="/settings" method="POST" enctype="multipart/form-data">
+ <p>You can receive all your subscriptions by email:<br/>
+ Sent to <select name="account">
+ <option value="">Disabled</option>
+ {% for email in emails %}
+ <option value="{{ email }}" {% if eopts.getEmail()== email %} selected="selected" {% endif %}>
+ {{ email }}
+ </option>
+ {% endfor %}
+ </select> every day at <select name="time">
+ {% for hour in hours %}
+ <option value="{{ hour }}" {% if eopts.getSubscriptionHour() == hour %} selected="selected" {%
+ endif %}>
+ {{ hour }}:00 GMT
+ </option>
+ {% endfor %}
+ </select>
+ <input type="hidden" name="page" value="email-subscr"/>
+ <input type="submit" value="OK"/></p>
+ </form>
+ {% endif %}
+ <p>&nbsp;</p>
+ <p>You can post to Juick via e-mail. Send your <span style="text-decoration: underline">plain text</span>
+ messages to special secret e-mail. You can attach one photo or video file.</p>
+ <p>Secret email: {% if ehash is not empty %} <strong>{{ ehash }}</strong> {% else %}-{% endif %}</p>
+ <form action="/settings" method="post">
+ <p><input type="hidden" name="page" value="email"/><input type="submit" value=" Generate new "/></p>
+ </form>
+ </fieldset>
+ <fieldset>
+ <legend style="background: url(//static.juick.com/settings/facebook.png) no-repeat; padding-left: 58px; line-height: 48px;">
+ Facebook
+ </legend>
+ {% if fbstatus.isConnected() %}
+ {% if fbstatus.isCrosspostEnabled() %}
+ <form action="/settings" method="post">
+ <div>
+ Facebook: <b>Enabled</b> &mdash;
+ <input type="hidden" name="page" value="facebook-disable"/>
+ <input type="submit" value=" Disable "/>
+ </div>
+ </form>
+ {% else %}
+ <form action="/settings" method="post">
+ <div>
+ Facebook: <b>Disabled</b> &mdash;
+ <input type="hidden" name="page" value="facebook-enable"/>
+ <input type="submit" value=" Enable "/>
+ </div>
+ </form>
+ {% endif %}
+ {% else %}
+ <p>Cross-posting to Facebook: <a href="/_fblogin"><img src="//static.juick.com/facebook-connect.png" alt="Connect to Facebook"/></a></p>
+ {% endif %}
+ </fieldset>
+ <fieldset>
+ <legend style="background: url(//static.juick.com/settings/twitter.png) no-repeat; padding-left: 58px; line-height: 48px;">
+ Twitter</legend>
+ {% if twitter_name is not empty %}
+ <form action="/settings" method="post">
+ <div>Twitter: <b>{{ twitter_name }}</b> &mdash;
+ <input type="hidden" name="page" value="twitter-del"/>
+ <input type="submit" value=" Disable "/>
+ </div>
+ </form>
+ {% else %}
+ <p>Cross-posting to Twitter: <a href="/_twitter"><img src="//static.juick.com/twitter-connect.png"
+ alt="Connect to Twitter"/></a></p>
+ {% endif %}
+ </fieldset>
+
+</article>
+{% endblock %}
+{% block "column" %}
+{% include "views/partial/settings_tabs.html" %}
+{% endblock %} \ No newline at end of file
diff --git a/juick-www/src/main/resources/views/settings_password.html b/juick-www/src/main/resources/views/settings_password.html
new file mode 100644
index 00000000..e9c2dce0
--- /dev/null
+++ b/juick-www/src/main/resources/views/settings_password.html
@@ -0,0 +1,17 @@
+{% extends "layouts/content.html" %}
+{% block content %}
+<article>
+ <fieldset>
+ <legend>Changing your password</legend>
+ <form action="/settings" method="post">
+ <input type="hidden" name="page" value="password"/>
+ <p>Change password: <input type="password" name="password" size="8"/> <input type="submit"
+ value=" Update "/><br/>
+ <i>(max. length - 16 symbols)</i></p>
+ </form>
+ </fieldset>
+</article>
+{% endblock %}
+{% block "column" %}
+{% include "views/partial/settings_tabs.html" %}
+{% endblock %} \ No newline at end of file
diff --git a/juick-www/src/main/resources/views/settings_privacy.html b/juick-www/src/main/resources/views/settings_privacy.html
new file mode 100644
index 00000000..48756d8e
--- /dev/null
+++ b/juick-www/src/main/resources/views/settings_privacy.html
@@ -0,0 +1,9 @@
+{% extends "layouts/content.html" %}
+{% block content %}
+<article>
+ <p>Privacy</p>
+</article>
+{% endblock %}
+{% block "column" %}
+{% include "views/partial/settings_tabs.html" %}
+{% endblock %} \ No newline at end of file
diff --git a/juick-www/src/main/resources/views/settings_result.html b/juick-www/src/main/resources/views/settings_result.html
new file mode 100644
index 00000000..3f5482d4
--- /dev/null
+++ b/juick-www/src/main/resources/views/settings_result.html
@@ -0,0 +1,9 @@
+{% extends "layouts/content.html" %}
+{% block content %}
+<article>
+ <p>{{ result | raw }}</p>
+</article>
+{% endblock %}
+{% block "column" %}
+{% include "views/partial/settings_tabs.html" %}
+{% endblock %} \ No newline at end of file
diff --git a/juick-www/src/main/static/style.css b/juick-www/src/main/static/style.css
index a80d58fa..e7c6f2cc 100644
--- a/juick-www/src/main/static/style.css
+++ b/juick-www/src/main/static/style.css
@@ -235,6 +235,10 @@ q { border-left: 1px dashed #CCC; margin: 10px 0 10px 10px; padding-left: 10px;
.icon--ei-comment {
margin-top: -3px;
}
+fieldset {
+ margin-top: 25px;
+ border: 1px dotted #ccc;
+}
/******************************************************************************/
@media screen and (max-width: 850px) {