diff options
34 files changed, 811 insertions, 103 deletions
diff --git a/juick-api/src/main/java/com/juick/api/controllers/Messages.java b/juick-api/src/main/java/com/juick/api/controllers/Messages.java index f30a7687..723d2f15 100644 --- a/juick-api/src/main/java/com/juick/api/controllers/Messages.java +++ b/juick-api/src/main/java/com/juick/api/controllers/Messages.java @@ -3,8 +3,8 @@ package com.juick.api.controllers; import com.juick.Tag; import com.juick.User; import com.juick.api.ApiServer; -import com.juick.api.util.HttpBadRequestException; -import com.juick.api.util.HttpForbiddenException; +import com.juick.server.util.HttpBadRequestException; +import com.juick.server.util.HttpForbiddenException; import com.juick.server.helpers.Status; import com.juick.service.MessagesService; import com.juick.service.TagService; diff --git a/juick-api/src/main/java/com/juick/api/controllers/Notifications.java b/juick-api/src/main/java/com/juick/api/controllers/Notifications.java index ff3679c0..cd31ad39 100644 --- a/juick-api/src/main/java/com/juick/api/controllers/Notifications.java +++ b/juick-api/src/main/java/com/juick/api/controllers/Notifications.java @@ -4,8 +4,8 @@ import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.databind.ObjectMapper; import com.juick.Message; import com.juick.User; -import com.juick.api.util.HttpBadRequestException; -import com.juick.api.util.HttpForbiddenException; +import com.juick.server.util.HttpBadRequestException; +import com.juick.server.util.HttpForbiddenException; import com.juick.server.helpers.Status; import com.juick.server.helpers.TokensList; import com.juick.service.MessagesService; diff --git a/juick-api/src/main/java/com/juick/api/controllers/Others.java b/juick-api/src/main/java/com/juick/api/controllers/Others.java index e2d802d8..852c03d6 100644 --- a/juick-api/src/main/java/com/juick/api/controllers/Others.java +++ b/juick-api/src/main/java/com/juick/api/controllers/Others.java @@ -1,8 +1,8 @@ package com.juick.api.controllers; import com.juick.User; -import com.juick.api.util.HttpForbiddenException; -import com.juick.api.util.HttpNotFoundException; +import com.juick.server.util.HttpForbiddenException; +import com.juick.server.util.HttpNotFoundException; import com.juick.server.helpers.PrivateChats; import com.juick.service.PMQueriesService; import com.juick.service.UserService; diff --git a/juick-api/src/main/java/com/juick/api/controllers/PM.java b/juick-api/src/main/java/com/juick/api/controllers/PM.java index c928a11e..ffbea4b5 100644 --- a/juick-api/src/main/java/com/juick/api/controllers/PM.java +++ b/juick-api/src/main/java/com/juick/api/controllers/PM.java @@ -2,8 +2,8 @@ package com.juick.api.controllers; import com.juick.User; import com.juick.api.ApiServer; -import com.juick.api.util.HttpBadRequestException; -import com.juick.api.util.HttpForbiddenException; +import com.juick.server.util.HttpBadRequestException; +import com.juick.server.util.HttpForbiddenException; import com.juick.service.PMQueriesService; import com.juick.service.UserService; import com.juick.util.UserUtils; diff --git a/juick-api/src/main/java/com/juick/api/controllers/Post.java b/juick-api/src/main/java/com/juick/api/controllers/Post.java index 6d273f7a..53cfc3e5 100644 --- a/juick-api/src/main/java/com/juick/api/controllers/Post.java +++ b/juick-api/src/main/java/com/juick/api/controllers/Post.java @@ -2,10 +2,10 @@ package com.juick.api.controllers; import com.juick.User; import com.juick.api.ApiServer; -import com.juick.api.util.HttpBadRequestException; -import com.juick.api.util.HttpForbiddenException; -import com.juick.api.util.HttpNotFoundException; -import com.juick.api.util.HttpUtils; +import com.juick.server.util.HttpBadRequestException; +import com.juick.server.util.HttpForbiddenException; +import com.juick.server.util.HttpNotFoundException; +import com.juick.server.util.HttpUtils; import com.juick.service.MessagesService; import com.juick.service.SubscriptionService; import com.juick.service.UserService; diff --git a/juick-api/src/main/java/com/juick/api/controllers/Subscriptions.java b/juick-api/src/main/java/com/juick/api/controllers/Subscriptions.java index 42be9903..b93ec1f3 100644 --- a/juick-api/src/main/java/com/juick/api/controllers/Subscriptions.java +++ b/juick-api/src/main/java/com/juick/api/controllers/Subscriptions.java @@ -2,8 +2,8 @@ package com.juick.api.controllers; import com.juick.Message; import com.juick.User; -import com.juick.api.util.HttpBadRequestException; -import com.juick.api.util.HttpForbiddenException; +import com.juick.server.util.HttpBadRequestException; +import com.juick.server.util.HttpForbiddenException; import com.juick.service.MessagesService; import com.juick.service.SubscriptionService; import com.juick.service.UserService; diff --git a/juick-api/src/main/java/com/juick/api/controllers/Users.java b/juick-api/src/main/java/com/juick/api/controllers/Users.java index 396a716c..d6035cf2 100644 --- a/juick-api/src/main/java/com/juick/api/controllers/Users.java +++ b/juick-api/src/main/java/com/juick/api/controllers/Users.java @@ -1,8 +1,8 @@ package com.juick.api.controllers; import com.juick.User; -import com.juick.api.util.HttpForbiddenException; -import com.juick.api.util.HttpNotFoundException; +import com.juick.server.util.HttpForbiddenException; +import com.juick.server.util.HttpNotFoundException; import com.juick.service.UserService; import com.juick.util.UserUtils; import com.juick.util.WebUtils; diff --git a/juick-api/src/test/java/com/juick/api/tests/MessagesTests.java b/juick-api/src/test/java/com/juick/api/tests/MessagesTests.java index e0f9b840..9f74c00d 100644 --- a/juick-api/src/test/java/com/juick/api/tests/MessagesTests.java +++ b/juick-api/src/test/java/com/juick/api/tests/MessagesTests.java @@ -38,6 +38,7 @@ import static org.mockito.Mockito.when; import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.httpBasic; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.options; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; /** @@ -173,12 +174,10 @@ public class MessagesTests { @Test public void homeTestWithMessagesAndRememberMe() throws Exception { - String ugnichName = "ugnich"; - String uginchPassword = "MyPassw0rd!"; String msgText = "Привет, я - Угнич"; String hash = "12345678"; - User user = getUser(1, ugnichName, uginchPassword); + User user = getUser(1, ugnichName, ugnichPassword); Message msg = getMessage(user, msgText); when(userService.getUIDbyName(ugnichName)) @@ -198,7 +197,7 @@ public class MessagesTests { mockMvc.perform( get("/home") - .with(httpBasic(ugnichName, uginchPassword))) + .with(httpBasic(ugnichName, ugnichPassword))) .andExpect(status().isOk()) .andReturn(); @@ -211,11 +210,8 @@ public class MessagesTests { } @Test - public void homeTestWithMEssagesAndSimpleCors() throws Exception { - String ugnichName = "ugnich"; - String uginchPassword = "MyPassw0rd!"; - - User user = getUser(1, ugnichName, uginchPassword); + public void homeTestWithMessagesAndSimpleCors() throws Exception { + User user = getUser(1, ugnichName, ugnichPassword); Message msg = getMessage(user, null); when(userService.getFullyUserByName(ugnichName)) @@ -229,7 +225,7 @@ public class MessagesTests { mockMvc.perform( get("/home") - .with(httpBasic(ugnichName, uginchPassword)) + .with(httpBasic(ugnichName, ugnichPassword)) .header("Origin", "http://api.example.net")) .andExpect(status().isOk()) .andExpect(header().string("Access-Control-Allow-Origin", "*")); @@ -237,16 +233,13 @@ public class MessagesTests { @Test public void homeTestWithPreflightCors() throws Exception { - String ugnichName = "ugnich"; - String uginchPassword = "MyPassw0rd!"; - - User user = getUser(1, ugnichName, uginchPassword); + User user = getUser(1, ugnichName, ugnichPassword); when(userService.getFullyUserByName(ugnichName)) .thenReturn(user); mockMvc.perform( options("/home") - .with(httpBasic(ugnichName, uginchPassword)) + .with(httpBasic(ugnichName, ugnichPassword)) .header("Origin", "http://api.example.net") .header("Access-Control-Request-Method", "POST") .header("Access-Control-Request-Headers", "X-PINGOTHER, Content-Type")) @@ -291,4 +284,11 @@ public class MessagesTests { .andExpect(jsonPath("$", hasSize(1))) .andExpect(jsonPath("$[0].messages", is(5))); } + @Test + public void postWithReferer() throws Exception { + mockMvc.perform(post("/post") + .param("body", "yo") + .with(httpBasic(ugnichName, ugnichPassword))) + .andExpect(status().isOk()); + } } diff --git a/juick-api/src/main/java/com/juick/api/util/HttpBadRequestException.java b/juick-server/src/main/java/com/juick/server/util/HttpBadRequestException.java index 3a42e999..cd862830 100644 --- a/juick-api/src/main/java/com/juick/api/util/HttpBadRequestException.java +++ b/juick-server/src/main/java/com/juick/server/util/HttpBadRequestException.java @@ -1,4 +1,4 @@ -package com.juick.api.util; +package com.juick.server.util; import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.ResponseStatus; diff --git a/juick-api/src/main/java/com/juick/api/util/HttpForbiddenException.java b/juick-server/src/main/java/com/juick/server/util/HttpForbiddenException.java index d8f4ddf3..7e85816e 100644 --- a/juick-api/src/main/java/com/juick/api/util/HttpForbiddenException.java +++ b/juick-server/src/main/java/com/juick/server/util/HttpForbiddenException.java @@ -1,4 +1,4 @@ -package com.juick.api.util; +package com.juick.server.util; import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.ResponseStatus; diff --git a/juick-api/src/main/java/com/juick/api/util/HttpNotFoundException.java b/juick-server/src/main/java/com/juick/server/util/HttpNotFoundException.java index 14f34cf0..378eadfc 100644 --- a/juick-api/src/main/java/com/juick/api/util/HttpNotFoundException.java +++ b/juick-server/src/main/java/com/juick/server/util/HttpNotFoundException.java @@ -1,4 +1,4 @@ -package com.juick.api.util; +package com.juick.server.util; import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.ResponseStatus; diff --git a/juick-api/src/main/java/com/juick/api/util/HttpUtils.java b/juick-server/src/main/java/com/juick/server/util/HttpUtils.java index ca75eae7..fa0b2ec2 100644 --- a/juick-api/src/main/java/com/juick/api/util/HttpUtils.java +++ b/juick-server/src/main/java/com/juick/server/util/HttpUtils.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -package com.juick.api.util; +package com.juick.server.util; import org.apache.commons.codec.digest.DigestUtils; import org.slf4j.Logger; diff --git a/juick-server/src/main/java/com/juick/service/EmailService.java b/juick-server/src/main/java/com/juick/service/EmailService.java new file mode 100644 index 00000000..f62f4b32 --- /dev/null +++ b/juick-server/src/main/java/com/juick/service/EmailService.java @@ -0,0 +1,8 @@ +package com.juick.service; + +/** + * Created by vitalyster on 09.12.2016. + */ +public interface EmailService { + boolean verifyAddressByCode(Integer userId, String code); +} diff --git a/juick-server/src/main/java/com/juick/service/EmailServiceImpl.java b/juick-server/src/main/java/com/juick/service/EmailServiceImpl.java new file mode 100644 index 00000000..bdd78609 --- /dev/null +++ b/juick-server/src/main/java/com/juick/service/EmailServiceImpl.java @@ -0,0 +1,33 @@ +package com.juick.service; + +import org.springframework.dao.EmptyResultDataAccessException; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.stereotype.Repository; +import org.springframework.transaction.annotation.Transactional; + +import javax.inject.Inject; + +/** + * Created by vitalyster on 09.12.2016. + */ +@Repository +@Transactional +public class EmailServiceImpl extends BaseJdbcService implements EmailService { + @Inject + public EmailServiceImpl(JdbcTemplate jdbcTemplate) { + super(jdbcTemplate, null); + } + + @Override + public boolean verifyAddressByCode(Integer userId, String code) { + try { + String address = getJdbcTemplate().queryForObject("SELECT account FROM auth WHERE user_id=? AND protocol='email' AND authcode=?", + String.class, userId, code); + getJdbcTemplate().update("INSERT INTO emails(user_id,email) VALUES (?,?)", userId, address); + getJdbcTemplate().update("DELETE FROM auth WHERE user_id=? AND authcode=?", userId, code); + } catch (EmptyResultDataAccessException e) { + return false; + } + return true; + } +} diff --git a/juick-spring-www/src/main/java/com/juick/www/controllers/HelpController.java b/juick-spring-www/src/main/java/com/juick/www/controllers/HelpController.java index dad3ff9f..49e24c8c 100644 --- a/juick-spring-www/src/main/java/com/juick/www/controllers/HelpController.java +++ b/juick-spring-www/src/main/java/com/juick/www/controllers/HelpController.java @@ -1,12 +1,68 @@ package com.juick.www.controllers; +import com.juick.User; +import com.juick.server.util.HttpNotFoundException; +import com.juick.service.UserService; +import com.juick.util.UserUtils; +import org.springframework.core.io.ClassPathResource; import org.springframework.stereotype.Controller; +import org.springframework.ui.ModelMap; +import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; +import javax.inject.Inject; +import java.io.IOException; +import java.net.URISyntaxException; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.security.Principal; +import java.util.Optional; +import java.util.stream.Collectors; + /** * Created by aalexeev on 11/21/16. */ @Controller -@RequestMapping("/help") public class HelpController { + @Inject + UserService userService; + + @RequestMapping({"/help", "/help/{lang}", "/help/{lang}/{page}"}) + protected String doGetHelp( + Principal principal, + @PathVariable("lang") Optional<String> lang, + @PathVariable("page") Optional<String> page, + ModelMap model) throws IOException, URISyntaxException { + String name = UserUtils.getUsername(principal, null); + User visitor = userService.getUserByName(name); + + lang.ifPresent(l -> { + if (l.length() != 2 || !l.matches("^[a-z]+$")) { + throw new HttpNotFoundException(); + } + }); + if (!lang.isPresent()) { + lang = Optional.of("ru"); + } + + page.ifPresent(p -> { + if (!p.matches("^[a-zA-Z0-9\\-]*$") || p.equals("navigation") || p.equals("index")) { + throw new HttpNotFoundException(); + } + }); + if (!page.isPresent()) { + page = Optional.of("index"); + } + + String filePath = "help/" + lang.get() + "/" + page.get(); + String navigationPath = "help/" + lang.get() + "/navigation"; + + model.addAttribute("title", "Помощь"); + model.addAttribute("visitor", visitor); + model.addAttribute("help_nav", Files.readAllLines(Paths.get(new ClassPathResource(navigationPath).getURI())) + .stream().collect(Collectors.joining())); + model.addAttribute("help_data", Files.readAllLines(Paths.get(new ClassPathResource(filePath).getURI())) + .stream().collect(Collectors.joining())); + return "views/help"; + } } diff --git a/juick-spring-www/src/main/java/com/juick/www/controllers/IndexController.java b/juick-spring-www/src/main/java/com/juick/www/controllers/IndexController.java index 2973bf30..91efd8aa 100644 --- a/juick-spring-www/src/main/java/com/juick/www/controllers/IndexController.java +++ b/juick-spring-www/src/main/java/com/juick/www/controllers/IndexController.java @@ -1,9 +1,26 @@ package com.juick.www.controllers; +import com.juick.Message; +import com.juick.User; +import com.juick.service.MessagesService; +import com.juick.service.TagService; +import com.juick.service.UserService; +import com.juick.util.UserUtils; +import com.juick.www.util.EncodeUtils; +import org.apache.commons.lang3.StringEscapeUtils; +import org.apache.commons.lang3.StringUtils; import org.springframework.stereotype.Controller; -import org.springframework.ui.Model; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.ui.ModelMap; +import org.springframework.web.bind.annotation.*; + +import javax.inject.Inject; +import java.io.IOException; +import java.net.URLEncoder; +import java.security.Principal; +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; +import java.util.stream.Collectors; /** * Created by aalexeev on 11/21/16. @@ -11,14 +28,94 @@ import org.springframework.web.bind.annotation.RequestParam; @Controller public class IndexController { - @RequestMapping("/") - public String index( - java.security.Principal userPrincipal, - @RequestParam(required = false, defaultValue = "0") int before, - Model model) { + @Inject + UserService userService; + @Inject + MessagesService messagesService; + @Inject + TagService tagService; + + @RequestMapping(value = "/", method = RequestMethod.GET) + protected String doGet( + Principal principal, + @CookieValue("ref") Optional<String> ref, + @RequestHeader("Referer") Optional<String> referer, + @RequestParam("show") Optional<String> paramShow, + @RequestParam("tag") Optional<String> paramTagStr, + @RequestParam(value = "before", required = false) Integer paramBefore, + @RequestParam(value = "search", required = false) String paramSearch, + ModelMap model) throws IOException { + + if (paramTagStr.isPresent()) { + return "redirect:/tag/" + URLEncoder.encode(paramTagStr.get(), "UTF-8"); + } + + if (StringUtils.isNotEmpty(paramSearch) && paramSearch.length() > 64) { + paramSearch = ""; + } + + String name = UserUtils.getUsername(principal, null); + User visitor = userService.getUserByName(name); - model.addAttribute("currentUser", userPrincipal); + String title; + if (visitor.getUid() > 0) { + title = "Популярные"; + } else { + title = "Микроблоги Juick: популярные записи"; + } + List<Integer> mids = new ArrayList<>(); - return "index"; + if (StringUtils.isNotEmpty(paramSearch)) { + title = "Поиск: " + StringEscapeUtils.escapeHtml4(paramSearch); + mids = messagesService.getSearch(EncodeUtils.encodeSphinx(paramSearch), + paramBefore); + } else if (!paramShow.isPresent()) { + mids = messagesService.getPopular(visitor.getUid(), paramBefore); + } else if (paramShow.get().equals("top")) { + return "redirect:/"; + } else if (paramShow.get().equals("my") && visitor.getUid() > 0) { + title = "Моя лента"; + mids = messagesService.getMyFeed(visitor.getUid(), paramBefore); + } else if (paramShow.get().equals("private") && visitor.getUid() > 0) { + title = "Приватные"; + mids = messagesService.getPrivate(visitor.getUid(), paramBefore); + } else if (paramShow.get().equals("discuss") && visitor.getUid() > 0) { + title = "Обсуждения"; + mids = messagesService.getDiscussions(visitor.getUid(), paramBefore); + } else if (paramShow.get().equals("recommended") && visitor.getUid() > 0) { + title = "Рекомендации"; + mids = messagesService.getRecommended(visitor.getUid(), paramBefore); + } else if (paramShow.get().equals("photos")) { + title = "Фотографии"; + mids = messagesService.getPhotos(visitor.getUid(), paramBefore); + } else if (paramShow.get().equals("all")) { + title = "Все сообщения"; + mids = messagesService.getAll(visitor.getUid(), paramBefore); + } + model.addAttribute("title", title); + model.addAttribute("visitor", visitor); + model.addAttribute("tags", tagService.getPopularTags()); + model.addAttribute("showAdv", true); + List<Message> msgs = messagesService.getMessages(mids); + List<Integer> blUIDs = userService.checkBL(visitor.getUid(), + msgs.stream().map(m -> m.getUser().getUid()).collect(Collectors.toList())); + model.addAttribute("msgs", + msgs.stream().map(msg -> { + msg.ReadOnly |= blUIDs.contains(msg.getUser().getUid()); + return msg; + }).collect(Collectors.toList()) + ); + if (mids.size() >= 20) { + String nextpage = "?before=" + mids.get(mids.size() - 1); + if (paramShow.isPresent()) { + nextpage += "&show=" + paramShow.get(); + } + if (StringUtils.isNotEmpty(paramSearch)) { + nextpage += "&search=" + paramSearch; + } + model.addAttribute("nextpage", nextpage); + } + //model.addAttribute("isModerator", userService.getModerators().contains(visitor.getUid())); + return "blog/index"; } } diff --git a/juick-spring-www/src/main/java/com/juick/www/controllers/SettingsController.java b/juick-spring-www/src/main/java/com/juick/www/controllers/SettingsController.java index eef41c38..a038389f 100644 --- a/juick-spring-www/src/main/java/com/juick/www/controllers/SettingsController.java +++ b/juick-spring-www/src/main/java/com/juick/www/controllers/SettingsController.java @@ -1,16 +1,76 @@ package com.juick.www.controllers; +import com.juick.User; +import com.juick.service.*; +import com.juick.util.UserUtils; +import org.apache.commons.lang3.StringUtils; import org.springframework.stereotype.Controller; +import org.springframework.ui.ModelMap; import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; + +import javax.inject.Inject; +import javax.servlet.ServletException; +import java.io.IOException; +import java.security.Principal; +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.IntStream; /** * Created by aalexeev on 11/21/16. */ @Controller public class SettingsController { + @Inject + UserService userService; + @Inject + TagService tagService; + @Inject + CrosspostService crosspostService; + @Inject + SubscriptionService subscriptionService; + @Inject + EmailService emailService; - @RequestMapping("/settings") - public String showSettings() { - return "index"; + @RequestMapping("settings") + public String showSettings( + Principal principal, + @RequestParam(required = false) String page, + @RequestParam(required = false) String code, + ModelMap context + ) throws ServletException, IOException { + String name = UserUtils.getUsername(principal, null); + User visitor = userService.getUserByName(name); + if (visitor.getUid() == 0) { + return "redirect:/login"; + } + List<String> pages = Arrays.asList("main", "password", "about", "auth-email", "privacy"); + if (StringUtils.isEmpty(page) || !pages.contains(page)) { + page = "main"; + } + context.put("title", "Настройки"); + context.put("visitor", visitor); + context.put("tags", tagService.getPopularTags()); + context.put("auths", userService.getAuthCodes(visitor)); + context.put("eopts", userService.getEmailOpts(visitor)); + context.put("ehash", userService.getEmailHash(visitor)); + context.put("emails", userService.getEmails(visitor)); + context.put("jids", userService.getAllJIDs(visitor)); + List<String> hours = IntStream.rangeClosed(0, 23).boxed() + .map(i -> StringUtils.leftPad(String.format("%d", i), 2, "0")).collect(Collectors.toList()); + context.put("hours", hours); + context.put("fbstatus", crosspostService.getFbCrossPostStatus(visitor.getUid())); + context.put("twitter_name", crosspostService.getTwitterName(visitor.getUid())); + context.put("telegram_name", crosspostService.getTelegramName(visitor.getUid())); + context.put("notify_options", subscriptionService.getNotifyOptions(visitor)); + context.put("userinfo", userService.getUserInfo(visitor)); + if (page.equals("auth-email")) { + String response = emailService.verifyAddressByCode(visitor.getUid(), code) ? + "OK!" : "Sorry, code unknown."; + context.put("result", response); + } + return String.format("views/settings_%s", page); } } diff --git a/juick-spring-www/src/main/java/com/juick/www/controllers/TagController.java b/juick-spring-www/src/main/java/com/juick/www/controllers/TagController.java index 5c3b6287..0961f683 100644 --- a/juick-spring-www/src/main/java/com/juick/www/controllers/TagController.java +++ b/juick-spring-www/src/main/java/com/juick/www/controllers/TagController.java @@ -1,14 +1,28 @@ package com.juick.www.controllers; +import com.juick.Message; +import com.juick.User; +import com.juick.server.util.HttpNotFoundException; +import com.juick.service.AdsService; import com.juick.service.MessagesService; import com.juick.service.TagService; +import com.juick.service.UserService; +import com.juick.util.UserUtils; +import com.juick.www.helpers.QueryString; +import org.apache.commons.lang3.StringEscapeUtils; import org.springframework.stereotype.Controller; -import org.springframework.ui.Model; +import org.springframework.ui.ModelMap; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import javax.inject.Inject; +import java.io.UnsupportedEncodingException; +import java.net.URLEncoder; +import java.security.Principal; +import java.util.List; +import java.util.Optional; +import java.util.stream.Collectors; /** * Created by aalexeev on 11/21/16. @@ -19,15 +33,75 @@ public class TagController { private TagService tagService; @Inject private MessagesService messagesService; + @Inject + private AdsService adsService; + @Inject + private UserService userService; @RequestMapping("/tag/{tagName}") - public String showTags( - @PathVariable String tagName, - @RequestParam(required = false, defaultValue = "0") int before, - Model model) { + protected String doGet( + Principal principal, + @PathVariable("tagName") String paramTagStr, + @RequestParam(value = "before", required = false, defaultValue = "0") Integer paramBefore, + @QueryString Optional<String> queryString, + ModelMap model) throws UnsupportedEncodingException { + String name = UserUtils.getUsername(principal, null); + User visitor = userService.getUserByName(name); + + com.juick.Tag paramTag = tagService.getTag(paramTagStr, false); + if (paramTag == null) { + throw new HttpNotFoundException(); + } else if (paramTag.SynonymID > 0 && paramTag.TID != paramTag.SynonymID) { + com.juick.Tag synTag = tagService.getTag(paramTag.SynonymID); + String url = "/tag/" + URLEncoder.encode(synTag.getName(), "UTF-8"); + if (queryString.isPresent()) { + url += "?" + queryString.get(); + } + return "redirect:" + url; + } else if (!paramTag.getName().equals(paramTagStr)) { + String url = "/tag/" + URLEncoder.encode(paramTag.getName(), "UTF-8"); + if (queryString.isPresent()) { + url += "?" + queryString.get(); + } + return "redirect:" + url; + } + + int visitor_uid = visitor != null ? visitor.getUid() : 0; - return "index"; + String title = "*" + StringEscapeUtils.escapeHtml4(paramTag.getName()); + List<Integer> mids = messagesService.getTag(paramTag.TID, visitor_uid, paramBefore, (visitor == null) ? 40 : 20); + model.addAttribute("title", title); + if (tagService.getTagNoIndex(paramTag.TID)) { + model.addAttribute("headers", "<meta name=\"robots\" content=\"noindex,nofollow\"/>"); + } else if (paramBefore > 0 || mids.size() < 5) { + model.addAttribute("headers", "<meta name=\"robots\" content=\"noindex\"/>"); + } + if (mids.size() > 0) { + int vuid = visitor != null ? visitor.getUid() : 0; + int ad_mid = adsService.getAdMid(vuid); + if (ad_mid > 0 && mids.indexOf(ad_mid) == -1) { + mids.add(0, ad_mid); + adsService.logAdMid(vuid, ad_mid); + } else { + ad_mid = 0; + } + } + model.addAttribute("visitor", visitor); + List<Message> msgs = messagesService.getMessages(mids); + List<Integer> blUIDs = userService.checkBL(visitor_uid, + msgs.stream().map(m -> m.getUser().getUid()).collect(Collectors.toList())); + model.addAttribute("msgs", + msgs.stream().map(msg -> { + msg.ReadOnly |= blUIDs.contains(msg.getUser().getUid()); + return msg; + }).collect(Collectors.toList()) + ); + if (mids.size() >= 20) { + String nextpage = "/tag/" + URLEncoder.encode(paramTag.getName(), "UTF-8") + "?before=" + mids.get(mids.size() - 1); + model.addAttribute("nextpage", nextpage); + } + return "blog/index"; } @RequestMapping("/tag") diff --git a/juick-spring-www/src/main/java/com/juick/www/helpers/QueryString.java b/juick-spring-www/src/main/java/com/juick/www/helpers/QueryString.java new file mode 100644 index 00000000..0eb6c76f --- /dev/null +++ b/juick-spring-www/src/main/java/com/juick/www/helpers/QueryString.java @@ -0,0 +1,14 @@ +package com.juick.www.helpers; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Created by vt on 22/03/16. + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.PARAMETER) +public @interface QueryString { +}
\ No newline at end of file diff --git a/juick-spring-www/src/main/java/com/juick/www/helpers/QueryStringResolver.java b/juick-spring-www/src/main/java/com/juick/www/helpers/QueryStringResolver.java new file mode 100644 index 00000000..812c4497 --- /dev/null +++ b/juick-spring-www/src/main/java/com/juick/www/helpers/QueryStringResolver.java @@ -0,0 +1,31 @@ +package com.juick.www.helpers; + +import org.springframework.core.MethodParameter; +import org.springframework.web.bind.support.WebDataBinderFactory; +import org.springframework.web.context.request.NativeWebRequest; +import org.springframework.web.method.support.HandlerMethodArgumentResolver; +import org.springframework.web.method.support.ModelAndViewContainer; + +import javax.servlet.http.HttpServletRequest; +import java.lang.annotation.Annotation; +import java.util.Optional; + +public class QueryStringResolver implements HandlerMethodArgumentResolver { + @Override + public boolean supportsParameter(MethodParameter parameter) { + Annotation[] parameterAnnotations = parameter.getParameterAnnotations(); + for (Annotation parameterAnnotation : parameterAnnotations) { + if (QueryString.class.isInstance(parameterAnnotation)) { + return true; + } + } + + return false; + } + + @Override + public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception { + HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class); + return Optional.ofNullable(request.getQueryString()); + } +}
\ No newline at end of file diff --git a/juick-spring-www/src/main/java/com/juick/www/util/EncodeUtils.java b/juick-spring-www/src/main/java/com/juick/www/util/EncodeUtils.java new file mode 100644 index 00000000..a444ec4d --- /dev/null +++ b/juick-spring-www/src/main/java/com/juick/www/util/EncodeUtils.java @@ -0,0 +1,10 @@ +package com.juick.www.util; + +/** + * Created by vitalyster on 09.12.2016. + */ +public class EncodeUtils { + public static String encodeSphinx(String str) { + return str.replaceAll("@", "\\\\@"); + } +} diff --git a/juick-spring-www/src/main/webapp/WEB-INF/templates/layout/mainLayout.html b/juick-spring-www/src/main/webapp/WEB-INF/templates/layout/mainLayout.html index bbee7f6a..61062a3b 100644 --- a/juick-spring-www/src/main/webapp/WEB-INF/templates/layout/mainLayout.html +++ b/juick-spring-www/src/main/webapp/WEB-INF/templates/layout/mainLayout.html @@ -11,53 +11,21 @@ <script type="text/javascript" src="/scripts.js" th:href="@{/scripts.js}"></script> <title layout:title-pattern="$LAYOUT_TITLE - $CONTENT_TITLE">Juick.com</title> - + <meta layout:fragment="headers" /> <link rel="icon" href="//i.juick.com/favicon.png"/> <!--[if lt IE 9 & (!IEMobile 7)]> <script src="//cdnjs.cloudflare.com/ajax/libs/html5shiv/3.7.3/html5shiv.min.js"></script> <![endif]--> </head> <body> - -<section layout:fragment="content"> +<div th:replace="views/partial/navigation">Navigation block</div> +<section id="content"> + <p layout:fragment="content">Main content</p> </section> +<aside id="column"> + <p layout:fragment="column">Side column</p> +</aside> -<footer> - <div layout:fragment="custom-footer"></div> - <div id="footer"> - <div id="footer-right"> - <a href="/settings" th:href="@{/settings}" rel="nofollow" th:text="#{link.settings}">Настройки</a> · - <a href="/help/contacts" th:href="@{/help/contacts}" rel="nofollow" th:text="#{link.contacts}">Контакты</a> · - <a href="/help/" th:href="@{/help}" rel="nofollow" th:text="#{link.help}">Справка</a> · - <a href="/help/adv" th:href="@{/help/adv}" rel="nofollow" th:text="#{link.adv}">Реклама</a> - </div> - <div id="footer-social"> - <a href="https://twitter.com/Juick" rel="nofollow" class="ico32-twi">Twitter</a> - <a href="https://vk.com/juick" rel="nofollow" class="ico32-vk">VK</a> - <a href="https://www.facebook.com/JuickCom" rel="nofollow" class="ico32-fb">Facebook</a> - </div> - <div id="footer-left"> - <a href="juick.com">juick.com</a> © 2008-2016 - <div th:replace="${@settingsHolder.isShowSponsors()} ? ~{layout/sponsors :: sponsors} : _"></div> - </div> - </div> - <script> - (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){ - (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o), - m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m) - })(window,document,'script','//www.google-analytics.com/analytics.js','ga'); - ga('create','UA-385578-4','juick.com'); - ga('require','displayfeatures'); - ga('send','pageview'); - </script> - <script th:if="${@settingsHolder.isShowSape()}"> - var _acic={dataProvider:10}; - (function(){ - var e=document.createElement('script');e.type='text/javascript';e.async=true;e.src='//www2.aci'+'nt.net/aci.js'; - var t=document.getElementsByTagName('script')[0];t.parentNode.insertBefore(e,t); - })(); - </script> - </div> -</footer> +<footer th:replace="views/partial/footer">Footer</footer> </body> </html>
\ No newline at end of file diff --git a/juick-spring-www/src/main/webapp/WEB-INF/templates/layout/sponsors.html b/juick-spring-www/src/main/webapp/WEB-INF/templates/layout/sponsors.html deleted file mode 100644 index 6c68a867..00000000 --- a/juick-spring-www/src/main/webapp/WEB-INF/templates/layout/sponsors.html +++ /dev/null @@ -1,8 +0,0 @@ -<!DOCTYPE html> -<html xmlns:th="http://www.thymeleaf.org"> -<body> -<div th:fragment="sponsors"> - <span th:text="#{label.sponsors}">Спонсоры:</span> -</div> -</body> -</html>
\ No newline at end of file diff --git a/juick-spring-www/src/main/webapp/WEB-INF/templates/views/help.html b/juick-spring-www/src/main/webapp/WEB-INF/templates/views/help.html new file mode 100644 index 00000000..0500839b --- /dev/null +++ b/juick-spring-www/src/main/webapp/WEB-INF/templates/views/help.html @@ -0,0 +1,18 @@ +<!DOCTYPE html> +<html xmlns:th="http://www.thymeleaf.org" + xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout" + layout:decorate="~{layout/mainLayout}"> +<head> + <title th:text="${title}">Help title</title> +</head> + +<body> +<section id="content"> + <article layout:fragment="content" th:utext="${help_data}">Help text</article> +</section> +<aside id="column"> + <p layout:fragment="column" th:utext="${help_nav}">Help navigation</p> +</aside> + +</body> +</html>
\ No newline at end of file diff --git a/juick-spring-www/src/main/webapp/WEB-INF/templates/views/partial/footer.html b/juick-spring-www/src/main/webapp/WEB-INF/templates/views/partial/footer.html new file mode 100644 index 00000000..6978a2c0 --- /dev/null +++ b/juick-spring-www/src/main/webapp/WEB-INF/templates/views/partial/footer.html @@ -0,0 +1,34 @@ +<div id="footer"> + <div id="footer-right"> + <a href="/settings" rel="nofollow">Настройки</a> · + <a href="/help/ru/contacts" rel="nofollow">Контакты</a> · + <a href="/help/" rel="nofollow">Справка</a> · + <a href="/help/ru/adv" rel="nofollow">Реклама</a> + </div> + <div id="footer-social"> + <a href="https://twitter.com/Juick" rel="nofollow" class="ico32-twi">Twitter</a> + <a href="https://vk.com/juick" rel="nofollow" class="ico32-vk">ВКонтакте</a> + <a href="https://www.facebook.com/JuickCom" rel="nofollow" class="ico32-fb">Facebook</a> + </div> + <div id="footer-left">juick.com © 2008-2016 + {% if links %} + <br/>Спонсоры: {{ links }} + {% endif %} + </div> +</div> +<script> + (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){ + (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o), + m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m) + })(window,document,'script','//www.google-analytics.com/analytics.js','ga'); + ga('create','UA-385578-4','juick.com'); + ga('require','displayfeatures'); + ga('send','pageview'); + {% if (sapeon) %} + var _acic={dataProvider:10}; + (function(){ + var e=document.createElement('script');e.type='text/javascript';e.async=true;e.src='//www2.aci'+'nt.net/aci.js'; + var t=document.getElementsByTagName('script')[0];t.parentNode.insertBefore(e,t); + })(); + {% endif %} +</script>
\ No newline at end of file diff --git a/juick-spring-www/src/main/webapp/WEB-INF/templates/views/partial/homecolumn.html b/juick-spring-www/src/main/webapp/WEB-INF/templates/views/partial/homecolumn.html new file mode 100644 index 00000000..5293918d --- /dev/null +++ b/juick-spring-www/src/main/webapp/WEB-INF/templates/views/partial/homecolumn.html @@ -0,0 +1,6 @@ +<p class="tags"> + {% include "views/partial/tags.html" %} + {% if showAdv %} + <a href="http://ru.wix.com/">конструктор сайтов</a> + {% endif %} +</p>
\ No newline at end of file diff --git a/juick-spring-www/src/main/webapp/WEB-INF/templates/views/partial/navigation.html b/juick-spring-www/src/main/webapp/WEB-INF/templates/views/partial/navigation.html new file mode 100644 index 00000000..2863d0c3 --- /dev/null +++ b/juick-spring-www/src/main/webapp/WEB-INF/templates/views/partial/navigation.html @@ -0,0 +1,37 @@ +<header> + <div id="logo"><a href="/">Juick</a></div> + <nav id="global"> + <ul> + <li><a href="/">Популярные</a></li> + <li><a href="/?show=all" rel="nofollow">Все сообщения</a></li> + <li><a href="/?show=photos" rel="nofollow">Фотографии</a></li> + </ul> + </nav> + <div id="search"> + <form action="/"> + <input type="text" name="search" class="text" placeholder="Поиск" value="{{ search }}"/> + </form> + </div> + <section id="headdiv"> + {% if visitor.getUID() > 0 %} + <nav id="user"> + <ul> + <li><a href="/?show=my">Моя лента</a></li> + <li><a href="/pm/inbox">Приватные</a></li> + <li><a href="/?show=discuss">Обсуждения</a></li> + <li><a href="/?show=recommended">Рекомендации</a></li> + </ul> + </nav> + <nav id="actions"> + <ul> + <li><a href="/#post">Написать</a></li> + <li><a href="/{{ visitor.getName() }}">@{{ visitor.getName() }}</a></li> + <li><a href="/logout">Выйти</a></li> + </ul> + </nav> + {% else %} + <p>Чтобы добавлять сообщения и комментарии, <a href="#" onclick="return Juick.openDialogLogin()">представьтесь</a>. + </p> + {% endif %} + </section> +</header> diff --git a/juick-spring-www/src/main/webapp/WEB-INF/templates/views/partial/settings_tabs.html b/juick-spring-www/src/main/webapp/WEB-INF/templates/views/partial/settings_tabs.html new file mode 100644 index 00000000..d7901d5e --- /dev/null +++ b/juick-spring-www/src/main/webapp/WEB-INF/templates/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-spring-www/src/main/webapp/WEB-INF/templates/views/partial/tags.html b/juick-spring-www/src/main/webapp/WEB-INF/templates/views/partial/tags.html new file mode 100644 index 00000000..4d05b7fb --- /dev/null +++ b/juick-spring-www/src/main/webapp/WEB-INF/templates/views/partial/tags.html @@ -0,0 +1,3 @@ +{% for tag in tags %} + <a href="/tag/{{ tag | urlencode }}" title="{{ tag }}">{{ tag }}</a> +{% endfor %}
\ No newline at end of file diff --git a/juick-spring-www/src/main/webapp/WEB-INF/templates/views/settings_about.html b/juick-spring-www/src/main/webapp/WEB-INF/templates/views/settings_about.html new file mode 100644 index 00000000..ff82b542 --- /dev/null +++ b/juick-spring-www/src/main/webapp/WEB-INF/templates/views/settings_about.html @@ -0,0 +1,31 @@ +<!DOCTYPE html> +<html xmlns:th="http://www.thymeleaf.org" + xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout" + layout:decorate="~{layout/mainLayout}"> +<head> + <title th:text="${title}">Settings title</title> +</head> + +<body> +<section id="content"> + <article layout:fragment="content"> + <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 "http://"</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, <50Kb. Also, JPG and GIF supported.</small></p> + <p><input type="hidden" name="page" value="about"/><input type="submit" value=" OK "/></p> + </form> + </article> +</section> +<aside id="column"> + <p th:replace="views/partial/settings/tabs">Settings navigation</p> +</aside> + +</body> +</html>
\ No newline at end of file diff --git a/juick-spring-www/src/main/webapp/WEB-INF/templates/views/settings_auth-email.html b/juick-spring-www/src/main/webapp/WEB-INF/templates/views/settings_auth-email.html new file mode 100644 index 00000000..d4788fd6 --- /dev/null +++ b/juick-spring-www/src/main/webapp/WEB-INF/templates/views/settings_auth-email.html @@ -0,0 +1,20 @@ +<!DOCTYPE html> +<html xmlns:th="http://www.thymeleaf.org" + xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout" + layout:decorate="~{layout/mainLayout}"> +<head> + <title th:text="${title}">Settings title</title> +</head> + +<body> +<section id="content"> + <article layout:fragment="content"> + <p th:text="${result}">Authentication result</p><p><a href="/settings">Settings</a>.</p> + </article> +</section> +<aside id="column"> + <p th:replace="views/partial/settings/tabs">Settings navigation</p> +</aside> + +</body> +</html>
\ No newline at end of file diff --git a/juick-spring-www/src/main/webapp/WEB-INF/templates/views/settings_main.html b/juick-spring-www/src/main/webapp/WEB-INF/templates/views/settings_main.html new file mode 100644 index 00000000..42eff2e3 --- /dev/null +++ b/juick-spring-www/src/main/webapp/WEB-INF/templates/views/settings_main.html @@ -0,0 +1,167 @@ +<!DOCTYPE html> +<html xmlns:th="http://www.thymeleaf.org" + xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout" + layout:decorate="~{layout/mainLayout}"> +<head> + <title th:text="${title}">Settings title</title> +</head> + +<body> +<section id="content"> + <article layout:fragment="content"> + <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 ("Message posted")</p> + <p><input type="checkbox" name="subscr_notify" value="1" {% if notify_options.isSubscriptionsEnabled() %} + checked="checked" {% endif %}/> Subscriptions notifications ("@user subscribed...")</p> + <p><input type="checkbox" name="recomm" value="1" {% if notify_options.isRecommendationsEnabled() %} + checked="checked" {% endif %}/> Posts recommendations ("Recommended by @user")</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> — + <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> + — <a href="#" + onclick="alert(\'To confirm, please send "AUTH {{ auth.getAuthCode() }}" (without quotes) from this account to "juick@juick.com".\'); 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> </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> — + <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> — + <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> — + <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> +</section> +<aside id="column"> + <p th:replace="views/partial/settings/tabs">Settings navigation</p> +</aside> + +</body> +</html>
\ No newline at end of file diff --git a/juick-spring-www/src/main/webapp/WEB-INF/templates/views/settings_password.html b/juick-spring-www/src/main/webapp/WEB-INF/templates/views/settings_password.html new file mode 100644 index 00000000..4c6e0d4d --- /dev/null +++ b/juick-spring-www/src/main/webapp/WEB-INF/templates/views/settings_password.html @@ -0,0 +1,26 @@ +<!DOCTYPE html> +<html xmlns:th="http://www.thymeleaf.org" + xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout" + layout:decorate="~{layout/mainLayout}"> +<head> + <title th:text="${title}">Settings title</title> +</head> + +<body> +<section id="content"> + <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> +</section> +<aside id="column"> + <p th:replace="views/partial/settings/tabs">Settings navigation</p> +</aside> + +</body> +</html>
\ No newline at end of file diff --git a/juick-spring-www/src/main/webapp/WEB-INF/templates/views/settings_result.html b/juick-spring-www/src/main/webapp/WEB-INF/templates/views/settings_result.html new file mode 100644 index 00000000..ddde1baf --- /dev/null +++ b/juick-spring-www/src/main/webapp/WEB-INF/templates/views/settings_result.html @@ -0,0 +1,18 @@ +<!DOCTYPE html> +<html xmlns:th="http://www.thymeleaf.org" + xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout" + layout:decorate="~{layout/mainLayout}"> +<head> + <title th:text="${title}">Settings title</title> +</head> + +<body> +<section id="content"> + <p th:utext="${result}">Settings update status</p> +</section> +<aside id="column"> + <p th:replace="views/partial/settings/tabs">Settings navigation</p> +</aside> + +</body> +</html>
\ No newline at end of file |